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

パルクエの二つのバージョン

概要

  • DuckDB の開発者によるParquetフォーマット進化の障壁に関する議論
  • Parquet Version 2の仕様とエコシステム全体への影響
  • バージョン2のパフォーマンス検証結果
  • エコシステムでの互換性問題と導入判断の難しさ
  • 進化の課題と将来展望

Parquetフォーマット進化の障壁

  • DuckDB 開発者による記事「Query Engines: Gatekeepers of the Parquet File Format」での指摘
    • ParquetファイルをSQLテーブルとして扱う Query Engine が最新仕様へ未対応
    • エコシステム全体の進化が停滞する要因
  • この問題は Query Engine だけでなく、周辺ツール全体に波及
    • Carpetリリース直後、ParquetフォーマットVersion 2の存在に気付く
    • Java ParquetライブラリはVersion 2をデフォルトで有効化しない仕様
  • 仕様が確定済みでも、エコシステム全体で実装状況が不十分
    • Pandas(Python)でVersion 2ファイルの読み込み不可問題を経験
    • 互換性のため即座にロールバック対応

Parquet Version 2の仕様と実装状況

  • 仕様は確定済みだが、実装・対応状況はエコシステムでバラバラ
    • どこまで対応すれば「Version 2互換」と言えるか未合意
    • Pull Requestやメーリングリストで4年以上議論が継続
  • 仕様内で独立して進化できる2つの概念
    • 列データの エンコーディング方式 (RLE_DICTIONARY、DELTA_BYTE_ARRAY等)
    • エンコード済みデータの ファイル内配置構造 (Data Page V2)
  • エンコーディング改善は列単位の非互換、ページ構造変更はファイル全体の非互換に直結
  • 新しい論理型(例:VARIANT)は特定バージョンに依存せず追加可能
    • 例:DATEはint64、Big DecimalやStringはBYTE_ARRAYで表現
  • 機械学習分野ではParquetやORCの限界も顕在化
    • FacebookのNimble、LanceDBのLV2など新フォーマットの登場
    • ただし、これらはニッチ用途と位置付け、Parquetがデータエンジニアリング分野で主流継続予想

Parquet Version 2のパフォーマンス検証

  • ファイル書き込み時にバージョン指定はプロパティ設定のみで簡単

    • 例:CarpetWriterでWriterVersion.PARQUET_2_0を指定
  • イタリア政府データセット・New Yorkタクシーデータセットを用いた比較

    • ファイルサイズ比較

      | フォーマット | Version 1 | Version 2 | 改善率 | |---|---|---|---| | CSV | 1761MB | 1761MB | - | | UNCOMPRESSED | 564MB | 355MB | 37% | | SNAPPY | 220MB | 198MB | 10% | | GZIP | 146MB | 138MB | 5% | | ZSTD | 148MB | 144MB | 2% | | LZ4_RAW | 209MB | 192MB | 8% | | LZO | 215MB | 195MB | 9% |

      • Version 2の新エンコーディングにより、圧縮前で大きな効果
      • 追加圧縮の効果は相対的に小さくなる傾向
    • 書き込み速度比較

      | フォーマット | Version 1 | Version 2 | 改善率 | |---|---|---|---| | UNCOMPRESSED | 25.0s | 23.6s | 6% | | SNAPPY | 25.2s | 23.5s | 7% | | GZIP | 39.3s | 35.8s | 9% | | ZSTD | 27.3s | 25.7s | 6% | | LZ4_RAW | 24.9s | 23.8s | 4% | | LZO | 26.0s | 24.6s | 5% |

      • 特に数値型が多いデータセットで書き込み速度が大幅改善
      • GZIP圧縮時の改善が顕著
    • 読み込み速度比較

      | フォーマット | Version 1 | Version 2 | 改善率 | |---|---|---|---| | UNCOMPRESSED | 11.4s | 11.3s | 1% | | SNAPPY | 12.5s | 11.5s | 8% | | GZIP | 13.6s | 12.8s | 6% | | ZSTD | 13.1s | 12.2s | 7% | | LZ4_RAW | 12.8s | 11.3s | 12% | | LZO | 13.1s | 12.1s | 7% |

      • 読み込み速度も全体的に改善
      • 特に10進数型が多いデータセットで効果大

互換性問題と導入判断

  • Parquetの進化を批判する意図ではなく、 オープンフォーマット進化の難しさ を記録
  • Parquetの利便性・恩恵は小さな不便を大きく上回る
  • 最新仕様によるファイルサイズ・処理速度の改善はあるが、劇的ではない
  • エコシステムでVersion 2の採用が進んでいない現状
    • サードパーティ連携時の互換性問題を考慮し、導入の判断が必要
  • 全工程を自前で管理できる場合は、 最新仕様採用も選択肢

