【问题标题】:cassandra get all records in time rangecassandra 获取时间范围内的所有记录
【发布时间】:2013-09-12 21:53:25
【问题描述】:

我必须使用以 (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)可以在给定的列族中顺利运行,或者我们必须更改设计?

【问题讨论】:

    标签: cassandra cql


    【解决方案1】:

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

    【讨论】:

    • 对于“5 分钟时间窗口”,什么是有效的?
    • @nilspetersohn 你必须在这里使用ALLOW FILTERING,因为分区键没有被限制。如果您要查询个人user_id,则不需要ALLOW FILTERING,查询效率会更高。您必须事先知道表中的所有user_ids。 -- 另请注意,当理查德说在大时间窗口内高效时,他并不是指快速。如果表中有大量数据,无论如何过滤都会很慢。
    【解决方案2】:

    看来hotness 能够按时间(或任何范围)查询是指定一些“其他列”作为您的分区键,然后将时间戳指定为“集群列”

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

    和查询(重要的部分是它是一个“快速”查询并且不需要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(因此可以按天查询)或其他什么。

    如果您使用“按天分组”风格的技巧,那么二级索引也是一种选择(尽管二级索引似乎只适用于“EQ”= 运算符?)。

    【讨论】:

      【解决方案3】:

      一般来说,这可能表明您尚未对架构进行建模以适应您的数据查询,这是 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有效。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-06-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-01
        • 1970-01-01
        相关资源
        最近更新 更多