世界を動かす技術を、日本語で。

DuckLakeは統合データレイクおよびカタログフォーマットです

概要

DuckLakeは、 ParquetファイルSQLデータベース を活用した、シンプルかつ強力なデータレイク機能を提供 DuckDBチーム が開発した、オープンで独立したフォーマット 複数のデータベース と連携可能で、柔軟なデプロイシナリオを実現 スナップショットACIDトランザクション など、データレイクに必要な主要機能を網羅 MITライセンスで公開されており、商用・非商用問わず利用可能

DuckLakeの特徴と構成

  • ParquetファイルSQLデータベース を組み合わせたデータレイク構成
  • DuckDBチーム によるオープンでスタンドアロンなフォーマット
  • カタログ管理 はPostgreSQL、SQLite、MySQL、DuckDBなど、主要なSQLデータベースで対応
  • 必要なものは「 カタログ用データベース」と「 Parquetファイル保存用ストレージ」のみ
  • オブジェクトストレージ(例: AWS S3)にも対応

デプロイシナリオ

  • クライアントは 複数のDuckLakeクライアント を同時接続可能
    • PostgreSQL、MySQL、SQLiteなど、ACIDトランザクションと主キー制約をサポートするSQLシステムに対応
  • DuckDB をカタログデータベースとして利用する場合は、 単一クライアント のみ利用可

主要機能

  • スナップショットタイムトラベルクエリスキーマ進化パーティショニング 対応
  • 軽量スナップショット により、頻繁なコンパクション不要で多数のスナップショット管理
  • ACIDトランザクション による複数テーブルにまたがる同時アクセス保証
  • 統計情報 によるフィルタープッシュダウンで、大規模データセットでも高速クエリ実行

DuckLakeの利用方法

  • DuckDB の拡張機能(Extension)として提供
  • DuckDB、SQLite、PostgreSQL、MySQLでのセットアップ例
    • DuckDB:
      • INSTALL ducklake;
      • ATTACH 'ducklake:metadata.ducklake' AS my_ducklake;
      • USE my_ducklake;
    • PostgreSQL:
      • INSTALL ducklake;
      • INSTALL postgres;
      • ATTACH 'ducklake:postgres:dbname=ducklake_catalog host=your_postgres_host' AS my_ducklake (DATA_PATH 'data_files/');
      • USE my_ducklake;
    • SQLite:
      • INSTALL ducklake;
      • INSTALL sqlite;
      • ATTACH 'ducklake:sqlite:metadata.sqlite' AS my_ducklake (DATA_PATH 'data_files/');
      • USE my_ducklake;
    • MySQL:
      • INSTALL ducklake;
      • INSTALL mysql;
      • ATTACH 'ducklake:mysql:db=ducklake_catalog host=your_mysql_host' AS my_ducklake (DATA_PATH 'data_files/');
      • USE my_ducklake;

よくある質問

  • DuckLakeを使う理由

    • 軽量な オールインワン型データレイク &カタログソリューション
    • 複数DuckDBインスタンスによる同時読み書き( マルチプレイヤーDuckDB)が可能
    • DuckLake単体利用でも タイムトラベルクエリデータパーティショニング、複数ファイル保存などのメリット
  • DuckLakeとは何か

    • DuckDB発のデータレイク/レイクハウス技術の総称
    • DuckLakeレイクハウスフォーマット仕様
    • DuckLake DuckDB拡張機能(データセットの読み書き対応)
    • DuckLakeフォーマットで保存されたデータセットそのもの
  • ライセンス

    • DuckLake仕様およびDuckLake DuckDB拡張機能は MITライセンス で公開
    • 商用・非商用問わず利用可能

まとめ

  • DuckLake は、複雑なレイクハウス構成を避けつつ、 柔軟性・拡張性・高速性 を兼ね備えたデータレイク基盤
  • 多様なデータベース との連携や ACIDトランザクション軽量スナップショット など、エンタープライズ用途にも十分対応
  • MITライセンス で自由に導入可能な点も大きな魅力

Hackerたちの意見

