Cassandraのはじめ方─手を動かしてNoSQLを体感しよう

第6回 Cassandraでデータの更新・削除をするには

この記事を読むのに必要な時間:およそ 6 分

前回はCassandraへデータを投入する方法を説明しました。今回はデータの更新と削除についてご説明します。

データ更新ではタイムスタンプに注意

Cassandraにおけるデータ更新は,実はインサートのときと同じAPIを使います。1点だけ違うのは,更新の場合はタイムスタンプが重要になることです。タイムスタンプが以前に入れたものより後になっていないと,データが更新されません。

以下のコードでそれを確かめてみましょう。

リスト1 SimpleUpdate

Date oldDate = new SimpleDateFormat("yyyy/MM/dd").parse("1970/01/01");
long oldTimestamp = oldDate.getTime();
Cassandra.Client client = new Cassandra.Client(protocol);
try {
	final String key = "sample_update1";
	final String columnName = "update_hoge";
	String value = "original_value";
	long timestamp = System.currentTimeMillis();

	final ColumnPath columnPath = new ColumnPath(COLUMN_FAMILY);
	columnPath.setColumn(columnName.getBytes());
	// 1件カラムをインサート
	client.insert(KEYSPACE, key, columnPath, value.getBytes(),
			timestamp, ConsistencyLevel.ONE);

	value = "update_value";
	timestamp = System.currentTimeMillis();
	// 同一カラムを更新日付を後にしてアップデート
	client.insert(KEYSPACE, key, columnPath, value.getBytes(),
			timestamp, ConsistencyLevel.ONE);

	value = "update2_value";
	timestamp = oldTimestamp;
	// 同一カラムを更新日付を前にしてアップデート
	client.insert(KEYSPACE, key, columnPath, value.getBytes(),
			timestamp, ConsistencyLevel.ONE);

} catch (InvalidRequestException e) {
    ...

Cassandra-cliを使って確認してみてください。

cassandra> get Keyspace1.Standard1['sample_update1']
=> (column=7570646174655f686f6765, value=update_value, timestamp=1277138220269)
Returned 1 results.

データが更新日付が後のもので上書きされているのがわかるでしょうか。

実行してみるとわかるのですが,Cassandraでは更新日付がきちんとデータ投入時より後になってないと更新できません。例外も出さないため,注意が必要です。タイムスタンプは日付をきちんととらなくてはいけない理由がこのあたりにあります。

batch_mutateを使った場合でも,カラムがあれば同様に更新できます。

1行ならremove,まとめてならbatch_mutateで削除

次はデータの削除です。データを削除するには以下の2つの方法があります。

  • removeメソッド削除する
  • batch_mutateでDeletionオブジェクトをセットして削除する

1行を削除するような処理は前者で問題ありません。一方,まとめて削除したいようなケースでは後者のほうがbatch_mutateメソッドで,削除を表現するDeletionオブジェクトを使って削除するのがよいです。ThriftのAPIを1行ずつコールしないので,効率よく処理できます。

ではそれぞれの詳細を見ていきましょう。

removeメソッドで削除する場合の3つの選択肢

removeメソッドで削除する場合,以下の3つの選択肢があります。

  • ① キーで指定したロウ内のカラムを削除する
  • ② キーで指定したロウ内のスーパーカラムを削除する
  • ③ そのキーのロウごと削除する

これらは,インサートのときと同じように,すべてColumnPathで指定します。ColumnPathにはカラムファミリの指定が必須ですが,それ以外は上記の①~③に応じて設定する内容を変えます。

①キーで指定したロウ内のカラムを削除する

以下は特定カラムを削除するサンプルコードの抜粋です。このサンプルでは,カラムを1つ追加して,そのデータを削除することを試みています。

注目していただきたいことが2点あります。1点目は,ColumnPathを使う際に,setColumnで明示的に削除するColumnを指定していることです。

2点目は,更新のときと同様に古いタイムスタンプで削除を試みますが,それはうまくいかずにデータは削除されないことです。削除されたデータを検索メソッドであるgetで読み出そうとすると,NotFoundExceptionが発生します。タイムスタンプをインサート時より後にしてあげるときちんとデータが削除されます。

リスト2 DeleteColumnWithRemove

Date oldDate = new SimpleDateFormat("yyyy/MM/dd").parse("1970/01/01");
long oldTimestamp = oldDate.getTime();
Cassandra.Client client = new Cassandra.Client(protocol);
try {
	final String key = "sample_delete1";
	final String columnName = "delete_hoge";
	String value = "削除のサンプルです";
	long timestamp = System.currentTimeMillis();

	final ColumnPath columnPath = new ColumnPath(COLUMN_FAMILY);
	columnPath.setColumn(columnName.getBytes());
	// 1件カラムをインサート
	client.insert(KEYSPACE, key, columnPath, value.getBytes(),
			timestamp, ConsistencyLevel.ONE);

	// 古いタイムスタンプで削除しようとすると,削除できない.特に例外も出ない。
	client.remove(KEYSPACE, key, columnPath, oldTimestamp,
			ConsistencyLevel.ALL);

	// 削除されていない事を確認
	ColumnOrSuperColumn ret = client.get(KEYSPACE, key, columnPath,
			ConsistencyLevel.ONE);
	Column retColumn = ret.getColumn();
	String retName = new String(retColumn.getName());
	String retValue = new String(retColumn.getValue());
	System.out.println("カラムキー : " + retName);
	System.out.println("カラム値: " + retValue);
	System.out.println("タイムスタンプ: " + retColumn.getTimestamp());

	timestamp = System.currentTimeMillis();
	// タイムスタンプを更新して削除.
	client.remove(KEYSPACE, key, columnPath, timestamp,
			ConsistencyLevel.ALL);

	// 削除されていてカラムが既に無いのでNotFoundException発生
	ret = client.get(KEYSPACE, key, columnPath, ConsistencyLevel.ONE);

著者プロフィール

大谷晋平(おおたにしんぺい)

オープンソースプログラマ。WebフレームワークT2の開発をしながらHadoop/NoSQLミドルウェアにも手を出す。最近ではもっぱらHadoop,Cassandra,Avro,kumofsなどに興味津々。

blog:http://d.hatena.ne.jp/shot6/

Twitter:http://twitter.com/shot6/

コメント

コメントの記入