進化の課題と将来展望

  • オープンフォーマット進化には 合意形成の難しさ実装状況の不均一性 という構造的課題
  • エコシステム全体での 対応状況の見極め が重要
  • 新しい用途や分野での限界が見えてきた場合、 新フォーマットの検討 も必要
  • しかし、Parquetは今後もデータエンジニアリング分野で 中心的役割 を果たす見通し

Hackerたちの意見

私はオープンソースソフトウェアの長年の支持者でありユーザーとして言いますが、こういう問題があるからこそ、政府や企業は今でもOracleやSQL Serverを使い続けているんです。著者は変更を元に戻せましたが、ある業界では、計画外のデータの利用不可が発生すると、その企業でのキャリアが終わることもあります。ベンダーから「問題ない」と確認するCYAメールがないとね。そのCYAメールと責任を追及できる相手がいるからこそ、Oracleは劣ったソフトウェアソリューションを提供する企業と7桁や8桁のライセンス契約を結ぶんです。Linuxは、リーナスのリーダーシップのおかげで、このリスク問題を解決し、商業用UNIXオペレーティングシステムを完全に置き換えることができたようです。スタックの上下で、他の多くのプロジェクトも同じ成功を収められることを願っています。

コメントの最初の方で「こういう問題」と言ってたから、4年間のコアについての議論のことかと思ったよ。

それに、CERNがまた独自のファイルフォーマットを使ってるのはなんでだろう、2025年にね。https://cds.cern.ch/record/2923186

人々がOracleを使い続けるのは、たくさんのコードがあって移行がコスト高すぎるからなんだ。Oracleもソフトウェアの問題には免疫がないよ。実際、今年はクラウドのバグのあるアップグレードのせいで、2つの週末を失ったんだ。生産クラスタが失敗状態になっちゃってさ。

丁寧に反対しますが、政府や企業がOracleやSQL Serverを使い続けるのは、ほぼシスフィスのようなものです。実際に可能ですが(私たちもやっています)、それには止まることなく取り組むチームが必要です。本当に大変な作業です。

ごめんなさい、この記事を誤解していると思います。著者が変更を元に戻すと言っているのは、データベースのことではなく、彼のライブラリのバージョンのことを指しています。もし誰かが彼の新しいバージョンを使ったら、問題があったとしたら、Pandasがそのフォーマットをサポートしていないからコードが動かなかっただけだと思います。この記事は、新しいParquetフォーマットのバージョンが広く採用されていないことについてで、今Parquetコミュニティは異なる方向に引っ張られている状態にあります。これは、密接に結びつく必要のない2つの異なる焦点から生じているのです。この記事で議論されている問題がソフトウェアの信頼性にどう関係するのか、私には理解できません。

著者は変更を元に戻すことができたけど、いくつかの業界では、計画外の企業全体のデータ利用不可イベントは、その会社でのキャリアの終わりを意味するんだ。もし(大規模な)ソフトウェアのアップデートが障害を引き起こしたら、ソフトウェアを責めるべきじゃなくて、不十分なテストと検証を責めるべきだよ。大企業(俺もいくつか働いたことがあるけど)は、新しい技術を採用するのが遅いのは、非常に慎重で、すべてが適切にテストされてから導入したいからなんだ。それが、彼らが今でもOracleやSQL Server(そしてHP-UXやIBMi)を使っている理由でもある。これらの製品は動いていて、何世代もの社員が使ってきたからね。彼らがフェンスの向こう側に移ることを考えるには、かなりのメリットが必要だよ。

そうそう、2010年代にPythonコードでParquetを効果的に使うために何年も待たなきゃいけなかったんだ。主に2つ(PyarrowとFastparquet)があって、互いに互換性がなかったし、Sparkとも互換性がなかったからね。Parquetのサポートは、ブラウザにおけるJavaScriptのサポートに似てる。期待するすべてのプラットフォームで互換性があるときだけ、より高度な機能を使えるんだよね。

icebergとdelta lakeがv2をサポートしない限り、導入は本当に難しいよ。私はParquetをたくさん使ってるけど、v2.0があることすら知らなかった。

なんでv2.0を採用しないんだろう?

https://www.jeronimo.dev/the-two-versions-of-parquet/#perfor... この見出しの最初の段落は、私が圧縮アルゴリズムに関する前の投稿で考慮していなかったマークダウンエラーだね。

