Riak CSのデータをHiveに取り込むなど

みんなでやるRiakアドベントカレンダーの記事。昨年はそういえば辛かったのだけど、今年は沢山の人が参加してくれてとても嬉しいのである。…といいつつ準備するネタがなくてエントリーするのは躊躇していたのだけども。

プログラミング Hive

プログラミング Hive

目的

Riak CSはサーバーを集めてなんとなくクラスタ化するとREST APIでアクセスできるという謎のソフトウェアストレージだ。近い製品や似た製品、ライバル製品はいろいろあるが混乱を呼ぶのでここでは書かない。とはいえデータストアだけあってもこのクラウド時代にデータ貯めるだけじゃあつまらない。プログラムは処理系とデータが集まってこそ使える…ということで、安直な分散処理システムということでHadoopとくっつけて使うのは次のソフトウェアデザイン2014年2月号で出てしまうので、今度はHiveとくっつけて使ってみようという目論見である。

誰得なのか

Hiveといえばアドホッククエリとかバッチ処理をHiveQLというクエリ言語の処理系である。一番よく表に出てくる使い方はログ解析の処理系に使ってアクセス解析とかサイト改善とか、BIツールの代わりに使う場合もある。MapReduceにHDFSを使ってI/O分散をするケースじゃない場合とかだとまあ別にHDFSじゃなくてもいいよねということはある。…と思っていたら、Riak Meetup Tokyo #3mixiの事例 を出してもらえることになったけど、まあそういう使い方ができる。

Riak CSのインストールとか動作確認

Gitから落としてきてソースコードから入れる 方法もあるが、RPMやYumのパッケージから入れる方がよい。理由はErlang/OTPのバージョンにRiakが追随できていないので、古いR15B0xを使わないといけなくてハマったりするからだ。まあ特にハマるところはないという前提で。いずれにせよ、ダウンロードページから落としてきて適当に入れて設定してもらえばよい。健闘を祈る。

このとき、 cs_root_host とかポート番号はデフォルトのままにしておくとよい。

$ s3cmd mb s3://hive
Bucket 's3://hive/' created
$ s3cmd ls 
2013-12-21 13:17  s3://hive

Hive のインストールとか動作確認

これは本当に大変だった。

Hadoop のインストールと用意

これは必要かどうかはちょっとわかっていない。ぼくの環境がそうなっているだけ、ということなので。Hadoop 1.2.1を理研のミラーから落としてきて入れてある。解凍したものは普通にHadoopをセットアップする要領で入れていこう。ただし、JobTrackerやTaskTrackerを上げておく必要はない(ふつうにHiveがローカルモードで動作してくれるっぽい、よくわからない)。

S3にアクセスするので jets3t.properties を conf ディレクトリに入れておく必要がある。よくわからないけど紆余曲折の末こういう感じになった:

storage-service.internal-error-retry-max=5
storage-service.disable-live-md5=false
threaded-service.max-thread-count=20
threaded-service.admin-max-thread-count=20
s3service.max-thread-count=20
s3service.admin-max-thread-count=20
s3service.https-only=false
httpclient.proxy-host=localhost
httpclient.proxy-port=8080

ローカルで動かすので SSL はデフォルトで使わないようにしたりしてある。他のものは特に根拠はなので、なくても動くだろう。$HADOOP_HOMEなどが正しく設定されていないとHiveも多分うごかない。アクセスキーなどをhadoop-site.xmlにS3の場合と同様に書いておく必要がある。うまく設定できていると

$ hadoop jar mapreduce-examples.jar wordcount s3n://foobar/bar /tmp/output

とかそういうのが動いてくれる。このあたりの方法はソフトウェアデザインの来年2月号にもう少しだけ詳しく書いたので、そちらを見てもらいたい。ぜひとも買ってもらいたい。

Hiveのインストールと用意

Hiveも理研のミラーから 0.12.0 を落としてきて解凍。途中までふつうに設定しておく。まずはローカルで動かすのにかなり苦労したのだけど(MySQLなんてやるんじゃなかった)…HIVE_HOMEとかmetastoreとかは、普通にそこまではできたとして。 conf にも念のため jets3t.properties を同じものを入れておく。hive-site.xml はこんな感じ。

<property>
  <name>hive.metastore.warehouse.dir</name>
  <value>/home/kuenishi/hadoop/hive/warehouse</value>
  <description>location of default database for the warehouse</description>
</property>

元データは @ITのHive記事 の data.tar.gz を使う。この中に perf.csv というのがあって、都道府県の番号と都道府県名が並んでいるだけだ。これをあとでロードするが、とりあえずローカルのファイルからテーブルを作ってみる。 data.tar.gz を解凍すると localfiles というディレクトリができて驚いた。

