watsonx.data 2.0.1 で Presto を使用した CLI によるバッチモード ingestion を実行してみた

# はじめに
watsonx.data 2.0.0 から CLI ("ibm-lh data-copy" コマンド) による Ingestion (データの取り込み) は Presto と Spark と Spark REST API の3つのモードをサポートするようになりました。

・Prestoを使用するモードは、watsonx.data 1.1.x と同じ Prestoを使用するモードです。
・Sparkを使用するモードは、watsonx.data 1.1.x と同じSparkを使用するモードです。
・Spark REST APIを使用するモードは、watsonx.data 2.0.0 で追加された新しいモードです。
それぞれのモードでIngestionを実行するために ENABLED_INGEST_MODE 環境変数を設定します。

|ENABLED_INGEST_MODEの値|モード|
|:---|:---|
|PRESTO|Prestoを使用するモード|
|SPARK_LEGACY|Sparkを使用するモード|
|SPARK|Spark REST APIを使用するモード|


**今回は Presto モードのCLI Ingestionの実行方法について ご紹介します。**

## 前提
IBM Cloud Pak for Data (CP4D) 5.0.0/5.0.1上に「データ・ソース・サービス」の一つである **watsonx.data 2.0.0/2.0.1** がインストールされている事。
CP4Dが5.0.0の場合はwatsonx.dataは2.0.0、CP4Dが5.0.1の場合はwatsonx.dataは2.0.1をインストールします。
本記事の検証は、CP4D 5.0.1 に watsonx.data 2.0.1 をインストールした環境を使用しています。

## 事前準備
### 1. ibm-lh-client のインストール
watsonx.data のクライアントツールである **ibm-lh-client** をクライアント・マシンにインストールします。本検証では Red Hat Enterprise Linux 8.6 に ibm-lh-client をインストールしています。
インストールは下記のマニュアルの手順に従って容易に実行する事ができます。
[Installing ibm-lh-client](https://www.ibm.com/docs/en/watsonx/watsonxdata/2.0.x?topic=package-installing-lh-client)

手順の中で、環境変数 LH_RELEASE_TAG にインストールする ibm-lh-client のバージョンを設定しますが、**LH_RELEASE_TAG=latest** に設定すると その時点での最新バージョンのパッケージがダウンロードされてインストールされます。2024年8月23日時点での最新バージョンは 2.0.1 となります。

### 2. Ingestionで取り込むデーター、取り込み元の表、ステージングの場所の準備
Ingestionで取り込むデーター(ソース)、取り込み先(ターゲット)の表、ステージングの場所を予め準備しておく必要があります。
本検証では取り込むデーターも取り込み先の表もステージングの場所も、IBM Cloud Object Storage に作成したバケット内に用意しました。

取り込み先の表は、watsonx.data のWebコンソールのインフラストラクチャー・マネージャーで**Apache Iceberg** タイプとして登録したターゲット用のカタログにスキーマを作成し、スキーマの下に表を作成しておきます。

PrestoのIngestionではステージング表が必要ですので、IBM Cloud Object Storage にステージング用のバケットを用意しました。インフラストラクチャー・マネージャーで **Apache Hive タイプ** として登録したステージング用のカタログにスキーマを作成しておきます。ステージング表はIngestionを実行した時に毎回動的に作成され、Ingestionが終了すると削除されます。

取り込み元、ステージング、ターゲットのカタログはそれぞれ インフラストラクチャー・マネージャーでPrestoエンジンと結び付けておきます。カタログと結び付ける度にPrestoエンジンの再起動が実行されます。

事前準備が完了した状態のインフラストラクチャー・マネージャーの表示は以下のようになります。watsonx.data ではバケットはストレージとして表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1359991/cefd4e88-b963-44d0-79e9-7fd82d73a967.png)

### 3. 環境変数の設定
Presto を使用した CLI のIngestion を実行する場合、下記の環境変数を設定する必要があります。
|環境変数名|環境変数の意味|
|:---|:---|
|ENABLED_INGEST_MODE|Ingestionのモード(必須)|
|SOURCE_S3_CREDS|ソースのバケットのS3資格情報 (必須)|バケットのS3資格情報 (必須)|
|STAGING_S3_CREDS|ステージングに使用するバケットのS3資格情報 (必須)|
|TARGET_S3_CREDS|ターゲットのバケットのS3資格情報 (必須)|

