Dip*_*low 14 cql distinct cassandra
执行两个相同的请求,但DISTINCT关键字会产生意外结果.如果没有关键字,结果就可以了,但是使用DISTINCT,看起来像where子句被忽略了.为什么?
Cqlsh版本:
Connected to Test Cluster at localhost:9160.
[cqlsh 4.1.1 | Cassandra 2.0.6 | CQL spec 3.1.1 | Thrift protocol 19.39.0]
Run Code Online (Sandbox Code Playgroud)
表考虑:
DESCRIBE TABLE events;
CREATE TABLE events (
userid uuid,
"timestamp" timestamp,
event_type text,
data text,
PRIMARY KEY (userid, "timestamp", event_type)
) WITH
bloom_filter_fp_chance=0.010000 AND
caching='KEYS_ONLY' AND
comment='' AND
dclocal_read_repair_chance=0.000000 AND
gc_grace_seconds=864000 AND
index_interval=128 AND
read_repair_chance=0.100000 AND
replicate_on_write='true' AND
populate_io_cache_on_flush='false' AND
default_time_to_live=0 AND
speculative_retry='99.0PERCENTILE' AND
memtable_flush_period_in_ms=0 AND
compaction={'class': 'SizeTieredCompactionStrategy'} AND
compression={'sstable_compression': 'LZ4Compressor'};
Run Code Online (Sandbox Code Playgroud)
表内容:
SELECT * FROM events;
userid | timestamp | event_type | data
--------------------------------------+--------------------------+------------+------
aaaaaaaa-be1c-44ab-a0e8-f25cf6064b0e | 1970-01-17 09:06:17+0100 | toto | null
4271a78f-be1c-44ab-a0e8-f25cf6064b0e | 1970-01-17 09:06:17+0100 | toto | null
4271a78f-be1c-44ab-a0e8-f25cf6064b0e | 1970-01-17 09:07:17+0100 | toto | null
4271a78f-be1c-44ab-a0e8-f25cf6064b0e | 1970-01-17 09:08:17+0100 | toto | null
4271a78f-be1c-44ab-a0e8-f25cf6064b0e | 1970-01-17 09:09:17+0100 | toto | null
4271a78f-be1c-44ab-a0e8-f25cf6064b0e | 1970-01-17 09:10:17+0100 | toto | null
(6 rows)
Run Code Online (Sandbox Code Playgroud)
Request1:没有DISTINCT的请求
SELECT userid FROM events WHERE timestamp > '1970-01-17 09:07:17+0100' ALLOW FILTERING;
userid
--------------------------------------
4271a78f-be1c-44ab-a0e8-f25cf6064b0e
4271a78f-be1c-44ab-a0e8-f25cf6064b0e
4271a78f-be1c-44ab-a0e8-f25cf6064b0e
(3 rows)
Run Code Online (Sandbox Code Playgroud)
Request2:与DISTINCT相同的请求
SELECT DISTINCT userid FROM events WHERE timestamp > '1970-01-17 09:07:17+0100' ALLOW FILTERING;
userid
--------------------------------------
aaaaaaaa-be1c-44ab-a0e8-f25cf6064b0e
4271a78f-be1c-44ab-a0e8-f25cf6064b0e
(2 rows)
Run Code Online (Sandbox Code Playgroud)
这里编辑1是一些背景.
这个表"事件"受到大量写入的影响,它每秒接收约1k个插入,并且我有一个批处理脚本,每5分钟检查一次这些事件.
此批处理脚本有2个需求:
1-获取在过去5分钟内处于活动状态的所有用户标识(即最近5分钟内事件中存在的每个用户标识)
2-获取与这些用户标识相关的所有事件(不仅仅是最后一个) 5分钟)
我曾经有两个不同的表来处理这个问题.第一个请求的一个表"activeusers"和我在这里为第二个请求描述的"events"表.我的问题只是它需要我的服务器在收到一个事件时写入两个不同的表.所以我只使用事件表尝试了这个.
Aar*_*ron 20
它是这样发生的,因为在Cassandra中CQL DISTINCT被设计为仅返回表(列族)的分区(行)键...它必须是唯一的.因此,该WHERE子句只能在使用时对分区键进行操作DISTINCT(在您的情况下,它不是非常有用).如果DISTINCT取出,WHERE则可以用来评估每个分区键中的聚类(列)键(尽管如此ALLOW FILTERING).
我不得不提到,这ALLOW FILTERING不是你应该做的很多事情......而且绝对不是在制作中.如果该查询是您需要经常运行的查询(userids在某个查询之后查询事件timestamp),那么我建议您通过以下方式对数据进行分区event_type:
PRIMARY KEY (event_type, "timestamp", userid)
Run Code Online (Sandbox Code Playgroud)
然后你就可以在没有的情况下运行这个查询了ALLOW FILTERING.
SELECT userid FROM events WHERE event_type='toto' AND timestamp > '1970-01-17 09:07:17+0100'
Run Code Online (Sandbox Code Playgroud)
在不了解您的应用程序或用例的情况下,这可能对您有用,也可能没有用.但请将其视为一个示例,并指出可能有更好的方法来构建模型以满足您的查询模式.查看Patrick McFadin关于时间序列数据建模的文章,了解有关如何为此问题建模的更多想法.
如Aaron所述,使用DISTINCT关键字时,只能按分区键进行过滤。其背后的原因是DISTINCT查询背后的算法以及Cassandra将数据存储到磁盘/内存中的方式。
为了理解这一点,我将进行类比:
Cassandra存储类似于书籍索引的信息。如果要搜索称为“我的第三章”的章节,则只需查看索引的第一级,因此只需要在相对较小的集合中进行迭代搜索即可。但是,如果要查找属于“我的第二章”的子章节“我的第四子章节”,则必须在2个不同的集合中进行2次迭代搜索,两个都很小,前提是索引至少有2个水平。您需要做得越深,花费的时间就越长(如果它处于索引的开头,您可能会很幸运并且发现它非常快,但是在这种算法中,您必须测试均值和最坏情况)并且索引将需要更复杂。
Cassandra做类似的事情:键空间->表->分区键->聚簇键->列需要深入的工作,需要在内存中包含更多的设置,而寻找内容的时间将更长。用于执行DISTINCT查询的索引甚至可能只包含集合,直到分区键级别为止,因此仅允许搜索分区键。
您需要认识到,搜索具有子章节的任何章节称为“我的第二子章节”(类似于您的查询)仍然需要2级深度索引和2级迭代搜索。
如果他们决定支持在聚类键上使用DISTINCT,那么您的查询就可以了。同时,可能必须使用称为set的内置类型或类似的东西自行处理重复值,才能对它们进行乘法运算过滤。
Aaron提出的解决方案(在时间戳之后使用用户ID作为聚类密钥)也没有(在客户端过滤)该解决方案也不使用DISTINCT快速机制。他的建议不需要客户端过滤,因为它已经为您解决了这一问题,但是存在两个主要缺点:它不提供向后兼容性,因为您将不得不重新创建表并使用恒定的分区键,因此不允许Cassandra可以在其节点之间分配此数据。请记住,同一分区键的每个值都存储在同一节点中。
| 归档时间: |
|
| 查看次数: |
37926 次 |
| 最近记录: |