Watson Studio (Notebook)からICOSにアクセスする


はじめに

Watson StudioのNotebookから、ICOSにあるオブジェクトを使って色々なことをする機会があったので、こちらに記録として残しておこうと思います。

SQL Queryは使わずに、直接ICOSにアクセスする方法になります。SQL Queryを使うと、もっと色々なことが出来るのですが、それはまた別の機会に記載出来ればと。

事前準備

ライト・アカウント

本記事の内容は、IBM Cloud ライト・アカウントで実施可能です。アカウントをお持ちで無い方は、以下のURL先から登録ください。

Watson Studio

ライトプランをオーダーしておきます。ちなみに、以前のライトプランには、無料でいくらでも使える最小構成のランタイムがありましたが、2020年6月現在は使えませんのでお気をつけください。

ただ、50CUH(Capacity Unit Hours)という無料枠は変わらずあります。最小構成のランタイムで100時間分になりますので、その枠内で利用します。

ICOS (IBM Cloud Object Storage)

こちらもライトプランをオーダーし、適当な名前でバケットを作成しておきます。バケットはRegionalで、ロケーションはjp-tokとします。

テスト用ファイルの準備

以下のようなコマンドを実行して、テスト用のファイルを1500個ほど作成し、上で作成したバケットに保管しておきます。

for i in $(seq -f %04g 1 1500); do echo ${i} > data-${i}.txt; done

APIキーの作成

以下のURLから、任意の名前で自身のアカウントのAPIキーを作成して、そのキーの文字列を控えておきます。作成直後しか見ることが出来ないので、ご注意ください。

Watson Studioでの作業

プロジェクトの作成

まず新規のプロジェクトを作成します。トップ画面の右側にある 「New Project」 をクリックします。

次に、「Create an empty project」 をクリックします。

最後に適当なプロジェクト名を入力し、「Create」をクリックしてプロジェクトを作成します。このとき、右側の「Storage」というところに、事前に作成しておいたICOSインスタンスが表示されています。複数のICOSインスタンスをお持ちの場合は、任意のものをここで選択します。ここで選んだICOSインスタンスには、このプロジェクトの設定内容等を保管するためのバケットが自動的に作成されます。

最小構成のランタイム(Environment)の作成

50CUHの無料枠を有効活用するため、最小構成のランタイムを事前に定義します。作成したプロジェクトのダッシュボードで、Environmentsタブをクリックし、中程にある「New environment definition」をクリックします。

適当な名前を入力し、「Hardware configuration」で一番スペックの低い「1vCPU and 4GB RAM」を選択します。「Software version」は「Default Python 3.6」のままで、「Create」をクリックします。

Notebookの作成

プロジェクトのダッシュボードの上部にある、「プロジェクトに追加」をクリックし、「Notebook」をクリックします。

適当なNotebook名を入力し、Select runtimeのところでは、先に作成した最小構成のランタイムを選択してから、「Create」をクリックします。

ランタイムが起動した後、Notebookの編集画面に入ります。なお、作成済みのNotebookは、プロジェクトダッシュボードの「Assets」タブページからアクセス可能です。

Notebookの記述

事前処理

1つ目のセルで、必要なモジュールのimportなどを実施しておきます。

from datetime import datetime, date, timedelta
import pytz
import json
import sys

JST = pytz.timezone('Asia/Tokyo')

次に、AWS SDK for Python (Boto3)のICOS版?、ibm_boto3の設定を行います。ibm_api_key_idのところは、先に作成したAPIキーに置き換えてください。

from botocore.client import Config
import ibm_boto3

cosclient = ibm_boto3.client(service_name='s3',
    ibm_api_key_id='********************************',
    ibm_auth_endpoint="https://iam.cloud.ibm.com/oidc/token",
    config=Config(signature_version='oauth'),
    endpoint_url='https://s3.private.jp-tok.cloud-object-storage.appdomain.cloud')

ibm_boto3を使って、本記事以外でどんなことが出来るかは、こちらをご参照ください。

オブジェクト一覧の取得

次のセルで、ICOSバケット上のオブジェクトの情報を取得します。list_objectsメソッドを使用しますが、その際、バケット名、プレフィックスを指定します。bucketには、事前に作成しておいたバケット名を指定します。prefixは、今回の場合は、事前に作成したテスト用ファイルを示すdata-とします。

本家boto3でも同じなのですが、list_objectsメソッドは、最大1000件しか返すことが出来ません。ただ、1000件以上ある場合は、IsTruncatedフィールドがTrueで返され、NextMarkerフィールドに、次にここから読み込んで欲しいという情報があるので、これをmarkerにセットして、次の1000件を読み込む、というのを繰り返します。

try 〜 exceptを使っているのは、オブジェクトやバケットが存在しなかったり、アクセスポリシーでブロックされた場合の例外を処理するためです。

bucket = 'icos-test-bucket'    # 事前に作成したバケット名
prefix = 'data-'               # オブジェクトを入手する際のプレフィックス
marker = ''                    # オブジェクトを入手する際の1つ目のオブジェクトを示すパス。初回はブランク
contents = []                  # オブジェクトの情報を格納するための変数

try:
    while True:
        response = cosclient.list_objects(Bucket=bucket, Prefix=prefix, Marker=marker)
        contents.extend(response['Contents'])
        if response['IsTruncated'] == True:  # 1000件超える場合
            marker = response['NextMarker']
        else:
            break
except Exception as e:
    if str(e) == '\'Contents\'':
        print('オブジェクトが見つかりませんでした')
    else:
        print('以下のエラーでICOSにアクセス出来ませんでした。')
        print(str(e))
    sys.exit(1)

オブジェクト属性情報の取得

前のセルで取得した情報は、JSON形式のリストになっており、個々のオブジェクトのパス(Key)、サイズ(Size)、最終更新日時(LastModified)などの情報が入っています。これをcsv形式で取得してみます。最終更新日時は、日本時間で取得するようにしています。

allfilelist = 'Key,Size,LastModified\n'
for item in contents:
    allfilelist = allfilelist + item['Key'] + ',' + str(item['Size']) + ',' + datetime.strftime(item['LastModified'].astimezone(JST), '%Y/%m/%d %H:%M:%S') + '\n'

print(allfilelist)

こんな結果が表示されるはずです。

Key,Size,LastModified
data-0001.txt,5,2020/06/03 17:47:02
data-0002.txt,5,2020/06/03 17:47:02
data-0003.txt,5,2020/06/03 17:47:02
data-0004.txt,5,2020/06/03 17:47:02
data-0005.txt,5,2020/06/03 17:47:02
・・・略・・・

オブジェクトの中身の取得

get_objectメソッドを使って、オブジェクトの中身を読み取り、1つの文字列変数に繋げて保管してみます。テキストファイルの文字コードに応じて、.decode('Shift_JIS')などと付与することで、日本語も問題なく処理できます。

data = ""
for item in contents:
    body = cosclient.get_object(Bucket=bucket,Key=item['Key'])['Body'].read().decode('Shift_JIS')
    data = data + body

バケットへのファイル出力

最後に、put_objectメソッドを使って、収集した情報をバケットにファイルとして出力します。

cosclient.put_object(Bucket=bucket,Key='data.txt', Body=data)
cosclient.put_object(Bucket=bucket,Key='allfilelist.txt', Body=allfilelist)

まとめ

Watson Studio の Notebook を使って、ICOS上のオブジェクトに対する基本的な操作を試してみました。