【问题标题】:Select 2000 most recent log entries in cassandra table using CQL (Latest version)使用 CQL(最新版本)在 cassandra 表中选择 2000 个最近的日志条目
【发布时间】:2013-08-18 21:37:24
【问题描述】:

你如何通过timeuuid进行查询和过滤,即假设你有一个表

create table mystuff(uuid timeuuid primary key, stuff text);

你是怎么做的:

select uuid, unixTimestampOf(uuid), stuff
from mystuff
order by uuid desc
limit 2000

我还希望能够获取下一个较旧的 2000 等等,但这是一个不同的问题。错误是:

Bad Request: ORDER BY is only supported when the partition key is restricted by an EQ or an IN.

为了以防万一,真正的表格实际上是这样的:

CREATE TABLE audit_event (
  uuid timeuuid PRIMARY KEY,
  event_time bigint,
  ip text,
  level text,
  message text,
  person_uuid timeuuid
) WITH
  bloom_filter_fp_chance=0.010000 AND
  caching='KEYS_ONLY' AND
  comment='' AND
  dclocal_read_repair_chance=0.000000 AND
  gc_grace_seconds=864000 AND
  read_repair_chance=0.100000 AND
  replicate_on_write='true' AND
  populate_io_cache_on_flush='false' AND
  compaction={'class': 'SizeTieredCompactionStrategy'} AND
  compression={'sstable_compression': 'SnappyCompressor'};

【问题讨论】:

    标签: cassandra cql


    【解决方案1】:

    我建议你设计你的桌子有点不同。用你目前的设计来实现你的要求是相当困难的。

    目前audit_event 表中的每个条目都会收到另一个uuid,Cassandra 在内部将创建许多短行。查询此类行效率低下,而且它们是随机排序的(除非使用字节排序分区器,您应该避免使用for good reasons)。

    但是 Cassandra 非常擅长对列进行排序。如果(回到你的例子)你这样声明你的表:

    CREATE TABLE mystuff(
      yymmddhh varchar, 
      created timeuuid,  
      stuff text, 
      PRIMARY KEY(yymmddhh, created)
    );
    

    Cassandra 在内部会创建一行,其中键是一天中的小时,列名是实际创建的时间戳,数据是内容。这将提高查询效率。

    假设您有以下数据(为了方便起见,我不会去 2k 条记录,但想法是一样的):

    insert into mystuff(yymmddhh, created, stuff) VALUES ('13081615', now(), '90');
    insert into mystuff(yymmddhh, created, stuff) VALUES ('13081615', now(), '91');
    insert into mystuff(yymmddhh, created, stuff) VALUES ('13081615', now(), '92');
    insert into mystuff(yymmddhh, created, stuff) VALUES ('13081615', now(), '93');
    insert into mystuff(yymmddhh, created, stuff) VALUES ('13081615', now(), '94');
    insert into mystuff(yymmddhh, created, stuff) VALUES ('13081616', now(), '95');
    insert into mystuff(yymmddhh, created, stuff) VALUES ('13081616', now(), '96');
    insert into mystuff(yymmddhh, created, stuff) VALUES ('13081616', now(), '97');
    insert into mystuff(yymmddhh, created, stuff) VALUES ('13081616', now(), '98');
    

    现在假设我们要选择最后两个条目(假设我们知道“最新”行键是“13081616”),您可以通过执行如下查询来做到这一点:

    SELECT * FROM mystuff WHERE yymmddhh = '13081616' ORDER BY created DESC LIMIT 2 ;
    

    这应该给你这样的东西:

     yymmddhh | created                              | stuff
    ----------+--------------------------------------+-------
     13081616 | 547fe280-067e-11e3-8751-97db6b0653ce |    98
     13081616 | 547f4640-067e-11e3-8751-97db6b0653ce |    97
    

    要获取接下来的 2 行,您必须从 created 列中获取最后一个值并将其用于下一个查询:

    SELECT * FROM mystuff WHERE  yymmddhh = '13081616' 
    AND created < 547f4640-067e-11e3-8751-97db6b0653ce 
    ORDER BY created DESC LIMIT 2 ;
    

    如果您收到的行数少于预期,则应将行键更改为另一个小时。

    行键处理/计算

    现在我假设我们知道我们要用来查询数据的行键。如果您记录大量信息,我会说这不是问题 - 您可以只使用当前时间并发出查询,将小时设置为我们现在的时间。如果我们用完了行,我们可以减去一个小时并发出另一个查询。

    但是,如果您不知道数据的位置,或者数据分布不均,您可以创建元数据表,在其中存储有关行键的信息:

    CREATE TABLE mystuff_metadata(
      yyyy varchar, 
      yymmddhh varchar, 
      PRIMARY KEY(yyyy, yymmddhh)
    ) WITH COMPACT STORAGE;
    

    行键将按年份组织,因此要获取当前年份的最新行键,您必须发出查询:

    SELECT yymmddhh 
    FROM  mystuff_metadata where yyyy = '2013' 
    ORDER BY yymmddhh DESC LIMIT 1;
    

    您的审计软件必须在开始时和稍后每小时更改时(例如在将数据插入mystuff 之前)对该表进行条目。

    【讨论】:

    • 感谢您的详细而有用的回答!我现在正在努力解决(并测试它)。谢谢!
    • @Jacob 没问题,只是我忘记提及的一件事。不要让你的行超宽。保持在几兆字节(您可以测试何时性能最佳)。
    • 完美运行,非常感谢!!我从 yyyymmdd 分组开始,并根据需要进行调整。
    • @Jacob 没问题,如果您打算始终按“DESC”顺序查看数据,您还可以查看“聚类顺序”。你可以这样声明你的表,最新的行在开头,所以当数据增长时检索它会更快。
    猜你喜欢
    • 2023-03-10
    • 2016-05-08
    • 1970-01-01
    • 2017-03-19
    • 2014-11-27
    • 1970-01-01
    • 2020-10-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多