LoginSignup
6
12

More than 3 years have passed since last update.

Watson Discovery(フルサポート版)に日本語大量文書を投入

Last updated at Posted at 2018-06-28

(2019-07-15) いつの間にかライブラリ名から新しくなってしまい、以下の記事が役にたたなくなってしまいました。新しい記事Jupyter NotebookからWatson Discoveryを操作する(2019-07-15最新版)を書き直したので、今後はこちらを参照して下さい。

(2018-07-01) シドニーのサイトの場合の認証方式追記

はじめに

リリースノートに記載のとおり、2018-06-25にWatson Discoveryでようやく日本語のフルサポート(NLUによるアノテーション機能等が追加された)が行われました。
このタイミングで、日本語文書のテストをしてみたく、試すときに使ったJupyterNotebookを連携します。
試しに10000行のデータでやってみましたが、全件問題なくアップロードできました。
(10000行=10000件のデータ量はライトアカウントの場合上限を超えています。自分の環境でこのテストを行う場合、スタンダードライセンスが必要ですのでご注意下さい。)

Jupyternotebookのリンクはこちら

前提

Jupyter Notebook環境

Jupyter NotebookはWatson Studioのものを使っています。
Watson Develpoer CloudのライブラリはNotebookから
!pip install watson-developer-cloud
としてもいいのですが、Watson StudioのExvironment設定に以下の記述をして対応しました。

# Please add conda channels here
channels:
- defaults

# Please add conda packages here
dependencies:

# Please add pip packages here
# To add pip packages, please comment out the next line
- pip:
  - watson-developer-cloud==1.4.0

インスタンスの地域

(2018-07-01)
デフォルトの地域である「シドニー」でインスタンスを作ると、認証の方法が従来から変更になります。
この記事では従来型の「米国南部」ケースと両方のパターンを記載しました。

対象データ

以下の例では、こんな形式のCSVファイルを読み込んでアップロードすることを想定しています。
項目名、項目数はコードを変えれば変更可能な作りになっています。

image.png

手順解説

コレクション作成まで

Level2対応のタイミングでUIから日本語コレクションを作れるのかと思いきや、まだ多少時間がかかるようです。
なので、現時点は従来通りAPI呼出しでコレクション作成まで行う必要があります。

credentail情報設定

管理コンソールのcredentail情報をコピーします(アイコンクリックで可能)。
サイトにより情報は異なります。

【米国南部】

# 
credencial = {
  "url": "https://gateway.watsonplatform.net/discovery/api",
  "username": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "password": "xxxxxxxxxxxx"
}

【シドニー】

credencial = {
  "apikey": "xxxxxx",
  "iam_apikey_description": "xxxxxx",
  "iam_apikey_name": "xxxxxx",
  "iam_role_crn": "xxxxxx",
  "iam_serviceid_crn": "xxxxxx",
  "url": "https://gateway-syd.watsonplatform.net/discovery/api"
}

ライブラリ読み込み

このステップもサイトにより異なります。
この段階では、単に変数の定義をしているだけで、実際にAPIを発行するのはもう一つ先のステップになるので注意して下さい。

【米国南部】

import json
from watson_developer_cloud import DiscoveryV1
# In the constructor, letting the SDK manage the IAM token
discovery = DiscoveryV1(version = '2018-03-05',
                        username = credencial['username'],
                       password = credencial['password'])

【シドニー】

import json
from watson_developer_cloud import DiscoveryV1
discovery = DiscoveryV1(version='2018-03-05',
                        iam_api_key=credencial['apikey'],
                        url=credencial['url'])

environment_id取得

ここから先の手順はサイトによらず共通になります。
environment_idがすでにあるときはそのIDを取得、ない場合は新規に作成を行うスクリプトです。

environments = discovery.list_environments()['environments']
if len(environments) == 1 :
    # Environment作成
    response = discovery.create_environment(name="my_environment")
    environment_id = response['environment_id']
else :
    # 既存env_id取得
    environment_id = environments[1]['environment_id']

print('environment_id: ', environment_id)

collection_id取得

environment_id同様、すでにIDがある場合はその値を取得し、ない場合は新規に作成を行います。

collections = discovery.list_collections(environment_id = environment_id)['collections']
if len(collections) == 0:
    # Collection作成
    col_name = 'JP_TEST'
    collection = discovery.create_collection(
        environment_id = environment_id, 
        name = col_name, 
        language='ja')
    collection_id = collection['collection_id']
