Delta Lakeのジェネレーテッドカラム
プレビュー
この機能は パブリック プレビュー段階です。
Delta Lakeの生成された列は、テーブル内の他の列に対するユーザー定義式から値を自動的にコンピュートし、格納します。生成された列に値を指定せずにテーブルに書き込むと、Delta Lake はそれらを自動的にコンピュートします。値を指定する場合、それらは(<value> <=> <generation expression>) IS TRUEを満たす必要があります。そうしないと、書き込みは失敗します。Databricksの制約を参照してください。
たとえば、price_with_taxのデータを指定する書き込みを必要とせずに、base_price * 1.1からprice_with_tax列をコンピュートできます。
通常の列と同様に、生成された列はテーブルの基になるデータファイルに物理的に格納されます。
生成された列を有効にすると、テーブルライタープロトコルがアップグレードされます。これは、外部の Delta Lake クライアントとの互換性に影響を与える可能性があります。Delta Lake 機能の互換性とプロトコルを参照してください。
ジェネレーテッドカラムを含むテーブルを作成する
次の例は、生成されたカラムを持つテーブルを作成する方法を示しています:
- SQL
- Python
- Scala
CREATE TABLE default.people10m (
id INT,
firstName STRING,
middleName STRING,
lastName STRING,
gender STRING,
birthDate TIMESTAMP,
dateOfBirth DATE GENERATED ALWAYS AS (CAST(birthDate AS DATE)),
ssn STRING,
salary INT
)
DeltaTable.create(spark) \
.tableName("default.people10m") \
.addColumn("id", "INT") \
.addColumn("firstName", "STRING") \
.addColumn("middleName", "STRING") \
.addColumn("lastName", "STRING", comment = "surname") \
.addColumn("gender", "STRING") \
.addColumn("birthDate", "TIMESTAMP") \
.addColumn("dateOfBirth", DateType(), generatedAlwaysAs="CAST(birthDate AS DATE)") \
.addColumn("ssn", "STRING") \
.addColumn("salary", "INT") \
.execute()
DeltaTable.create(spark)
.tableName("default.people10m")
.addColumn("id", "INT")
.addColumn("firstName", "STRING")
.addColumn("middleName", "STRING")
.addColumn(
DeltaTable.columnBuilder("lastName")
.dataType("STRING")
.comment("surname")
.build())
.addColumn("lastName", "STRING", comment = "surname")
.addColumn("gender", "STRING")
.addColumn("birthDate", "TIMESTAMP")
.addColumn(
DeltaTable.columnBuilder("dateOfBirth")
.dataType(DateType)
.generatedAlwaysAs("CAST(dateOfBirth AS DATE)")
.build())
.addColumn("ssn", "STRING")
.addColumn("salary", "INT")
.execute()
サポートされている式
生成式は、同じ入力に対して常に同じ結果を返す決定論的なSQL関数を使用できます。例えば:
- 算術演算:
base_price * 1.1 - 文字列関数:
CONCAT(first_name, ' ', last_name)SUBSTRING(col, 1, 3) - 日付関数:
CAST(birthDate AS DATE)、YEAR(eventTime)
以下の関数タイプはサポートされていません:
- ユーザー定義関数
- 集計関数
- ウィンドウ関数
- 複数の行を返す関数
パーティションフィルター生成
Databricks は、すべての新しい Delta Lake テーブルにリキッドクラスタリングを推奨しています。「テーブルにリキッドクラスタリングを使用する」を参照してください。
生成された列を使用してテーブルをパーティション化し、ベース列に対してクエリを実行すると、Delta Lake は可能な場合、パーティションフィルターを自動的に導出します。生成されたパーティション列で明示的にフィルター処理する必要はありません。Delta Lake は、ベース列の値からパーティション範囲を推論します。
Photon は Databricks Runtime 10.4 LTS 以下で必要です。Photonは Databricks Runtime 11.3 LTS 以降では必要ありません。
パーティションフィルターの生成は、次の式でサポートされています。
CAST(col AS DATE)colのタイプはTIMESTAMPです。YEAR(col)colのタイプはTIMESTAMPです。YEAR(col), MONTH(col)によって定義される2つのパーティション列、およびcolの型はTIMESTAMPです。YEAR(col), MONTH(col), DAY(col)によって定義された3つのパーティション列があり、colの型はTIMESTAMPです。YEAR(col), MONTH(col), DAY(col), HOUR(col)によって定義された4つのパーティション列と、colの型はTIMESTAMPです。SUBSTRING(col, pos, len)colのタイプですSTRINGDATE_FORMAT(col, format)colのタイプはTIMESTAMPです。- 日付形式は、
yyyy-MMおよびyyyy-MM-dd-HHのパターンでのみ使用できます。 - Databricks Runtime 10.4 LTS 以降では、次のパターンを使用することもできます:
yyyy-MM-dd。
- 日付形式は、
例: 単一のパーティション
たとえば、次のテーブルがあるとします。
CREATE TABLE events(
eventId BIGINT,
data STRING,
eventType STRING,
eventTime TIMESTAMP,
eventDate date GENERATED ALWAYS AS (CAST(eventTime AS DATE))
)
PARTITIONED BY (eventType, eventDate)
その後に以下のクエリーを実行する場合:
SELECT * FROM events
WHERE eventTime >= "2020-10-01 00:00:00" AND eventTime <= "2020-10-01 12:00:00"
Delta Lake は、パーティションフィルターが指定されていなくても、以前のクエリがパーティション date=2020-10-01 のデータのみを読み取るように、自動的にパーティションフィルターを生成します。
EXPLAIN 句を使用し、指定されたプランを確認して、Delta Lake がパーティション フィルターを自動的に生成するかどうかを確認します。
例:複数のパーティション
たとえば、次のテーブルがあるとします。
CREATE TABLE events(
eventId BIGINT,
data STRING,
eventType STRING,
eventTime TIMESTAMP,
year INT GENERATED ALWAYS AS (YEAR(eventTime)),
month INT GENERATED ALWAYS AS (MONTH(eventTime)),
day INT GENERATED ALWAYS AS (DAY(eventTime))
)
PARTITIONED BY (eventType, year, month, day)
その後に以下のクエリーを実行する場合:
SELECT * FROM events
WHERE eventTime >= "2020-10-01 00:00:00" AND eventTime <= "2020-10-01 12:00:00"
Delta Lake は、パーティションフィルターが指定されていなくても、以前のクエリがパーティション year=2020/month=10/day=01 のデータのみを読み取るように、自動的にパーティションフィルターを生成します。
EXPLAIN 句を使用し、指定されたプランを確認して、Delta Lake がパーティション フィルターを自動的に生成するかどうかを確認します。
ID 列
Delta Lake テーブルで ID 列を宣言すると、並列トランザクションは無効になります。ターゲットテーブルへの並列書き込みが不要なユースケースでのみ、ID 列を使用してください。ID 列の制限を参照してください。
Delta Lake の ID 列は、テーブルに挿入された各レコードに一意の値を割り当てる生成列の一種です。次の例は、テーブル作成ステートメント中に識別列を宣言するための基本的な構文です。
- SQL
- Python
- Scala
CREATE TABLE table_name (
id_col1 BIGINT GENERATED ALWAYS AS IDENTITY,
id_col2 BIGINT GENERATED ALWAYS AS IDENTITY (START WITH -1 INCREMENT BY 1),
id_col3 BIGINT GENERATED BY DEFAULT AS IDENTITY,
id_col4 BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH -1 INCREMENT BY 1)
)
from delta.tables import DeltaTable, IdentityGenerator
from pyspark.sql.types import LongType
DeltaTable.create()
.tableName("table_name")
.addColumn("id_col1", dataType=LongType(), generatedAlwaysAs=IdentityGenerator())
.addColumn("id_col2", dataType=LongType(), generatedAlwaysAs=IdentityGenerator(start=-1, step=1))
.addColumn("id_col3", dataType=LongType(), generatedByDefaultAs=IdentityGenerator())
.addColumn("id_col4", dataType=LongType(), generatedByDefaultAs=IdentityGenerator(start=-1, step=1))
.execute()
import io.delta.tables.DeltaTable
import org.apache.spark.sql.types.LongType
DeltaTable.create(spark)
.tableName("table_name")
.addColumn(
DeltaTable.columnBuilder(spark, "id_col1")
.dataType(LongType)
.generatedAlwaysAsIdentity().build())
.addColumn(
DeltaTable.columnBuilder(spark, "id_col2")
.dataType(LongType)
.generatedAlwaysAsIdentity(start = -1L, step = 1L).build())
.addColumn(
DeltaTable.columnBuilder(spark, "id_col3")
.dataType(LongType)
.generatedByDefaultAsIdentity().build())
.addColumn(
DeltaTable.columnBuilder(spark, "id_col4")
.dataType(LongType)
.generatedByDefaultAsIdentity(start = -1L, step = 1L).build())
.execute()
ID 列のScalaとPython APIは、Databricks Runtime 16.0 以降で使用できます。
ID 列を持つテーブルを作成するためのすべての SQL 構文オプションについては、「CREATE TABLE [USING]」を参照してください。
オプションで、以下の項目を指定できます:
- 開始値です。
- ステップサイズ。正または負の値を指定できます。
開始値とステップサイズは両方とも1がデフォルトです。0 のステップサイズを指定することはできません。
ID列によって割り当てられる値は一意であり、指定されたステップの方向に、指定されたステップサイズの倍数でインクリメントされますが、連続していることは保証されません。例えば、開始値が0でステップサイズが2の場合、すべての値は正の偶数ですが、一部の偶数はスキップされる可能性があります。
句GENERATED BY DEFAULT AS IDENTITYを使用する場合、INSERT操作ではID列に値を指定できます。手動で値を設定する機能を上書きするために、GENERATED ALWAYS AS IDENTITY となるように節を変更してください。
ID 列は BIGINT 型のみをサポートし、割り当てられた値が BIGINTでサポートされている範囲を超えると操作は失敗します。
ID 列の値とデータの同期については、 ALTER TABLE ...COLUMN 句をご覧ください。
CTAS と ID 列
CREATE TABLE table_name AS SELECT (CTAS) ステートメントを使用する場合、スキーマ、ID 列の制約、またはその他のテーブル仕様を定義することはできません。
ID 列を持つ新しいテーブルを作成し、既存のデータを設定するには、次のようにします。
- 適切なスキーマ、ID 列の定義、およびその他のテーブルプロパティを含めてテーブルを作成してください。
INSERT操作を実行する。
次の例では、DEFAULT キーワードを使用して ID 列を定義します。テーブルに挿入されたデータに ID 列の有効な値が含まれている場合、これらの値が使用されます。
CREATE OR REPLACE TABLE new_table (
id BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 5),
event_date DATE,
some_value BIGINT
);
-- Inserts records including existing IDs
INSERT INTO new_table (id, event_date, some_value)
SELECT id, event_date, some_value FROM old_table;
-- Insert records and generate new IDs
INSERT INTO new_table (event_date, some_value)
SELECT event_date, some_value FROM new_records;
ID列の制限
ID 列の操作には、次の制限があります:
- ID カラムが有効なテーブルでは、並列トランザクションはサポートされていません。
- テーブルをID列でパーティション分割することはできません。
ALTER TABLEを使用してADD、REPLACE、またはCHANGEのID列を操作することはできません。- 既存のレコードのID列の値を更新することはできません。
既存のレコードのIDENTITY値を変更するには、レコードを削除し、新しいレコードとしてINSERTする必要があります。
生成列と列マスク
生成された列は、列マスクが適用されている列を参照できません。生成された値が、マスクによって保護されている基になるデータを明らかにするためです。エラーが発生し、クエリーは失敗します。「行フィルターと列マスク」を参照してください。
エラーの例を次に示します
-
マスクされた列を参照する式を持つジェネレーテッドカラムを作成することはできません。COLUMN_MASKS_GENERATED_COLUMN_UNSUPPORTED を発生します。
SQLCREATE TABLE tbl (
a INT MASK masking_function,
generated_col INT GENERATED ALWAYS AS (a + 1)
) USING DELTA; -
すでに生成された列が参照している列には、列マスクを適用できません。以下を発生 COLUMN_MASKS_REFERENCED_BY_GENERATED_COLUMN.ADD_MASK。
SQLCREATE TABLE tbl (
a INT,
generated_col INT GENERATED ALWAYS AS (a + 1)
) USING DELTA;
ALTER TABLE tbl ALTER COLUMN a SET MASK masking_function; -
生成された列が既にマスクされた列を参照しているテーブルからの読み取りもブロックされます。「COLUMN_MASKS_REFERENCED_BY_GENERATED_COLUMN.READ_BLOCKED」が発生します。
これらのエラーをすべて解決するには、生成された列とマスクされた列が重複しないようにテーブルを再設計する必要があります。