マニフェストはこちら: https://ducklake.select/manifesto/

Icebergの競合製品で、メタデータの膨張などの欠点に対処しています: https://quesma.com/blog-detail/apache-iceberg-practical-limi... Snowflakeもメタデータ用にFoundationDBを使っていたのに対し、Icebergはメタデータ層でもblobストレージを使おうとしています。

メタデータの膨張はいくつかの要因によるけど、管理可能だよ。* スナップショットの数 * 頻繁な大規模スキーマ変更 * 小さなファイルや行レベルの更新が多い * 統計がたくさん 最後のやつは、確かに大きなスキーマではかなり悪化してた気がする。ほとんどのエンジンにはこれを助ける方法がある - コンパクション、スナップショットのエクスポートなど… ただ、最終的にはユーザー次第かも。S3テーブルはこれをある程度やってくれるはず。メタデータが1-5MB未満なら、実際には問題ないよ。コミットレートはメタデータのサイズとライターの数に実質的に制限される。私は1GB以上のメタデータファイルを本番環境で修正するためのスクリプトを書いたことがある。通常は、ファイルを削除せずにスナップショットをプルーニングしたり(後でバケットポリシーに頼って整理する)、古いスキーマバージョンを削除したりしてた。

私も同じ印象を持ったけど、彼らの動画を見た後では競合とは呼べないかな: https://youtu.be/zeonmOO9jm4?t=4032 彼らはマニフェストとメタデータファイルをオンデマンドで書くことでIcebergとの同期をサポートしていて、すでにIcebergの読み込みサポートもある。彼らはIcebergのコアの問題を修正しただけで、DuckLakeはIcebergと非常に良い双方向の形で使えるから、直接の競合ではないと思う。

ここには好きな点がたくさんありますが、メタデータが新しいDucklakeフォーマットに入ると、大規模データセットに必要な良いクエリの並列処理がどうやって実現できるのか想像しにくいです。Icebergはすでに多くの高性能クエリエンジンにしっかりサポートされていて、そのサポートは大量のデータを扱う際に重要です。

もし間違ってたら誰か訂正してほしいんだけど、私の理解ではDuckDBが常にクエリエンジンになるから、DuckDBのクエリ並列処理(シングルノードだけどマルチスレッドでディスクスピリングなど)や、DuckLakeが提供するファイルプルーニングや述語プッシュダウンなどの統計ベースの最適化にアクセスできると思う。DuckLakeはDuckDBに強く結びついていると思う(私たちのユースケースには良いことだね)。再度言うけど、これは私の理解だから、間違ってたら教えて。

DuckDBのメタデータを保存する必要はないよ。自分のPostgreSQLやMySQLに置いておけば大丈夫、Iceberg REST Catalogみたいにね。クエリの並列処理は、エッジで計算を行えるようにすることで解決しているから、コンピュート層の水平スケーリングが可能になるんだ。メタデータ層のスケーラビリティ問題を解決することにはあまり注力していないから、DuckDBのコンピュートノードがたくさんエッジで動いている場合は、PostgreSQLを独立してスケールさせる必要があるかも。

これめっちゃいいね!個人的にIcebergに対して一番不満だったのは、ノートパソコンで試すのがすごく難しいこと。Delta LakeはバニラのPython実装があるけど、それはバラバラでバグも多い印象。Icebergはローカルでは全然動かなかったし、JVMクラスターと大量のセットアップが必要だった。SQLite/Postgres+DuckDB+Parquetファイルをblobストレージで使おうとしたこともあるけど、かなり手間がかかった。これならすぐに使えるみたいで、かなり合理的なデータサイズにスケールアップできそう。DuckDBの人たちの仕事は通常素晴らしいから、彼らがこの分野を理解しているのは明らか。試すのが楽しみ!

PyIcebergは試してみた?純粋なPython実装で、結構うまく動くよ。SQLカタログと、組み込みのSQLite SQLカタログを介したインメモリカタログもサポートしてる。 https://py.iceberg.apache.org/

Delta-io(deltalake-rベース)は、ローカルで非常に簡単に動くよ。pip installして、書くだけでカタログも全部揃うから。 https://delta-io.github.io/delta-rs/

