Cassandra 中的多列相等限制

Multi Column equality Restrictions in Cassandra

考虑以下 table:

CREATE TABLE routes (
start text,
end text,
validFrom timestamp,
validTo timestamp,
PRIMARY KEY (start, end, validFrom, validTo)
);

如何编写一个 cql 查询来查找从 A 点到 B 点并且在日期 x 和日期 y 之间有效的所有路线。本质上等同于以下 SQL 语句:

SELECT * from routes where start = 'A' and end = 'B' and validFrom <= x and validTo >= y.

我一直在通读 Cassandra Docs,我的印象是给定的 table 不可能进行这样的查询。如果是这种情况,那么如何对数据建模才能启用这样的查询。

SELECT * from routes where start = 'A' and end = 'B' and validFrom <= x and validTo >= y

由于 Cassandra 在磁盘上存储数据的方式,它无法为这样的查询提取连续范围的行。所以你需要做的是稍微调整一下你的模型。

CREATE TABLE routes (
  start text,
  end text,
  valid timestamp,
  toFrom text,
  name text,
  PRIMARY KEY (start, end, valid, toFrom)
);

通过将 to/from valid 时间合并到一个列中,您现在可以对其执行范围查询,检查开始和结束。每行都需要存储两次。一次是 "Valid To" 时间,一次是 "Valid From" 时间。 toFrom 列有助于区分这一点。

现在我可以运行这个查询:

> SELECT * FROM routes 
    WHERE start='A' AND end='B' 
    AND valid>='2016-02-01'AND valid<='2016-02-20';

 start | end | valid                    | tofrom | name
-------+-----+--------------------------+--------+---------
     A |   B | 2016-02-01 06:00:00+0000 |      F | combo 1
     A |   B | 2016-02-14 06:00:00+0000 |      T | combo 1
     A |   B | 2016-02-15 06:00:00+0000 |      F | combo 2

(3 rows)

只是一个想法,但使用复合分区键(如 PRIMARY KEY ((start, end), valid, toFrom))可能更适合更好的数据分布。虽然这真的取决于你的查询模式......所以如果你需要查询以 "A" 开头的所有行(例如),那将不起作用。

编辑 20160221

I accepted your answer but now I thought about it some more I don't think this will work. E.g. I think the query: SELECT * FROM routes WHERE start='A' AND end='B' AND valid>='2016-02-01' AND valid<='2016-02-13'; will yield no results even though the "Combo 1" route should be valid.

实际上,确实有效:

> SELECT * FROM routes 
    WHERE start='A' AND end='B' 
    AND valid>='2016-02-01'AND valid<='2016-02-13';

 start | end | valid                    | tofrom | name
-------+-----+--------------------------+--------+---------
     A |   B | 2016-02-01 06:00:00+0000 |      F | combo 1

(1 rows)

话虽如此,我明白你的意思。如果你应该 select 一个发生在有效 to/from 之间的时间段(不包括在内),它将产生零行......像这样:

    > SELECT * FROM routes 
    WHERE start='A' AND end='B' 
    AND valid>='2016-02-02'AND valid<='2016-02-13';

 start | end | valid                    | tofrom | name
-------+-----+--------------------------+--------+---------

(0 rows)

这是一个合理的担忧。有两点:

  1. 就你的问题"equivalent to the following SQL statement"而言,你在关系数据库中仍然会遇到同样的问题(在我的 MariaDB 测试实例)。实际上,情况会更糟,因为在 Cassandra 中查询 valid>='2016-02-01'AND valid<='2016-02-13' returns 一行,但在 MariaDB 中 validFrom>='2016-02-01' AND validTo<='2016-02-13' returns 什么也没有。

  2. 这真的变成了一个业务逻辑问题,与您的数据存储无关紧要。为避免此问题,您应该查看您的业务 logic/requirements,并确定 valid to/from 之间的最长时间。然后您可以调整您的查询,使其始终超过该时间。示例:如果路由的有效期最长为两到三周,那么一次查询一个月就足够了。