WindowsでSQLクエリエンジンのApache Drillを動かす

先日、Windows向けに[Hiveをビルドして動かした](http://qiita.com/qtwi/items/59e135b0a4c46e37c876)。Hiveには、よいUDFが複数あってよいのだが、クエリ毎に MapReduceするので、大規模データでないとオーバーヘッドが大きい。
同じデータをもっと手軽にクエリしたり、あるいはもっと他のデータストアを同じ方法でクエリできれば、特に、Windowsのような環境では利便性がよいかもしれない。

Apache Drillは、CSVやJSON形式のローカルファイルやHDFS上のファイル、Hive, HBase, MongoDBなどに統一したSQLを提供するクエリエンジンで、分散クエリにも対応して、Google Dremel (BigQuery) のオープンソース実装とされている。
JDBCにも対応しているので、外部のBIツールなどから接続して利用もできる。

Hive, HBase, MongoDB、ローカルファイルと分散したデータが１つのSQLで処理できることは便利な場面があると思う。ユーザー行動履歴がHiveにあって、アプリのデータはMongoDB、市場リサーチデータはCSVファイルになっているようなときに、これを１つのSQLインターフェイスで処理できたら、どうだろう。

*現状のDrillでは、最も多いと思う MySQLがサポートされていないが、Apache Sqoop を使うことで、取り込んで扱う方法もある(http://qiita.com/qtwi/items/7e2258c1a67171662c00) 。*


他のHadoop関連プロダクト同様 Windows対応がうたわれているが、設定などの解説が少なくて、誰でも簡単に動かせそうにないので、パッチを作成して、簡単にビルドして動かした。

今回のDrillのバージョンは、0.7.0で、オリジナルのDrillは、Hadoop 2.4.1、Hive 0.13.1に対応しているが、この記事シリーズの以前からの流れでは、Hadoop 2.6.0、Hive 0.12.0なので、今回のDrillは、これに対応している。Hiveは若干バージョンダウンになっている。

今回も 前回のHive、Spark、Azkaban同様、MSYS/MinGW環境で、ビルドと動作をさせる（Cygwin環境は試していないが動作するはず）。
スタンドアロンのクライアントはコマンドプロンプトからも動作する。

ビルドが面倒な場合、以下から、HadoopやHiveなども含め、ビルド済みバイナリを入手できる。

(http://sourceforge.jp/projects/win-hadoop/releases/62852)




## Drillのビルド
Drill のソースをApache Archivesからダウンロード(https://archive.apache.org/dist/drill/drill-0.7.0/apache-drill-0.7.0-src.tar.gz) して展開する。
Githubからのクローンでもビルドできるが、pomの書かれ方が若干異なるので、パッチが適用できるかは確認していない。
パッチ(https://github.com/qtwi/msys-apache-drill-0.7.0/raw/master/patch/apache-drill-0.7.0-2.6.0-0.12.0-src-0002r.patch) を入手して適用する。

```sh:
cd apache-drill-0.7.0-src
patch -u -p1 < ../apache-drill-0.7.0-2.6.0-0.12.0-src-0002r.patch
```

Windowsで動作させるために、Hadoopのネイティブライブラリが必要なので、これも先日のHadoop 2.6.0のビルドで作成したものを、入手できるようにしてあるので、(https://github.com/qtwi/msys-apache-drill-0.7.0/raw/master/hadoop-winutils/hadoop-winutils-2.6.0.zip) を distribution/srcの下にlib フォルダを作成し、コピーする。

```sh:
mkdir distribution/src/lib
cp ../hadoop-winutils-2.6.0.zip distribution/src/lib
```

ここまでできたら、maven でビルド開始する。

```
mvn -e clean install -DskipTests
```

Drillのビルドは、rat-checkが走るので、mavenのログなどをDrillのフォルダ以下に作成してしまうと、ビルドがエラーするので、注意する。

ビルドが終了したら、distribution/target/apache-drill-0.7.0 に一揃いのバイナリができあがっているので、これを任意のアプリフォルダ（例えば、C:\Apache）にコピーする。

```sh:
mv distribution/target/apache-drill-0.7.0/apache-drill-0.7.0 c:/apache
```

## Drillの設定
今回のパッチで、Windows向けの基本的な設定もしてあるので、ローカルでスタンドアロンで動作させるなら、特に何も設定しなくてもDrillを起動できる。

設定は、conf/drill-override.conf ファイルで行っているが、特に気をつけるのは、各パスの設定で、デフォルトは、LinuxやOSXでのパス設定になっているが、Windows形式のパスでないと、起動しなかったり、起動した後でエラーが発生するなどするので、注意する。

```json:drill-override.conf
drill.exec: {
  cluster-id: "drillbits1",
  zk.connect: "localhost:2181",
  metrics: {
    context: "drillbit",
    jmx: {
      enabled: true
    },
    log: {
      enabled: false,
      interval: 60
    }
  },
  http: {
    enabled: true,
    port: 8047
  },
  sys.store.provider: {
    class: "org.apache.drill.exec.store.sys.local.LocalPStoreProvider",
    local: {
      path: "c:/tmp/drill",
      write: true
    },
    # class: "org.apache.drill.exec.store.sys.zk.ZkPStoreProvider",
    zk: {
      blobroot: "file:///c:/tmp/log/drill"
  },
  trace: {
    directory: "c:/tmp/drill-trace",
    filesystem: "file:///"
  },
  tmp: {
    directories: ["c:/tmp/drill"],
    filesyystem: "drill-local:///"
  },
  sort.external.spill: {
    directories: ["c:/tmp/drill/spill"],
    fs: "file:///"
  },
  verbose: false,
  debug.error_on_leak: true
}
```

## Drillを試す
スタンドアロンのDrillは、Sqlline で起動する。

```
bin/sqlline
```

Sqllineは、コマンドプロンプトからも起動できる。

```cmd:
bin\sqlline.cmd
```

Sqllineのプロンプトが表示されたら、Drillのエンジンに接続する。

```
!connect jdbc:drill:zk=local
```

ユーザー名とパスワードをきかれるので、どちらにも `admin` を使用する。
zk=localとは、ZooKeeperを使わずにローカルで利用する指定。これにより、Drillのエンジン（Drillbit）が同時に起動する。
あとででてくるが、zk にZooKeeperのアドレスを指定することもできる。

ここで利用した jdbc:drill:zk=.. は、そのまま JDBCのドライバーインターフェイスになるので、ZooKeeperを利用して（zk=localではなく）Drillbitを起動していれば、Sqllineの代わりに別のBIツールなどからの接続にも利用できる。

ZooKeeperを利用すれば、Drillは簡単に分散環境を構築できる。
ZooKeeperは、Windowsでも、特別なパッチもビルドすることなく、動作させることができる。


あとは、通常のSQLコマンドを利用できるが、ここでは、サンプルデータをクエリしてみる。

```sql:
select count(*) from cp.`employee.json`;
```

```sql:
select * from dfs.`c:/apache/apache-drill-0.7.0/sample-data/region.parquet` limit 30;
```

ここで、cp はクラスパスを意味するデータベースで、クラスパス上に含まれるデータを探すためのスキーマで、dfs はファイルシステムのためのスキーマで、こちらはデフォルトではローカルファイルシステムになっている。
利用できるスキーマは、`show databases;` で確認できる。

さらにDrillは、httpサービスが動作しており、http://localhost:8047/ にアクセスすると、Web上から、クエリを送信したり、クエリのプロファイルを確認したり、ストレージプラグインの管理を利用できる。
次に、HiveとmongoDBをクエリする方法をみる。

## DrillでHiveのデータをクエリする
Hiveのデータを扱うには、まず、Drillを起動するときに、HADOOP_HOME環境変数がただしく設定されている必要がある。

```sh:
export HADOOP_HOME=c:/apache/hadoop-2.6.0
```

利用環境によっては、HADOOP_CONF_DIRやHADOOP_CLASSPATHの設定も行う必要があるかもしれない。HADOOP_CLASSPATHは、hadoop-commonとhadoop-hdfsのクラスが入っていれば、とりあえずは動作すると思う。

つぎに、DrillのHiveストレージプラグインを設定して、有効化しなければならない。
Hiveストレージプラグインの設定には、２つの方法があり、１つは、リモート設定と、もう１つは組み込みローカル設定とある。
リモート設定は、Hiveのメタストアがローカルマシン上にないときに設定する方法で、組み込みローカル設定は、Hiveのメタストアがローカル上にあるときに設定できる。
ローカル設定では、スタンドアロンでHiveを動作させていた場合に、データがローカルファイルシステム上にあるときにも利用できるが、Hiveの実装上の問題により、エラーがよくでる。

ここでは、リモート設定を行う。
まず、HadoopのHDFSが動作していることを確認し、Hiveをリモートメタストアサービスとして起動する。

```
bin/hive --service metastore
```

ブラウザで、http://localhost:8047/storage/hive にアクセスし、以下のように設定し、Enable ボタンを押して、Hiveストレージプラグインを有効化する。

```json:
{
  "type": "hive",
  "enabled": false,
  "configProps": {
    "hive.metastore.uris": "thift://localhost:9083",
    "hive.metastore.warehouse.dir": "/user/hive/warehouse",
    "fs.default.name": "hdfs://127.0.0.1:9000/",
    "hive.metastore.sasl.enabled": "false"
  }
}
```

ここで、hive.metastore.uris は、先ほど起動した、Hiveのメタストアサービスのもので、他のマシン上で動作しているなら、そのアドレスにする。fs.default.name は、HDFSのnamenodeのアドレスとポートを設定する。

Sqlline が起動していれば、`show databases;`を実行すれば、hive のスキーマが増えていることが確認できる。

Hiveに、sampleデータベースがあり flight テーブルがあるとすると、以下のようにしてクエリできる。

```sql:
select * from hive.sample.flight where delay > 100;
```

ここでもしエラーがでる場合は、fs.default.name の設定を確認し直してみる。例えば、hdfs:ではなくhttp:にしているとエラーするし、metastore上のHDFSのURIのホストがlocalhostではなく、127.0.0.1 であれば、fs.default.name のそれも127.0.0.1 になっていないとエラーする。

ほか、注意がいる点としては、Hiveストレージプラグインの設定変更をしたり、無効化するような場合にも、Hiveのメタストアサービスが動作していなければならない。メタストアサービスを止めた状態では、設定変更もできなくなるので注意する。

## DrillでMongoDBのデータをクエリする
MongoDB もHive同様に、ストレージプラグインを有効化すればよい。Hiveのように、面倒な設定もほとんどないので、通常は、 http://localhost:8047/storage/mongo にアクセスして、Enableボタンを押せば、よいだろう。
分散環境では、シャードごとに Drillbit（クエリエンジン）を起動する。

`show databases;`でスキーマを確認すると、mongo. のものが並んでいるはずである。
ここで、mydbデータベースにtestコレクションがあるとすると以下のようにクエリできる。

```sql:
select * from mongo.mydb.test;
```

## 分散環境とJDBC接続
分散環境の設定は、ZooKeeper を起動し、Sqlline の代わりに、Drillbit を各マシン上で起動する。

$ZOOKEEPER_HOME/conf/zoo.cfg の設定のうち、dataDir をWindowsのパスになるように設定したら、コマンドプロンプトから、ZooKeeper を起動する。

```
bin\zkServer.cmd 
```

ZooKeeper を起動できたら、
各マシンの conf/drill-override.conf に zk.connect にZooKeeperのアドレスリストを設定し、sys.store.provider の class を LocalPStoreProvider から、ZkPStoreProvider (`class: "org.apache.drill.exec.store.sys.zk.ZkPStoreProvider"
`) に設定する。
オプションとして、複数の ZooKeeper に接続するには、conf/drill-override.conf の `drill.exec.zk.connect` に ZooKeeperのリストを設定する。クラスタ名は、conf/drill-override.conf の `drill.exec.cluster-id` で指定したものになる。

sh からDrillbit（クエリエンジン）を起動する。 

```
bin/drillbit start
```

あとは、Sqlline （または何かBIツール）をクライアントとして起動する。

```
bin/sqlline -u jdbc:drill:zk=localhost:2181 -n admin -p admin
```

zk=ホスト名(IPアドレス):ポート[/drill/クラスタ名] とすることで、すでに起動しているDrillbitに接続して起動するようになる。

BIツールを利用するためのJDBCドライバーは、jars/jdbc-driver フォルダにある。
JDBCドライバーとして追加するとき、conf/drill-override.conf の設定そのままの場合、URLを `zk=localhost:2181/drill/drillbits1` として、JDBCドライバーとして指定するクラスは、`org.apache.drill.jdbc.Driver` になる。 


JDBC以外の接続については、MapRがODBCドライバーも配布している(http://package.mapr.com/tools/MapR-ODBC/MapR_Drill/MapRDrill_odbc/) が、今回は試していない。
ODBCドライバーとインストールと詳細は、https://cwiki.apache.org/confluence/display/DRILL/Step+1.+Install+the+MapR+Drill+ODBC+Driver にある。

## トラブルシューティング
やや設定になやむこともあるかもしれないが、ここでは、ログの設定や何度もエラーが発生するような場合について。

HiveやMongoDBなどのストレージプラグインを有効にしているときに比較的、出会うトラブルは、Drillが、HiveやMongoDBに接続できないとき、すべてのクエリが失敗することがあること。log/sqlline.logや log/drillbit.log をよくみると気づけるが、Web UIや表面的にはわかりにくいので、まずは、各サービスにうまく接続できてることを確認する。

Drillに設定されたプロパティを確認したいときは、`select * from sys.options;`とする。

Sqlline のログは、conf/drill-env.sh にDRILL_LOG_DIR で設定した場所か、log/sqlline.log にあると思うが、conf/logback.xml ファイルを編集し、logger の level を debug にすれば、より詳しいログが残るようになる。

```xml:
<logger name="org.apache.drill" additivity="false">
  <level value="debug" />
  <appender-ref ref="FILE" />
</logger>
```

また log4j のログ設定はされていないので、conf に作成するとよいかもしれない。
これでも、エラーの原因が特定できず、復旧できない場合、Drillが作成するファイルをいったん削除してしまう方法がある。
Drillを終了し（Sqlline上から、 !quit を入力）、C:\tmp\drill フォルダを削除して、再度、Sqlline を起動する。

例えば、Web UI上から、プロファイルが表示されない（エラーになる）ような場合、C:\tmp\drill\profiles フォルダを削除して、起動し直すことでプロファイルが表示できるようになると思う。

今回のパッチでは、シェルスクリプトのSqllineには、デバッグオプションを追加してあるので、`bin/sqlline --debug` として起動すれば、デバッガをsocketポート8800で待ち受けるので、デバッガを接続できる。


以上、お疲れさまでした。