Delta Lakeとは何か？

こちらの続きと言えるでしょう。

https://qiita.com/taka_yayoi/items/31190da754106b2d284e

Delta Lakeも触り始めて約三年経ちます。しかし、当時は「一体全体Delta Lakeって何？？」となってました。

サンプルなどを動かしたり、ブログ記事を翻訳していく中でようやく「こういうものか」となってきた次第です。

なお、弊社エンジニアによる網羅的な記事もあります。こちらを読んでいただいた方が良いと思いますが、自分の復習も兼ねてまとめてみます。

https://ktksq.hatenablog.com/entry/deltalake

その他のDatabricksコアコンポーネントの記事はこちらです。

https://qiita.com/taka_yayoi/items/799b0320e4d8ae2e4234

# Delta Lakeとは

Delta Lakeのサイトです。

https://delta.io/

こちらには以下の説明があります。

> [Delta Lake](https://databricks.com/wp-content/uploads/2020/08/p975-armbrust.pdf)はSpark、PrestoDB、Flink、Trino、Hive、そして、Scala、Java、Rust、Ruby、PythonのAPIを含む計算エンジンを伴う[レイクハウスアーキテクチャ](http://cidrdb.org/cidr2021/papers/cidr2021_paper17.pdf)の構築を可能とするオープンソースのストレージフレームワークです。

これでDelta Lakeが理解できたとしたらスゴいと思います。以下の図でイメージが掴めてくるかもしれません。

![Screenshot 2025-05-28 at 21.01.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/2d33c04a-eb75-44d9-9e33-ed90a31b57b0.png)


左がストリーミングやバッチで取り込まれるデータソース、右側が分析や機械学習のようなユースケースとなっています。その間に鎮座しているのがDelta Lakeです。
そしてその下には、**お使いの既存のデータレイク**とあります。これらのキーワードに着目するとDelta Lakeが何なのかが見えてくると思います。

# レイクハウスアーキテクチャとは

Databricksが提唱しているアーキテクチャであり、レイクハウスというキーワードもDatabricksが作り出したものです。

https://www.databricks.com/jp/glossary/data-lakehouse

https://qiita.com/taka_yayoi/items/438f762126f57868aa35

名前の由来は従来からあるデータプラットフォームである、データ**レイク**とデータウェア**ハウス**とを組み合わせたものです。

## データウェアハウスとは

長い歴史を持つデータプラットフォームであり、構造化データの取り扱いに長けています。一方で、画像、音声、テキストのような非構造化データの取り扱いや(一部はサポートされていますが)機械学習は不得手です。このため、約10年前からデータレイクが活用されるようになりました。

![Screenshot 2023-08-21 at 9.52.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/cd4cdaa7-1057-1695-a165-0536e0bc52f0.png)

## データレイクとは

クラウドのオブジェクトストレージ(AWSのS3、AzureのADLS、Google CloudのGCSなど)を活用することで、構造化データ、非構造化データを問わずにデータを蓄積、活用できるデータプラットフォームとして活用が進んできました。オブジェクトストレージの耐障害性、コストパフォーマンスなどのメリットがありますが、一方で、ガバナンスが効かない、パフォーマンスが出ないなどの課題を抱えていました。

![Screenshot 2023-08-21 at 9.52.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/db1a7b5d-8f9d-2464-74e1-dda5894dab84.png)

## レイクハウスとは

上述のデータウェアハウスとデータレイクの課題をお互いを補完し合うことで解決するのが**レイクハウス**です。
![Screenshot 2023-08-21 at 9.56.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/14c0f88b-5e4c-0768-b454-56c5fc050ea9.png)

具体的には以下のように補完します。

- **データウェアハウス**ではプロプライエタリなデータフォーマットを用いておりベンダーロックインされてしまう　→　**データレイク**上のオープンフォーマットを使用する
- **データウェアハウス**では構造化データが取り扱えない(あるいは困難)　→ **データレイク**に任意のフォーマットを格納可能
- **データレイク**でファイルスキャンが発生するとパフォーマンスが出ない　→　**データレイク**上で**データウェアハウス**のインデックスのようなパフォーマンス改善の仕組みを活用可能
- **データレイク**ではトランザクション保証がされない　→ データレイク上で**データウェアハウス**のようなトランザクション保証を実現

言い換えれば、データレイクとデータウェアハウスの良いところ取りをしているのが**レイクハウス**です。レイクハウスではデータを**データレイク**に格納しますが、その際の上述の課題を**データウェアハウス**で培われた技術で解決しています。

以下に、データウェアハウス、データレイク、データレイクハウスの違いをまとめます。

|  | データウェアハウス | データレイク | データレイクハウス |
|:--|:--|:--|:--|
|**データフォーマット**   |クローズド、プロプライエタリなフォーマット   |オープンフォーマット   |オープンフォーマット  |
|**データタイプ**   |構造化データ、一部の準構造化データ   | 全てのタイプ：構造化データ、準構造化データ、テキストデータ、非構造化(生)データ  |全てのタイプ：構造化データ、準構造化データ、テキストデータ、非構造化(生)データ   |
|**データアクセス**   |SQLのみ、ファイルへの直接アクセスは未サポート   |SQL、R、Pythonなど他の言語による直接のファイルアクセスのためのオープンAPI   |SQL、R、Pythonなど他の言語による直接のファイルアクセスのためのオープンAPI   |
|**信頼性**   |ACIDトランザクションによる高品質、高信頼性のデータ   |低品質、データスワンプ   |ACIDトランザクションによる高品質、高信頼性のデータ   |
|**ガバナンス、セキュリティ**   |テーブルの行/列レベルでのきめ細かいセキュリティ、ガバナンス   |ファイルレベルのセキュリティ、貧弱なガバナンス   |テーブルの行/列レベルでのきめ細かいセキュリティ、ガバナンス   |
|**パフォーマンス**   |高   |低   |高   |
|**スケーラビリティ**   |スケーリングによるコストは指数関数的に増加   |データタイプに関係なく、低コストで大規模データを保持できるようにスケーリング   |データタイプに関係なく、低コストで大規模データを保持できるようにスケーリング   |
|**ユースケースサポート**   |BI、SQLアプリケーション、意思決定に限定   |機械学習に限定   |BI、SQL、機械学習に対応できるアーキテクチャ   |

そして、このレイクハウスを実現するために欠かせないソフトウェアがDelta Lakeとなります。
![Screenshot 2023-08-21 at 9.56.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/64c5da8f-ffc3-89ca-2e1f-0609af9bafaa.png)

# Bronze、Silver、Goldとは

聞き慣れない方もいらっしゃるかと思いますが、これらは[メダリオンアーキテクチャ](https://qiita.com/taka_yayoi/items/f3d9028cf533e2c78b9d)の構成要素となります。[こちら](#delta-lakeとは)で触れたようにデータソースからユースケースを繋いでいるのがデータパイプラインとなります。生データそのままでは分析や機械学習で活用することは困難であり、何かしらのデータ加工が必要となります。この加工処理を行うのがデータパイプラインです。そして、このデータパイプラインは多段になることが多いので、それらを整理するために用いる考え方がメダリオンアーキテクチャとなります。これは整理学であり、特定の機能を指すものではありません。

- **ブロンズ(bronze)**: 生データの保持、履歴管理用途のテーブル 
- **シルバー(silver)**: クレンジング、他のテーブルと結合した状態のテーブル
- **ゴールド(gold)**: 分析で用いる集計テーブル、機械学習で用いる特徴量テーブル

![Screenshot 2023-08-21 at 10.45.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/fba355dd-dbf9-ba60-c13f-7e3ecbf4fe8f.png)

Delta Lakeを用いることで、このようなメダリオンアーキテクチャの実現が容易になります。

# データレイクとDelta Lakeの関係は

[こちら](#delta-lakeとは)で**お使いの既存のデータレイク**として触れたように、レイクハウスにおけるデータの置き場所は**データレイク**です。その際に生じる**データレイク**の課題をDelta Lake(が提供する**データウェアハウス**由来の機能)で解決しているのが**レイクハウス**となります。

Delta Lakeのデータファイル自体はデータレイクに格納されます。後ほどのサンプルで説明しますが、Delta Lakeはファイルとしてだけではなく、SQLで操作可能な**テーブル**としても取り扱うことが可能です(最初がこれが分からなかったです)。この際にはDelta Lakeをメタストア(HiveメタストアやUnity Catalogメタストア)に登録する必要があります。

# Delta Lakeの提供機能

Deltaエンジンなどの関連機能は存在しますが、Delta Lake自体はデータフォーマットと考えていただくのが良いかと思います。以下のような機能を提供しています。フォーマットという意味ではベースは[Apache Parquet](https://parquet.apache.org/)です。これにトランザクションログの機能が追加されたものがDelta Lakeです。データの読み書きにおいては、Apache Sparkとの親和性が高いです。

![Screenshot 2023-08-21 at 11.01.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/2446912e-1cb5-16bf-7aa7-121964d52059.png)

- **ACIDトランザクション**
    - データの更新処理はすべて[トランザクションログ](https://qiita.com/taka_yayoi/items/b7f628c219463e055592)に記録されます。トランザクションログによって、データレイクに対する操作を完全に成功するか、後でリトライするために完全にロールバックされるかすることが可能となります。
![Screenshot 2023-08-21 at 11.06.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/87192bf6-d409-3cb5-4fa4-2be8dc441f66.png)
- **インデックス** Delta Lakeの実態はオブジェクトストレージ上のファイルなので、最も性能が出ないファイルの**フルスキャン**は一番避けるべき事象です。Delta Lakeではこれを実現するための[様々な機能](https://qiita.com/taka_yayoi/items/3d41a022c0d81b78afaf)を提供しています。
    - パーティショニング：典型的なクエリーに対するファイルレイアウト
    - データスキッピング：統計情報に基づくファイルの刈り込み
    - Z-Ordering：複数カラムに基づくレイアウトの最適化
- **タイムトラベル、監査ログ** Delta Lakeに対する更新処理はすべてトランザクションログに記録されます。これによって任意のタイミングのデータ断面にアクセス([タイムトラベル](https://qiita.com/taka_yayoi/items/47b58eb8696b278a3a82#%E9%81%8E%E5%8E%BB%E3%81%AE%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%AE%E3%82%B9%E3%83%8A%E3%83%83%E3%83%97%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%E3%81%AE%E3%82%AF%E3%82%A8%E3%83%AA%E3%83%BC%E3%82%BF%E3%82%A4%E3%83%A0%E3%83%88%E3%83%A9%E3%83%99%E3%83%AB))することができます。
    - 実験、レポートの再現：特定のタイミング、バージョンのデータを参照
    - アクシデントからのロールバック：1日前のデータにロールバック
![Screenshot 2023-08-21 at 11.05.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/38061fb0-4b80-a7a4-34b4-34494946eb51.png)
- **スキーマエンフォースメント**
    - Delta Lakeテーブルのスキーマを強制することが可能です。これによってデータのスキーマが勝手に変更され、データ品質が低下することを避けることができます。なお、ビジネス要件の変更に応じて明示的に[スキーマを進化](https://qiita.com/taka_yayoi/items/0336b4bbf9b0daaf92d1)させることもできます。
- **バッチとストリーミングの統合**
    - Delta Lakeのテーブルに対しては[バッチ処理](https://qiita.com/taka_yayoi/items/47b58eb8696b278a3a82)でも[ストリーミング処理](https://qiita.com/taka_yayoi/items/41d97a7c552f947729a0)でも書き込みが可能なので、データパイプラインをシンプルにすることができます。
- **DMLオペレーション**
    - Delta LakeにはANSI SQLを用いて読み書きを行うことができます。
- **オープンフォーマット**
- **大規模メタデータ管理**

# サンプル

こちらのチュートリアルを実行していきます。Databricksで実行していきます。

https://docs.databricks.com/ja/delta/tutorial.html

## テーブルの作成

`spark.read.load`でDelta Lakeのデータを読み込み、`write.saveAsTable`でテーブルに保存します。これによって、テーブルに対してSQLでアクセスできるようになります。

```py:Python
# ソースからデータのロード
df = spark.read.load("/databricks-datasets/learning-spark-v2/people/people-10m.delta")

# テーブルへのデータの書き込み
# カタログやデータベースを適宜選択してください
table_name = "takaakiyayoi_catalog.default.people_10m"
df.write.saveAsTable(table_name)
```

テーブルが作成されます。
![Screenshot 2023-08-21 at 11.30.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/6ebf093b-a7ab-235a-fb64-248efbe1cebe.png)

テーブルのメタデータを確認します。`%sql`マジックコマンドを使って直接SQLを実行します。

```sql:SQL
%sql
DESCRIBE DETAIL takaakiyayoi_catalog.default.people_10m;
```
![Screenshot 2023-08-21 at 11.37.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/983015b5-4d76-df9b-fa4a-962f3651a637.png)

更新日時やファイルパスなどを確認できます。

## UPSERT

UPSERTとはUpdateとInsertの組み合わせです。ターゲットテーブルに対してあるテーブルとの突き合わせを行い、一致する場合にはUpdate、一致しない場合にはInsertを行います。以下の例ではカラム`id`で一致するかどうかを判定しています。

```sql:SQL
%sql
CREATE OR REPLACE TEMP VIEW people_updates (
  id, firstName, middleName, lastName, gender, birthDate, ssn, salary
) AS VALUES
  (9999998, 'Billy', 'Tommie', 'Luppitt', 'M', '1992-09-17T04:00:00.000+0000', '953-38-9452', 55250),
  (9999999, 'Elias', 'Cyril', 'Leadbetter', 'M', '1984-05-22T04:00:00.000+0000', '906-51-2137', 48500),
  (10000000, 'Joshua', 'Chas', 'Broggio', 'M', '1968-07-22T04:00:00.000+0000', '988-61-6247', 90000),
  (20000001, 'John', '', 'Doe', 'M', '1978-01-14T04:00:00.000+000', '345-67-8901', 55500),
  (20000002, 'Mary', '', 'Smith', 'F', '1982-10-29T01:00:00.000+000', '456-78-9012', 98250),
  (20000003, 'Jane', '', 'Doe', 'F', '1981-06-25T04:00:00.000+000', '567-89-0123', 89900);

MERGE INTO takaakiyayoi_catalog.default.people_10m
USING people_updates
ON people_10m.id = people_updates.id
WHEN MATCHED THEN UPDATE SET *
WHEN NOT MATCHED THEN INSERT *;
```

3行がUpdateされ、3行がInsertされました。
![Screenshot 2023-08-21 at 11.40.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/5f38a1ec-e873-4dc1-0ef6-55e35b98a502.png)

この他にUPDATE、DELETE、INSERTも可能です。通常のデータベースと同じようにテーブルを操作することができます。

## 読み取り

PythonやSQLなどの言語からアクセスできます。

```py:Python
people_df = spark.read.table("takaakiyayoi_catalog.default.people_10m")
display(people_df)
```

```sql:SQL
%sql
SELECT * FROM takaakiyayoi_catalog.default.people_10m;
```

![Screenshot 2023-08-21 at 11.42.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/d3a4de4e-c62a-4b1c-fbc9-c931571d03d5.png)

## 履歴の参照

[上述](#delta-lakeの提供機能)したように、Delta Lakeのテーブルに対する更新処理はすべて記録されます。`DESCRIBE HISTORY`で履歴を確認できます。

```sql:SQL
%sql
DESCRIBE HISTORY takaakiyayoi_catalog.default.people_10m;
```
![Screenshot 2023-08-21 at 11.45.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/1ccdc644-39d2-ff1e-6ecf-77a5c74af3ce.png)

## タイムトラベル

Delta Lakeでは任意の断面のデータにアクセスすることができます。これがタイムトラベルです。以下の例ではバージョン番号`0`を指定しています。

```sql:SQL
SELECT * FROM takaakiyayoi_catalog.default.people_10m VERSION AS OF 0;
```

# まとめ

Delta Lakeを使い始めた当初は「ファイルなのかテーブルなのか？」と思っていましたが、結局のところその両方でした。今では大規模データのハンドリングにおいては欠かせないものとなっており、通常はテーブルを操作している感覚と大差ないので、Delta Lakeの存在を気にしなくなっていると言っても過言ではありません。しかし、Delta Lakeは奥深い(個人的にはDatabricks関連コンポーネントで一番奥深いと思ってます)ものであり、日々機能も改善されていっています。興味のある方は以下の記事もご覧ください。なお、DatabricksのデフォルトのデータフォーマットはDelta Lakeとなっていますので、フォーマットを指定することなしにご活用いただけます！

- [Delta Lakeクイックスタートガイド](https://qiita.com/taka_yayoi/items/345f503d5f8177084f24)
- [Delta Lakeのチュートリアル](https://qiita.com/taka_yayoi/items/d85855c94474141e479c)
- [Delta Lakeのベストプラクティス](https://qiita.com/taka_yayoi/items/472c85fba31aa2c50762)
- [DatabricksにおけるすべてのDelta的なものは何か？](https://qiita.com/taka_yayoi/items/91325c9141bad9b2c3cc)
- [はじめてのDelta Lakeへのデータ取り込み](https://qiita.com/taka_yayoi/items/c5355ecbc85f51c8503b)
- [Delta Lakeテーブルのバッチ読み込み・書き込み](https://qiita.com/taka_yayoi/items/47b58eb8696b278a3a82)
- [Deltaテーブルのdelete、update、merge](https://qiita.com/taka_yayoi/items/0d8350a2b4739392a52f)
- [Delta Lakeにダイビング：トランザクションログを読み解く](https://qiita.com/taka_yayoi/items/b7f628c219463e055592)
- [Delta Lakeにダイビング：スキーマの強制、進化](https://qiita.com/taka_yayoi/items/0336b4bbf9b0daaf92d1)
- [Delta Lakeにダイビング：DMLの内部処理\(Update、Delete、Merge\)](https://qiita.com/taka_yayoi/items/c264309e526a1d9ba149)
- [Delta Lakeのチェンジデータフィード](https://qiita.com/taka_yayoi/items/e3c40fce43561f73a50c)

### Databricksクイックスタートガイド

[Databricksクイックスタートガイド](https://www.amazon.co.jp/dp/B09V1YXFVQ/)


### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)