データがすでに特定の列でソートされているかどうかのメタデータを技術的にサポートしていると知ったとき、かなり混乱しました。私の目には、いくつかの簡単な最適化ができるように見えました。でも、最後に確認したとき、実際にはほとんど何も使われていないようで、一部のライブラリはこのフィールドすら読まないみたいです。

Arrowはデフォルトでv2.6ですが、互換性のために2.4にダウングレードするところもいくつか見ました。v1を実際に見たことはありません。

彼らは主に新しいエンコーディングについて話していて、それはdata_page_versionで管理されてるんだけど、デフォルトはv1のままなんだ。君が話してるのはスキーマとタイプについてのことだと思うけど、そっちの方が扱いやすいんじゃないかな。

こういう問題は、V1まで人気が出て、その後すぐに進化しないファイルフォーマットによく見られます。「シンプルバイナリエンコーディング」v2は、5年以上もリリース候補の段階で止まっていて、採用する価値がないと思われる欠陥があります。

HDMIが異なるレベルの仕様の完全性を同じ名前で呼ぶことを許可しているのに似ていますね。

『銀河ヒッチハイクガイド』では、シリウスサイバネティクス社のマーケティング部門を「革命が起こったときに最初に壁に向かう無思考のバカたち」と定義しています。

Parquetのリファレンス実装は巨大なJavaライブラリです。これが良いアイデアだとは思えません。RLEエンコーディングは、ランレングスエンコーディングとビットパッキングを切り替えますが、ビットパッキングの実装方法は、ビット幅、エンディアンネス、値の長さのすべての組み合わせを読み書きするために74,000行のJavaを生成するというものです。これが最適だとは信じられません。特定のCPU専用のケース(例えば、どこかの巨大クラスターで動いているParquet-Java)を除いて。もしビットパッキングだけなら、GPUにデータページをオフロードしてビット幅ごとの最適化実装を気にしなくて済むのですが、ランダムな間隔でエンコーディングを切り替える必要があるのは本当に頭が痛いです。実際のデータパターンに基づいて、これが良いアイデアである理由を示す設計文書が存在すればいいのにと思います。

補足:もしRunLengthBitPackingHybridDecoderで何かが実際にデコードされているのに、エンコーディングをRLEと呼んでいるなら、それは最初から悪いアイデアだった可能性が高いね。それに、検索するのもすごく難しくなるし。

Parquetのリファレンス実装は巨大なJavaライブラリだよ。これがいいアイデアだとは思えないな。あまり考えてないけど、理想的なリファレンス実装は、エンジンと一緒に動かして、arrowを使ってエンジンとparquetサービスの間でゼロコピーのバッファを共有するような、高度に最適化された「サービスライク」なプロセスだと思う。Parquetはarrowよりもかなり前からあったし、当時は(残念ながら)Javaがビッグデータの標準だったから、彼らはそのまま使い続けたんだ。 > ビットパッキングの実装方法は、ビット幅、エンディアン、値の長さのすべての組み合わせを読み書きするために74,000行のJavaを生成することだと思う。これはJavaの動的ディスパッチの特性を避けるためにやったんだろうね。C++やRustを使った場合も似たようなことが起こるけど、それはコンパイラレベルでの話だから、こういうことをやるにはずっと理にかなってると思う。

不完全なリファレンスと混乱した実装のファイルフォーマットがあっても、全くファイルフォーマットがないよりはマシだと思う。Parquetは、システム間で中程度のデータを移動する必要がある人や、ちょっとしたデータセットでも正確さやバグ防止を気にする人にとって、前の状況よりも生活の質が大幅に向上したんだ。もしParquetがなかったら、HDF5やORCがそのニッチを埋めていたかもしれないけど、現実的には脆弱なCSV/TSVに戻っていたと思う。

デコーダーに74 KLOC?それはおかしいよ。invokedynamicを使おうよ。確かに、invokedynamicは通常インタプリタの実装とかと関連付けられるけど、実はこのユースケースには完璧なんだ。必要に応じて正しいコードを生成して、JVMにキャッシュさせれば、次の呼び出しも手で書いたのと同じくらい速くなるんだ。もう2005年じゃないんだから、みんなJVMの本当の力を使うことを学ぶべきだよ。こういうことがJVMを特別なものにしてるんだ。

同様に、Apache SparkとScalaのバージョンについて。Sparkは長い間Scala 2.12で動いていて、最終的に2.13をサポートするようになったんだ。今でもScala 3.xをサポートする計画はないよ。Databricksは今年の5月にようやく2.13のサポートを始めたばかりだし…。