首页 文章

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

提问于
浏览
23

我必须使用以(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,查询与给定的列系列顺利运行或de我们必须更改设计?

3 回答

  • 0

    超时是因为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分钟的时间窗口,这将是非常低效的 .

  • 31

    看来hotness能够按时间(或任何范围)查询是指定一些"other column"作为您的分区键,然后将时间戳指定为"clustering column"

    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');
    

    和查询(重要的部分是它是"fast"查询和 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(因此可以按天查询)或不是 .

    如果您使用"group by day"样式技巧,那么辅助索引也是一个选项(尽管二级索引似乎只适用于"EQ" = 运算符?) .

  • 2

    一般来说,这可能表明您没有建模您的架构以适合您的数据查询,这是Cassandra的做事方式(https://docs.datastax.com/en/cql/3.3/cql/ddl/dataModelingApproach.html)......

    因此,理想情况下,您需要为您的架构建模以适应查询 . 关于如何为Cassandra进行时间序列建模有一些资源,尽管例如this slideshare似乎与您不希望广告支持您想要执行的查询类似 . 我实际上找不到支持"get me all data for a certain time range"查询的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';
    

    请注意,这有效 without ALLOW FILTERING .

相关问题