さくらVPSでApache Cassandra 0.7でいろいろデータを取得してみる
昨日の「さくらVPSでApache Cassandra 0.7の動的キースペースを作成してみる」の続きで、「get_slice」「multiget」「multiget_slice」「batch_mutate」を確認してみる。
「multiget」に関しては、Cassandra WikiのAPIページを参照していると「Deprecated in 0.6 - use multiget_slice instead」とあるので省きました。
「get_slice」を試す(setSlice_range)
「get_slice」は、SliceRangeクラスで抽出範囲を指定する方法と、setColumn_namesメソッドで取得対象カラムを
指定するやり方があるみたいです。(他に取得方法があるかは、調査不足です。)
ここでは、SliceRangeクラスを利用して、カラムの値を取得してみます。
// ColumnParent には ColumnFamily 名または ColumnFamily/SuperColumn 名を指定 ColumnParent columnParent = new ColumnParent("Standard2"); SliceRange sliceRange = new SliceRange(); // "a" から "m" までを取得 sliceRange.setStart("a".getBytes("UTF8")); sliceRange.setFinish("m".getBytes("UTF8")); SlicePredicate slicePredicate = new SlicePredicate(); slicePredicate.setSlice_range(sliceRange); // get_slice を呼ぶ List<ColumnOrSuperColumn> results = client.get_slice(ByteBuffer.wrap(key.getBytes("UTF-8")), columnParent, slicePredicate, ConsistencyLevel.ONE); for (int i = 0; i < results.size(); i++) { ColumnOrSuperColumn result = results.get(i); Column col = result.column; System.out.printf("[%d] カラム名:[%s] 値:[%s] タイムスタンプ:[%s]\n", i + 1, new String(col.getName(), "UTF8"), new String(col.getValue(), "UTF8"), new Date(col.timestamp)); }
「get_slice」を試す(setColumn_names)
「get_slice」で、setColumn_namesメソッドを利用するやり方を紹介します。
// ColumnParent には ColumnFamily 名または ColumnFamily/SuperColumn 名を指定 ColumnParent columnParent = new ColumnParent("Standard2"); List<ByteBuffer> colNames = new ArrayList<ByteBuffer>(); colNames.add(ByteBuffer.wrap("first".getBytes("UTF-8"))); colNames.add(ByteBuffer.wrap("last".getBytes("UTF-8"))); colNames.add(ByteBuffer.wrap("age".getBytes("UTF-8"))); slicePredicate.setColumn_names(colNames); SlicePredicate slicePredicate = new SlicePredicate(); slicePredicate.setSlice_range(sliceRange); // get_slice を呼ぶ List<ColumnOrSuperColumn> results = client.get_slice(ByteBuffer.wrap(key.getBytes("UTF-8")), columnParent, slicePredicate, ConsistencyLevel.ONE); for (int i = 0; i < results.size(); i++) { ColumnOrSuperColumn result = results.get(i); Column col = result.column; System.out.printf("[%d] カラム名:[%s] 値:[%s] タイムスタンプ:[%s]\n", i + 1, new String(col.getName(), "UTF8"), new String(col.getValue(), "UTF8"), new Date(col.timestamp)); }
「multiget_slice」を試す
「multiget_slice」は、複数のキーを対象にデータを取得することができます。
テストデータを追加する
キーをもう一つ追加しました。
set Standard2['sasakinozomi']['first'] = 'nozomi' set Standard2['sasakinozomi']['last'] = 'sasaki' set Standard2['sasakinozomi']['age'] = '22'
インサート結果は、下記の通りです。
[default@Keyspace1] get Standard2['sasakinozomi']; => (column=age, value=3232, timestamp=1294970184260000) => (column=first, value=6e6f7a6f6d69, timestamp=1294970172148000) => (column=last, value=736173616b69, timestamp=1294970178051000) Returned 3 results.
テストデータ「michibatajessica」「sasakinozomi」を取得する
取得したいデータのキーを指定して、一気に取得します。
SliceRange sliceRange = new SliceRange(); // 取得カラムの範囲を指定。全部取得する場合は空の byte 配列を指定 sliceRange.setStart(new byte[0]); sliceRange.setFinish(new byte[0]); SlicePredicate slicePredicate = new SlicePredicate(); slicePredicate.setSlice_range(sliceRange); List<ByteBuffer> rowKeys = new ArrayList<ByteBuffer>(); rowKeys.add(ByteBuffer.wrap("michibatajessica".getBytes("UTF-8"))); rowKeys.add(ByteBuffer.wrap("sasakinozomi".getBytes("UTF-8"))); Map<ByteBuffer, List<ColumnOrSuperColumn>> results = client.multiget_slice(rowKeys, columnParent, slicePredicate, ConsistencyLevel.ONE); for (Map.Entry<ByteBuffer, List<ColumnOrSuperColumn>> entry : results.entrySet()) { ByteBuffer 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.getName(), "UTF8"), new String(col.getValue(), "UTF8"), new Date(col.timestamp)); } System.out.println("--------------------"); }
ここで気づいたのは、「cassandra-cli」でデータをsetすると、何故か時刻がおかしくなる模様。
(どこのデータを取得しているのか分かりません。)
よって、複数データを一気に投入できる「batch_mutate」メソッドも試してみた。
「batch_mutate」を試す
「batch_mutate」メソッドの引数は、下記の通りです。
void batch_mutate(Map<ByteBuffer, Map<String, List<Mutation>>> mutation_map, ConsistencyLevel consistency_level)
引数は、2つですが、「Mutation」のMAPを作成するのが一苦労です。
// key と カラムファミリの Map の Map を作成 Map<ByteBuffer, Map<String, List<Mutation>>> mutaionMap = new HashMap<ByteBuffer, Map<String, List<Mutation>>>(); // レコードを挿入 long timestamp = System.currentTimeMillis(); // 登録・更新したい値から Mutation オブジェクトの List を作成 List<Mutation> columns = new ArrayList<Mutation>(); columns.add(toMutation("first", "Jessica", timestamp)); columns.add(toMutation("last", "Michibata", timestamp)); columns.add(toMutation("age", "25", timestamp)); List<Mutation> columns2 = new ArrayList<Mutation>(); columns2.add(toMutation("first", "nozomi", timestamp)); columns2.add(toMutation("last", "sasaki", timestamp)); columns2.add(toMutation("age", "22", timestamp)); // カラムファミリと Mutation のリストの Map を作成 Map<String, List<Mutation>> innerMap = new HashMap<String, List<Mutation>>(); Map<String, List<Mutation>> innerMap2 = new HashMap<String, List<Mutation>>(); innerMap.put(cfName, columns); innerMap2.put(cfName, columns2); // 取り合えず同じ内容を key だけ別にして追加。 mutaionMap.put(ByteBuffer.wrap("michibatajessica3".getBytes("UTF-8")), innerMap); mutaionMap.put(ByteBuffer.wrap("sasakinozomi3".getBytes("UTF-8")), innerMap2); client.batch_mutate(mutaionMap, ConsistencyLevel.ONE);
キー「michibatajessica」「sasakinozomi」は、timestampが現在時刻では無くなっていたので
removeメソッドを利用して一度、削除しました。
その後、「batch_mutate」メソッドを利用しても新規にデータが挿入されず。
「cassandra-cli」を実行してもデータを挿入できず。
「remove」「insert」は、うまく動作するのですが、なぜかうまくデータが挿入できなくなりました。
(理由調査中)
とりあえず、キーを変更したところうまく「batch_mutate」で挿入できるようになりました。
まとめ
ここまで試したThrift APIをまとめてみます。
表1. APIまとめ
No | メソッド名 | 説明 |
---|---|---|
1 | get | 特定キーからカラムまたはスーパーカラム1つを取り出す |
2 | insert | 特定キーで1カラムデータを作成する |
3 | remove | 特定キーで1カラムデータを削除する |
4 | get_slice(setSlice_range) | スライスされたカラムまたはスーパーカラムの集合を返す(範囲抽出) |
5 | get_slice(setColumn_names) | スライスされたカラムまたはスーパーカラムの集合を返す(カラム指定) |
6 | multiget_slice | 複数キーに対して複数のget_sliceを並列にこなす |
7 | batch_mutate | 複数キーに対して複数のデータを作成/更新/削除する |