どぅーちゅいむーにー

これ、Twitterでよくね?という日々の記録かも

Shell で操作してみる

HBase の環境が一応できたということで、まずは触ってみる。

ドキュメントとしては、Getting Started の他には API ドキュメント、Wikiと FAQ という感じらしい。
正直、Cassandra もそうだが、wiki がかなりわかりにくいと思う(探しにくいだけ?)。

ので、Shell を使ってアクセスし、help を実行したときに表示されるコマンドを1つずつ試してみることにします(できるものだけ)。
ちなみに、wiki で shell を検索したら、そのページは見つけました↓
http://wiki.apache.org/hadoop/Hbase/Shell

  • 以下、実行しているコマンド

ざっと、試したコマンドを以下に。

  1. create:テーブルの作成
  2. list:テーブル一覧
  3. describe:テーブル情報の表示
  4. put:値の設定
  5. get:値取得
  6. scan:走査
  7. delete/deleteall:削除
  8. count:行カウント
  9. disable:テーブルの無効
  10. drop:テーブルの削除


  • 一般的な点

まずはテーブル作成といきたいところですが、テーブル作成(create)の文法ででてくる「ディクショナリ」については GENERAL NOTES を参照ということなので、先に GENERAL NOTES を。

・テーブル名、カラム名はクォート(シングルクォートで囲う)すること
・カンマがコマンドパラメータのデリミタ(区切り文字)
・リターンを押下するとコマンドが実行される
・ディクショナリはテーブルの生成(creation)や変更?(alternation)で使われるディクショナリは Ruby における Hash のこと。
 サンプルを以下に。
 {'key1' => 'value1', 'key2' => 'value2', ...}
 はじめと終わりは中カッコ(curley-braces)でくくる。key と value は '=>' で区切られる。
 通常、キーは固定文字列を指定するわけですが、固定文字列の場合はクォートする必要はないようです。
 'Object.constants' という表現で、その環境における定数を参照することができるようです(現時点でピンときませんが)。
・バイナリ形式の key または value を扱う場合、ダブルクォートを使って16進または8進表記する必要がある

hbase> get 't1', "key\x03\x3f\xcd"
hbase> get 't1', "key\003\023\011"
hbase> put 't1', "test\xef\xff", 'f1:', "\x01\x33\x40"

こんな感じでしょうか。
ダブルクォートを使って、shell コマンドの結果を value として設定するといったことができるような雰囲気なのですが、現時点ではちょっと置いておきます。

  • テーブルを生成:create/list/describe

さっそくテーブルを作成。文法的なイメージはこんな感じでしょうか?
create テーブル名[, カラムファミリ]*

テーブル名の後、カラムファミリごとの定義をディクショナリで指定。
help にある実行例を以下に。

hbase> create 't1', {NAME => 'f1', VERSIONS => 5}
hbase> create 't1', {NAME => 'f1'}, {NAME => 'f2'}, {NAME => 'f3'}
hbase> # The above in shorthand would be the following:
hbase> create 't1', 'f1', 'f2', 'f3'
hbase> create 't1', {NAME => 'f1', VERSIONS => 1, TTL => 2592000, BLOCKCACHE => true}

ピンとこない部分もあるのですが、とりあえず、今回は次のようなテーブルを作成してみたいと思います。
テーブル名は people で。'name' も prop じゃん、という話はとりあえず置いておきます。

キーprop:ageprop:occupationtest:abc
issei33SEThis is a pen.
suzuki25Consultantfoo
saito40Teacherhoge
さっそく HBase に接続してテーブルを作成してみます。
というわけで特に何も考えず myhdsf2 で実行したのですが・・・

myhdfs2> ./bin/hbase shell
HBase Shell; enter 'help<RETURN>' for list of supported commands.
Version: 0.20.3, r902334, Mon Jan 25 13:13:08 PST 2010
hbase(main):001:0> create 'people', 'prop', 'test'
NativeException: org.apache.hadoop.hbase.MasterNotRunningException: 127.0.0.1:60000

というわけで、怒られてしまいました・・・
そんなわけで、myhdfs1 で再チャレンジ。

myhdfs1> ./bin/hbase shell
HBase Shell; enter 'help<RETURN>' for list of supported commands.
Version: 0.20.3, r902334, Mon Jan 25 13:13:08 PST 2010
hbase(main):001:0> create 'people', 'prop', 'test'
0 row(s) in 2.1520 seconds

今度は問題なく作られたようで。


テーブルの一覧を見てみる

hbase(main):007:0> list
people
                                                             
