HBase Shellは、HBaseを操作する対話型ツール。
(OracleのSQL*Plus、JavaDBのij、PostgreSQLのpsqlのようなもの)
|
|
(Windowsの場合、Cygwin(bash)から)以下のコマンドでHBase Sehllを起動する。
$ /usr/local/hbase-0.20.3/bin/hbase shell
--helpを付けるとコマンドのオプションが表示される。
$ /usr/local/hbase-0.20.3/bin/hbase shell --help HBase Shell command-line options: format Formatter for outputting results: console | html. Default: console format-width Width of table outputs. Default: 110 characters. -d | --debug Set DEBUG log levels.
なお、HBase ShellはJRubyで書かれているらしい。(HBASE_HOME/bin/hirb.rb)
(なのでJRubyの文を実行することが出来る)
HBase Shellからhelpコマンドを打ち込むとHBase Shellのコマンド一覧が表示される。
hbase(main):001:0> help
分類 | コマンド名 | 引数 | 概要 | RDBのSQL相当 | 更新日 |
---|---|---|---|---|---|
HBase Shell | exit | HBase Shellを終了する。 | |||
version | HBaseのバージョンを表示する。 | ||||
tools | HBase外部ツール?(拡張コマンド?)の一覧を表示する。 | ||||
テーブル定義 | list | テーブル一覧を表示する。 | (Oracle)user_tables | ||
exists | 1 | テーブルの存在有無を表示する。 | |||
create | 1- | テーブルを作成する。 | create table | ||
drop | 1 | テーブルを削除する。 | drop table | ||
disable | 1 | テーブルを使用不可に変更する。 | |||
enable | 1 | テーブルを使用可能に変更する。 | |||
describe | 1 | テーブルの定義を表示する。 | (Oracle)desc | ||
alter | 2 | 列ファミリーの定義を変更する。 | alter | 2010-07-06 | |
truncate | 1 | テーブルを再作成(データをクリア)する。 | truncate table | ||
データ表示 | scan | 1-2 | テーブルのデータ(セル)を全て表示する。 | select * | |
count | 1-2 | テーブルのレコード数(ROWの数)を表示する。 | select count(*) | ||
get | 2-3 | セルの内容を表示する。 | select | ||
データ更新 | put | 4-5 | セルの値をセットする。 | insert/update | |
incr | 3 | セルの値を加算する。 | update | 2010-07-12 | |
delete | 3-4 | セル(テーブルの値)の最新履歴を削除する。 | update | ||
deleteall | 2-4 | セル(テーブルの値)の全履歴を削除する。 | delete | ||
クラスター | status | 0-1 | クラスターの状態を表示する。 | ||
shutdown | クラスターをシャットダウンする。 |
また、HBase ShellはJRubyで動いているので、JRubyの文を実行することが出来る。
テーブル一覧を表示するコマンド。
→Java APIのlistTables()
hbase(main):001:0> list TEST_TYPE student 2 row(s) in 0.0160 seconds
テーブルの存在有無を表示するコマンド。
hbase(main):002:0> exists 'test' false 1 row(s) in 0.0000 seconds
テーブルを作成するコマンド。
→Java APIのcreateTable()
hbase(main):003:0> create 'test' 0 row(s) in 2.2030 seconds
hbase(main):014:0> create 'test2','data1','data2' 0 row(s) in 0.1400 seconds
hbase(main):015:0> create 'test2', {NAME => 'data1'}, {NAME => 'data2'}
hbase(main):019:0> create 'test3',{NAME => 'data1',VERSIONS => 1} 0 row(s) in 2.1560 seconds
パラメーター名 | デフォルト値 | 説明 |
---|---|---|
NAME | 列ファミリー名 | |
VERSIONS | 3 | 最大履歴数(履歴管理する最大件数) |
COMPRESSION | none | |
IN_MEMORY | false | |
BLOCKCACHE | true | |
BLOCKSIZE | 64 * 1024 | |
TTL | Integer.MAX_VALUE | Time-to-live(以前のデフォルト値は-1だったらしい) |
BLOOMFILTER | false |
テーブルを削除するコマンド。
→Java APIのdeleteTable()
削除する前にテーブルを使用不可にしておく必要がある。
hbase(main):034:0> drop 'test5'
IOError: Table test5 is enabled. Disable it first
hbase(main):035:0> disable 'test5'
0 row(s) in 2.0630 seconds
hbase(main):036:0> drop 'test5'
0 row(s) in 0.0150 seconds
0 row(s) in 0.0000 seconds
0 row(s) in 0.0470 seconds
テーブルの使用可否を切り替えるコマンド。
(テーブルの定義を変更する際はテーブルを使用不可にする必要がある)
→Java APIのdisableTable()・enableTable()
hbase(main):024:0> disable 'test' 0 row(s) in 2.0630 seconds
hbase(main):025:0> enable 'test' 0 row(s) in 0.0310 seconds
テーブルの定義を表示するコマンド。
→Java APIのgetTableDescriptor()
hbase(main):043:0> describe 'test2' DESCRIPTION ENABLED {NAME => 'test2', FAMILIES => [{NAME => 'data1', COMPRESSION => 'NONE' true , VERSIONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMOR Y => 'false', BLOCKCACHE => 'true'}, {NAME => 'data2', COMPRESSION => 'NONE', VERSIONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN _MEMORY => 'false', BLOCKCACHE => 'true'}]} 1 row(s) in 0.0310 seconds
右の方にひっそり表示されているENABLEDのtrue/falseは、テーブルの使用可否の状態を表している。
→Java APIのisTableEnabled()
テーブルの定義を変更するコマンド。
(変更する前にテーブルを使用不可にしておく必要がある)
METHODにtable_attとdelete以外を指定する(もしくはMETHODを省略する)と、列ファミリーの属性の変更になる。
列ファミリーが存在していなかった場合は列ファミリーの追加となる。
hbase(main):055:0> alter 'test2',{NAME=>'data2'} …data2が無ければ追加される 0 row(s) in 0.0310 seconds
VERSIONSを変更するには以下のようにする。
hbase(main):053:0> alter 'test2',{NAME=>'data1', VERSIONS=>1} 0 row(s) in 0.0310 seconds
→Java APIのaddColumn()・modifyColumn()
列ファミリーを削除する場合はMETHODにdeleteを指定する。
hbase(main):061:0> alter 'test2',{NAME=>'data2', METHOD=>'delete'} 0 row(s) in 0.0320 seconds
テーブル属性(MAX_FILESIZE・READONLY・MEMSTORE_FLUSHSIZE)を変更する場合はMETHODにtable_attを指定する。
hbase(main):001:0> alter 'test2',{METHOD=>'table_att', READONLY=>true}
とヘルプには書かれているのだが、エラーが出る…。
NameError: uninitialized constant HBase::Admin::DEFERRED_LOG_FLUSH
HBase0.20.3ではMAX_FILESIZEやREADONLYといった定数はHTableDescriptorクラスで定義されているのだが、DEFERRED_LOG_FLUSHは定義されていない。
これが無いせいでHBASE_HOME/bin/HBase.rbの実行が途中でエラーになっている模様。
という訳で、適当にDEFERRED_LOG_FLUSHを定義してやれば実行が続行されるので無事変更できる。
hbase(main):009:0> DEFERRED_LOG_FLUSH="DEFERRED_LOG_FLUSH"
=> "DEFERRED_LOG_FLUSH"
hbase(main):010:0> alter 'test2',{METHOD=>'table_att', READONLY=>true}
0 row(s) in 0.0470 seconds
つーか、HBase.rbからDEFERRED_LOG_FLUSH関連の行は削除されるみたいだなー。
(Javaなら(存在していない変数は使えないので)コンパイルエラーになるからこんなバグはすぐ分かるんだけどなぁ)
※DEFERRED_LOG_FLUSHは0.20より後のバージョンで追加される予定だったようだ。[2010-07-06]
テーブルのデータをクリアする、というかテーブルを再作成するコマンド。
テーブルを使用不可にし、dropしてから再作成する。
hbase(main):003:0> truncate 'test2' Truncating test2; it may take a while Disabling table... 0 row(s) in 2.0940 seconds Dropping table... 0 row(s) in 0.0150 seconds 0 row(s) in 0.0000 seconds 0 row(s) in 0.0620 seconds Creating table... 0 row(s) in 4.5310 seconds
テーブルにデータをセットするコマンド。
(データが存在していなければ追加になる。データが存在していれば更新になる)
→Java APIのPut
例 | 備考 |
---|---|
hbase(main):001:0> put 'test','key1','data','value1' 0 row(s) in 0.0620 seconds hbase(main):002:0> put 'test','key1','data:','value1' 0 row(s) in 0.0620 seconds |
testテーブルにROW(キー)='key1'で 列「data : 」(qualifier無し)に値「value1」を登録。 |
hbase(main):018:0> put 'test','key1','data:q1','value2' 0 row(s) in 0.0150 seconds |
testテーブルにROW(キー)='key1'で 列「data : q1」(qualifier有り)に値「value2」を登録。 |
hbase(main):026:0> put 'test','key1','data:','value3',1267846496789 0 row(s) in 0.0630 seconds |
時刻付きで値を登録。 |
データ(セル)はバージョン管理されており、日時(timestamp)を暗黙に持っている。
日時を明示しなかった場合は、現在日時で登録される。
指定した日時が既に存在していた場合は上書きされる。
指定した日時が最も古いバージョンよりも古くて履歴最大件数(VERSIONS)よりも前になる場合は登録されない。(指定する日時によって登録されたりされなかったり?)
データ(セル)をlong型とみなして値を加算する。[2010-07-12]
→Java APIのincrementColumnValue
例 | 備考 |
---|---|
hbase(main):012:0> put 'test2','cnt1','data:cnt',"\x00\x00\x00\x00\x00\x00\x00\x01" 0 row(s) in 0.0000 seconds hbase(main):013:0> incr 'test2','cnt1','data:cnt',10 0 row(s) in 0.0160 seconds hbase(main):014:0> scan 'test2' ROW COLUMN+CELL cnt1 column=data:cnt, timestamp=1278943079875, value=\x00\x00\x00\x00\x00\x00\x00\x0B 1 row(s) in 0.0150 seconds |
JRubyでどうやってlong値を指定すればいいのか知らないので、適当(爆) |
hbase(main):015:0> incr 'test2','cnt1','data:cnt' 0 row(s) in 0.0000 seconds hbase(main):016:0> scan 'test2' ROW COLUMN+CELL cnt1 column=data:cnt, timestamp=1278943079875, value=\x00\x00\x00\x00\x00\x00\x00\x0C 1 row(s) in 0.0000 seconds |
値を省略すると、1だけ加算される。 |
long型でない値(8バイトより短いデータ)が入っていると、例外が発生する。
hbase(main):020:0> put 'test2','cnt','data:cnt7',"\x00\x00\x00\x00\x00\x00\x01"
0 row(s) in 0.0150 seconds
hbase(main):021:0> incr 'test2','cnt','data:cnt7'
NativeException: org.apache.hadoop.hbase.client.RetriesExhaustedException: Trying to contact region server 192.168.0.2:1032
for region test2,,1278942259906, row 'cnt', but failed after 7 attempts.
Exceptions:
java.io.IOException: java.io.IOException: java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method)
at org.apache.hadoop.hbase.util.Bytes.putBytes(Bytes.java:224)
at org.apache.hadoop.hbase.regionserver.Store.updateColumnValue(Store.java:1526)
at org.apache.hadoop.hbase.regionserver.HRegion.incrementColumnValue(HRegion.java:2563)
〜
また、qualifierの無い列ファミリー(「:
」無し)を指定すると、例外が発生する…。
hbase(main):022:0> put 'test2','cnt','data',"\x00\x00\x00\x00\x00\x00\x00\x01"
0 row(s) in 0.0000 seconds
hbase(main):023:0> incr 'test2','cnt','data'
NativeException: org.apache.hadoop.hbase.client.RetriesExhaustedException: Trying to contact region server 192.168.0.2:1032
for region test2,,1278942259906, row 'cnt', but failed after 7 attempts.
Exceptions:
java.io.IOException: java.io.IOException: java.lang.NullPointerException
at org.apache.hadoop.hbase.regionserver.ColumnCount.<init>(ColumnCount.java:47)
at org.apache.hadoop.hbase.regionserver.ExplicitColumnTracker.buildColumnList(ExplicitColumnTracker.java:159)
at org.apache.hadoop.hbase.regionserver.ExplicitColumnTracker.reset(ExplicitColumnTracker.java:151)
at org.apache.hadoop.hbase.regionserver.ExplicitColumnTracker.<init>(ExplicitColumnTracker.java:63)
at org.apache.hadoop.hbase.regionserver.QueryMatcher.<init>(QueryMatcher.java:142)
at org.apache.hadoop.hbase.regionserver.Store.get(Store.java:1449)
at org.apache.hadoop.hbase.regionserver.HRegion.incrementColumnValue(HRegion.java:2536)
〜
ただし、「:
」を付けていれば、qualifier無しの列ファミリーでも大丈夫。
hbase(main):024:0> incr 'test2','cnt','data:' hbase(main):025:0> scan 'test2' ROW COLUMN+CELL cnt column=data:, timestamp=1278943857875, value=\x00\x00\x00\x00\x00\x00\x00\x02 1 row(s) in 0.0160 seconds
テーブルのデータ(セル)を表示するコマンド。
→Java APIのGet
例 | 備考 |
---|---|
hbase(main):060:0> get 'test','key1' COLUMN CELL data: timestamp=1267897532954, value=value1 data:q1 timestamp=1267895704390, value=value2 2 row(s) in 0.0160 seconds |
testテーブルのROW(キー)='key1'の 各データ(最新版)を全て表示。 |
hbase(main):062:0> get 'test','key1',{COLUMN=>'data:'} COLUMN CELL data: timestamp=1267897532954, value=value1 1 row(s) in 0.0000 seconds |
列名を指定。 (COLUMNSでも通るっぽい) |
hbase(main):064:0> get 'test','key1',{COLUMN=>'data:',TIMESTAMP=>1267897532953} COLUMN CELL data: timestamp=1267897532953, value=value11 1 row(s) in 0.0000 seconds |
列名とバージョン(日時)を指定。 |
hbase(main):065:0> get 'test','key1',{COLUMN=>'data:',VERSIONS=>5} COLUMN CELL data: timestamp=1267897532954, value=value1 data: timestamp=1267897532953, value=value11 data: timestamp=1267897532952, value=value0 3 row(s) in 0.0160 seconds |
表示する最大履歴数を指定。 |
表示する履歴件数(VERSIONS)を指定すると、その件数までのバージョンが表示される。
ただしそもそもテーブル定義でVERSIONSを指定(デフォルトは3件)していると、そのバージョン数までしか管理されていない。
ヘルプによると、COLUMNに配列を指定すると複数の列を条件にすることが出来る。
のだが、実際に試すとHBase0.20.3ではエラーが出る。
hbase(main):089:0> get 'test','key1',{COLUMN => ['data:', 'data:q1']}
NoMethodError: undefined method `to_java_bytes' for ["data:", "data:q1"]:Array
HBASE_HOME/bin/Hirb.rbが間違ってるので、以下の様に修正すれば動くようになる。
(Javaなら(型をはっきりさせないといけないので)コンパイルエラーになるからこんなバグはすぐ分かるんだけどなぁ)
elsif columns.class == Array for column in columns split = KeyValue.parseColumn(columns.to_java_bytes) ↓ split = KeyValue.parseColumn(column.to_java_bytes)
hbase(main):001:0> get 'test','key1',{COLUMN => ['data:', 'data:q1']}
COLUMN CELL
data: timestamp=1267897532954, value=value1
data:q1 timestamp=1267895704390, value=value2
2 row(s) in 0.0790 seconds
データ(セル)の特定バージョンを削除するコマンド。
(全バージョンを消したい場合はdeleteallを使用する)
→Java APIのDelete(deleteColumn())
例 | 備考 |
---|---|
hbase(main):007:0> delete 'test','key1','data:' 0 row(s) in 0.0000 seconds |
testテーブルのROW(キー)='key1'の列「data: 」の最新セルを削除。 |
hbase(main):008:0> delete 'test','key1','data:',1267897532952 |
日時(バージョン)を指定。 |
削除されるのは指定した日時のデータ(セル)のみ。省略時は最新版。
なので、最新版を削除すると、その前のバージョンの値がget等で取得されることになる。
データ(セル)の全履歴を削除するコマンド。
→Java APIのDelete(deleteColumns())
例 | 備考 |
---|---|
hbase(main):018:0> deleteall 'test','key1','data:' 0 row(s) in 0.0000 seconds |
testテーブルのROW(キー)='key1'の列「data: 」を削除。 |
hbase(main):021:0> deleteall 'test','key1' 0 row(s) in 0.0150 seconds |
testテーブルの指定されたキーの全データ(セル)を削除。 (RDB(SQL)のdelete文に相当) |
hbase(main):052:0> deleteall 'test','key1',nil,1267903199750 0 row(s) in 0.0000 seconds |
時刻を指定。 (列名にnilを指定しているので、全列が対象) |
テーブルのレコード数(ROWの個数)を表示するコマンド。
(似た機能:RowCounterクラス)
例 | 備考 |
---|---|
hbase(main):068:0> count 'TEST_TYPE' 5 row(s) in 0.0460 seconds |
TEST_TYPEテーブルの件数を表示。 |
hbase(main):069:0> count 'TEST_TYPE',2 Current count: 2, row: KEY00002 Current count: 4, row: KEY00004 5 row(s) in 0.0470 seconds |
中間ログ出力の指定。 2を指定すると、2件毎に処理途中での件数を表示する。 デフォルトは1000件ずつ。 |
テーブルの全データを表示するコマンド。
→Java APIのScan
例 | 備考 |
---|---|
hbase(main):080:0> scan 'test' ROW COLUMN+CELL key1 column=data:, timestamp=1267904054000, value=value1 key1 column=data:q1, timestamp=1267904062859, value=value2 key1 column=data:q2, timestamp=1267904876109, value=value5 key2 column=data:, timestamp=1267904079890, value=value3 key3 column=data:q1, timestamp=1267904734875, value=value4 3 row(s) in 0.0150 seconds |
testテーブルの全データ(セル)を表示。 (RDB(SQL)のselect文に相当) |
hbase(main):089:0> scan 'test',{COLUMNS=>'data:q1'} ROW COLUMN+CELL key1 column=data:q1, timestamp=1267904062859, value=value2 key3 column=data:q1, timestamp=1267904734875, value=value4 2 row(s) in 0.0150 seconds |
列名を指定。 |
hbase(main):090:0> scan 'test',{COLUMNS=>['data:q1','data:q2']} ROW COLUMN+CELL key1 column=data:q1, timestamp=1267904062859, value=value2 key1 column=data:q2, timestamp=1267904876109, value=value5 key3 column=data:q1, timestamp=1267904734875, value=value4 2 row(s) in 0.0160 seconds |
複数列を指定。 |
hbase(main):091:0> scan 'test',{STARTROW=>'key2'} ROW COLUMN+CELL key2 column=data:, timestamp=1267904079890, value=value3 key3 column=data:q1, timestamp=1267904734875, value=value4 2 row(s) in 0.3910 seconds hbase(main):093:0> scan 'test',{STOPROW=>'key2'} ROW COLUMN+CELL key1 column=data:, timestamp=1267904054000, value=value1 key1 column=data:q1, timestamp=1267904062859, value=value2 key1 column=data:q2, timestamp=1267904876109, value=value5 1 row(s) in 0.0310 seconds |
ROW(キー)の範囲を指定。 STARTROWは“それ以降(STARTROW自身を含む)”の指定。 STOPROWは“それより前(STOPROW自身を含まない)”の指定。 |
hbase(main):097:0> scan 'test',{LIMIT=>2} ROW COLUMN+CELL key1 column=data:, timestamp=1267904054000, value=value1 key1 column=data:q1, timestamp=1267904062859, value=value2 key1 column=data:q2, timestamp=1267904876109, value=value5 key2 column=data:, timestamp=1267904079890, value=value3 2 row(s) in 0.0470 seconds |
表示レコード数を制限。 (ROW数の制限であって、表示されるセル数の制限ではない) |
hbase(main):101:0> scan 'test',{MAXLENGTH=>32} ROW COLUMN+CELL key1 column=data:, timestamp=1267904054000, value=v key1 column=data:q1, timestamp=1267904062859, value=v key1 column=data:q2, timestamp=1267904876109, value=v key2 column=data:, timestamp=1267904079890, value=v key3 column=data:q1, timestamp=1267904734875, value=v 3 row(s) in 0.0310 seconds |
表示桁数を指定。 (各行の「timestamp〜」以降の文字数を指定するもの) |
hbase(main):109:0> scan 'test',{VERSIONS=>2, STOPROW=>'key2'}
ROW COLUMN+CELL
key1 column=data:, timestamp=1267904054000, value=value1
key1 column=data:, timestamp=1267904053999, value=value12
key1 column=data:q1, timestamp=1267904062859, value=value2
key1 column=data:q2, timestamp=1267904876109, value=value5
1 row(s) in 0.0160 seconds
|
表示履歴数を指定。 デフォルトはVERSIONS=>1なので、最新データしか表示されない。 |
hbase(main):110:0> scan 'test',{TIMESTAMP=>1267904079890} ROW COLUMN+CELL key2 column=data:, timestamp=1267904079890, value=value3 1 row(s) in 0.0150 seconds |
日時(タイムスタンプ)を指定。 |
hbase(main):114:0> import org.apache.hadoop.hbase.filter.ValueFilter => Java::OrgApacheHadoopHbaseFilter::ValueFilter hbase(main):150:0> import org.apache.hadoop.hbase.filter.BinaryComparator => Java::OrgApacheHadoopHbaseFilter::BinaryComparator hbase(main):151:0> filter=ValueFilter.new(ValueFilter::CompareOp::EQUAL, hbase(main):152:1* BinaryComparator.new("value1".to_java_bytes)) => #<Java::OrgApacheHadoopHbaseFilter::ValueFilter:0x19302fb @java_object=#<Java ::JavaObject:0xa8cd58>> hbase(main):155:0> scan 'test',{"FILTER"=>filter} ROW COLUMN+CELL key1 column=data:, timestamp=1267904054000, value=value1 1 row(s) in 0.0310 seconds |
値が「value1」であるセルを全て取得。 (ヘルプには載っていないが)scanにはフィルターを指定できる。 「FILTER」という定数は定義されていないので、クォーテーションで囲む必要がある。 FilterはJavaの(HBaseの)クラスなので、インスタンスを作って渡す。 →JavaAPIのFilter |
HBase ShellはJRuby(HBASE_HOME/bin/hirb.rbやHBase.rb)で書かれており、対話ツール上からもJRubyの文が書ける。
hbase(main):001:0> java.text.SimpleDateFormat.new("yyyy/MM/dd HH:mm:ss.SSS").format(1267861000875)
=> "2010/03/06 16:36:40.875"
hbase(main):002:0> import java.text.SimpleDateFormat => Java::JavaText::SimpleDateFormat hbase(main):012:0> SimpleDateFormat.new("yyyy/MM/dd HH:mm:ss.SSS").format(1267861000875) => "2010/03/06 16:36:40.875"
hbase(main):004:0> sdf=java.text.SimpleDateFormat.new("yyyy/MM/dd HH:mm:ss.SSS") => #<Java::JavaText::SimpleDateFormat:0x34a1c8 @java_object=#<Java::JavaObject:0x1696e4c>> hbase(main):005:0> sdf.parse('2010/03/06 12:34:56.789').getTime() => 1267846496789
HBase0.20.3のHBase.rbにはいくつかバグ(定義されているべき変数が定義されていないとか)があるようだ。
Javaなら定義されていない変数があったらコンパイル時にエラーになるのでそういうバグはすぐ分かるのだが。
一方でJRubyはスクリプト言語だけあって、使用者でもすぐ直すことが出来るのは便利だ。
Javaだと原因が発見できたとしても、ソースを入手してコンパイルし直してアーカイブを作り直して…とやらなきゃならないので、普通は使用者が直すのは無理だから。