はじめに
Watson StudioのNotebookから、ICOSにあるオブジェクトを使って色々なことをする機会があったので、こちらに記録として残しておこうと思います。
SQL Queryは使わずに、直接ICOSにアクセスする方法になります。SQL Queryを使うと、もっと色々なことが出来るのですが、それはまた別の機会に記載出来ればと。
事前準備
ライト・アカウント
本記事の内容は、IBM Cloud ライト・アカウントで実施可能です。アカウントをお持ちで無い方は、以下のURL先から登録ください。
Watson Studio
Liteプランをオーダーしておきます。ちなみに、以前のLiteプランには、無料でいくらでも使える最小構成のランタイムがありましたが、2020年6月現在は使えませんのでお気をつけください。さらに、2022年5月以降、50CUH(Capacity Unit Hours)あった無料枠が、10CUHに削減されてしまいました。
また、2022年4月1日にWatson Studioのプランが変更され、それまであったStandardとEnterpriseの有償プランが、Professionalプランに統合されています。以前の有償プランでは、一定数を超えた登録ユーザーあたりにも課金されていましたが、CUHのみの課金に変更されています。
2022年4月以前に作成済のStandardとEnterpriseプランは継続して利用可能のようですが、現状の使いっぷりとユーザー数を踏まえて、Professionalプランの方がお得な場合は、乗り換えた方がよいかもしれません。
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での作業
プロジェクトの作成
まず新規のプロジェクトを作成します。トップ画面の左上にある 「Create a project」 をクリックします。
次に、「Create an empty project」 をクリックします。
最後に適当なプロジェクト名を入力し、「Create」をクリックしてプロジェクトを作成します。このとき、右側の「Storage」というところに、事前に作成しておいたICOSインスタンスが表示されています。複数のICOSインスタンスをお持ちの場合は、任意のものをここで選択します。ここで選んだICOSインスタンスには、このプロジェクトの設定内容等を保管するためのバケットが自動的に作成されます。
最小構成のランタイム(Environment)の作成
2022年5月30日時点で利用可能なランタイムのPythonは3.9で、最小構成(1vCPU)のランタイムがデフォルトで用意されているので、そちらををご利用ください。以下は、1vCPUのランタイムがデフォルトで存在しなかった場合に、カスタムのランタイムを作成する手順です。
作成したプロジェクトのダッシュボードのManageタブページ内で、メニューからEnvironmentをクリック。そこにあるTempatesタブページ内で、「New template」をクリックします。
適当な名前を入力し、「Hardware configuration」で一番スペックの低い「1vCPU and 4GB RAM」を選択します。「Software version」は最新のPython、2022年5月時点では「IBM Runtime 22.1 on Python 3.9」を選択し、「Create」をクリックします。
Notebookの作成
プロジェクトのダッシュボードのAssetsタブページ内にある、「New asset」をクリックします。
Code editorのページにある「Jupyter notebook editor」をクリックします。
適当な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上のオブジェクトに対する基本的な操作を試してみました。