1 row(s) in 0.0120 seconds

できてますね(なかった状態はみてませんが・・・)。


テーブル定義を見てみる。

hbase(main):010:0> describe 'people'
DESCRIPTION                                                             ENABLED           
 {NAME => 'people', FAMILIES => [
   {NAME => 'prop', COMPRESSION => 'NONE' true, VERSIONS => '3',
    TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMORY => 'false',
    BLOCKCACHE => 'true'},
   {NAME => 'test', COMPRESSION => 'NONE', VERSIONS => '3',
    TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMORY => 'false',
    BLOCKCACHE => 'true'}
 ]}

1 row(s) in 0.0440 seconds

細かい点はおいといて、prop と test というファミリが作成されている、ってことはわかります。
※実際の表示から整形しています。

  • データを設定してみよう:put

データの設定はputで行います。
文法的にはput テーブル名, 行キー, セル, 値[, タイムスタンプ]となるようです。
テーブル、行、カラム(とオプションでタイムスタンプ)を指定して値を設定します。
テーブル t1 の r1 行のカラム c1 に、タイムスタンプ ts1 で 'value' を設定する場合は次のようなコマンドとなる。

hbase> put 't1', 'r1', 'c1', 'value', ts1

では、さっそく。

hbase(main):011:0> put 'people', 'issei', 'prop:age', '33'
0 row(s) in 0.0070 seconds
hbase(main):012:0> put 'people', 'issei', 'prop:occupation', 'SE'
0 row(s) in 0.0090 seconds
hbase(main):013:0> put 'people', 'issei', 'test:abc', 'This is a pen.'
0 row(s) in 0.0080 seconds

これで1行ぶんですね。
続けて suzuki と saito についても登録します。

hbase(main):014:0> put 'people', 'suzuki', 'prop:age', '25'
0 row(s) in 0.0100 seconds
hbase(main):015:0> put 'people', 'suzuki', 'prop:occupation', 'Consultant'
0 row(s) in 0.0140 seconds
hbase(main):016:0> put 'people', 'suzuki', 'test:abc', 'foo'
0 row(s) in 0.0080 seconds
hbase(main):017:0> put 'people', 'saito', 'prop:age', '40'
0 row(s) in 0.0080 seconds
hbase(main):018:0> put 'people', 'saito', 'prop:occupation', 'Teacher'
0 row(s) in 0.0120 seconds
hbase(main):019:0> put 'people', 'saito', 'test:abc', 'hoge'
0 row(s) in 0.0080 seconds


  • データ取得:get

行単位、セル単位で値が取得できるようです。文法的には
get テーブル名, 行[, カラムや条件]
という感じでしょうか。プログラムからアクセスする場合はもっと細かく指定できるのかもしれませんが。
people テーブルについていくつかやってみます。

hbase(main):021:0> get 'people', 'issei'
COLUMN                       CELL                                                         
 prop:age                    timestamp=1271901645856, value=33                            
 prop:occupation             timestamp=1271901686162, value=SE                            
 test:abc                    timestamp=1271901702050, value=This is a pen.                
3 row(s) in 0.0180 seconds
hbase(main):022:0> get 'people', 'issei', {COLUMN => 'test:abc'}
COLUMN                       CELL                                                         
 test:abc                    timestamp=1271901702050, value=This is a pen.                
1 row(s) in 0.0140 seconds

タイムスタンプやバージョンについてはまだやっていないので、今回はパスということで。
ただ、help だとできるような感じで書かれている、複数カラム指定がNGになる・・・
タイプミスしてる?

