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

how to update data in cassandra using IN operator

我有一个具有以下架构的 table。

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

如果群组发生任何变化(例如更改群组名称或在 table 中添加新朋友等),我需要跟踪时间。因此,每当任何相关 table.

发生任何变化时,我都需要通过 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 运算符执行更新操作吗?如果没有,那么有什么可能的方法来做到这一点?

提前致谢。

由于 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 的单独 table 来维护组的时间,即:

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

这里的缺点是,无论何时你想获得这些数据,你都需要从这个 table select,但这似乎是可以管理的。