**必須の環境変数の設定方法について説明していきます。**

予め OCPクラスターにログインし、watsonx.data がインストールされているプロジェクトに変更しておきます。
例)
```
$ oc project cpd-operands
Now using project "cpd-operands" on server "https://api.66820424808b98001eb03c88.cloud.techzone.ibm.com:6443".
```

**ENABLED_INGEST_MODE**
「はじめに」に記述したとおり、ENABLED_INGEST_MODE には PRESTO を設定します。
例)
```
export ENABLED_INGEST_MODE=PRESTO
```
**SOURCE_S3_CREDS**
Ingestionのソースファイルが含まれているバケットの資格情報を、下記のフォーマットで設定します。設定する値は使用するオブジェクト・ストレージのコンソール等から入手します。
```
AWS_ACCESS_KEY_ID=<access_key>,AWS_SECRET_ACCESS_KEY=<secret_key>,ENDPOINT_URL=<endpoint_url>,AWS_REGION=<region>,BUCKET_NAME=<bucket_name>
```

例)
```
export SOURCE_S3_CREDS="AWS_ACCESS_KEY_ID=XXXXXXXXXX,AWS_SECRET_ACCESS_KEY=YYYYYYYYYY,ENDPOINT_URL=https://s3.jp-tok.cloud-object-storage.appdomain.cloud,AWS_REGION=jp-tok,BUCKET_NAME=src-bucket1"
```
**STAGING_S3_CREDS**
ステージングに使用するのバケットの資格情報を、SOURCE_S3_CREDSと同じフォーマットで設定します。設定する値は使用するオブジェクト・ストレージのコンソール等から入手します。
例)
```
export STAGING_S3_CREDS="AWS_ACCESS_KEY_ID=XXXXXXXXXX,AWS_SECRET_ACCESS_KEY=YYYYYYYYYY,ENDPOINT_URL=https://s3.jp-tok.cloud-object-storage.appdomain.cloud,AWS_REGION=jp-tok,BUCKET_NAME=stg-bucket1"
```
**TARGET_S3_CREDS**
Ingestionのターゲット側のバケットの資格情報を、SOURCE_S3_CREDSと同じフォーマットで設定します。設定する値は使用するオブジェクト・ストレージのコンソール等から入手します。
例)
```
export TARGET_S3_CREDS="AWS_ACCESS_KEY_ID=XXXXXXXXXX,AWS_SECRET_ACCESS_KEY=YYYYYYYYYY,ENDPOINT_URL=https://s3.jp-tok.cloud-object-storage.appdomain.cloud,AWS_REGION=jp-tok,BUCKET_NAME=tgt-bucket1"
```
### 4. ibm-lh data-copy コマンドに指定するパラメーターの決定
"ibm-lh data-copy" コマンドに指定するパラメーターを決定します。本記事では、ソースファイルとして S3 互換のバケット内の Parquet ファイルを指定する場合に必要なパラメーターについてのみ説明します。

|パラメーター|パラメーターの意味|
|:---|:---|
|source-data-files|S3 バケット内の Paquet ファイルか CSV ファイル、又はフォルダーへのパス。フォルダーのパスの場合は最後が"/"である必要があります。|
|target-table|<カタログ名>.<スキーマ名>.<テーブル名> の形式のターゲット表。|
|ingestion-engine-endpoint|"hostname=<hostname>, port=<port>" の形式のIngestionに使用するエンジンのエンドポイント。|
|dbuser|Ingestionに使用するCP4Dのユーザー名。|
|dbpassword|Ingestionに使用するCP4Dのユーザーのパスワード。|
|staging-location|<バケット名>.<スキーマ名> の形式のステージングに使用するS3 バケット名とスキーマ名。|
|staging-hive-catalog|デフォルトのステージングのカタログを使用しない場合、ステージングに使用するカタログの名前を指定する。|
|staging-hive-schema|ステージングのカタログのスキーマ名。|
|trust-store-path|Ingestionが実行される "ibm-lh data-copy" のコンテナ内の truststore 資格情報のパス。**root ユーザー以外でIngestionを実行する場合必須。**|
|trust-store-password|Ingestionが実行される"ibm-lh data-copy" のコンテナ内の truststore 資格情報のパスワード。決め打ちで **changeit** を指定。**root ユーザー以外でIngestionを実行する場合必須。**|

