DuckLakeで軽量レイクハウスを試してみた

## はじめに

DuckLakeは、DuckDB上で軽量に扱えるレイクハウス形式です。ローカル環境でParquetに対応したデータ管理ができ、トランザクションやタイムトラベルも可能です。DuckDBと拡張モジュールで動作するため導入が非常に簡単で、複雑な設定も不要です。SQLやPythonの知識だけで、データレイクの高度な機能が使えます。この記事では、実際にDuckLakeを動かしながらその特徴を紹介します。


## 事前準備（macOS/Homebrew）

DuckLakeはDuckDBの拡張として動作します。以下の手順でローカルに構築できます。

### 1. DuckDBのインストール

```bash
brew install duckdb
```

### 2. DuckDBの起動

```bash
duckdb
```

### 3. DuckLake拡張の導入

```sql
INSTALL ducklake;
LOAD ducklake;
```

## DuckLakeの基本操作

DuckLakeの基本的な使い方は非常にシンプルです。以下は、DuckDB上にDuckLake形式のテーブルを作成して操作する一連の流れです。

```sql
-- DuckLake形式のメタデータカタログをファイルに定義して接続
ATTACH 'ducklake:metadata.ducklake' AS my_lake;

-- テーブル作成（例：社員IDと名前）
CREATE TABLE my_lake.employees (id INTEGER, name TEXT);

-- データ挿入
INSERT INTO my_lake.employees VALUES
  (101, '田中'),
  (102, '佐藤'),
  (103, '鈴木'),
  (104, '高橋'),
  (105, '伊藤');

-- データ確認
SELECT * FROM my_lake.employees;
```

```
出力例：
┌──────┬──────┐
│  id  │ name │
│ int  │ text │
├──────┼──────┤
│ 101  │ 田中 │
│ 102  │ 佐藤 │
│ 103  │ 鈴木 │
│ 104  │ 高橋 │
│ 105  │ 伊藤 │
└──────┴──────┘
```

この操作により、カレントディレクトリ内に `metadata.ducklake` というファイルと、その中に `data_files/` フォルダが作成され、Parquetファイルが格納されます。

```sql
-- Parquetファイルの確認（DuckDBのglob関数を使って確認可能）
FROM glob('metadata.ducklake.files/*');
```

```
出力例：
┌────────────────────────────────────────────────────────────┐
│                         file                              │
│                        varchar                            │
├────────────────────────────────────────────────────────────┤
│ metadata.ducklake.files/ducklake-abc12345.parquet         │
└────────────────────────────────────────────────────────────┘
```

このように、DuckLakeでは標準SQLだけでメタデータ管理・ファイル確認・Parquet保存までが一貫して行えます。

この時点で、Parquetファイルとメタデータファイルがローカルに生成されており、すでにLakehouseとしての構造が完成しています。


## DuckLakeでのSQL体験

以下のように、スナップショットの履歴を確認することで、どのバージョンがいつ作成されたかを明確に把握できます。これがタイムトラベルや差分取得を行う前提になります。

```sql
FROM ducklake_snapshots('my_lake');
```

```
出力例：
┌─────────────┬────────────────────────────┬────────────────┬───────────────────────────────────┐
│ snapshot_id │       snapshot_time        │ schema_version │              changes              │
│    int64    │  timestamp with time zone  │     int64      │      map(varchar, varchar[])      │
├─────────────┼────────────────────────────┼────────────────┼───────────────────────────────────┤
│           5 │ 2025-05-28 10:18:00.079+09 │              2 │ {tables_created=[main.employees]} │
│           6 │ 2025-05-28 10:18:14.397+09 │              2 │ {tables_inserted_into=[2]}        │
│           7 │ 2025-05-28 10:26:26.474+09 │              3 │ {tables_dropped=[2]}              │
│           8 │ 2025-05-28 10:27:00.503+09 │              4 │ {tables_created=[main.employees]} │
│           9 │ 2025-05-28 10:27:03.114+09 │              4 │ {tables_inserted_into=[3]}        │
│          10 │ 2025-05-28 10:28:29.08+09  │              4 │ {tables_deleted_from=[3]}         │
└─────────────┴────────────────────────────┴────────────────┴───────────────────────────────────┘
```

ここからは、先ほど作成した `employees` テーブルを使って、DuckLakeならではの機能を試していきます。

DuckLakeの大きな特長は、従来のLakehouseフォーマットに必要だったマニフェストファイルや複雑なAPIを使わず、SQLだけですべて操作できる点です。

### タイムトラベル（過去のスナップショットを参照）

以下の手順で、スナップショットを作成し、タイムトラベル機能を正しく利用できます。

```sql
--　特定の社員IDを削除
DELETE FROM my_lake.employees WHERE id = 105;
```

```sql
-- 過去のスナップショット（削除前の状態）を確認
SELECT * FROM my_lake.employees AT (VERSION => 9);
```

このクエリで、削除される前の状態（id=105を含む）を確認できます。スナップショットIDは `FROM ducklake_snapshots('my_lake')` で事前に確認してください。
![スクリーンショット 2025-05-28 10.50.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/6a8a21a2-960f-45ea-926e-5122ee2f44ac.png)


### 差分の確認（何が変わったかを明示的に確認）

```sql
FROM ducklake_table_changes('my_lake', 'main', 'employees', 9, 10);
```

この関数は、指定した2つのスナップショット間でどのような変更があったか（追加・削除など）を行単位で確認できます。

![スクリーンショット 2025-05-28 10.56.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/83996a91-02a5-4871-82c7-d73ab2dfa330.png)


### ロールバック（完全なトランザクション制御）

```sql
BEGIN TRANSACTION;
  DELETE FROM my_lake.employees;
  SELECT * FROM my_lake.employees; -- 空になる
ROLLBACK;

SELECT * FROM my_lake.employees; -- 元に戻る
```

この例では、削除した操作を即座に取り消すことができます。DuckLakeはACIDトランザクションを完全にサポートしており、実験的なデータ操作や一時的な変更でも安全に扱うことが可能です。

![スクリーンショット 2025-05-28 10.51.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/4c12df2f-bcd1-43ff-ae01-d5b112e25145.png)



## まとめ

DuckLakeは、DuckDB上で動作するシンプルなレイクハウス形式で、Parquet形式でのデータ保存とACIDトランザクションに対応しています。タイムトラベルやスナップショットの差分確認など、分析・検証に便利な機能をSQLだけで使えるのが特徴です。DuckDB拡張として手軽に導入でき、特別なセットアップは不要です。小規模な分析環境や開発用途で、手軽にレイクハウスの特性を体験したい人にとって非常に魅力的な選択肢です。