我正在尝试将SQL中相对常见的需求转换为Cassandra中的高效数据模型。我试图决定如何最好地建模我的数据,以便我可以按照我希望在应用程序中报告它们的顺序在Cassandra中订购我的行。通常情况下,这对于群集列来说是一个很好的情况,除了我想要命令我的结果的数据是一个每日更新几次的度量。
我将在SQL中解释问题,然后分享我发生的数据建模方法。我想知道的是,有没有人遇到过与我相似的要求,如果有的话,你是如何对卡桑德拉的数据进行建模的。
这是我试图解决的问题。
假设我有一个如下定义的raw_data表:
CREATE TABLE raw_data (
A varchar,
B varchar,
C varchar,
D varchar,
ts timestamp,
val varint
PRIMARY KEY (ts,A,B,C,D)
);
我还有一个汇总表
CREATE TABLE summary_table (
A varchar,
B varchar,
C varchar,
total_val varint
PRIMARY KEY (A,B,C)
);
我的摘要表中的数据由我的应用程序以与
对应的方式聚合SELECT A, B, C, SUM(val) FROM raw_data GROUP BY A, B, C
我希望能够执行如下查询:
SELECT B, C, total_val FROM summary_table WHERE A = "Something" ORDER BY total_val DESC LIMIT 1000;
也就是说,我想将我的汇总表子集为特定的A值,然后返回前1000行,按total_val排序
我的应用程序每隔几分钟更新一次Total_val,因为其他数据会流式传输到我的raw_data表中。所以我不能将total_val用作数据的聚类列
我想要决定的是如何最好地在Cassandra中对这类问题进行建模 - 我需要在其中使用WHERE CLAUSE对汇总表进行子集并对结果集进行排序(不断更新) )以DESC顺序。
某些结果集可能会相当大 - 几十万行(也就是说,在我的汇总表中有一些值为SELECT COUNT(*) FROM summary_table WHERE A = "some value"
非常适合的值,非常大,成千上万)。在发送到我的应用程序之前对这些数据进行排序和丢弃显然效率低下。
此外,这似乎不是二级指数的一个很好的用例。在较小的结果集上,它们非常高效。对于较大的,它们是滞后的,我怀疑可能有更好的方法来处理这个问题。
我考虑对此进行建模的另一种方法是将较大的结果集缓存到内存中,这样至少在我需要对数千行进行排序时,我至少在内存中这样做。我还考虑过一个二级汇总表,它已经预先填充了我希望向我的应用程序公开的前1000行...虽然我不能想到一个好的方法来保留这些数据是最新的,并避免与我的原始汇总表完全相同的问题。
是否有人遇到过这样的问题,您需要使用WHERE子句过滤摘要数据,并按描述顺序排序(经常更改)结果?如果是这样,当某些WHERE子句返回数千行时,您是否找到了一种方法来提高性能?如果是这样,你是怎么做的?
答案 0 :(得分:4)
我能想到的最好方法是:
CREATE TABLE summary_table (
time_bucket long,
A varchar,
total_val int,
timestamp long,
B varchar,
C varchar,
PRIMARY KEY ((time_bucket, A), total_val, timestamp, B, C)
) WITH CLUSTERING ORDER BY (total_val DESC);
使用此结构,您实际上不会覆盖total_val
。而是为每个新值插入一个新行,然后在查询时丢弃除最新时间戳之外的所有时间戳。 time_bucket
的值应该是您的时间戳舍入到您可以在查询时计算的某个时间间隔(您可能必须一次查询多个存储桶,但如果可能,请尝试将其限制为仅两个)。如果您想知道,time_bucket
和A
会成为您的分区键,这可以防止无限制的行增长。
换句话说,您已将摘要表转换为时间序列数据。如果需要,您可以在旧列中添加TTL,以便它们自然消失。只要你的时间段是理智的,你就不会遇到查询大量墓碑的问题。