**各パラメーターの設定ついて説明します。**

**source-data-files**
"s3://<バケット名>/<ファイル名>" 又は "s3://<バケット名>/<フォルダー名>/<ファイル名>" 又は "s3://<バケット名>/<フォルダー名>/ の形式でソースファイルを指定します。
"s3://<バケット名>/<フォルダー名>/ の形式で指定すると同じフォルダー名のファイルが全てソース・ファイルとなります。
```
1個のファイルを指定する例)
--source-data-files s3://srcbucket1/parquet_folder/test1.parquet

フォルダー名を指定する例)
--source-data-files s3://srcbucket1/parquet_folder/
```

**target-table**
"<カタログ名>/<スキーマ名>/<ターゲット表名>" の形式でターゲット表を指定します。watsonx.data 1.1.x で **target-tables** だったパラメーター名が **target-table** に変更されました。
例)
```
--target-tables trgbucket1.target1.gvt_data_v
```

**ingestion-engine-endpoint**
Ingestionに使用するPrestoエンジンのエンドポイントを"hostname=<hostname>, port=<port>" の形式で指定します。
例)
```
Prestoエンジンの route のホスト名を確認します。
下記のコマンドの出力の2列目の文字列がホスト名となりますので hostname= に指定します。port= の値は 443で固定です。

$oc get route | grep presto | grep -v prestissimo
ibm-lh-lakehouse-presto-01-presto-svc  ibm-lh-lakehouse-presto-01-presto-svc-cpd-operands.apps.66820424808b98001eb03c88.cloud.techzone.ibm.com   ibm-lh-lakehouse-presto-01-presto-svc  8443   reencrypt   None

--ingestion-engine-endpoint "hostname=ibm-lh-lakehouse-presto-01-presto-svc-cpd-operands.apps.66820424808b98001eb03c88.cloud.techzone.ibm.com,port=443"
```

**dbuser**
Ingestionに使用するCP4Dのユーザー名を指定します。
例)
```
--dbuser cpadmin
```

**dbpassword**
Ingestionに使用するCP4Dのユーザーのパスワードを指定します。
例)
```
--dbpassword password
```
**staging-location**
ステージングの場所を "s3://<バケット名>/<スキーマ名>/" の形式で指定します。
例)
--staging-location  s3://stg-bucket1/staging1/

**staging-hive-catalog**
ステージングに使用するバケットのカタログ名を指定します。
例)
```
--staging-hive-catalog stgbucket1
```

**staging-hive-schema**
ステージングに使用するカタログのスキーマ名を指定します。
例)
```
--staging-hive-schema  staging1
```

**trust-store-path**
Ingestionが実行される "ibm-lh data-copy" のコンテナ内の truststore 資格情報のパスを指定します。**trust-store-password と共に、root ユーザー以外でIngestionを実行する場合必須となります。**

例
```
ingestion-engine-endpoint で確認したホスト名を hostname変数に設定し、port変数にポート番号(443で固定)を設定します。

hostname=ibm-lh-lakehouse-presto-01-presto-svc-cpd-operands.apps.66820424808b98001eb03c88.cloud.techzone.ibm.com
port=443

trust-store-path の値は下記のように設定します。
--trust-store-path "/mnt/infra/tls/aliases/$hostname:$port.crt" 
```
**trust-store-password**
例) 決め打ちなので下記のように設定します。
```
--trust-store-password changeit
```
## バッチモード Ingestion の実行
### スクリプト・ファイルの作成
これまで説明した環境変数の設定と "ibm-lh data-copy" へのパラメーターを元にバッチモード Ingestion 用のスクリプト・ファイルを作成し、実行権限を付けます。バッチモードのため、予め "ibm-lh data-copy" のコンテナを起動する事なく、クライアント・マシンのコマンド・プロンプトから直接スクリプトを実行する事ができます。
本検証ではスクリプト・ファイルは <ibm-lh-client Home>/bin ディレクトリーに配置してあります。

