Spark ユース・ケースでの AWS EMR の使用
このリリースでは、外部Sparkエンジンの登録オプションは watsonx.data 非推奨となり、バージョン で削除されます 2.3。 watsonx.data には、Glutenアクセラレーション対応Sparkエンジンやネイティブ watsonx.data Sparkエンジンなど、プロビジョニングして直接使用できる組み込みSparkエンジンが既に含まれています。
このトピックでは、 Amazon Web Services Elastic MapReduce (AWS EMR) から Spark アプリケーションを実行して IBM® watsonx.data Spark ユース・ケースを実現する手順について説明します。
- データの取り込み
- データ照会
- 表の保守
前提条件
-
IBM® watsonx.data インスタンスをプロビジョンします。
-
S3 バケットを使用してカタログを作成します。
-
S3 バケット資格情報を取得します。
-
AWSで EMR クラスターをセットアップします。 詳しくは、 EMR クラスターのセットアップ を参照してください。
-
IBM® watsonx.dataから以下の情報を取り出します。
- データシートの URLは watsonx.dataから。 データシートの資格情報の取得に関する詳細は、 メタデータ・サービス(MDS)の資格情報の取得を参照してください。
- watsonx.dataのデータシート資格情報。 データシートの資格情報の取得に関する詳細は、 メタデータ・サービス(MDS)の資格情報の取得を参照してください。
バージョン watsonx.data 以降 2.2.0、ユーザー名として
ibmlhtokenおよびibmlhapikeyを使用した認証は非推奨となります。 これらの形式はリリース 2.3.0 で段階的に廃止されます。 今後のバージョンとの互換性を確保するため、新しいフォーマットibmlhapikey_<username>およびibmlhtoken_<username>を使用してください。
概要
AWS S3 バケットにあるソース・データを処理するには、以下のいずれかの方法を使用できます。
- AWS での watsonx.data インスタンスのセットアップ
- IBM Cloud ベースの watsonx.data インスタンスを構成し、 AWS S3 バケット・ベースのカタログを組み込みます。
watsonx.data 照会エンジンは、 AWS S3 バケットからのデータに対して照会を実行できます。 どちらの場合も、 AWS EMR Spark を使用して、データ取り込みおよび Iceberg ベースのスキーマ保守操作を実行できます。
サンプル・ユース・ケースについて
サンプルの Python ファイル (amazon-lakehouse.py) は、スキーマ (amazonschema) の作成、表の作成、およびデータの取り込みを示しています。 また、表の保守操作もサポートします。 サンプルの機能について詳しくは、 サンプル・ユース・ケースについて を参照してください。
サンプル・ユース・ケースの実行
Spark サンプル Python ファイルを実行する手順に従います。
-
AWS EMR クラスターに接続します。 SSH を使用して EMR クラスターに接続する方法について詳しくは、 EMR クラスターのセットアップ を参照してください。
-
以下のサンプル Python ファイルを保存します。
Spark サンプル Python ファイル
from pyspark.sql import SparkSession import os def init_spark(): spark = SparkSession.builder.appName("lh-hms-cloud")\ .enableHiveSupport().getOrCreate() return spark def create_database(spark): # Create a database in the lakehouse catalog spark.sql("create database if not exists lakehouse.amazonschema LOCATION 's3a://lakehouse-bucket-amz/'") def list_databases(spark): # list the database under lakehouse catalog spark.sql("show databases from lakehouse").show() def basic_iceberg_table_operations(spark): # demonstration: Create a basic Iceberg table, insert some data and then query table spark.sql("create table if not exists lakehouse.amazonschema.testTable(id INTEGER, name VARCHAR(10), age INTEGER, salary DECIMAL(10, 2)) using iceberg").show() spark.sql("insert into lakehouse.amazonschema.testTable values(1,'Alan',23,3400.00),(2,'Ben',30,5500.00),(3,'Chen',35,6500.00)") spark.sql("select * from lakehouse.amazonschema.testTable").show() def create_table_from_parquet_data(spark): # load parquet data into dataframce df = spark.read.option("header",True).parquet("s3a://source-bucket-amz/nyc-taxi/yellow_tripdata_2022-01.parquet") # write the dataframe into an Iceberg table df.writeTo("lakehouse.amazonschema.yellow_taxi_2022").create() # describe the table created spark.sql('describe table lakehouse.amazonschema.yellow_taxi_2022').show(25) # query the table spark.sql('select * from lakehouse.amazonschema.yellow_taxi_2022').count() def ingest_from_csv_temp_table(spark): # load csv data into a dataframe csvDF = spark.read.option("header",True).csv("s3a://source-bucket-amz/zipcodes.csv") csvDF.createOrReplaceTempView("tempCSVTable") # load temporary table into an Iceberg table spark.sql('create or replace table lakehouse.amazonschema.zipcodes using iceberg as select * from tempCSVTable') # describe the table created spark.sql('describe table lakehouse.amazonschema.zipcodes').show(25) # query the table spark.sql('select * from lakehouse.amazonschema.zipcodes').show() def ingest_monthly_data(spark): df_feb = spark.read.option("header",True).parquet("s3a://source-bucket-amz//nyc-taxi/yellow_tripdata_2022-02.parquet") df_march = spark.read.option("header",True).parquet("s3a://source-bucket-amz//nyc-taxi/yellow_tripdata_2022-03.parquet") df_april = spark.read.option("header",True).parquet("s3a://source-bucket-amz//nyc-taxi/yellow_tripdata_2022-04.parquet") df_may = spark.read.option("header",True).parquet("s3a://source-bucket-amz//nyc-taxi/yellow_tripdata_2022-05.parquet") df_june = spark.read.option("header",True).parquet("s3a://source-bucket-amz//nyc-taxi/yellow_tripdata_2022-06.parquet") df_q1_q2 = df_feb.union(df_march).union(df_april).union(df_may).union(df_june) df_q1_q2.write.insertInto("lakehouse.amazonschema.yellow_taxi_2022") def perform_table_maintenance_operations(spark): # Query the metadata files table to list underlying data files spark.sql("SELECT file_path, file_size_in_bytes FROM lakehouse.amazonschema.yellow_taxi_2022.files").show() # There are many smaller files compact them into files of 200MB each using the # `rewrite_data_files` Iceberg Spark procedure spark.sql(f"CALL lakehouse.system.rewrite_data_files(table => 'amazonschema.yellow_taxi_2022', options => map('target-file-size-bytes','209715200'))").show() # Again, query the metadata files table to list underlying data files; 6 files are compacted # to 3 files spark.sql("SELECT file_path, file_size_in_bytes FROM lakehouse.amazonschema.yellow_taxi_2022.files").show() # List all the snapshots # Expire earlier snapshots. Only latest one with comacted data is required # Again, List all the snapshots to see only 1 left spark.sql("SELECT committed_at, snapshot_id, operation FROM lakehouse.amazonschema.yellow_taxi_2022.snapshots").show() #retain only the latest one latest_snapshot_committed_at = spark.sql("SELECT committed_at, snapshot_id, operation FROM lakehouse.amazonschema.yellow_taxi_2022.snapshots").tail(1)[0].committed_at print (latest_snapshot_committed_at) spark.sql(f"CALL lakehouse.system.expire_snapshots(table => 'amazonschema.yellow_taxi_2022',older_than => TIMESTAMP '{latest_snapshot_committed_at}',retain_last => 1)").show() spark.sql("SELECT committed_at, snapshot_id, operation FROM lakehouse.amazonschema.yellow_taxi_2022.snapshots").show() # Removing Orphan data files spark.sql(f"CALL lakehouse.system.remove_orphan_files(table => 'amazonschema.yellow_taxi_2022')").show(truncate=False) # Rewriting Manifest Files spark.sql(f"CALL lakehouse.system.rewrite_manifests('amazonschema.yellow_taxi_2022')").show() def evolve_schema(spark): # demonstration: Schema evolution # Add column fare_per_mile to the table spark.sql('ALTER TABLE lakehouse.amazonschema.yellow_taxi_2022 ADD COLUMN(fare_per_mile double)') # describe the table spark.sql('describe table lakehouse.amazonschema.yellow_taxi_2022').show(25) def clean_database(spark): # clean-up the demo database spark.sql('drop table if exists lakehouse.amazonschema.testTable purge') spark.sql('drop table if exists lakehouse.amazonschema.zipcodes purge') spark.sql('drop table if exists lakehouse.amazonschema.yellow_taxi_2022 purge') spark.sql('drop database if exists lakehouse.amazonschema cascade') def main(): try: spark = init_spark() clean_database(spark) create_database(spark) list_databases(spark) basic_iceberg_table_operations(spark) # demonstration: Ingest parquet and csv data into a wastonx.data Iceberg table create_table_from_parquet_data(spark) ingest_from_csv_temp_table(spark) # load data for the month of Feburary to June into the table yellow_taxi_2022 created above ingest_monthly_data(spark) # demonstration: Table maintenance perform_table_maintenance_operations(spark) # demonstration: Schema evolution evolve_schema(spark) finally: # clean-up the demo database #clean_database(spark) spark.stop() if __name__ == '__main__': main() -
以下のコマンドを実行して、 指定 された場所からメタデータサービスJARファイルをワークステーションにダウンロードしてください。 Sparkのバージョンに基づいてJARファイルを選択できます。
JAR ファイルは、クラスターのすべてのノード上の
/home/hadoopロケーションに存在している必要があります。 とをメモしておいてspark.driver.extraClassPathください。spark.executor.extraClassPathたとえば、Sparkを使用している 3.x 場合は、以下のJARファイルを含めてください。 Spark の場合 4.x、 場所 から適切なフォルダを選択してください。
wget https://github.com/IBM-Cloud/IBM-Analytics-Engine/raw/master/wxd-connectors/hms-connector/hive-exec-2.3.9-core.jar wget https://github.com/IBM-Cloud/IBM-Analytics-Engine/raw/master/wxd-connectors/hms-connector/hive-common-2.3.9.jar wget https://github.com/IBM-Cloud/IBM-Analytics-Engine/raw/master/wxd-connectors/hms-connector/hive-metastore-2.3.9.jar -
AWS EMRクラスタのデータシート接続の詳細を設定し、 watsonx.data メタデータサービス(MDS)に接続します。メタデータサービス(MDS)。 EMR 7.3.0 (Spark 3.5.1 )ベースのクラスターからspark-submitを使用するサンプルコマンドは次のとおりです:
EC2 クラスターで EMR からコマンドを実行して、サンプル・スパーク・ジョブをサブミットします。
spark-submit \ --deploy-mode cluster \ --jars https://repo1.maven.org/maven2/org/apache/iceberg/iceberg-spark-runtime-3.4_2.12/1.4.0/iceberg-spark-runtime-3.4_2.12-1.4.0.jar,/usr/lib/hadoop/hadoop-aws.jar,/usr/share/aws/aws-java-sdk/aws-java-sdk-bundle*.jar,/usr/lib/hadoop-lzo/lib/* \ --conf spark.sql.catalogImplementation=hive \ --conf spark.driver.extraClassPath=/home/hadoop/hive-common-2.3.9.jar:/home/hadoop/hive-metastore-2.3.9.jar:/home/hadoop/hive-exec-2.3.9-core.jar \ --conf spark.executor.extraClassPath=/home/hadoop/hive-common-2.3.9.jar:/home/hadoop/hive-metastore-2.3.9.jar:/home/hadoop/hive-exec-2.3.9-core.jar \ --conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \ --conf spark.sql.iceberg.vectorization.enabled=false \ --conf spark.sql.catalog.lakehouse=org.apache.iceberg.spark.SparkCatalog \ --conf spark.sql.catalog.lakehouse.type=hive \ --conf spark.hive.metastore.uris==<<change_endpoint>> \ --conf spark.hive.metastore.client.auth.mode=PLAIN \ --conf spark.hive.metastore.client.plain.username=ibmlhapikey \ --conf spark.hive.metastore.client.plain.password=<<change_pswd>> \ --conf spark.hive.metastore.use.SSL=true \ --conf spark.hive.metastore.truststore.type=JKS \ --conf spark.hive.metastore.truststore.path=file:///etc/pki/java/cacerts \ --conf spark.hive.metastore.truststore.password=changeit \ amazon-lakehouse.py
パラメーター値:
- <<change_endpoint>> : メタストアにアクセスするためのメタデータサービスURIエンドポイント。 データシートの資格情報の取得に関する詳細は、 メタデータサービス(MDS)の資格情報の取得を参照してください。
- <<change_pswd>> : メタストアにアクセスするためのパスワード。 データシートの資格情報の取得に関する詳細は、 メタデータサービス(MDS)の資格情報の取得を参照してください。
EMR 7.3.0 (Spark 3.5.1 )クラスターでSpark Pythonファイルを実行するには、 指定 された場所からIceberg JARファイルをダウンロードし、同じ 手順 に従ってください。