Cassandra 复合聚类键和排序查询
Posted
技术标签:
【中文标题】Cassandra 复合聚类键和排序查询【英文标题】:Cassandra compound clustering key and queries with ordering 【发布时间】:2015-01-13 22:05:16 【问题描述】:我们大量使用 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 不允许这样做。
【问题讨论】:
WHERE user_id = ? ORDER BY timestmp ASC, seq ASC
- 在 cassandra 中可以进行此查询(对于您的第二个模式),例如: select * from user_events where user_id = 'xyz' order by timestmp ASC;这将以timestmp 的升序返回。如果用户“xyz”在同一时间戳执行超过 2 个事件,则 seq 值将按插入顺序进行维护。
【参考方案1】:
我将无法执行 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');
通过“River”的user_id
查询该数据会得到:
aploetz@cqlsh:***> 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。
【讨论】:
以上是关于Cassandra 复合聚类键和排序查询的主要内容,如果未能解决你的问题,请参考以下文章
使用 IF NOT EXISTS 使用主键和聚类列进行唯一插入