hbase(main):026:0> get 'people', 'issei', {COLUMN => ['prop:age', 'test:abc']}
NoMethodError: undefined method `to_java_bytes' for ["prop:age", "test:abc"]:Array


  • 走査(?):scan

getはキー指定のデータ取得なわけですが、scan はその名の通り(?)テーブルのデータを走査するためのものです。
文法的にはこんな感じでしょうか。
scan テーブル名[, 条件など]
条件など、のところには LIMIT(上限)、STARTROW(開始行)、STOPROW(終了行)、TIMESTAMP(タイムスタンプ。用途不明)、COLUMNS(走査対象カラム)を指定する感じです。
上述のテーブルにおいて、単に scan 'people' をするとこんな感じです。

hbase(main):005:0> scan 'people'
ROW                          COLUMN+CELL                                                  
 issei                       column=prop:age, timestamp=1271901645856, value=33           
 issei                       column=prop:occupation, timestamp=1271901686162, value=SE    
 issei                       column=test:abc, timestamp=1271901702050, value=This is a pen.
 saito                       column=prop:age, timestamp=1271901818772, value=40           
 saito                       column=prop:occupation, timestamp=1271901827465, value=Teacher
 saito                       column=test:abc, timestamp=1271901836594, value=hoge         
 suzuki                      column=prop:age, timestamp=1271901775977, value=25           
 suzuki                      column=prop:occupation, timestamp=1271901787836, value=Consultant
 suzuki                      column=test:abc, timestamp=1271901804853, value=foo          
3 row(s) in 0.0600 seconds

カラム指定(COLUMNS => 'prop:age')

hbase(main):007:0> scan 'people', { COLUMNS => ['prop:age']}
ROW                          COLUMN+CELL                                                  
 issei                       column=prop:age, timestamp=1271901645856, value=33           
 saito                       column=prop:age, timestamp=1271901818772, value=40           
 suzuki                      column=prop:age, timestamp=1271901775977, value=25           
3 row(s) in 0.0510 seconds

追加で LIMIT 指定

hbase(main):008:0> scan 'people', { COLUMNS => ['prop:age'], LIMIT => 2}
ROW                          COLUMN+CELL                                                  
 issei                       column=prop:age, timestamp=1271901645856, value=33           
 saito                       column=prop:age, timestamp=1271901818772, value=40           
2 row(s) in 0.0370 seconds

という感じになりました。
あとは用途によって、というところなので、現時点ではこれくらいにしておきます。

  • セル/行の削除:delete/deleteall

次に削除。文法としては
delete テーブル名, キー, カラム
のようです。
saito さんの prop:occupation を削除してみます。

hbase(main):013:0> delete 'people', 'saito'
ArgumentError: wrong # of arguments(2 for 3)

hbase(main):014:0> delete 'people', 'saito', 'prop:occupation'
0 row(s) in 0.0140 seconds
hbase(main):015:0> get 'people', 'saito'
COLUMN                       CELL                                                         
 prop:age                    timestamp=1271901818772, value=40                            
 test:abc                    timestamp=1271901836594, value=hoge                          
2 row(s) in 0.0200 seconds

予想通り、deleteの場合、カラムを指定しないと怒られました。
deleteall で saito さんの行を削除してみます。

hbase(main):017:0> deleteall 'people', 'saito'
0 row(s) in 0.0110 seconds
hbase(main):018:0> get 'people', 'saito'
COLUMN                       CELL                                                         
0 row(s) in 0.0060 seconds

こちらはテーブル名、キーのみでいけました。

  • カウント:count

テーブル内の行数を数えてみる。とは言ってもたった2行(deleteallで削除したので)なので、面白みもないのですが。

hbase(main):019:0> count 'people'
2 row(s) in 0.0160 seconds

Hadoop の行数カウント MapReduce が実行される(?)からか、時間がかかることがあるそうです。
まぁ、現時点では・・・

  • テーブルの削除とステータス変更:drop/disable

テーブルを削除(drop)する前には、disable にする必要がある、とあります。
ので、試してみる。
テーブルの状態は、describe テーブル名としたときに表示されるようです。

hbase(main):024:0> describe 'people'
DESCRIPTION                                                     ENABLED
 {NAME => 'people', FAMILIES => [{NAME => 'prop', COMPRESSION => 'NONE' true,
...
1 row(s) in 0.0420 seconds

この状態でdropを試みてみる。

hbase(main):027:0* drop 'people'
IOError: Table people is enabled. Disable it first
>||
ダメですね。
というわけで、disable にしてみる。
>|sh|
hbase(main):028:0> disable 'people'
0 row(s) in 2.1020 seconds
hbase(main):029:0> describe 'people'
DESCRIPTION                                                  ENABLED
 {NAME => 'people', FAMILIES => [{NAME => 'prop', COMPRESSION => 'NONE' false,
...
hbase(main):030:0> describe 'people'

んー。ENABLE のままですね・・・
まぁ、とりあえずこの状態でdropしてみる。

hbase(main):031:0> drop 'people'
0 row(s) in 0.0130 seconds
0 row(s) in 0.0110 seconds
0 row(s) in 0.0880 seconds
hbase(main):032:0> list
0 row(s) in 0.0210 seconds

よくわかりませんが、drop できたようです。describe のときの ENABLED は参考にならないんですかねー。
今のところ困るわけではないので、この件はまたの機会に。


enable を試す前に drop してしまったので、enable についてもまたの機会に。

というわけで、今回はこんなところで。