ブログBlog

GoからCloudera Impalaに繋いでみた

mentaiko
2015.02.19

近年、ビッグデータというキーワードと共にApache Hadoopが注目されています。
皆さんはHadoopにどんなイメージを持っているでしょうか?何だか難しそうですよね。
ですが、Cloudera Impalaを使えば既存のRDBと同じようにSQLでデータの取り扱いができます。
今回はGoとSQLでCloudera Impalaからデータを取り出すまでの手順を解説したいと思います。

環境

以下の環境で動作確認しました。

機能 OS IPアドレス
ODBCクライアント CentOS6.5 64bit 192.168.128.2
Cloudera Impala QuickStart VMs for CDH 5.3.x 192.168.128.1
ソフト名 バージョン
Go 1.4.1
unixODBC 2.2.14-14.el6
Cloudera ODBC Driver for Impala 2.5.23

インストール手順

Installation Guide for Cloudera ODBC 2.5.23 Driver for Impalaを参考にインストールを進めます。

依存パッケージおよびドライバ

まずは依存パッケージとドライバをインストールします。

$ sudo yum install -y cyrus-sasl cyrus-sasl-gssapi cyrus-sasl-plain unixODBC
$ sudo rpm -Uvh https://downloads.cloudera.com/connectors/impala_odbc_2.5.23.1024/Linux/EL6/ClouderaImpalaODBC-2.5.23.1024-1.el6.x86_64.rpm

unixODBCがリンクするライブラリ名がso.1でハードコードされているのでシンボリックリンクを張ります。
これをやっておかないとうまく動きません。

$ sudo ln -sf libodbc.so.2.0.0 /usr/lib64/libodbc.so.1
$ sudo ln -sf libodbcinst.so.2.0.0 /usr/lib64/libodbcinst.so.1
$ ls -l /usr/lib64/libodbc.so* /usr/lib64/libodbcinst.so*
lrwxrwxrwx 1 root root     16  2月 11 15:47 2015 /usr/lib64/libodbc.so -> libodbc.so.2.0.0
lrwxrwxrwx 1 root root     16  2月 11 15:49 2015 /usr/lib64/libodbc.so.1 -> libodbc.so.2.0.0
lrwxrwxrwx 1 root root     16  2月 11 15:47 2015 /usr/lib64/libodbc.so.2 -> libodbc.so.2.0.0
-rwxr-xr-x 1 root root 417720  7月 10 17:15 2014 /usr/lib64/libodbc.so.2.0.0
lrwxrwxrwx 1 root root     20  2月 11 15:47 2015 /usr/lib64/libodbcinst.so -> libodbcinst.so.2.0.0
lrwxrwxrwx 1 root root     20  2月 15 01:56 2015 /usr/lib64/libodbcinst.so.1 -> libodbcinst.so.2.0.0
lrwxrwxrwx 1 root root     20  2月 11 15:47 2015 /usr/lib64/libodbcinst.so.2 -> libodbcinst.so.2.0.0
-rwxr-xr-x 1 root root  68928  7月 10 17:15 2014 /usr/lib64/libodbcinst.so.2.0.0

設定ファイル

設定ファイルは3つあり、それぞれ以下の優先度で配置できます。

  • odbc.ini
    1. 環境変数ODBCINIのファイル (例: ODBCINI=/etc/odbc.ini)
    2. ~/.odbc.ini
    3. /etc/odbc.ini
  • odbcinst.ini
    1. 環境変数ODBCSYSINIのフォルダにodbcinst.iniを配置 (例: ODBCSYSINI=/etc)
    2. ~/.odbcinst.ini
    3. /etc/odbcinst.ini
  • cloudera.impalaodbc.ini
    1. 環境変数CLOUDERAIMPALAINIのファイル (例: CLOUDERAIMPALAINI=/etc/cloudera.impalaodbc.ini)
    2. /opt/cloudera/impalaodbc/lib/64/cloudera.impalaodbc.ini

今回はすべてconfディレクトリにコピーして環境変数で指定します。

$ mkdir -p work/conf
$ cd work
$ cp /opt/cloudera/impalaodbc/lib/64/cloudera.impalaodbc.ini conf/
$ cp /opt/cloudera/impalaodbc/Setup/odbc.ini conf/
$ cp /opt/cloudera/impalaodbc/Setup/odbcinst.ini conf/
$ export ODBCINI=$PWD/conf/odbc.ini
$ export ODBCSYSINI=$PWD/conf
$ export CLOUDERAIMPALAINI=$PWD/conf/cloudera.impalaodbc.ini

cloudera.impalaodbc.iniについて

  • ODBCInstLibはunixODBCのlibodbcinst.soを設定します。
  • DriverManagerEncodingはGoのためにUTF-16を設定します。
--- /opt/cloudera/impalaodbc/lib/64/cloudera.impalaodbc.ini 2015-01-19 10:23:00.000000000 +0900
+++ conf/cloudera.impalaodbc.ini    2015-02-15 17:32:47.580673175 +0900
@@ -7,7 +7,7 @@
 ## - SimbaDM can be used with UTF-8 or UTF-16.
 ##   The DriverUnicodeEncoding setting will cause SimbaDM to run in UTF-8 when set to 2 or UTF-16 when set to 1.

-DriverManagerEncoding=UTF-32
+DriverManagerEncoding=UTF-16
 ErrorMessagesPath=/opt/cloudera/impalaodbc/ErrorMessages/
 LogLevel=0
 LogPath=
@@ -19,10 +19,10 @@

 # Generic ODBCInstLib
 #   iODBC
