Java から Cassandra を使ってみる その4
Windows で Cassandra を動かしてみる
Java から Cassandra を使ってみる その1
Java から Cassandra を使ってみる その2
Java から Cassandra を使ってみる その3
の続きです。
尚、この記事の動作確認環境は以下の通りです。
- Windows Vista SP2
- java version 1.6.0_20
- apache-cassandra-0.6.1
複数の Column の値を取得してみる
今回は org.apache.cassandra.thrift.Cassandra.Client#multiget()、multiget_slice() メソッドを使用し、複数の行(key) に関連付けられたカラムの値を取得してみます。
前回までに使用してみた Cassandra の API では、指定したカラムの値のみ取得する get() と、指定した key に関連付けされた全てのカラムを取得可能な get_slice() がありました。
今回使ってみる multiget() と multiget_slice() は、それぞれの複数の key 対応版、といったイメージのものになります。
メソッド名 | 説明 |
---|---|
get | 指定した単一の key の指定した Column の値を取得。 |
multiget | 指定した複数の key の指定した Column の値を取得。 |
get_slice | 指定した単一の key の複数の Column の値を取得。 |
multiget_slice | 指定した複数の key の複数の Column の値を取得。 |
準備
まずは準備として、cassandra-cli より適当な値を追加しておきます。
ここでは、README.txt のサンプルとデータ構造を同じくした、以下のような値を追加してみました。
cassandra> set Keyspace1.Standard1['foo']['first'] = 'bar' Value inserted. cassandra> set Keyspace1.Standard1['foo']['last'] = 'baz' Value inserted. cassandra> set Keyspace1.Standard1['foo']['age'] = '99' Value inserted.
※ 注意
どうも現在のバージョン(0.6.1)では、コマンドプロンプトから cassandra-cli で追加したデータのタイムスタンプ値がおかしくなってしまうようです。
org.apache.cassandra.thrift.Cassandra.Client#insert() によるデータ登録では正常な値が入っているようなので、気になる場合は Java から値を入れた方が良いかもしれません。
今回のサンプルコードでは関係ありませんが、データの更新などが正常に行われなくなってしまう可能性があります。
multiget()
それでは、まずは multiget() を使用した以下のようなサンプルを動かしてみます。
package example.cassandra; import java.util.ArrayList; import java.util.Date; import java.util.Map; import org.apache.cassandra.thrift.Cassandra; import org.apache.cassandra.thrift.Column; import org.apache.cassandra.thrift.ColumnOrSuperColumn; import org.apache.cassandra.thrift.ColumnPath; import org.apache.cassandra.thrift.ConsistencyLevel; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.transport.TSocket; import org.apache.thrift.transport.TTransport; public class CassandraMultigetExample { public static void main(String[] args) { try { // Thrift を使用して Cassandra に接続 TTransport port = new TSocket("localhost", 9160); TProtocol protocol = new TBinaryProtocol(port); Cassandra.Client client = new Cassandra.Client(protocol); port.open(); // デフォルトで用意されている Keyspace を使用する String keySpace = "Keyspace1"; String columnFamily = "Standard1"; // 取得したいカラム名 String columnName = "first"; // ColumnPath の作成 ColumnPath columnPath = new ColumnPath(columnFamily); columnPath.setColumn(columnName.getBytes("UTF8")); Map<String, ColumnOrSuperColumn> results = client.multiget(keySpace, new ArrayList() {{add("jsmith"); add("foo");}}, columnPath, ConsistencyLevel.ONE); for (Map.Entry<String, ColumnOrSuperColumn> entry : results.entrySet()) { String key = entry.getKey(); ColumnOrSuperColumn result = entry.getValue(); Column col = result.column; System.out.printf("key:[%s] カラム名:[%s] 値:[%s] タイムスタンプ:[%s]\n", key, new String(col.name, "UTF8"), new String(col.value, "UTF8"), new Date(col.timestamp)); System.out.println("--------------------"); } port.close(); } catch(Exception e){ e.printStackTrace(); } } }
上記の実行結果は以下のようになります。
key:[foo] カラム名:[first] 値:[bar] タイムスタンプ:[Fri May 23 17:50:30 JST 42302] -------------------- key:[jsmith] カラム名:[first] 値:[John] タイムスタンプ:[Sat May 01 00:43:44 JST 2010] --------------------
指定した key である「jsmith」、「foo」の「first」カラムの値が取得できている事が分かります。
multiget_slice()
次に、multiget_slice() の動作を確認してみます。
以下のようなコードを実行しました。
package example.cassandra; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import org.apache.cassandra.thrift.Cassandra; import org.apache.cassandra.thrift.Column; import org.apache.cassandra.thrift.ColumnOrSuperColumn; import org.apache.cassandra.thrift.ColumnParent; import org.apache.cassandra.thrift.ConsistencyLevel; import org.apache.cassandra.thrift.SlicePredicate; import org.apache.cassandra.thrift.SliceRange; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.transport.TSocket; import org.apache.thrift.transport.TTransport; public class CassandraMultigetSliceExample { public static void main(String[] args) { try { // Thrift を使用して Cassandra に接続 TTransport port = new TSocket("localhost", 9160); TProtocol protocol = new TBinaryProtocol(port); Cassandra.Client client = new Cassandra.Client(protocol); port.open(); // デフォルトで用意されている Keyspace を使用する String keySpace = "Keyspace1"; // ColumnParent には ColumnFamily 名または ColumnFamily/SuperColumn 名を指定 ColumnParent columnParent = new ColumnParent("Standard1"); SliceRange sliceRange = new SliceRange(); // 取得カラムの範囲を指定。全部取得する場合は空の byte 配列を指定 sliceRange.setStart(new byte[0]); sliceRange.setFinish(new byte[0]); SlicePredicate slicePredicate = new SlicePredicate(); slicePredicate.setSlice_range(sliceRange); Map<String, List<ColumnOrSuperColumn>> results = client.multiget_slice(keySpace, new ArrayList() {{add("jsmith"); add("foo");}}, columnParent, slicePredicate, ConsistencyLevel.ONE); for (Map.Entry<String, List<ColumnOrSuperColumn>> entry : results.entrySet()) { String key = entry.getKey(); List<ColumnOrSuperColumn> list = entry.getValue(); for (int i = 0; i < list.size(); i++) { ColumnOrSuperColumn result = list.get(i); Column col = result.column; System.out.printf("key:[%s] [%d] カラム名:[%s] 値:[%s] タイムスタンプ:[%s]\n", key, i + 1, new String(col.name, "UTF8"), new String(col.value, "UTF8"), new Date(col.timestamp)); } System.out.println("--------------------"); } port.close(); } catch(Exception e){ e.printStackTrace(); } } }
実行結果は以下のようになります。
key:[foo] [1] カラム名:[age] 値:[99] タイムスタンプ:[Sat May 24 09:41:35 JST 42302] key:[foo] [2] カラム名:[first] 値:[bar] タイムスタンプ:[Fri May 23 17:50:30 JST 42302] key:[foo] [3] カラム名:[last] 値:[baz] タイムスタンプ:[Fri May 23 23:42:37 JST 42302] -------------------- key:[jsmith] [1] カラム名:[age] 値:[42] タイムスタンプ:[Sun May 02 02:37:33 JST 2010] key:[jsmith] [2] カラム名:[first] 値:[John] タイムスタンプ:[Sat May 01 00:43:44 JST 2010] key:[jsmith] [3] カラム名:[last] 値:[Smith] タイムスタンプ:[Sun May 02 02:37:05 JST 2010] --------------------
指定した key 以下の全ての Column の値が取得できている事がわかります。
multiget_slice() では、get_slice() 同様、SliceRange や SlicePredicate#setColumn_names() により特定の Column のみを取得してくる事も可能です。
ここまでで CRUD 操作が一通りできるようになりました。
次回は conf/storage-conf.xml に独自のデータ構造を定義してみたいと思います。
Packt Publishing