UNION 型: データ型が混在するカラムのサポート

この記事は 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 が出るころには、より使いやすくなっているはずです。