Cassandra复合聚类键和带有排序的查询

时间:2015-01-13 22:05:16

标签: cassandra schema cql

我们大量使用cassandra宽行来存储每个用户的时间序列,因为它们非常适合该用例。我们假设我们有一张表:

create table user_events ( user_id text, timestmp timestamp, event text, primary key((user_id), timestmp));

如果可能发生时间戳冲突(同一用户可以使用相同的时间戳发出两个不同的事件),该怎么办?假设我们对所有事件都有一个排序(每个事件都有一个序列int),调整这个模式来解决这个问题的最佳方法是什么。

如果我按以下方式修改架构:

create table user_events ( user_id text, timestmp timestamp, seq int, event text, primary key((user_id), timestmp, seq));

我无法做WHERE user_id = ? ORDER BY timestmp ASC, seq ASC - cassandra不允许这样做。

1 个答案:

答案 0 :(得分:0)

  

我将无法做WHERE user_id =? ORDER BY timestmp ASC,seq ASC - cassandra不允许这样做。

您可能会看到错误,因为您正在重复ASC。这应该有效:

WHERE user_id = ? ORDER BY timestmp,seq ASC

此外,只要您将主键定义为PRIMARY KEY((user_id),timestmp,seq)),您甚至不需要指定ORDER BY x[,y] ASC。它将按顺序将数据聚集在磁盘上,从而将其返回给您已按此顺序排序。只有当您想要按结果降序排列结果时(或者与定义结果相反的情况),才需要ORDER BY

  

如果时间戳发生冲突怎么办?

我认为您的额外seq列应该足够了,具体取决于您计划插入数据的方式。如果您从客户端设置timestmp,那么您应该没问题。但是,看看当我(使用你的第二个表)INSERT行时,以两种不同的方式创建时间戳时会发生什么。

INSERT INTO user_events(user_id,timestmp,seq,event) VALUES ('Mal',dateof(now()),1,'commanding');
INSERT INTO user_events(user_id,timestmp,seq,event) VALUES ('Wash',dateof(now()),1,'piloting');
INSERT INTO user_events(user_id,timestmp,seq,event) VALUES ('River',dateof(now()),1,'freaking out');
INSERT INTO user_events(user_id,timestmp,seq,event) VALUES ('River',dateof(now()),3,'being weird');
INSERT INTO user_events(user_id,timestmp,seq,event) VALUES ('River',dateof(now()),2,'killing reavers');
INSERT INTO user_events(user_id,timestmp,seq,event) VALUES ('River','2015-01-13 13:14-0600',1,'freaking out');
INSERT INTO user_events(user_id,timestmp,seq,event) VALUES ('River','2015-01-13 13:14-0600',3,'being weird');
INSERT INTO user_events(user_id,timestmp,seq,event) VALUES ('River','2015-01-13 13:14-0600',2,'killing reavers');

通过user_id“River”查询该数据会产生:

aploetz@cqlsh:stackoverflow> SELECT * FROM user_events WHERE user_id='River';
 user_id | timestmp                 | seq | event
---------+--------------------------+-----+-----------------
   River | 2015-01-13 13:14:00-0600 |   1 |    freaking out
   River | 2015-01-13 13:14:00-0600 |   2 | killing reavers
   River | 2015-01-13 13:14:00-0600 |   3 |     being weird
   River | 2015-01-14 12:58:41-0600 |   1 |    freaking out
   River | 2015-01-14 12:58:57-0600 |   3 |     being weird
   River | 2015-01-14 12:58:57-0600 |   2 | killing reavers

(6 rows)

请注意,使用now()函数生成timeuuid,然后将其转换为带dateof()的时间戳会导致带有timestmp的两行“2015-01-14 12:58:57- 0600“看起来是一样的。但它们并不相同,正如您在seq列中所说的那样。

所以在使用/生成时间戳时要小心一点。它们可能看起来相同,但它们可能不会存储为相同的值。为了安全起见,我会改用timeuuid。