else:
    collection_id = collections[0]['collection_id']

print('collection_id: ', collection_id)

必要であれば、このタイミングでエンリッチ設定の変更を行います。
一度コレクションを日本語で作ってしまえば、エンリッチ設定変更はUIから可能です。

CSVファイル読込み

取り込みたいCSVファイルはあらかじめ、Watson Studioのデータアセットとしてアップロードしておきます。
以下のコードではCSVファイルの先頭行はヘッダ行になっている前提です。

下記のコードは、Watson StudioのJupyter固有のもので、Watson Studioのツールで自動生成したコードに一部手直しをする想定です。
普通にローカルのcsvを読み込むのであれば、普通にpd.read_csv関数呼び出しでOKです。
要は、このセルが終わった段階で、CSVデータがdf_dataに入っていればいいです。

infile = 'data_xxxxxx.csv'

# このセルは、ツール生成のものを一部手で修正します。

import sys
import types
import pandas as pd
from botocore.client import Config
import ibm_boto3

def __iter__(self): return 0

client_xxxxxx = ibm_boto3.client(service_name='s3',
    ibm_api_key_id='xxxxxx',
    ibm_auth_endpoint="https://iam.ng.bluemix.net/oidc/token",
    config=Config(signature_version='oauth'),
    endpoint_url='https://s3-api.us-geo.objectstorage.service.networklayer.com')

# Key=のパラメータは変数利用に修正しました
body = client_38bc5a04c29444d093d357a963ea4f0d.get_object(Bucket='xxxxxxx',Key=infile)['Body']
# add missing __iter__ method, so pandas accepts body as file-like object
if not hasattr(body, "__iter__"): body.__iter__ = types.MethodType( __iter__, body )

# DataFrame名は df_dataに修正しました
df_data = pd.read_csv(body)
df_data.head()

読み込んだデータをDiscovey Collectionに書き込み

以下のサンプルコードは、CSVの項目名がpat_id,pat_name,pat_sumamry,pat_textとなっていて、このうちのpat_textに対してエンリッチをかける前提のものです。
要件に応じて適宜修正をかけて下さい。
いきなり全量をアップロードすると、バグがあったとき面倒なので、

  • 最初は数行
  • うまくいったら100行程度
  • これでうまくいったら全量

の3段階でアップロードすることをお勧めします。

21件以上処理中なのに追加文書登録をするとエラーになるようなので、1件登録する度に現在何件処理中か確認して、危なそうな時はタイマーで待ちを入れるロジックを追加しています。

import os
import time
for i in range(len(df_data)):
    item = df_data.iloc[i,:]
    data = {}

    # 以下はCSVの項目名によって修正して下さい
    data['pat_id'] = str(item['pat_id'])
    data['pat_name'] = item['pat_name']
    data['summury'] = item['pat_summury']
    data['text'] = item['pat_text']
    # print(data)
    filename = data['pat_id'] + '.json'
    f = open(filename, 'w')
    json.dump(data, f)
    f.close()
    collection = discovery.get_collection(environment_id, collection_id)
    proc_docs = collection['document_counts']['processing']
    while True:
        if proc_docs < 20:
            break
        print('busy. waiting..')
        time.sleep(10)
        collection = discovery.get_collection(environment_id, collection_id)
        proc_docs = collection['document_counts']['processing']

    # print(json.dumps(collection, indent=2))
    with open(filename) as f:
        add_doc = discovery.add_document(environment_id, collection_id, file = f)
    os.remove(filename)
    # print(json.dumps(add_doc, indent=2))

(おまけ1)データ削除用スクリプト

テストでアップした少量データ削除用のスクリプトです。

# 文書件数取得
collection = discovery.get_collection(environment_id, collection_id)
doc_count = collection['document_counts']['available']

results = discovery.query(environment_id, collection_id, return_fields='id', count=doc_count)["results"]
ids = [item["id"] for item in results]

for id in ids:
    print('deleting doc: id =' + id)
    discovery.delete_document(environment_id, collection_id, id)

(おまけ2) 類似検索

Discoveryでは類似検索も可能です。手順は【マメ知識】Watson Discoveryで類似文書検索を行うに書いておきましたので、参考とされて下さい。

6
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
12