例)
```
$ cat presto-batch-ingestion-parq-qiita.sh
export ENABLED_INGEST_MODE=PRESTO
echo "Ingest mode="$ENABLED_INGEST_MODE
export SOURCE_S3_CREDS="AWS_ACCESS_KEY_ID=XXXXXXXXXX,AWS_SECRET_ACCESS_KEY=YYYYYYYYYY,ENDPOINT_URL=https://s3.jp-tok.cloud-object-storage.appdomain.cloud,AWS_REGION=jp-tok,BUCKET_NAME=src-bucket1"
export STAGING_S3_CREDS="AWS_ACCESS_KEY_ID=XXXXXXXXXX,AWS_SECRET_ACCESS_KEY=YYYYYYYYYY,ENDPOINT_URL=https://s3.jp-tok.cloud-object-storage.appdomain.cloud,AWS_REGION=jp-tok,BUCKET_NAME=stg-bucket1"
export TARGET_S3_CREDS="AWS_ACCESS_KEY_ID=XXXXXXXXXX,AWS_SECRET_ACCESS_KEY=YYYYYYYYYY,ENDPOINT_URL=https://s3.jp-tok.cloud-object-storage.appdomain.cloud,AWS_REGION=jp-tok,BUCKET_NAME=tgt-bucket1"

hostname=ibm-lh-lakehouse-presto-01-presto-svc-cpd-operands.apps.66820424808b98001eb03c88.cloud.techzone.ibm.com
port=443

bash ./ibm-lh data-copy \
--source-data-files s3://src-bucket1/parquet_folder/test1.parquet \
--staging-location  s3://stg-bucket1/staging2/ \
--target-table tgtbucket1.target1.gvt_data_v \
--ingestion-engine-endpoint "hostname=ibm-lh-lakehouse-presto-01-presto-svc-cpd-operands.apps.66820424808b98001eb03c88.cloud.techzone.ibm.com,port=443" \
--dbuser cpadmin \
--dbpassword isel4you \
--staging-hive-catalog stgbucket1 \
--staging-hive-schema  staging1 \
--trust-store-path "/mnt/infra/tls/aliases/$hostname:$port.crt" \
--trust-store-password changeit
```
スクリプト・ファイルを実行します。
例)
```
$ ./presto-batch-ingestion-parq-qiita.sh
Ingest mode=PRESTO
Start data migration
Ingesting SECTION: cmdline
staging-hive-catalog="stgbucket1"
Reading parquet file:s3://src-bucket1/parquet_folder/test1.parquet
Inferring source schema...
Schema inferred
Ingesting source folder s3://stg-bucket1/staging1/stage_1724395407_6_41d8afaaad1e/stage1/ into target table target1.gvt_data_v

Current State: 100% FINISHED
Done with stage 1 of 1
Complete migration
```
**最後に "Complete migration" が表示されれば Ingestion は成功です。**

Ingestionの実行が失敗した場合、"ibm-lh data-copy" に "--debug" オプションを付けて実行すると、標準出力に Ingestionの実行の詳細な情報が表示され、失敗の原因の特定に役に立つ場合があります。

以上で、watsonx.data 2.0.1 で Presto を使用した CLI によるバッチモード ingestion の実行方法の紹介を終わります。

**Spark を使用した watsonx.data 2.0.1 でのCLI によるバッチモード ingestion の実行方法については以下の記事をご参照ください。**
[watsonx.data 2.0.1 で Spark を使用した CLI によるバッチモード ingestion を実行してみた](https://qiita.com/hkanba/items/115186be946bf1389710)

**Spark REST API を使用した watsonx.data 2.0.1 でのCLI によるバッチモード ingestion の実行方法については以下の記事をご参照ください。**
[watsonx.data 2.0.1 で Spark REST API を使用した CLI によるバッチモード ingestion を実行してみた](https://qiita.com/hkanba/items/0bb17dea817728ee5ae6)