如何使用IN运算符更新cassandra中的数据

时间:2015-03-04 06:24:08

标签: cassandra cassandra-2.0 cql3

我有一个包含以下架构的表。

CREATE TABLE IF NOT EXISTS group_friends(
groupId timeuuid,
friendId bigint,
time bigint,
PRIMARY KEY(groupId,friendId));

如果组中发生任何更改(例如更改组名或在表中添加新朋友等),我需要跟踪时间。因此,每当任何相关表中发生任何更改时,我都需要通过groupId更新时间字段的值。

由于cassandra中的更新需要提及where子句中的所有主键,因此该查询将不会运行。

update group_friends set time = 123456 where groupId = 100;

所以我可以这样做。

update group_friends set time=123456 where groupId=100 and friendId in (...);

但它显示以下错误 - >

[Invalid query] message="Invalid operator IN for PRIMARY KEY part friendid"

有没有办法在群集列中使用IN运算符执行更新操作?如果没有,那么可能的方法是什么?

提前致谢。

1 个答案:

答案 0 :(得分:3)

由于friendId是一个聚类列,因此在这种情况下批处理操作可能是一个合理且性能良好的选择,因为所有更新都将在同一个分区中进行(假设您使用相同的组ID进行更新)。例如,使用java驱动程序,您可以执行以下操作:

Cluster cluster = new Cluster.Builder().addContactPoint("127.0.0.1").build();
Session session = cluster.connect("friends");

PreparedStatement updateStmt = session.prepare("update group_friends set time = ? where groupId = ? and friendId = ?");

long time = 123456;
UUID groupId = UUIDs.startOf(0);
List<Long> friends = Lists.newArrayList(1L, 2L, 4L, 8L, 22L, 1002L);
BatchStatement batch = new BatchStatement(BatchStatement.Type.UNLOGGED);
for(Long friendId : friends) {
    batch.add(updateStmt.bind(time, groupId, friendId));
}
session.execute(batch);
cluster.close();

这样做的另一个好处是,由于可以从BatchStatement推断出分区键,因此驱动程序将使用令牌感知路由将请求发送到拥有此数据的副本,从而跳过网络跃点。

虽然这实际上只是一次写入,但要注意批量的大小。你应该注意不要太大。

在一般情况下,通过单独执行每个语句而不是使用批处理,您实际上不会出错。 CQL传输允许单个连接上的许多请求,并且本质上是异步的,因此您可以一次执行许多请求,而不会出现每个连接请求的典型性能成本。

有关批量编写数据的详细信息,请参阅:Cassandra: Batch loading without the Batch keyword

或者,可能有更简单的方法来完成你想要的。如果您真正想要实现的目标是维持群组更新时间,并且您希望群组中的所有朋友都能保持相同,那么您可以将时间设为static column。这是Cassandra 2.0.6中的一项新功能。这样做是为了分享groupId分区中所有行的列值。这样你只需要更新一次时间,甚至可以在用于将朋友添加到组中的查询中设置时间,这样就可以完成一次写操作。

CREATE TABLE IF NOT EXISTS friends.group_friends(
  groupId timeuuid,
  friendId bigint,
  time bigint static,
  PRIMARY KEY(groupId,friendId)
);

如果你还不能使用Cassandra 2.0.6+,你可以创建一个名为group_metadata的独立表来维护组的时间,即:

CREATE TABLE IF NOT EXISTS friends.group_metadata(
  groupId timeuuid,
  time bigint,
  PRIMARY KEY(groupId)
);

这方面的缺点是,无论何时想要获取此数据,您都需要从此表中进行选择,但这似乎是可以管理的。