この記事は Apache Drill Advent Calendar 2015 の3日目の記事です。
少し前の記事で、一つのカラムにデータ型が混在したデータを読むときの注意点を説明しました。
その後リリースされた Drill 1.3 で、[DRILL-3229] Create a new EmbeddedVector にて改良が進行中のコードが取り込まれたことにより、データ型が混在するカラムの取り扱いができるようになりました。具体的には、UNION 型というデータ型が新たに追加され、個々のフィールドごとに異なるデータ型を内部で保持できるようになっています。
以前の記事同様、次のようなデータを用意します(以前の記事の時のデータとはほんの少し異なりますが、その理由は後述)。
$ cat /tmp/sensor.json [ {"sensor_id":15, "timestamp":"2015-10-29 08:00:00.004", "temperature":14.8}, {"sensor_id":15, "timestamp":"2015-10-29 08:05:00.011", "temperature":14.9}, {"sensor_id":15, "timestamp":"2015-10-29 08:10:00.002", "temperature":15}, {"sensor_id":15, "timestamp":"2015-10-29 08:15:00.012", "temperature":15.2}, {"sensor_id":15, "timestamp":"2015-10-29 08:20:00.009", "temperature":15.3} ]
UNION 型を有効にするために、プロパティ exec.enable_union_type を true にします。
$ apache-drill-1.3.0/bin/drill-embedded 0: jdbc:drill:zk=local> ALTER SESSION SET `exec.enable_union_type` = true;
そして SELECT * してみると、エラーなくちゃんとクエリが実行されることがわかります。このデータの temperature カラムは小数点を含むデータと含まないデータがあるので DOUBLE 型と INT 型が混在しているのですが、UNION 型を有効にすることで両方の型を格納できるようになっています。
0: jdbc:drill:zk=local> SELECT * FROM dfs.`/tmp/sensor.json`; +------------+--------------------------+--------------+ | sensor_id | timestamp | temperature | +------------+--------------------------+--------------+ | 15 | 2015-10-29 08:00:00.004 | 14.8 | | 15 | 2015-10-29 08:05:00.011 | 14.9 | | 15 | 2015-10-29 08:10:00.002 | 15 | | 15 | 2015-10-29 08:15:00.012 | 15.2 | | 15 | 2015-10-29 08:20:00.009 | 15.3 | +------------+--------------------------+--------------+ 5 rows selected (0.17 seconds)
ただし temperature カラムに集計関数を使おうとするとエラーがでます。今のところ、集計関数は UNION 型をサポートしていないためです。
0: jdbc:drill:zk=local> SELECT . . . . . . . . . . . > sensor_id, . . . . . . . . . . . > AVG(temperature) temperature . . . . . . . . . . . > FROM dfs.`/tmp/sensor.json` . . . . . . . . . . . > GROUP BY sensor_id; Error: UNSUPPORTED_OPERATION ERROR: Union type not supported in aggregate functions Fragment 0:0 [Error Id: 4186f733-5b00-415b-ab0a-f85eb070d2bd on 192.168.111.4:31010] (state=,code=0)
このような場合は以前の記事同様 CAST を使ってやれば OK です。
0: jdbc:drill:zk=local> SELECT . . . . . . . . . . . > sensor_id, . . . . . . . . . . . > AVG(CAST(temperature AS DOUBLE)) temperature . . . . . . . . . . . > FROM dfs.`/tmp/sensor.json` . . . . . . . . . . . > GROUP BY sensor_id; +------------+---------------------+ | sensor_id | temperature | +------------+---------------------+ | 15 | 15.040000000000001 | +------------+---------------------+ 1 row selected (0.339 seconds)
ところで、冒頭に述べたように、以前の記事と完全に同じデータを使わなかった理由は、現時点では UNION 型は FLATTEN 関数をサポートしていないためです。下のような "data" をキーとする配列があった場合、FLATTEN(data) でデータが展開できることを期待したいところですが、UNION 型が扱えないのでエラーになります。[DRILL-3229] Create a new EmbeddedVector はまだ「IN PROGRESS」なステータスなので、完了すればちゃんと動くようになるでしょう。
{ "data":[ {"sensor_id":15, "timestamp":"2015-10-29 08:00:00.004", "temperature":14.8}, {"sensor_id":15, "timestamp":"2015-10-29 08:05:00.011", "temperature":14.9}, ... ] }
ちなみに、[DRILL-3229] Create a new EmbeddedVector はより大きな課題である [DRILL-3228] Implement Embedded Type の一部です。UNION 型に関連する機能が揃うバージョン 1.4 が出るころには、より使いやすくなっているはずです。