Prestoソースコードリーディング
RecordSetというインタフェースも発見した。RecordCursorを返すメソッドと、List<ColumnType>を返すメソッドを持つ。RecoreSet == テーブルのインタフェースかな。シンプル。
2013-11-15 22:01:04ConnectorMetadata, ConnectorSplitManager, ConnectorRecordSetProvider, ConnectorHandleResolver の4つをインタフェースを実装してやれば、カスタムconnectorを実装できる。
2013-11-15 22:05:25connectorはデータソースで、メタデータとデータを管理する。データの管理はSplitとRecordReaderに別れ、ファイル群がSplitで管理され、SplitをRecordReaderで読み出す。SplitはPartitionでグループ化されて管理されている。
2013-11-15 22:12:15Splitは、そのファイルが保存されているホストのアドレスを持つ任意のオブジェクト。HDFSを意識した設計だけど、ちゃんと疎結合化されているから、ハックするのは簡単そう。
2013-11-15 22:14:33カラムの属性に、パーティションキーであるか否かというフラグがあるな。一方でPartitionにはそのキーを返すメソッドがある。パーティションキーになっているカラムに対してWHERE文がかかっていたら、それに対応するPartitionをとってくるのかな。
2013-11-15 22:19:01さらにそのPartitionの中のSplit群に対してRecordCursorを作って、データを読み出す。パーティショニングはハッシュパーティショニングが前提なのかなぁ。パーティションキーになっているカラムに対し、WHEREで不等式を使って範囲を指定した場合の挙動が気になる。
2013-11-15 22:21:00パーティションなる粒度にして欲しく無いんだけども、ここは困ったな。100 < partitionKey AND partitionKey < 500 とか書いたら、100から500まで400個ものパーティションIDを検索するのかな。範囲が86400とかになったらどうなる…
2013-11-15 22:25:22む。ハック可能になっているな。ConectorSplitManager.getPartitionsメソッドに対して、定数が右辺値になった条件が渡るようになっている。そうして一旦絞り込んで得られたPartitionに対してさらにパーティショニングキーでマッチをかけるという二段構え。
2013-11-15 22:31:53しかも丁寧にも全カラムに対する定数条件が渡ってくるな。これはpushdownが実装しやすい。前段でのみ絞り込み、後段のPartitionに対するパーティショニングキーを使ったマッチは常にtrueになるように細工すれば良さそう。
2013-11-15 22:33:08ぁぁ…いやダメだコレ。定数が右辺値になった条件と言っても、オペレータが常に == だ。それは困る。< とか > も拾って欲しいのだけど、ExpressionUtil.extractConstantValuesと、プラグインインタフェース自体も変更しないとダメ。
2013-11-15 22:34:21ConnectorSplitManagerWithRange extend ConnectorSplitManagerみたいなインタフェースを追加したり、ExpressionUtil.extractConstantRangesを実装したりが必要だな。
2013-11-15 22:39:07それにSplitManagerを変更して instanceof ConnectorSplitManagerWithRange で分岐して処理を切り分ける実装が必要になるな。
2013-11-15 22:39:44そしてExpressionUtil.extractConstantRangesの実装は結構複雑になるな。右辺値はオペレータによっては必ずしも定数でなくても良い。例えば column1 < 条件の右辺値は、定数でなくても取り得る最大の値が分かれば絞り込みが可能になる。
2013-11-15 22:41:00このあたりは真面目に実装してpull-reqする手はあるな。右辺値はUDFでも良いから、UDFがプラグインで追加可能な仕様であるならば、extractConstantRangesも拡張可能である必要があり、少々複雑になり得るけども。
2013-11-15 22:42:34UDFにgetPossibleLargestValue()とgetPossibleSmallestValue()メソッドが付いていると、その辺りの実装はしやすくなるけど、それはそれで難しそうだな。
2013-11-15 22:43:23LocalExecutionPlannerという実行計画ノードを発見した。ローカル実行モードがありそうだ。
2013-11-15 22:46:26FunctionRegistryというクラスがある。シンプルなscalar関数、aggregate関数、window関数が登録されている。このListはimmutableだなぁ。関数の追加は意図していないのだろうか。でも簡単な変更にプラガブルにすることができそう。
2013-11-15 22:49:14いっそリフレクションでぶっ込めば、現状のコードでも追加はできるし、それほど難しく無さそう。Hiveと違い、GenericUDFは存在せず、各型についてメソッドを定義しないといけない。正しい選択だと思う。
2013-11-15 22:51:261つのscalar関数は1クラスではなく1メソッド。これなら実装はもの凄く簡単だな。しかし同時に決定性な関数しかかけなくなっているあたり賢いけど、勢い余って汚い関数を書きたくなったときに困りそう。まぁwindow関数があるから必要ないかな。
2013-11-15 22:53:12集約関数は、固定長引数と可変長引数で二つの基底クラスがある。いずれもデータの入力、中間集約結果の出力、中間集約結果の入力、最終集約結果の出力、この4つのメソッドがメイン。謎なmodeとか無くて非常に分かりやすい。
2013-11-15 22:57:19ソースは読みやすくて、疎結合化がしっかりしていてメンテナンスしやすい印象。あとは性能が出るのであれば、色々なコネクタが出てきて長く生き残る製品になるのではないかな。
2013-11-15 23:04:01例えば先のツイートのようにPartition一覧の絞り込み条件に範囲を受け取れるように改造を施せば、バックエンドにRDBMSを使用できる。具体的には分散したPostgreSQLにデータを保存し、PrestoでMPPを投げる、StadoのようなDWH製品はシンプルに作れるはず。
2013-11-15 23:06:20