読者です 読者をやめる 読者になる 読者になる

Apache Drill で日本語を扱うときの注意

Drill

言語の設定がUTF-8になっている環境であれば、データに日本語が含まれていても基本的に問題はありません。

$ echo $LANG
ja_JP.UTF-8

次のようなCSVファイルを

$ cat /tmp/test.csv
1,くまモン,熊本
2,ふなっしー,船橋
3,せんとくん,奈良

次のSQLで取得すると、カラム名、データともきちんと表示されます。まあ、マルチバイト文字が入っていると水平の表示位置がずれるのですが。

$ apache-drill-1.0.0/bin/drill-embedded
0: jdbc:drill:zk=local> SELECT
. . . . . . . . . . . >   COLUMNS[0] 番号,
. . . . . . . . . . . >   COLUMNS[1] 名前,
. . . . . . . . . . . >   COLUMNS[2] 住所
. . . . . . . . . . . > FROM dfs.`/tmp/test.csv`;
+-----+--------+-----+
| 番号  |   名前   | 住所  |
+-----+--------+-----+
| 1   | くまモン   | 熊本  |
| 2   | ふなっしー  | 船橋  |
| 3   | せんとくん  | 奈良  |
+-----+--------+-----+
3 rows selected (2.711 seconds)

ところがSQLの中で文字列リテラルとして日本語を記述すると、次のようなエラーが出ます。

0: jdbc:drill:zk=local> SELECT
. . . . . . . . . . . >   COLUMNS[0] 番号,
. . . . . . . . . . . >   COLUMNS[1] 名前,
. . . . . . . . . . . >   COLUMNS[2] 住所
. . . . . . . . . . . > FROM dfs.`/tmp/test.csv`
. . . . . . . . . . . > WHERE COLUMNS[2] = '熊本';
5 29, 2015 2:13:32 午後 org.apache.calcite.runtime.CalciteException <init>
重大: org.apache.calcite.runtime.CalciteException: Failed to encode '熊本' in character set 'ISO-8859-1'
Error: SYSTEM ERROR: org.apache.calcite.runtime.CalciteException: Failed to encode '熊本' in character set 'ISO-8859-1'


[Error Id: 0a2a7793-19e2-4792-9820-7d5af813b934 on mbp:31010] (state=,code=0)

これは「熊本」という文字列をISO-8859-1文字セットで扱おうとして失敗したという内容です。DrillはSQLパーサの部分にApache Calciteを利用しているため、 Calciteのドキュメントを見てみましょう。

Apache Calcite - SQL Language
http://calcite.incubator.apache.org/docs/reference.html

データ型のCHAR(n)の説明の部分にこんな記載があります。

データ型説明範囲と例
CHAR(n), CHARACTER(n) 固定長文字列 'Hello', '' (空文字列), _latin1'Hello', n'Hello', _UTF16'Hello', 'Hello' 'there' (複数パートに分割されたリテラル)

これを見ると、どうも「_UTF16'文字列'」という書き方をするとうまくいきそうな予感がします。確かに文字列のJavaにおける内部表現はUTF-16です。

文字列の部分を書き換えて、もう一度先ほどのクエリを実行してみます。

0: jdbc:drill:zk=local> SELECT
. . . . . . . . . . . >   COLUMNS[0] 番号,
. . . . . . . . . . . >   COLUMNS[1] 名前,
. . . . . . . . . . . >   COLUMNS[2] 住所
. . . . . . . . . . . > FROM dfs.`/tmp/test.csv`
. . . . . . . . . . . > WHERE COLUMNS[2] = _UTF16'熊本';
+-----+--------+-----+
| 番号  |   名前   | 住所  |
+-----+--------+-----+
| 1   | くまモン   | 熊本  |
+-----+--------+-----+
1 rows selected (1.543 seconds)

こんどはうまくいきました。

ただ、毎回文字列が現れるところで「_UTF16」と入れるのは面倒ですね。これをデフォルトにできないものでしょうか。と思い、Calciteのソースコードを見ていくと

  /**
   * The string property "saffron.default.charset" is the name of the default
   * character set. The default is "ISO-8859-1". It is used in
   * {@link org.apache.calcite.sql.validate.SqlValidator}.
   */
  public final StringProperty defaultCharset =
      new StringProperty(this, "saffron.default.charset", "ISO-8859-1");

「saffron.default.charset」というプロパティにUTF-16を指定すればよさそうな感じです。これを記載するのは、設定ファイルdrill-env.shの中の環境変数DRILL_SHELL_JAVA_OPTSのところにします。文字セット名は、いろいろ試したところ、「UTF-16LE」である必要があるようです。

$ vi apache-drill-1.0.0/conf/drill-env.sh
export DRILL_SHELL_JAVA_OPTS="-Dsaffron.default.charset=UTF-16LE"

これで、個別に「_UTF16」の指定をしなくても、日本語が扱えるようになりました。