cassandra获得时间范围内的所有记录

时间:2013-09-09 11:58:15

标签: cassandra cql

我必须使用以(user_id,timestamp)为键的列族。在我的查询中,我想获取给定时间范围内的所有记录,与user_id无关。这是确切的表模式:

CREATE TABLE userlog (
  user_id text,
  ts timestamp,
  action text,
  app_type text,
  channel_name text,
  channel_session_id text,
  pid text,
  region_id text,
  PRIMARY KEY (user_id, ts)
)

我试图运行

SELECT * FROM userlog  WHERE ts >= '2013-01-01 00:00:00+0200' AND  ts <= '2013-08-13 23:59:00+0200' ALLOW FILTERING;

在包含小数据集的本地cassandra安装中正常工作但

失败
Request did not complete within rpc_timeout.

在包含所有数据的生产系统上。

是否有一个优选的cql查询可以与给定的列族一起平滑运行,或者我们必须更改设计吗?

3 个答案:

答案 0 :(得分:32)

超时是因为Cassandra花费的时间超过了超时(默认为10秒)才能返回数据。对于您的查询,Cassandra将在返回之前尝试获取整个数据集。对于多个记录,这可能比超时更容易。

对于生成大量数据的查询,您需要进行分页,例如

SELECT * FROM userlog WHERE ts >= '2013-01-01 00:00:00+0200' AND  ts <= '2013-08-13 23:59:00+0200' AND token(user_id) > previous_token LIMIT 100 ALLOW FILTERING;

其中user_id是之前返回的user_id。您还需要在ts上进行分页,以保证您获得最后返回的user_id的所有记录。

或者,在Cassandra 2.0.0(刚发布)中,分页是透明完成的,因此原始查询应该没有超时或手动分页。

ALLOW FILTERING表示Cassandra正在读取您的所有数据,但仅返回指定范围内的数据。只有范围是大部分数据时,这才有效。如果你想在例如5分钟的时间窗口,这将是非常低效的。

答案 1 :(得分:3)

似乎hotness能够按时间(或任何范围)查询是指定某些&#34;其他列&#34;作为分区键,然后将时间戳指定为&#34;群集列&#34;

CREATE TABLE postsbyuser (
     userid bigint,
     posttime timestamp,
     postid uuid,
     postcontent text,
     PRIMARY KEY ((userid), posttime)
   ) WITH CLUSTERING ORDER BY (posttime DESC);

插入虚假数据

  insert into postsbyuser (userid, posttime) values (77, '2013-04-03 07:04:00');

和查询(重要的部分是它是&#34;快速&#34;查询和ALLOW FILTERING不是必需的,它应该是这样的):

  SELECT * FROM postsbyuser where userid=77 and posttime > '2013-04-03 07:03:00' and posttime < '2013-04-03 08:04:00';

您还可以使用技巧group by day(因此可以按天查询)或不使用。

如果您按天使用&#34;组&#34;样式技巧然后二级索引也是一个选项(虽然二级索引似乎只适用于&#34; EQ&#34; =运算符?)。

答案 2 :(得分:0)

通常,这可能表明您尚未对架构进行建模以适合数据查询,这是Cassandra的处理方式(https://docs.datastax.com/en/cql/3.3/cql/ddl/dataModelingApproach.html)...

因此,理想情况下,您可以对架构进行建模以适合查询。尽管有一些关于如何为Cassandra进行时间序列建模的资源,但是例如this slideshare似乎与您所拥有的类似-但这并不是广告宣传您想要执行的查询。我认为我实际上没有找到支持“在特定时间范围内获取所有数据”查询的Cassandra模式示例。

在任何情况下,对于本答案的其余部分,我都将假定您受此迭代所用的模式约束。

您可以通过两个查询来做到这一点:

SELECT DISTINCT user_id FROM userlog;

然后,对于每个用户,

SELECT * FROM userlog WHERE
  user_id='<user>'
  AND ts >= '2013-01-01 00:00:00+0200'
  AND ts <= '2013-08-13 23:59:00+0200';

如果一组用户ID是中小型,则可以使用IN查询来摆脱困境:

SELECT * FROM userlog WHERE
  user_id IN ('sampleuser', 'sampleadmin', ...)
  AND ts >= '2013-01-01 00:00:00+0200'
  AND ts <= '2013-08-13 23:59:00+0200';

请注意,此操作 ALLOW FILTERING