こちらがステップバイステップのセットアップだよ。S3とRDSを使ってるけど、ローカルのsqliteに入れ替えるのも簡単だよ。 https://www.definite.app/blog/cloud-iceberg-duckdb-aws

確かにローカルで試すのはすごく簡単だよ!例えば、marimoノートブックで、数行のコードだけでできるよ。 https://www.youtube.com/watch?v=x6YtqvGcDBY (開示:私はmarimoの開発者です。)

これに関して何かまとめようかなって考えてるんだ。k3sと連携するヘルムチャートみたいなやつ。datapainsにはtrinoを動かすためのいいものがあって、ちょっとハッキングすればhivemetastoreも動かせるよ。ちょっといじってみたら、trinoでicebergコネクタが動くようになって、全体の流れが分かったんだ。データをダムなHiveにロードして、そこに向けたtrinoテーブルを使って、insert from select ...でicebergに入れてる。もしduckの連中が簡単に動かせるものを持ってたら、他の連中のランチを食べ始めるかもしれないね。

一周回ってきたね。データベースを作りたいなら、データベースのように作らなきゃいけない。DuckDBの皆さん、ありがとう!

私の理解では、MotherDuckはDuckDBの「マルチプレイヤーモード」を提供することに注力していると思ってた。DuckDB Labsがデータレイクをネイティブにサポートしているのは面白いね。MotherDuckは、DuckDBのノートブックインターフェースを提供することでUI層に移行しようとしているのかも。

いい指摘だね!公式発表を期待しつつ、MotherDuckがDuckLakeカタログをホストし、DuckDBを使ってDuckLakesをクエリできるようにするつもりだって確認できるよ。

