Alibaba Cloud E-MapReduce (EMR) Delta Lake は強力なデータ処理機能を提供します。これにより、データを管理し、データの品質と整合性を確保できます。このトピックでは、EMR Delta Lake を使用してデータの削除、更新、マージ、およびその他のデータ管理操作を実行する方法について説明します。
DELETE
データを削除します。サンプルコード:
DELETE FROM delta_table [AS t] [WHERE t.date < '2019-11-11'];import io.delta.tables.
val deltaTable = DeltaTable.forPath(spark, "/tmp/delta_table")
deltaTable.delete("date < '2019-11-11'")
import org.apache.spark.sql.functions.
import spark.implicits.
deltaTable.delete(col("date") < "2019-11-11")DELETE ステートメントで条件を指定しない場合、すべてのデータが削除されます。
サブクエリを持つ WHERE 句はサポートされていません。ただし、サブクエリが SQL ステートメントで表現されたスカラサブクエリである場合は、
spark.sql.uncorrelated.scalar.subquery.preexecution.enabledパラメーターをtrueに設定できます。このようにして、サブクエリを持つ WHERE 句を使用できます。例:DELETE FROM delta_table WHERE t.date < (SELECT date FROM ref_table WHERE ....)別のテーブルの行と一致する行を削除する場合は、MERGE ステートメントを使用します。たとえば、MERGE ステートメントを使用して
DELETE FROM target WHERE target.col = ref.col ...ステートメントを置き換えます。
UPDATE
データを更新します。サンプルコード:
UPDATE delta_table [AS t] SET t.id = t.id + 1 [WHERE t.date < '2019-11-11'];import io.delta.tables._
val deltaTable = DeltaTable.forPath(spark, "/tmp/delta_table")
deltaTable.updateExpr( // SQL 形式の文字列を使用します。
"name = 'Robet'",
Map("name" -> "'Robert'")
import org.apache.spark.sql.functions._
import spark.implicits._
deltaTable.update( // SQL 関数を使用し、暗黙的な変換を実行します。
col("name") === "Robet"),
Map("name" -> lit("Robert"));サブクエリを持つ WHERE 句はサポートされていません。ただし、サブクエリが SQL ステートメントで表現されたスカラサブクエリである場合は、
spark.sql.uncorrelated.scalar.subquery.preexecution.enabledパラメーターをtrueに設定できます。このようにして、サブクエリを持つ WHERE 句を使用できます。例:UPDATE delta_table SET t.id = t.id + 1 WHERE t.date < (SELECT date FROM ref_table WHERE ....)別のテーブルの行と一致する行を更新する場合は、MERGE ステートメントを使用します。たとえば、MERGE ステートメントを使用して
UPDATE target SET target.col = ref.col ...またはUPDATE target WHERE target.col = ref.col ...ステートメントを置き換えます。
MERGE
データをマージします。サンプルコード:
MERGE INTO target AS t
USING source AS s
ON t.date = s.date
WHEN MATCHED [AND t.name = 'should_update'] THEN UPDATE SET target.name = source.name
WHEN MATCHED [AND t.name = 'should_delete'] THEN DELETE
WHEN NOT MATCHED [AND s.name = 'should_insert'] THEN INSERT (t.date, t.name, t.id) VALUES (s.date, s.name.s.id)import io.delta.tables._
import org.apache.spark.sql.functions._
val updatesDF = ... // updates DataFrame[date, id, name] を定義します
DeltaTable.forPath(spark, "/tmp/delta_table")
.as("target")
.merge(updatesDF.as("source"), "target.id = source.id")
.whenMatched("target.name = 'should_update'")
.updateExpr(Map("target.name" -> "source.name"))
.whenMatched("target.name = 'should_delete'")
.delete()
.whenNotMatched("source.name = 'shoulde_insert'")
.insertExpr(
Map(
"date" -> "updates.date",
"eventId" -> "updates.eventId",
"data" -> "updates.data"))
.execute()UPDATE 句または INSERT 句でアスタリスク (
*) をワイルドカードとして使用できます。句がUPDATE SET *またはINSERT *の場合、すべてのフィールドが更新または挿入されます。サブクエリを持つ ON 条件はサポートされていません。ただし、サブクエリが SQL ステートメントで表現されたスカラサブクエリである場合は、
spark.sql.uncorrelated.scalar.subquery.preexecution.enabledパラメーターをtrueに設定できます。このようにして、サブクエリを持つ ON 条件を使用できます。
ALTER TABLE
既存のテーブルのスキーマとプロパティを変更します。ALTER TABLE ステートメントを実行して、テーブルに対して次の操作を実行できます。
ADD COLUMN:テーブルに列を追加します。
RENAME COLUMN:列の名前を変更します。このステートメントを使用するには、列マッピングを有効にする必要があります。
DROP COLUMN:テーブルから列を削除します。このステートメントを使用するには、列マッピングを有効にする必要があります。
SET/UNSET TBLPROPERTIES:テーブルの説明やストレージ形式など、テーブルのプロパティを設定します。
RENAME TO:テーブルの名前を変更します。
ADD COLUMN 操作を実行してパーティションテーブルに列を追加する場合は、パーティションフィールドの前に新しいフィールドを追加することをお勧めします。これは、Hive などのクエリエンジンを使用して Delta テーブルをクエリする際のデータ例外を防ぐのに役立ちます。
次のサンプルコードは、指定した位置に列を追加する方法の例を示しています。
-- delta_tbl テーブルのスキーマは (id IN, name STRING, pt STRING) です。pt はパーティションフィールドです。
-- name フィールドの後、pt フィールドの前に new_col フィールドを追加します。
ALTER TABLE dbName.tableName ADD COLUMN (new_col STRING AFTER name);DESCRIBE HISTORY
Delta テーブルの操作履歴の詳細を表示します。
このステートメントは、バージョン番号、操作時刻、ユーザー ID、ユーザー名、操作タイプ、操作パラメーター、ジョブ情報、ノートブック情報、クラスター ID、現在の操作の基になっているテーブルのバージョン、分離レベル、データを直接追加するかどうか、および操作メトリックを順番に表示します。
上記のほとんどのフィールドの値は null として表示されます。
例:
すべての操作レコードを表示します。
DESC HISTORY dbName.tableName;最新の操作レコードを表示します。
DESC HISTORY dbName.tableName limit 1;
CONVERT
Parquet テーブルを Delta テーブルに変換します。
CONVERT ステートメントは、特定のパスにあるすべての Parquet データファイルをトラバースし、現在の Parquet テーブルのスキーマを推測し、Delta テーブルに必要なメタデータ情報を生成します。Parquet テーブルがパーティションテーブルの場合、パーティションフィールドとパーティションフィールドのデータ型を指定する必要があります。
例:
指定されたパスにある Parquet データファイルを Delta テーブルに変換します。
CONVERT TO DELTA parquet.`oss://region/path/to/tbl_without_partition`;指定されたパスにある Parquet データファイルを Delta テーブルに変換し、dt フィールドと hour フィールドをパーティションフィールドとして設定します。
CONVERT TO DELTA parquet.`oss://region/path/to/tbl_with_partition` PARTITIONED BY (dt string, hour int);
CONVERT ステートメントを実行した後、テーブルパスは Delta テーブルに必要な形式に変換されますが、Delta テーブルは作成されません。CREATE TABLE ステートメントを実行して Delta テーブルを作成する必要があります。ステートメントでテーブルフィールドとパーティションフィールドを指定しないでください。サンプルコード:
CREATE TABLE tbl_without_partition
USING delta
LOCATION "oss://region/path/to/tbl_without_partition";OPTIMIZE
小さなファイルをマージするか、Z オーダーを実装することにより、Delta テーブルのデータレイアウトを最適化します。このステートメントはクエリ効率を向上させます。OPTIMIZE ステートメントを使用して、次の操作を実行できます。
パーティションテーブル内の 1 つ以上の指定されたパーティションを最適化します。
テーブルの特定の非パーティションフィールドに Z オーダーを実装して、コンパクトな最適化中にテーブルのデータレイアウトを最適化します。
サンプルコード:
set spark.databricks.delta.stats.skipping=true;
set spark.databricks.delta.stats.collect=true;
-- dbName.tableName テーブル全体を最適化します。
OPTIMIZE dbName.tableName;
-- date フィールドの値が 2021-04-01 より前のパーティションを最適化します。
OPTIMIZE dbName.tableName WHERE date < '2021-04-01';
-- date フィールドの値が 2021-04-01 より前のパーティションを最適化し、col2 列と col3 列に Z オーダーを実装します。
OPTIMIZE dbName.tableName WHERE date < '2021-04-01' ZORDER BY (col2, col3);ほとんどの場合、ストリーミングデータを Delta Lake に取り込む場合、各バッチのデータ量は少なくなります。その結果、多数の小さなファイルが生成されます。OPTIMIZE ステートメントを定期的に実行して、小さなファイルをマージできます。
クエリモードが固定されている場合は、Z オーダーを実装してデータレイアウトを最適化できます。たとえば、一部の非パーティションフィールドがクエリ条件として指定されている場合は、Z オーダーを実装できます。
VACUUM
不要になったデータファイルと、テーブルパスから保持期間よりも長く保存されているデータファイルを削除します。
VACUUM ステートメントは、次のデータファイルは削除しません。
Delta テーブルの最新バージョンに関連付けられているデータファイル。
SAVEPOINT ステートメントが実行された特定のバージョンに関連付けられているデータファイル。
次のいずれかの方法を使用して、データファイルの保持期間を指定できます。
テーブルプロパティパラメーター
delta.deletedFileRetentionDurationを設定します。デフォルトの保持期間は 1 週間です。VACUUM ステートメントで保持期間を時間単位で指定します。
構文
VACUUM (path=STRING | table=tableIdentifier) (RETAIN number HOURS)? (DRY RUN)?例
-- データファイルを削除します。 VACUUM dbName.tableName; -- 24 時間以上保持されているデータファイルを削除します。 VACUUM dbName.tableName RETAIN 24 HOURS; -- 24 時間以上保持されているデータファイルを表示します。 VACUUM dbName.tableName RETAIN 24 HOURS DRY RUN;説明VACUUM ステートメントを定期的に実行してデータファイルを削除し、より多くのストレージスペースを解放できます。
データファイルを削除する前に、
DRY RUNで終わる VACUUM ステートメントを実行して、削除されるデータファイルを表示できます。
SAVEPOINT
Delta テーブルの履歴バージョンを永続的に保持します。
Delta Lake が Delta テーブルでチェックポイント操作を実行するたびに、ログのメタデータファイルが削除されます。delta.checkpointInterval パラメーターは、チェックポイント操作の間隔を指定するために使用されます。delta.logRetentionDuration パラメーターは、ログのメタデータファイルの保持期間を指定するために使用されます。デフォルトでは、メタデータファイルは 30 日間保持されます。VACUUM ステートメントを実行すると、履歴バージョンで不要になったデータファイルも削除されます。SAVEPOINT ステートメントを実行して、データファイルとログのメタデータファイルを永続的に保持できます。タイムトラベル機能とともに SAVEPOINT ステートメントを使用して、履歴バージョンのデータを読み取ることができます。
例:
ID が 0 のバージョンを保持します。
CREATE SAVEPOINT delta.`/path/to/delta_tbl` VERSION AS OF 0;説明/path/to/delta_tblは Delta テーブルのファイルシステムパスです。特定の時点より前にリリースされた最新バージョンを保持します。
CREATE SAVEPOINT dbName.tableName TIMESTAMP AS OF "2021-04-01 10:00:00";
SAVEPOINT 操作のレコードを削除または表示します。
SAVEPOINT 操作のレコードを削除します。
-- 特定のバージョンのデータを削除します。 DROP SAVEPOINT delta.`/path/to/delta_tbl` VERSION AS OF 0; -- 特定のタイムスタンプより前のデータを削除します。 DROP SAVEPOINT dbName.tableName TIMESTAMP AS OF "2021-04-01 10:00:00";SAVEPOINT 操作のレコードを表示します。
次のステートメントは、SAVEPOINT 操作のバージョン番号、バージョン送信時刻、SAVEPOINT 操作時刻、およびその他の情報を返します。
SHOW SAVEPOINT delta.`/path/to/delta_tbl`; SHOW SAVEPOINT dbName.tableName;
ROLLBACK
Delta テーブルを特定の履歴バージョンにロールバックします。
必要なデータファイルまたはログのメタデータファイルが失われているために指定された履歴バージョンを復元できない場合は、エラーが報告されます。例:
Delta テーブルを ID が 0 のバージョンにロールバックします。
ROLLBACK delta.`/path/to/delta_tbl` VERSION AS OF 0;Delta テーブルを特定の時点より前にリリースされた最新バージョンにロールバックします。
ROLLBACK dbName.tableName TIMESTAMP AS OF "2021-04-01 10:00:00";