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

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

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

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

スーパーカラムを削除する場合は,ColumnPathでsetSuperColumn()でスーパーカラムを指定してください。

さらにスーパーカラム内の特定カラムだけを削除することもできます。下記のサンプルでは,ColumnPath#setSuperColumn()とsetColumn()を併用して,スーパーカラム内の特定カラムだけを削除しています。

リスト3 DeleteOneColumnOfSuperColumnWithRemove

final String superColumnName = "hogehoge1";
final String key = "delete_one_column";
long timestamp = System.currentTimeMillis();

// スーパーカラムをインサートしておく
insertSuperColumn(superColumnName, key, client, timestamp);

// データがきちんと入ったかgetメソッドで確認する
ColumnPath columnPath = new ColumnPath(COLUMN_FAMILY);
columnPath.setSuper_column(superColumnName.getBytes());
ColumnOrSuperColumn ret = client.get(KEYSPACE, key, columnPath,
		ConsistencyLevel.QUORUM);
SuperColumn superColumn = ret.getSuper_column();
System.out.println("削除前");
for (Column c : superColumn.getColumns()) {
	String retName = new String(c.getName());
	String retValue = new String(c.getValue());
	System.out.printf("\tカラムキー :\t%s\n", retName);
	System.out.printf("\tカラム値:\t%s\n", retValue);
	System.out.printf("\tタイムスタンプ:\t%s\n", c.getTimestamp());
}

timestamp = System.currentTimeMillis();

// 削除用のColumnPathを作る。スーパーカラム内の特定カラムが削除したいのでそのカラム名"fooKey"を指定する。
ColumnPath deletePath = new ColumnPath(COLUMN_FAMILY);
deletePath.setSuper_column(superColumnName.getBytes());
deletePath.setColumn("fooKey".getBytes());
client.remove(KEYSPACE, key, deletePath, timestamp,
		ConsistencyLevel.ALL);

// 削除されたかどうか確認する。このケースでは,スーパーカラム自体は残り,カラム"fooKey"だけがなくなっている。
ret = client
		.get(KEYSPACE, key, columnPath, ConsistencyLevel.QUORUM);
superColumn = ret.getSuper_column();
System.out.println("削除後");
for (Column c : superColumn.getColumns()) {
	String retName = new String(c.getName());
	String retValue = new String(c.getValue());
	System.out.printf("\tカラムキー :\t%s\n", retName);
	System.out.printf("\tカラム値:\t%s\n", retValue);
	System.out.printf("\tタイムスタンプ:\t%s\n", c.getTimestamp());
}

③キーで指定したロウごと削除する

キーで指定したロウごと削除することもできます。この方法が最も簡単なのですが,ColumnPathでsetSuperColumn()もsetColumn()せずに削除するとロウそのものを削除することになる点に注意してください。

リスト4 DeleteEntireRowWithRemove

final String superColumnName = "sample1";
final String key = "delete_entire_row";
long timestamp = System.currentTimeMillis();

// スーパーカラムをインサートしておく
insertSuperColumn(superColumnName, key, client, timestamp);

ColumnPath columnPath = new ColumnPath(COLUMN_FAMILY);
columnPath.setSuper_column(superColumnName.getBytes());

// スーパーカラムがデータとしてあるか確認する。
ColumnOrSuperColumn ret = client.get(KEYSPACE, key, columnPath,
		ConsistencyLevel.QUORUM);
SuperColumn superColumn = ret.getSuper_column();
for (Column c : superColumn.getColumns()) {
	String retName = new String(c.getName());
	String retValue = new String(c.getValue());
	System.out.println("カラムキー : " + retName);
	System.out.println("カラム値: " + retValue);
	System.out.println("タイムスタンプ: " + c.getTimestamp());
}

timestamp = System.currentTimeMillis();

// ロウごと削除する。
client.remove(KEYSPACE, key, new ColumnPath(COLUMN_FAMILY),
		timestamp, ConsistencyLevel.ALL);

// ロウごと消えているため,NotFoundExceptionが発生する。
client.get(KEYSPACE, key, columnPath, ConsistencyLevel.QUORUM);

batch_mutateメソッドで削除する

removeメソッドでも十分機能的には事足りるのですが,スーパーカラムなどをもっと大量に削除したい場合はbatch_mutateを使ったほうが効果的です。batch_mutateのDeletionにある以下の2つのオプションが役立ちます。

  • スーパーカラムを設定して削除する
  • SlicePredicate(カラム名の集合か,一定数のレンジ)を設定して削除する

では実際のサンプルコードを見てみましょう。

リスト5 SuperColumnDeleteWithDeletion

final String superColumnName = "sample1";
final String key = "super_sample1";
long timestamp = System.currentTimeMillis();

// スーパーカラムをインサート
insertSuperColumn(superColumnName, key, client, timestamp);

ColumnPath columnPath = new ColumnPath(COLUMN_FAMILY);
columnPath.setSuper_column(superColumnName.getBytes());

// データが投入されたか確認
ColumnOrSuperColumn ret = client.get(KEYSPACE, key, columnPath,
		ConsistencyLevel.QUORUM);
SuperColumn superColumn = ret.getSuper_column();
for (Column c : superColumn.getColumns()) {
	String retName = new String(c.getName());
	String retValue = new String(c.getValue());
	System.out.printf("\tカラムキー \t\t:%s\n", retName);
	System.out.printf("\tカラム値\t\t:%s\n", retValue);
	System.out.printf("\tタイムスタンプ\t:%s\n", c.getTimestamp());
}

timestamp = System.currentTimeMillis();

// batch_mutateの構造を作って,Deletionをセットする
Map<String, Map<String, List<Mutation>>> mutationMap = new HashMap<String, Map<String, List<Mutation>>>();
Map<String, List<Mutation>> map = new HashMap<String, List<Mutation>>();
List<Mutation> list = new ArrayList<Mutation>();
Mutation mutation = new Mutation();
// Deletionを作成し,スーパーカラムで所定の名前を指定する
Deletion deletion = new Deletion(timestamp);
deletion.setSuper_column(superColumnName.getBytes());
mutation.setDeletion(deletion);
list.add(mutation);
map.put(COLUMN_FAMILY, list);
mutationMap.put(key, map);

// 削除実行。
client.batch_mutate(KEYSPACE, mutationMap, ConsistencyLevel.ALL);

// 削除されたことを確認する。削除されていればNotFoundExceptionが発生する。
client.get(KEYSPACE, key, columnPath, ConsistencyLevel.QUORUM);

ほとんどのコードが前回のbatch_mutateを使ったインサートのときと同じなのですが,ポイントはDeletionを使うところです。

Deletionオブジェクトを設定するだけで削除処理とみなされるので,ユーティリティやフレームワークは比較的楽に作ることができそうです。もし削除の処理をライブラリやフレームワークなどで統一するのであれば,batch_mutateで統一するほうが実行効率がよくなります。

著者プロフィール

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

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

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

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