IBM Watson Retrieve and Rank から Watson Discovery に移行する

#IBM Watson Retrieve and Rank から Watson Discovery に移行する

Watson Retrieve and Rank(以下R&R)は、2017年10月に新規オーダーできなくなっていて、今使っているR&Rのインスタンスも2018年9月いっぱいで利用できなくなるそうです。
後継は Watson Discovery。
そこで、現在のデータをWatson Discoveryに移行することにしました。
単純にチュートリアルに従うだけでは移行できなかったので、その事も含めたメモ書きです。

Watson Discovery 自体に関しては、[この記事](https://qiita.com/ishida330/items/b823d7c5b55806f04242)が参考になります

#移行方法を決める
[Migrating from Watson Document Conversion and Retrieve and Rank](https://console.bluemix.net/docs/services/discovery/migrate-dcs-rr.html#migrating-from-watson-document-conversion-and-retrieve-and-rank) に機能比較や移行に関する情報がまとまっています。

> There are two practical options to migrate from Retrieve and Rank: migrating from source content, and migrating from indexed content. 

とあるようにR&Rを構築したソースデータでの移行する方法とR&Rのインスタンスから移行する方法あるようです。
ただし、

> This method is possible only if all the necessary content is in stored fields in Retrieve and Rank. If the content was only indexed but not stored, it will not be possible to query the content out of the service, and the data will have to be converted and split again from the source.

データをR&RのSolrを構築するときに、全データをストアしていない場合はインスタンスから移行できません。

今回は、構築済みR&Rを単純に一度だけ移行するのが目的ではなく、R&R用のデータの作成・更新の仕組みはそのまま使い、サービスだけをDiscoveryに切り替えることを想定しているので、ソースデータでの移行を行います。

#ソースデータによる移行
ソースデータによる移行のチュートリアルは [Tutorial: Migrating from Retrieve and Rank](https://console.bluemix.net/docs/services/discovery/migrate-rnr-tut.html#tutorial-migrating-from-retrieve-and-rank) です。
R&R用のjsonとcsvをそのまま使って、Discoveryのコレクションを構築します。

##準備
下記を準備します。

* R&R用のjsonとcsv
* cURL
* Python version 2
* [データのアップアップロード用スクリプト disco-upload.py](https://watson-developer-cloud.github.io/doc-tutorial-downloads/retrieve-and-rank/disco-upload.py)
* [トレーニング用スクリプト disco-train.py](https://watson-developer-cloud.github.io/doc-tutorial-downloads/retrieve-and-rank/disco-train.py)

なお、今回の実行環境はUbuntu 1604です。

##Discovery サービスの作成とクレデンシャルの確認
何はともあれコンソールからDiscovery サービスを作成します。
さらにクレデンシャルを確認します。
このように確認できます。

>{
  "url": "https://gateway.watsonplatform.net/discovery/api",
  "username": "63367fef-9d09-4be6-92fb-537a537f683e",
  "password": "1MJ1yLY7GYpF"
}

私は、こんな風に変数にして使います。

```
export USERNAME="63367fef-9d09-4be6-92fb-537a537f683e"
export PASSWORD="1MJ1yLY7GYpF"
```

##環境(Environment)の作成

まず、このように環境(Environment)を作ります。

```
curl -X POST -u $USERNAME:$PASSWORD -H "Content-Type: application/json" -d '{ "name": "my_environment", "description": "My environment" }' "https://gateway.watsonplatform.net/discovery/api/v1/environments?version=2017-11-07"
```

作成された環境のenvironment_idが返ってくるので

> {
  "environment_id" : "35059a8a-1d2d-455d-9cb8-bde58b990a2d",
  "name" : "my_environment",
  "description" : "My environment",
  "created" : "2017-11-30T01:27:14.008Z",
  "updated" : "2017-11-30T01:27:14.008Z",
  "status" : "active",
  "read_only" : false,
  "index_capacity" : {
    "documents" : {
      "available" : 0,
      "maximum_allowed" : 2000
    },
    "disk_usage" : {
      "used_bytes" : 0,
      "maximum_allowed_bytes" : 200000000
    },
    "collections" : {
      "available" : 0,
      "maximum_allowed" : 0
    }
  }
}

変数にセットしておきます。

```
export ENV_ID="35059a8a-1d2d-455d-9cb8-bde58b990a2d"
```

##コレクション(Collection)の作成

コレクションの作成ですが、チュートリアルでは、このようになっています。

> curl -X POST -u "{username}":"{password}" -H "Content-Type: application/json" -d '{ "name": "test_collection", "description": "My test collection", "configuration_id": "{configuration_id}", "language_code": "en" }' "https://gateway.watsonplatform.net/discovery/api/v1/environments/{environment_id}/collections?version=2017-11-07"

「configuration」に関しては、[Configuring your service](https://console.bluemix.net/docs/services/discovery/building.html#configuring-your-service) に情報があります。
指定しなければデフォルトが使われるので、指定しません。

また、言語設定を「language_code」として設定しているのは問題です。「"language_code": "ja"」としても、en のコレクションができてしまいました。正しくは「language」です。
はまりましたが、[こちらの記事](https://qiita.com/ishida330/items/b823d7c5b55806f04242)が役に立ちました。

結局、下記のように指定しました。

```
curl -X POST -u $USERNAME:$PASSWORD -H "Content-Type: application/json" -d '{  "name": "jp_collection",   "description": "My test collection",  "language": "ja" }' "https://gateway.watsonplatform.net/discovery/api/v1/environments/$ENV_ID/collections?version=2017-11-07"
```

作成されたコレクションのcollection_idが返ってくるので

> {
  "name" : "jp_collection",
  "collection_id" : "2d153ba2-3fdc-49a7-a076-63537e242b99",
  "description" : "My test collection",
  "created" : "2017-11-30T02:33:50.863Z",
  "updated" : "2017-11-30T02:33:50.863Z",
  "configuration_id" : "2004a693-8301-404a-87ff-1621580b8e75",
  "language" : "ja",
  "status" : "active"
}

変数にセットしておきます。

```
export COL_ID="2d153ba2-3fdc-49a7-a076-63537e242b99"
```

## json のアップロード

[データのアップアップロード用スクリプト disco-upload.py](https://watson-developer-cloud.github.io/doc-tutorial-downloads/retrieve-and-rank/disco-upload.py) を使ってjson形式の文書データをアップロードするのですが、2つ問題がありました。

ひとつめは、中で指定されているAPIバージョンが低いことです。バージョン指定が下記のように日本語が利用できない古いものが指定されていました。

> VERSION = '2017-09-01'

これを、下記にします。

> VERSION = '2017-11-07'

また、文書IDが整数であることを前提にしたスクリプトになっていました。
今回利用するJSONでは文書IDは「"id":  "97092C0FAD9B0513492580D10026EB57"」のような形式のため、文字列を受け入れるように修正しました。

>  curl_cmd = 'curl -X POST -u "%s" %s -F file=@%s "%s/%d?version=%s"' % (args.u, VERBOSE_CURL, DOCUMENT_FILENAME, COLLECTION_URL, doc_data['id'], VERSION)

の「%d」を「%s」にして

> curl_cmd = 'curl -X POST -u "%s" %s -F file=@%s "%s/%s?version=%s"' % (args.u, VERBOSE_CURL, DOCUMENT_FILENAME, COLLECTION_URL, doc_data['id'], VERSION)

にしました。

この修正で正常にアップロードできました。

```
python ./disco-upload.py -u $USERNAME:$PASSWORD -i RnR.json -e $ENV_ID -c $COL_ID
```

コレクションの確認を行います。

```
curl -u $USERNAME:$PASSWORD "https://gateway.watsonplatform.net/discovery/api/v1/environments/$ENV_ID/collections/$COL_ID?version=2017-11-07"
```

文書が登録されているのがわかります。

> {
  "collection_id" : "2d153ba2-3fdc-49a7-a076-63537e242b99",
  "name" : "jp_collection",
  "configuration_id" : "2004a693-8301-404a-87ff-1621580b8e75",
  "language" : "ja",
  "status" : "active",
  "description" : "My test collection",
  "created" : "2017-11-30T02:33:50.863Z",
  "updated" : "2017-11-30T02:33:50.863Z",
  "document_counts" : {
    "available" : 83,
    "processing" : 0,
    "failed" : 0
  },
  "disk_usage" : {
    "used_bytes" : 252247
  },
  "training_status" : {
    "data_updated" : "",
    "total_examples" : 0,
    "sufficient_label_diversity" : false,
    "processing" : false,
    "minimum_examples_added" : false,
    "successfully_trained" : "",
    "available" : false,
    "notices" : 0,
    "minimum_queries_added" : false
  }
}

## csv によるトレーニング

[トレーニング用スクリプト disco-train.py](https://watson-developer-cloud.github.io/doc-tutorial-downloads/retrieve-and-rank/disco-train.py) にもバージョン指定があるので修正します。

> VERSION = '2017-09-01'

これを、下記にします。

> VERSION = '2017-11-07'

トレーニングを実行します。

```
python ./disco-train.py -u $USERNAME:$PASSWORD -i RnR.csv -e $ENV_ID -c $COL_ID
```

コレクションの確認を行います。

```
curl -u $USERNAME:$PASSWORD "https://gateway.watsonplatform.net/discovery/api/v1/environments/$ENV_ID/collections/$COL_ID?version=2017-11-07"
```

しばらく「training_status」の「"processing" : true」になります。

> {
  "collection_id" : "2d153ba2-3fdc-49a7-a076-63537e242b99",
  "name" : "jp_collection",
  "configuration_id" : "2004a693-8301-404a-87ff-1621580b8e75",
  "language" : "ja",
  "status" : "active",
  "description" : "My test collection",
  "created" : "2017-11-30T02:33:50.863Z",
  "updated" : "2017-11-30T02:33:50.863Z",
  "document_counts" : {
    "available" : 83,
    "processing" : 0,
    "failed" : 0
  },
  "disk_usage" : {
    "used_bytes" : 252247
  },
  "training_status" : {
    "data_updated" : "2017-11-30T04:20:42.047Z",
    "total_examples" : 137,
    "sufficient_label_diversity" : false,
    "processing" : true,
    "minimum_examples_added" : true,
    "successfully_trained" : "",
    "available" : false,
    "notices" : 0,
    "minimum_queries_added" : true
  }
}

さらに待って、再度確認すると「training_status」は「"processing" : false」に戻り「"available" : true」になります。
これで準備OKです。

> {
  "collection_id" : "2d153ba2-3fdc-49a7-a076-63537e242b99",
  "name" : "jp_collection",
  "configuration_id" : "2004a693-8301-404a-87ff-1621580b8e75",
  "language" : "ja",
  "status" : "active",
  "description" : "My test collection",
  "created" : "2017-11-30T02:33:50.863Z",
  "updated" : "2017-11-30T02:33:50.863Z",
  "document_counts" : {
    "available" : 83,
    "processing" : 0,
    "failed" : 0
  },
  "disk_usage" : {
    "used_bytes" : 252247
  },
  "training_status" : {
    "data_updated" : "2017-11-30T04:12:52.259Z",
    "total_examples" : 137,
    "sufficient_label_diversity" : false,
    "processing" : false,
    "minimum_examples_added" : true,
    "successfully_trained" : "2017-11-30T04:23:57.117Z",
    "available" : true,
    "notices" : 0,
    "minimum_queries_added" : true
  }
}

## 検索

あとは検索するだけです。
検索には「query」と、より賢い「natural_language_query」があるそうです。

まず、検索文字列をutf-8でurlエンコーディングします。
(2018-05-14 長文対応に修正。参考: http://u-tamax.jp/2012/08/nkf%E3%81%A7url%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%89/ )

```
export Q=`echo -n "検索文字列 " | nkf -wMQ | sed 's/=$//g' | tr = % | tr -d "\n"`
```

「query」の場合は

```
curl -u $USERNAME:$PASSWORD "https://gateway.watsonplatform.net/discovery/api/v1/environments/$ENV_ID/collections/$COL_ID/query?version=2017-11-07&query=$Q"
```

「natural_language_query」の場合は

```
 curl -u $USERNAME:$PASSWORD "https://gateway.watsonplatform.net/discovery/api/v1/environments/$ENV_ID/collections/$COL_ID/query?version=2017-11-07&natural_language_query=$Q"
```

で検索します。

# まとめ
以前のR&Rに比べると構築ステップが、かなり少なくて済みます。Solrもなくなったので、Solr用のスキーマ設定もありません。その分、独自の単語、同義語、ストップワード設定はできなくなっています。

とりあえずR&RのデータそのままでDiscoveryによる検索ができるようになりました。
検索結果の比較やnatural_language_queryの有効性、Discoveryの特性に合わせたデータの追加・更新などを今後行いたいと思います。

なお、具体的なIDが入っていますが、この Discovery サービスは削除済みです。