-ODBCInstLib=libiodbcinst.so
+#ODBCInstLib=libiodbcinst.so

 #   SimbaDM / unixODBC
-#ODBCInstLib=libodbcinst.so
+ODBCInstLib=libodbcinst.so

 # AIX specific ODBCInstLib
 #   iODBC

odbcinst.iniは変更なしです。

[ODBC Drivers]
Cloudera ODBC Driver for Impala 32-bit=Installed
Cloudera ODBC Driver for Impala 64-bit=Installed

[Cloudera ODBC Driver for Impala 32-bit]
Description=Cloudera ODBC Driver for Impala (32-bit)
Driver=/opt/cloudera/impalaodbc/lib/32/libclouderaimpalaodbc32.so

[Cloudera ODBC Driver for Impala 64-bit]
Description=Cloudera ODBC Driver for Impala (64-bit)
Driver=/opt/cloudera/impalaodbc/lib/64/libclouderaimpalaodbc64.so

### The option below is for using unixODBC when compiled with -DSQL_WCHART_CONVERT.
### Execute 'odbc_config --cflags' to determine if you need to uncomment it.
## IconvEncoding=UCS-4LE

odbc.iniは以下の行を追記します。
DriverUnicodeEncodingはcloudera.impalaodbc.iniの説明に従って1を設定します。

[Impala]
Driver=/opt/cloudera/impalaodbc/lib/64/libclouderaimpalaodbc64.so
HOST=192.168.128.1
PORT=21050
Database=default
DriverUnicodeEncoding=1

動作確認

isqlコマンドでodbc.iniに追加したImpalaを指定してImpalaに接続してみます。
このときだけ環境変数LD_PRELOADの設定が必要なので注意してください。
クエリの実行結果が返ってくれば正常に動作しています。

$ export LD_PRELOAD=/usr/lib64/libodbcinst.so
$ isql Impala -m30
+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+
SQL> show databases
+-------------------------------+
| name                          |
+-------------------------------+
| _impala_builtins              |
| default                       |
+-------------------------------+
SQLRowCount returns -1
2 rows fetched
SQL> 

create table, insert, selectを試してみます。

SQL> use default
SQLRowCount returns -1
SQL> create table t (id int, name string)
SQLRowCount returns -1
SQL> show tables
+-------------------------------+
| name                          |
+-------------------------------+
| t                             |
+-------------------------------+
SQLRowCount returns -1
1 rows fetched
SQL> insert into t (id, name) values (1, "AAA"), (2, "BBB"), (3, "CCC")
SQLRowCount returns -1
SQL> select id, name from t
+------------+-------------------------------+
| id         | name                          |
+------------+-------------------------------+
| 1          | AAA                           |
| 2          | BBB                           |
| 3          | CCC                           |
+------------+-------------------------------+
SQLRowCount returns -1
3 rows fetched
SQL> 

GoとSQLでImpalaに接続

How do I connect Go on Linux to an ODBC Database?の接続文字列とクエリを変更すればそのまま動きます。

// #cgo linux LDFLAGS: -lodbc
package main

import (
    "database/sql"
    "log"

    _ "code.google.com/p/odbc"
)

const (
    DSN   = "DSN=Impala;"            // 接続文字列
    QUERY = "select id, name from t" // クエリ
)

func main() {
    db, err := sql.Open("odbc", DSN)
    if err != nil {
        log.Fatal(err)
    }

    var (
        id   int
        name string
    )

    rows, err := db.Query(QUERY)
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()
    for rows.Next() {
        err := rows.Scan(&id, &name)
        if err != nil {
            log.Fatal(err)
        }
        log.Printf("id: %d, name: %sn", id, name)
    }
    err = rows.Err()
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
}

実行すると以下のようにクエリ結果が表示されます。

$ go run odbc.go
2015/02/15 17:37:52 id: 1, name: AAA
2015/02/15 17:37:52 id: 2, name: BBB
2015/02/15 17:37:52 id: 3, name: CCC

接続文字列について

接続文字列の指定方法は次のように3つあります。
場合によって使い分けるとよいでしょう。

DSN only

odbc.iniに接続先を設定して、接続文字列ではそのカテゴリ名を設定します。

DSN = "DSN=Impala;"

設定ファイルは次の2つが必要です。

  • cloudera.impalaodbc.ini
  • odbc.ini

DSN less

odbc.iniは使用せずに、接続文字列で接続先を設定します。
DRIVERはodbcinst.iniのカテゴリ名を設定します。

DSN = "DRIVER={Cloudera ODBC Driver for Impala 64-bit};HOST=192.168.128.1;PORT=21050;Database=sandbox;"

設定ファイルは次の2つが必要です。

  • cloudera.impalaodbc.ini
  • odbcinst.ini

DSN combine

odbc.iniの定義をテンプレートにして、一部の設定を接続文字列で指定します。

DSN = "DSN=Impala;HOST=192.168.128.1;Database=sandbox;"

設定ファイルはDSN onlyと同様に次の2つが必要です。

  • cloudera.impalaodbc.ini
  • odbc.ini

まとめ

このようにCloudera ImpalaODBC Drivers & Connectors for Impalaを組み合わせる事によってHadoopの知識がなくてもSQLでデータを取り出す事ができました。
意外と簡単ではないでしょうか?

また、Apache Hiveよりも格段に速いので、バッチだけではなくフロントエンドから使う事もできそうです。

参考リンク


コメントを残す




本社 〒060-0042 札幌市中央区大通西9丁目3番地33 キタコーセンタービルディング9階
東京支店 〒103-0016 東京都中央区日本橋小網町17番18号 八幡日本橋小網町ビル1階

011-206-9235