これがMother Duck(https://motherduck.com/)とどう関係しているのか気になるな。彼らは「DuckDBを活用したデータウェアハウジング」をやってるけど、かなり前からやってるしね。

MotherduckはクラウドでDuckDBをホストしてるよ。DuckLakeはもっとオープンなシステムなんだ。DuckLakeでは、複数のリーダーとライターインスタンスを使ってペタバイト規模のウェアハウスを構築できるし、全てがS3やEC2インスタンス上でトランザクショナルに動くんだ。Motherduckには、ライターインスタンスが1つしかないとかの制限があるよ。リードレプリカは1分遅れることもあるし(トランザクショナルじゃない)。異なるインスタンスが同時に異なるテーブルに書き込むことはできない。DuckLakeは、トランザクショナルなメタデータ層でコンピュートとストレージの適切な分離を提供してくれるんだ。

どうでもいいことかもしれないけど、MotherDuckとDuckLakeはすごく相性がいいよ。MotherDuckのデータをDuckLakeに保存できるから、スケーラビリティや同時実行性、一貫性が向上するし、サードパーティのツールにも基礎データにアクセスできるようになるんだ。ここ数ヶ月ずっと取り組んできたから、もう少ししたら詳しい情報を共有するね。

仕事で貧乏人のデータレイクを作ってるんだけど、基本的にはdeltalake-rのPythonバインディングを使ってパーケットファイルをBlobストレージに置いて、DuckDBでクエリしてる。でも、同時書き込みの問題にいつも直面してるんだ。APIからデータを引っ張るために、x分ごとにトリガーされるクラウドファンクションがあって、それは大丈夫なんだけど、バックフィルを実行する必要があるとき、そのプロセスがタイマーでトリガーされたファンクションと同時に動くリスクがあるんだ。特に、バックフィルキューに何百もの実行が必要なジョブを詰め込んで、クラウドファンクションのワーカーが飽和し始めると、やばいことになる。

ファイル名にランダムに選ばれたサフィックスを追加してみたら?

書き込みを試みる前に、jsonファイルのリースを取って、その方法で書き込みをキューに入れた方がいいよ。

Parquetに関して、個人的にちょっとイライラしてることがあって、それが「データレイク / レイクハウス」のレイヤーで解決されてるんだけど、互換性がないんだよね。それは範囲パーティショニング。Parquetにぴったりなアプリケーションがあるんだけど、タイムスタンプ付きデータのソースがあって(基本的には時系列データなんだけど、間隔が均等じゃないこともある -- ログファイルみたいな感じ)、行はタイムスタンプと他のカラムがいくつかあるんだ。すべてのカラムはParquetがうまく扱えるデータ型だし[0]、データは蓄積されてバッチで書き出される。バッチはちゃんとしたサイズで、データはあるパーティションカラムで自然にパーティショニングされてる。各パーティションカラムの値には1つのライターしかいないから、ここまでは順調。バッチを書き込む操作は、単一のファイル作成かオブジェクトストアへの作成呼び出しで済むんだ。パーティションカラムは、実質的な標準のHiveパーティショニングスキームにマッピングされる。ただ、データは(明らかに)タイムスタンプでもパーティショニングされてるから、各バッチは重ならないタイムスタンプの範囲をカバーしてる。Hiveパーティショニングではこれを表現できないから、優れたクエリツールがデータを自然にインポートできないんだ。大きなハックをしないといけない。例えば「date」みたいな無意味なカラムでパーティショニングすることもできるけど、そうするとバッチを日付の境界に合わせる必要があって、クエリも見た目が悪くなる。ファイルを書いて「.parquet」をインポートすることもできるけど、パフォーマンスが落ちてお金がかかる。IcebergやDelta Lakeを使うのも、彼らのクライアントツールが範囲パーティションを扱えるからってだけのメリットなんだ。ほんと、他の複雑さは別にいらないんだよね。個人的には、みんなが範囲パーティショニング用のディレクトリ名やファイル名のスキームを考えてくれたらすごくいいと思う。[0] あと、Parquetの行とArrowの行、Thriftメッセージ、protobufメッセージなどはほぼ同じだけど、完全には一致しないのが気になる。単一のParquet行や行のストリーム用のバイナリフォーマットがあれば、ツール同士がデータを協力して生成しやすくなると思うんだ。

フッターメタデータがこのニーズに対して十分じゃないのはなぜ?メタデータには、関心のあるカラムからの最小・最大タイムスタンプ値が含まれているべきで、クエリを実行する際には、クエリツールがメタデータを読み込んで、そのParquetファイルを読むべきかどうかを判断するために最適化されるべきなんだ。

低レベルのarrow/parquetライブラリでは、行グループやデータページを制御できるよ(ただし、かなり手間がかかるけど)。arrow-rsクレートを使って、ファイルからデータをクエリする速度を劇的に改善したことがある(約10倍速くなった)。行グループによっては数行しかないものもあれば、何千行もあるものもあるけど、多くの行グループを検索しなくて済むのは偏りを無視できるからね。ただし、ファイルごとの行グループの制限(2^15)があることには注意が必要。

これってHiveのイライラポイントで、Parquetのじゃないかも?確かに、カラムの最小・最大範囲を見るためにParquetファイルを開く必要があるけど、そのデータだけで、範囲外のデータがあればそれ以上のリクエストは必要ないはず。そういうメタデータは、DuckLakeみたいなところにプッシュするのが有用だと思う。

Hiveは2種類のパーティショニングをサポートしてるよ、注入型と動的型ね。UNIX時間の時間みたいなパーティションキーを使うことも全然できるよ。それはあるエポックから始まる整数で、3600ずつ増えていくんだ。クエリエンジンによっては、クエリしたいパーティションやその範囲を指定しなきゃいけない場合もあるけど、datepartition >= adatepartition < bをクエリに使うこともできるよ。Icebergはそれを解決して、単にタイムスタンプを使わせてくれるみたい。おそらく、メタデータが関係ないパーティションを除外するのに賢いんだろうね。

これめっちゃクールだね!気づいたことが一つあるんだけど、table_statscolumn_statsのテーブルがスナップショットバージョンになってないんだよね。これって何に使うの?それってタイムトラベルクエリ(例えば、SELECT COUNT(*) FROM tbl WHERE snapshot_id=みたいな)に影響しないのかな?