【问题标题】:structuring Cassandra table for date queries为日期查询构建 Cassandra 表
【发布时间】:2020-08-12 01:36:34
【问题描述】:

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

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

实际上,股市每年开放约 253 天。因此,一只股票每年将有约 253 条记录。我不是在构建一个完整的数据库,但想对其进行设计以正确容纳 /。

如果我将日期作为分区键的一部分,那可能会跨节点传播吗?让日期范围查询变慢?

【问题讨论】:

  • 使用 Cassandra 时,您必须从需要运行的查询开始以指导您的数据模型选择 - 您已经开始考虑分区键对查询的影响,但如果不完全了解您打算运行的查询,建议将是试探性的和警告性的。
  • @Andrew 对于这个特定的练习,我会说给定一个符号和一个日期范围,返回记录。由于只有 1 条记录/天/符号(结束引号),我认为日期不应该在 PK 中。

标签: cassandra cql


【解决方案1】:

如果我将日期作为分区键的一部分,那可能不会跨节点传播吗?让日期范围查询变慢?

是的,在两个帐户上都是正确的。这种建模方法称为“时间分桶”,其主要用例是用于随时间增长的时间/事件数据。好消息是,您不需要这样做,除非您的分区预计会变大。根据您当前的预测,每个分区每年写入 253 行,这将是每年 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 年的数据,然后才会出现任何减速(我建议保持分区 quartercentiry 这样的东西就足够了?无论如何,在短期内,它会没事的。

编辑:

似乎 PK 中使用的任何日期部分都会跨节点传播数据,不是吗?

是的,分区键中使用的日期部分会跨节点传播数据。这实际上就是这样做的目的。您不希望以非绑定行增长的反模式结束,因为分区最终会变得如此之大,以至于它们将无法使用。这个想法是为了确保足够的数据分布。

假设 1/秒,我需要跨年查询,等等。分桶如何工作?

因此,时间分桶的诀窍是在数据分布和查询灵活性之间找到一个“快乐的媒介”。不幸的是,可能会出现查询将访问多个分区(节点)的边缘情况。但我们的想法是建立一个模型来很好地处理其中的大部分问题。

这里的示例问题 1/sec for a year,有点极端。但是解决它的想法是一样的。一天有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 数据库,因此探索一些其他工具是有价值的。

【讨论】:

  • Yahoo 历史数据实际上有 7 列,如果包含符号(日期和 6 位小数),则为 8 列。我认为每天 1 个记录仅对符号进行分区并在日期上进行聚类就“足够好”了。
  • 为了便于讨论,如果我以更小的间隔进行跟踪会怎样。可能不适合股票,也许是遥测数据?,但假设是 1/秒,我需要跨年查询,等等。这种分桶将如何工作?似乎 PK 中使用的任何日期部分都会跨节点传播数据,不是吗?
  • @SledgeHammer 已编辑。
  • 谢谢... p.s.如果您有兴趣,这里有一篇来自 Netflix 的关于他们如何处理这个问题的文章:netflixtechblog.com/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-20
  • 2014-05-28
  • 2010-11-13
  • 2015-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多