为日期查询构建Cassandra表



我正在学习Cassandra,作为一个练习数据集,我正在从雅虎获取历史股票数据。每个交易日都会有一个记录。

显然,我需要将股票符号作为分区键的一部分。我看到了关于是应该将日期作为分区键的一部分,还是将其作为集群列的矛盾信息?

实际上,股票市场每年开放约253天。因此,一只股票每年将有大约253张记录。我不是在构建一个完整的数据库,但我想设计它以适应/正确。

如果我把日期作为分区键的一部分,它不可能分布在节点之间吗?使日期范围查询变慢?

如果我将日期作为分区键的一部分,它不可能分布在节点之间吗?使日期范围查询变慢?

是,两个帐户都正确。这种建模方法被称为";时间分段;其主要用例是用于随时间增长的时间/事件数据。好消息是,您不需要这样做,除非您的分区预计会变大。根据您目前每年每个分区写入253行的预测,这只会是<每年40kb(见下文nodetool tablehistograms的计算(。

出于您的目的,我认为通过symbol进行分区和通过day进行集群就足够了。

CREATE TABLE stockquotes (
symbol text,
day date,
price decimal,
PRIMARY KEY(symbol, day))
WITH CLUSTERING ORDER BY (day DESC);

对于大多数基于时间的用例,我们往往更关心最近的数据(对于您的案例,这可能是真的,也可能不是真的(。如果是这样,那么按day降序写入数据将提高这些查询的性能。

然后(在写入一些数据后(,像这样的日期范围查询将起作用:

SELECT * FROM stockquotes 
WHERE symbol='AAPL'
AND day >= '2020-08-01' AND day < '2020-08-08';
symbol | day        | price
--------+------------+--------
AAPL | 2020-08-07 | 444.45
AAPL | 2020-08-06 | 455.61
AAPL | 2020-08-05 | 440.25
AAPL | 2020-08-04 | 438.66
AAPL | 2020-08-03 | 435.75
(5 rows)

为了验证分区大小,可以使用nodetool tablehistograms(一旦数据被刷新到磁盘(。

bin/nodetool tablehistograms stackoverflow.stockquotes
stackoverflow/stockquotes histograms
Percentile      Read Latency     Write Latency          SSTables    Partition Size        Cell Count
(micros)          (micros)                             (bytes)
50%                     0.00              0.00              0.00               124                 5
75%                     0.00              0.00              0.00               124                 5
95%                     0.00              0.00              0.00               124                 5
98%                     0.00              0.00              0.00               124                 5
99%                     0.00              0.00              0.00               124                 5
Min                     0.00              0.00              0.00               104                 5
Max                     0.00              0.00              0.00               124                 5

每年的分区大小=124字节x 253=31kb

考虑到很小的分区大小,这个模型可能适合在任何放缓之前至少30年的数据(我建议保留<=1mb的分区(。也许像quartercentiry这样的东西就足够了?不管怎样,在短期内,一切都会好起来的。

编辑:

PK中使用的任何日期部分似乎都会将数据分散到节点之间,不是吗?

是的,分区键中使用的日期部分会将数据分布在节点之间。这实际上就是这样做的目的。你不想以未绑定行增长的反模式结束,因为分区最终会变得太大,以至于无法使用。这个想法完全是为了确保充分的数据分布。

比方说1秒,我需要跨年查询,等等。这是怎么回事?

所以时间分段的诀窍是找到一个";快乐媒介";介于数据分布和查询灵活性之间。不幸的是,在边缘情况下,查询可能会碰到多个分区(节点(。但我们的想法是建立一个模型来很好地处理大多数问题。

这里的例子是一年1秒,这有点极端。但解决这个问题的想法是一样的。一天有86400秒。根据行的大小,这甚至可能太多了,无法一天一桶。但为了论证起见,说我们可以。如果我们在当天投球,PK看起来是这样的:

PRIMARY KEY ((symbol,day),timestamp)

WHERE子句开始看起来是这样的:

WHERE symbol='AAPL' AND day IN ('2020-08-06','2020-08-07');

另一方面,几天是可以的,但查询一整年会很麻烦。此外,我们不希望构建一个253天的IN子句。事实上,我不建议人们在IN上超过个位数。

这里的一种可能方法是从应用程序中激发253个异步查询(每天一个(,然后在那里对结果集进行组装和排序。使用Spark(在RDD中执行所有操作(也是一个不错的选择。事实上,Cassandra对于报告API来说并不是一个很好的DB,所以探索一些额外的工具是有价值的。