まずは外部テーブルとして登録してみる。

$ bin/hive
> create database postal;
OK

>CREATE TABLE pref (id INT, name STRING)                         
    >ROW FORMAT DELIMITED                                            
    >FIELDS TERMINATED BY ','                                        
    >LINES TERMINATED BY '\n'                                        
    > STORED AS TEXTFILE
    > LOCATION '/home/kuenishi/hadoop/localfiles'
    > ;

クエリをかける

> select * from pref where id = 5;
Total MapReduce jobs = 1
Launching Job 1 out of 1
Number of reduce tasks is set to 0 since there's no reduce operator
Execution log at: /tmp/kuenishi/.log
Job running in-process (local Hadoop)
Hadoop job information for null: number of mappers: 0; number of reducers: 0
2013-12-21 22:25:50,183 null map = 50%,  reduce = 0%
Ended Job = job_local1599025941_0001
Execution completed successfully
Mapred Local Task Succeeded . Convert the Join into MapJoin
OK
5       秋田県
Time taken: 7.819 seconds, Fetched: 1 row(s)

一行引いてくるだけなのに大袈裟w 無事にHiveはとりあえず動いた。注意しておきたいのは、 warehouse のディレクトリはローカルにあるので大きなデータを置かないようにしないといけないという点。

Riak CS を叩こうとしてみる

まずは同じデータをRiak CS上に置く。

$ s3cmd put pref.csv s3://hive/ext/
$ s3cmd ls -r s3://hive/ext/
2013-12-21 13:27       611   s3://hive/ext/pref/pref.csv

これを外部テーブルにする

    >CREATE TABLE pref2 (id INT, name STRING)                        
    > ROW FORMAT DELIMITED                        
    > FIELDS TERMINATED BY ','                    
    > LINES TERMINATED BY '\n'                    
    > STORED AS TEXTFILE                          
    > LOCATION 's3n://hive/ext/pref'              
    > ;
FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. MetaException(message:java.lang.IllegalArgumentException: AWS Access Key ID and Secret Access Key must be specified as the username or password (respectively) of a s3n URL, or by setting the fs.s3n.awsAccessKeyId or fs.s3n.awsSecretAccessKey properties (respectively).)

おおダメか、と、 hive-site.xml の設定に失敗しているとこれが出るのでhive-site.xmlに追加しておく。

<property>
  <name>fs.s3n.awsAccessKeyId</name>
  <value>J_PJJS7NEHXJSQQboom!</value>
</property>
<property>
  <name>fs.s3n.awsSecretAccessKey</name>
  <value>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==</value>
</property>

これを書いて一旦Hiveをログアウトして、もういちどコマンドを起動する。

hive (default)> use postal;
OK
Time taken: 0.016 seconds
hive (postal)> CREATE TABLE pref2 (id INT, name STRING)
             > ROW FORMAT DELIMITED
             > FIELDS TERMINATED BY ','
             > LINES TERMINATED BY '\n'
             > STORED AS TEXTFILE
             > LOCATION 's3n://hive/ext/pref'
             > ;
OK
Time taken: 0.686 seconds

キタ━(゚∀゚)━! 今度はクエリを投げる

hive (postal)> select * from pref2 where id=30;        
Total MapReduce jobs = 1
Launching Job 1 out of 1
Number of reduce tasks is set to 0 since there's no reduce operator
Execution log at: /tmp/kuenishi/.log
Job running in-process (local Hadoop)
Hadoop job information for null: number of mappers: 0; number of reducers: 0
2013-12-21 22:36:26,998 null map = 0%,  reduce = 0%
Ended Job = job_local1077531583_0001
Execution completed successfully
Mapred Local Task Succeeded . Convert the Join into MapJoin
OK
30      和歌山県
Time taken: 10.698 seconds, Fetched: 1 row(s)
hive (postal)> 

ここまで、思ったより簡単に動いてしまった…

まとめ

  • Riak CS上のデータをHiveの入力にするのは思ったより簡単だった
  • warehouse置き場はできればHDFSがよい(データ入力バウンドな処理なら)。
  • CPUバウンドとかReduceバウンドなクエリが多いならwarehouseを置いてもよいかも…
  • 必要に応じてインポートするべし

なんとか日付変わる前にできた。

番外

warehouse をRiak CS に置いても大丈夫そう…か?

<property>
  <name>hive.metastore.warehouse.dir</name>
  <value>s3n://hive/warehouse</value>
  <description>location of default database for the warehouse</description>
</property>

だけど、データのインポートを完全に試したわけじゃないのであまりオススメはできない。