コマンドラインで使ってみる
Phoenixの準備ができたので、実際に動かしてみましょう。下記のようにしてコマンドラインを立ち上げます。
$ cd bin $ ./sqlline.sh localhost
最初に、CREATE TABLEでテーブルを作成します。以下のようにCREATE文を入力するとテーブルが作成されます。
0: jdbc:phoenix:localhost> CREATE TABLE TBL1 ( . . . . . . . . . . . . .> COL1 VARCHAR NOT NULL PRIMARY KEY, . . . . . . . . . . . . .> COL2 INTEGER . . . . . . . . . . . . .> );
確認する場合は、!tablesと!columnsを使います。
0: jdbc:phoenix:localhost> !tables +------------+-------------+------------+------------+------------+------------+---------------------------+----------------+-------------+----------------+ | TABLE_CAT | TABLE_SCHEM | TABLE_NAME | TABLE_TYPE | REMARKS | TYPE_NAME | SELF_REFERENCING_COL_NAME | REF_GENERATION | INDEX_STATE | IMMUTABLE_ROWS | +------------+-------------+------------+------------+------------+------------+---------------------------+----------------+-------------+----------------+ | null | SYSTEM | TABLE | SYSTEM TABLE | null | null | null | null | null | false | | null | null | TBL1 | TABLE | null | null | null | null | null | false | +------------+-------------+------------+------------+------------+------------+---------------------------+----------------+-------------+----------------+ 0: jdbc:phoenix:localhost> !columns TBL1 +------------+-------------+------------+-------------+-----------+------------+-------------+---------------+----------------+----------------+----------+------------+------------+ | TABLE_CAT | TABLE_SCHEM | TABLE_NAME | COLUMN_NAME | DATA_TYPE | TYPE_NAME | COLUMN_SIZE | BUFFER_LENGTH | DECIMAL_DIGITS | NUM_PREC_RADIX | NULLABLE | COLUMN_DEF | SQL_DATA_T | +------------+-------------+------------+-------------+-----------+------------+-------------+---------------+----------------+----------------+----------+------------+------------+ | null | null | TBL1 | COL1 | 12 | VARCHAR | null | null | null | null | 0 | null | null | | _0 | null | TBL1 | COL2 | 4 | INTEGER | 10 | null | 0 | null | 1 | null | null | +------------+-------------+------------+-------------+-----------+------------+-------------+---------------+----------------+----------------+----------+------------+------------+
次に、データを入れてみましょう。
Phoenixでは、データを入れるときにUPSERT文を使います。UPSERTはINSERTとUPDATEをもじったものだと思いますが、データがない場合は新しくデータを作成し、ある場合は更新をします。
0: jdbc:phoenix:localhost> UPSERT INTO TBL1 VALUES ('aaa', 1); 0: jdbc:phoenix:localhost> UPSERT INTO TBL1 VALUES ('bbb', 2); 0: jdbc:phoenix:localhost> UPSERT INTO TBL1 VALUES ('ccc', 3);
入れたデータをSELECT文で見てみましょう。
0: jdbc:phoenix:localhost> SELECT * FROM TBL1; +------------+------+ | COL1 | COL2 | +------------+------+ | aaa | 1 | | bbb | 2 | | ccc | 3 | +------------+------+
データが入っていることが確認できると思います。
ここで、実際にHBase上にどのようにデータが入っているかをのぞいてみましょう。HBase shellを起動します。
$ <HBaseのインストールディレクトリ>/bin/hbase shell
HBase上では、Phoenix上で作成したテーブルと同じ名前のTableが作成されています。そのTableに対してscanをかけると、以下のように出力されます。
$ scan 'TBL1' ROW COLUMN+CELL aaa column=_0:COL2, timestamp=1389695144507, value=\x80\x00\x00\x01 aaa column=_0:_0, timestamp=1389695144507, value= bbb column=_0:COL2, timestamp=1389695144546, value=\x80\x00\x00\x02 bbb column=_0:_0, timestamp=1389695144546, value= ccc column=_0:COL2, timestamp=1389695144582, value=\x80\x00\x00\x03 ccc column=_0:_0, timestamp=1389695144582, value= 3 row(s) in 0.0420 seconds
主キーとして設定したCOL1がRowKeyにマッピングされ、COL2はColumn/Valueにマッピングされているのが分かります。ColumnFamilyとしては、デフォルト値の"_0"が設定されています。
ちなみに、各Rowに"_0"のColumnがあるのが分かると思います。一見余計なものに見えますが、これは主キー以外の列がNULLの場合にRowが消えてしまわないようにするためのものです。HBaseはColumnが存在しないRowを作ることができないため、このような工夫がなされています。
次に、以下のようなテーブルを作ってみましょう。今回は、主キーとして3つの列を指定しています。また、FAM1.COL4やFAM2.COL6のように、ピリオドで区切った列名を指定しました。
0: jdbc:phoenix:localhost> CREATE TABLE TBL2 ( . . . . . . . . . . . . .> COL1 VARCHAR NOT NULL, . . . . . . . . . . . . .> COL2 INTEGER NOT NULL, . . . . . . . . . . . . .> COL3 CHAR(2) NOT NULL, . . . . . . . . . . . . .> FAM1.COL4 VARCHAR, . . . . . . . . . . . . .> FAM1.COL5 VARCHAR, . . . . . . . . . . . . .> FAM2.COL6 VARCHAR . . . . . . . . . . . . .> CONSTRAINT PK PRIMARY KEY (COL1, COL2, COL3) . . . . . . . . . . . . .> );
さらに、データを入れます。
0: jdbc:phoenix:localhost> UPSERT INTO TBL2 VALUES ('aaa', 1, '12', 'bbb', 'ccc', 'ddd'); 0: jdbc:phoenix:localhost> SELECT * FROM TBL2; +------------+------+------+------------+------------+------------+ | COL1 | COL2 | COL3 | COL4 | COL5 | COL6 | +------------+------+------+------------+------------+------------+ | aaa | 1 | 12 | bbb | ccc | ddd | +------------+------+------+------------+------------+------------+
HBase上でscanをかけると、以下のようになります。
$ scan 'TBL2' ROW COLUMN+CELL aaa\x00\x80\x00\x00\x0112 column=FAM1:COL4, timestamp=1389695036362, value=bbb aaa\x00\x80\x00\x00\x0112 column=FAM1:COL5, timestamp=1389695036362, value=ccc aaa\x00\x80\x00\x00\x0112 column=FAM1:_0, timestamp=1389695036362, value= aaa\x00\x80\x00\x00\x0112 column=FAM2:COL6, timestamp=1389695036362, value=ddd 1 row(s) in 0.0380 seconds
今回のテーブルでは主キーを3つの列で指定しましたが、それらがすべてRowKeyの一部としてマッピングされています。
また、FAM1.COL4やFAM2.COL6のようにピリオドで区切った列名を指定すると、ピリオドより前に指定した文字列がColumnFamilyとなり、ピリオドより後ろに指定した文字列がColumnになります。
主キーはすべてRowKeyにマッピングされます。
また、列をColumnFamilyで分けたい場合は、ピリオド区切りで列名を指定すれば良いです。
Javaから使ってみる
PhoenixはJDBCをサポートしているので、以下のようにJavaからアクセスすることができます。
事前準備として、phoenix-2.2.2-install.tarを解凍した際に出力されたphoenix-2.2.2-client.jarにクラスパスを通す必要があります。
Connection connection = DriverManager.getConnection("jdbc:phoenix:localhost"); connection.setAutoCommit(true); Statement statement = connection.createStatement(); statement.executeUpdate( "CREATE TABLE TBL3 (" + "COL1 VARCHAR NOT NULL PRIMARY KEY," + "COL2 INTEGER" + ")"); statement.executeUpdate("UPSERT INTO TBL3 VALUES ('aaa', 1)"); statement.executeUpdate("UPSERT INTO TBL3 VALUES ('bbb', 2)"); statement.executeUpdate("UPSERT INTO TBL3 VALUES ('ccc', 3)"); ResultSet resultSet = statement.executeQuery("SELECT * FROM TBL3"); while (resultSet.next()) { System.out.println(resultSet.getString(1) + "," + resultSet.getInt(2));; } resultSet.close(); statement.close(); connection.close();
まとめ
今回は、HBaseをSQLで操作できるライブラリであるPhoenixについて説明し、実際に動かしてみました。次回は、トランザクションやセカンダリインデックスなど、Phoenixの高度な機能を使ってみたいと思います。
また、株式会社サイバーエージェントでは、Hadoop/HBaseエンジニアを募集しています。ご興味のある方はこちらからエントリーしていただければと思います。エンジニア>R&Dエンジニア>R&Dエンジニアを選択しエントリーしていただければ幸いです。