为日期查询构建 Cassandra table
structuring Cassandra table for date queries
我正在学习 Cassandra,作为练习数据集,我正在从 Yahoo 抓取历史股票数据。每个交易日将有一条记录。
显然,我需要将股票代码作为分区键的一部分。关于我是应该将日期作为分区键的一部分,还是应该将其作为集群列,我看到了相互矛盾的信息?
实际上,股票市场每年开市约 253 天。因此,一只股票每年将有约 253 条记录。我不是在构建一个完整的数据库,而是想设计它以适应/正确。
如果我将日期作为分区键的一部分,它不会分布在多个节点上吗?使日期范围查询变慢?
If I make the date part of the partition key, won't that be possibly be spread across nodes? Make a date range query slow?
是的,两个帐户都是正确的。这种建模方法称为“时间分桶”,其主要用例是 time/event 随时间增长的数据。好消息是,您不需要这样做,除非您的分区预计会变大。根据您当前的预测,每年每个分区写入 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);
对于大多数 time-based 用例,我们更倾向于关注最近的数据(您的案例可能是这样,也可能不是这样)。如果是这样,那么按 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 Whosebug.stockquotes
Whosebug/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 年的数据,然后再 slow-down(我建议保持分区 <= 1mb) .也许像 quartercentiry
这样的东西就足够了?不管怎样,短期内还是可以的。
编辑:
Seems like any date portion used in the PK would spread the data across nodes, no?
是的,分区键中使用的日期部分会跨节点传播数据。这实际上就是这样做的意义所在。您不希望以未绑定的行增长 anti-pattern 结束,因为分区最终会变得太大以至于无法使用。这个想法就是为了确保足够的数据分布。
lets say 1/sec and I need to query across years, etc. How would that bucketing work?
所以时间分桶的诀窍是在数据分布和查询灵活性之间找到一个“平衡点”。不幸的是,可能会出现查询会命中多个分区(节点)的边缘情况。但我们的想法是建立一个模型来很好地处理其中的大部分问题。
这里的示例问题是一年每秒 1 次,有点极端。但是解决的思路是一样的。一天有86400秒。根据行的大小,这甚至可能每天都太多了。但是为了争论,说我们可以。如果我们 bucket on day,PK 是这样的:
PRIMARY KEY ((symbol,day),timestamp)
WHERE
子句开始看起来像这样:
WHERE symbol='AAPL' AND day IN ('2020-08-06','2020-08-07');
另一方面,几天没问题,但查询一整年就很麻烦了。此外,我们不想构建 253 天的 IN
子句。事实上,我不建议人们在 IN
.
上超过个位数
一种可能的方法是从应用程序中触发 253 个异步查询(每天一个),然后 assemble 并在那里对结果集进行排序。使用 Spark(在 RDD 中做所有事情)也是一个不错的选择。实际上,Cassandra 并不是用于报告的出色数据库 API,因此探索一些其他工具很有价值。
我正在学习 Cassandra,作为练习数据集,我正在从 Yahoo 抓取历史股票数据。每个交易日将有一条记录。
显然,我需要将股票代码作为分区键的一部分。关于我是应该将日期作为分区键的一部分,还是应该将其作为集群列,我看到了相互矛盾的信息?
实际上,股票市场每年开市约 253 天。因此,一只股票每年将有约 253 条记录。我不是在构建一个完整的数据库,而是想设计它以适应/正确。
如果我将日期作为分区键的一部分,它不会分布在多个节点上吗?使日期范围查询变慢?
If I make the date part of the partition key, won't that be possibly be spread across nodes? Make a date range query slow?
是的,两个帐户都是正确的。这种建模方法称为“时间分桶”,其主要用例是 time/event 随时间增长的数据。好消息是,您不需要这样做,除非您的分区预计会变大。根据您当前的预测,每年每个分区写入 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);
对于大多数 time-based 用例,我们更倾向于关注最近的数据(您的案例可能是这样,也可能不是这样)。如果是这样,那么按 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 Whosebug.stockquotes
Whosebug/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 年的数据,然后再 slow-down(我建议保持分区 <= 1mb) .也许像 quartercentiry
这样的东西就足够了?不管怎样,短期内还是可以的。
编辑:
Seems like any date portion used in the PK would spread the data across nodes, no?
是的,分区键中使用的日期部分会跨节点传播数据。这实际上就是这样做的意义所在。您不希望以未绑定的行增长 anti-pattern 结束,因为分区最终会变得太大以至于无法使用。这个想法就是为了确保足够的数据分布。
lets say 1/sec and I need to query across years, etc. How would that bucketing work?
所以时间分桶的诀窍是在数据分布和查询灵活性之间找到一个“平衡点”。不幸的是,可能会出现查询会命中多个分区(节点)的边缘情况。但我们的想法是建立一个模型来很好地处理其中的大部分问题。
这里的示例问题是一年每秒 1 次,有点极端。但是解决的思路是一样的。一天有86400秒。根据行的大小,这甚至可能每天都太多了。但是为了争论,说我们可以。如果我们 bucket on day,PK 是这样的:
PRIMARY KEY ((symbol,day),timestamp)
WHERE
子句开始看起来像这样:
WHERE symbol='AAPL' AND day IN ('2020-08-06','2020-08-07');
另一方面,几天没问题,但查询一整年就很麻烦了。此外,我们不想构建 253 天的 IN
子句。事实上,我不建议人们在 IN
.
一种可能的方法是从应用程序中触发 253 个异步查询(每天一个),然后 assemble 并在那里对结果集进行排序。使用 Spark(在 RDD 中做所有事情)也是一个不错的选择。实际上,Cassandra 并不是用于报告的出色数据库 API,因此探索一些其他工具很有价值。