沼津暮らし

沼津で暮らしているウェブエンジニアが雑多に書くブログ

Hive , Presto , Drill のプッシュダウンの考察

最近は大きなデータを扱うクエリエンジンがたくさん増えてきました。

一昔前はデータをフルスキャンして処理するパターンが多かったのですが、やはりこの方法では処理コストが大きくなるのが課題となりました。

そこでデータの読み込みでの処理コストを削減するために最近ではデータベースのように必要なカラムだけを読み込んだり、不要な行・ページをスキップするプッシュダウンの機能を持ったビッグデータ向けのクエリエンジンが増えてきました。

今日は Hive , Presto , Drill のプッシュダウンについて見ていきたいと思います。

プッシュダウンの種類

テキストや行でデータを変換しているフォーマットの場合にはすべてのフィールドを全て読み込むことになります。

f:id:koijima_proto:20171220215504p:plain

ORCやParquetなどのカラムナーフォーマットの場合には列毎にデータを保持しているため、特定のカラムや列での統計情報(MaxやMin)などを持っているため列をスキップする機能が提供されています。

特定のカラムのみを読み込むことを垂直プッシュダウンとよびます。

f:id:koijima_proto:20171220215856p:plain

行方向で不要なカラムをスキップすることを水平プッシュダウンと呼びます。

(図では行をスキップする表現になっていますが、ORCやParquetなどはページとよばれる複数のレコード単位のスキップとなります)

f:id:koijima_proto:20171220220121p:plain

これを組み合わせることにより、必要最小限のデータを読み込むことが可能となります。

f:id:koijima_proto:20171220220213p:plain

一般的なクエリエンジンでのプッシュダウンまでの流れ

Hive , Presto , Drill などでは処理命令をSQL風で表現します。

SQLという意味では同じなのですが、このSQLを構文解析し、それぞれのクエリエンジンで表現されているプログラミング言語のオブジェクトに変換されます。

プッシュダウンではテーブルスキャンが行われるデータの入力部に実装しなければならないため、この処理を表現したオブジェクトを入力を行う処理に渡してプッシュダウンができるようにしています。

垂直プッシュダウンを行うには、処理で参照されるカラムのリストが必要です。

水平プッシュダウンを行うためには、Where句に書かれているフィルタ条件が必要となります。

ネストしているデータについて

多少の違いはありますがフラットなデータ構造の場合には、クエリエンジン毎による違いはありません。

差が出てくるのはネストしているようなデータ構造の場合にプッシュダウンに差が出てきます。

例えばDrillであればテーブルスキャンに必要なカラムをネストを前提にしたオブジェクトで表現されていますが、Hive,Prestoでは第一階層のカラムのみの情報しか受け取ることができません。

例えば以下の図で「Col-2-1」のみを参照する場合でもHive,PrestoはCol-2のデータを参照します。(遅延処理を行うため参照されるまで列の展開をしないため処理コストがかからない実装もありますが)

f:id:koijima_proto:20171220221535p:plain

Drillの場合にはネストしたカラムを表現したオブジェクトで渡されるため特定のカラムのみを読み込む事が可能となります。

f:id:koijima_proto:20171220222100p:plain

ただし、Arrayの場合にはクエリエンジンの性質上、要素の展開が必要なためプッシュダウンを有効にする事が困難になっています。

水平プッシュダウンについてはDrillはそもそもフィルタ条件をくれない、Hiveはフィルタ条件のオブジェクトを解析できればネストしてても可能、Prestoは第一階層のみ可能となっています。

まとめ

ざっくり各クエリエンジンでのプッシュダウンをまとめると以下となります。

f:id:koijima_proto:20171220223021p:plain

注意:常にアップデートが行われているので今書いている情報は既に古い可能性もあります。

この記事についてはクエリエンジンのテーブルスキャンにのみ着目をしていますが、その他の機能で特性がありますのであくまでもデータの読み込みに関してのみの情報になります。