Cassandra 卡桑德拉-按电话号码查询

Cassandra 卡桑德拉-按电话号码查询,cassandra,Cassandra,为这个冗长的问题提前道歉。。。 我使用Cassandra数据库来存储用户之间的消息。 每个用户都有一个专用的电话号码,我需要(a)查询两个号码之间的对话,而不管是谁发送/接收的(b)查询与特定号码相关的所有消息,而不管它是发送还是接收的。这两个查询都需要按时间戳按降序分页 考虑以下简化的模式 create table messages ( app_id uuid, message_id text, from_number text, to_number text,

为这个冗长的问题提前道歉。。。 我使用Cassandra数据库来存储用户之间的消息。 每个用户都有一个专用的电话号码,我需要(a)查询两个号码之间的对话,而不管是谁发送/接收的(b)查询与特定号码相关的所有消息,而不管它是发送还是接收的。这两个查询都需要按时间戳按降序分页

考虑以下简化的模式

create table messages
(
    app_id uuid,
    message_id text,
    from_number text,
    to_number text,
    timestamp bigint,
    body text,
    primary key (app_id, timestamp, message_id)
) WITH CLUSTERING ORDER BY (timestamp DESC);
以及以下数据

+------------------------------------+-------------+------------------------------------+-----------+----------+
|app_id                              |timestamp    |message_id                          |from_number|to_number |
+------------------------------------+-------------+------------------------------------+-----------+----------+
|aae22284-04ee-11eb-9391-bb67d1e2f833|1599376014000|ae8b041e-04ee-11eb-9391-bb67d1e2f833|1111111111 |2222222222|
|aae22284-04ee-11eb-9391-bb67d1e2f833|1599376014001|c7e81302-04ee-11eb-9391-bb67d1e2f833|2222222222 |1111111111 |
+------------------------------------+-------------+------------------------------------+-----------+----------+
为了按数字进行查询(两个同时进行,每个单独进行),我正在考虑在此模式中标识为
number\u list
number\u list\u freezed
numbers\u concat
的多个选项

create table messages
(
    app_id uuid,
    message_id uuid,
    from_number text,
    to_number text,
    timestamp bigint,
    number_list list<text>, <--- option 1
    number_list_frozen frozen<list<text>>, <--- option 2
    numbers_concat text, <--- option 3
    primary key (app_id, timestamp, message_id)
)
WITH CLUSTERING ORDER BY (timestamp DESC);

CREATE INDEX idx_numbers_list ON messages (number_list);
CREATE INDEX idx_numbers_list_frozen ON messages (FULL(number_list_frozen));
CREATE INDEX idx_numbers_concat ON messages (numbers_concat);
选项1-列表

将使用编号列表,并允许进行以下查询

SELECT from_number, to_number, timestamp
    FROM messages
    WHERE app_id = aae22284-04ee-11eb-9391-bb67d1e2f833
    AND number_list contains '1111111111';  // or 2222222222
当您想按任意数字进行查询时,这种方法很有效,但不能同时按任意数字进行查询,也就是说,这种方法不起作用

 WHERE app_id = aae22284-04ee-11eb-9391-bb67d1e2f833 
AND number_list = ['1111111111', '222222222222'];
(获取错误<代码>“集合列'编号'列表'(列表)不能受'='关系的限制”)

在尝试以下操作时也是如此-

WHERE app_id = aae22284-04ee-11eb-9391-bb67d1e2f833
AND number_list contains '1111111111' AND number_list contains '222222222222';
SELECT from_number, to_number, timestamp
    FROM messages
    WHERE app_id = aae22284-04ee-11eb-9391-bb67d1e2f833
    AND numbers_concat = '1111111111-2222222222';
我收到此错误“无法执行此查询,因为它可能涉及数据筛选,因此可能具有不可预测的性能。如果您希望在性能不可预测的情况下执行此查询,请使用“允许筛选”。 添加ALLOW FILTERING确实可以解决这个问题,但不能确定它对性能的影响

选项2-冻结列表 为了解决获取两者的问题,我尝试使用一个带有完整索引的冻结列表,它似乎只适用于名称所暗示的完全匹配,因此查询两个数字是可行的,但查询单个数字却不行(因为Cassandra将数据序列化为单个值)

e、 g.这很有效-

SELECT from_number, to_number
    FROM sms_server.messages10
    WHERE app_id = aae22284-04ee-11eb-9391-bb67d1e2f833
    AND number_list_frozen = ['1111111111', '222222222222'];
但事实并非如此(除非我添加了允许过滤)

  • 冻结列表在插入数据库之前将在应用程序级别进行排序,以确保一致性(无论通信方向如何,两个数字的冻结列表始终相同)。 我还尝试使用一个元组,在查询时它似乎类似于冻结列表
选项3-连接的数字 在这个选项中,我总是以升序连接数字,这样如果数字A发送到B或B发送到A,它将是相同的字符串(“A-B”)。因此,在
上方的行中,无论消息的方向如何,concat
始终等于
1111111111-2222222

我可以运行以下命令-

WHERE app_id = aae22284-04ee-11eb-9391-bb67d1e2f833
AND number_list contains '1111111111' AND number_list contains '222222222222';
SELECT from_number, to_number, timestamp
    FROM messages
    WHERE app_id = aae22284-04ee-11eb-9391-bb67d1e2f833
    AND numbers_concat = '1111111111-2222222222';
但这只是冻结列表的一种替代方法,因此唯一的问题是字符串索引与冻结列表索引相比是否有任何性能提升

选项4-同时使用列表和冻结列表,每个查询一个

选项5-使用地图

在这个选项中,我同时删除了from_number和to_number,并使用了一个映射

创建表消息 ( 应用程序id uuid, 消息_iduuid, 时间戳bigint, 数字地图 主键(应用程序id、时间戳、消息id) ) 使用聚类顺序(时间戳DESC)

e、 g.
{'from':'2222222','to':'111111111'}

它允许运行以下命令

select * from messages
    where  app_id = aae22284-04ee-11eb-9391-bb67d1e2f833
    and numbers_map contains '111111111111';
但再次检查两者,我必须使用允许过滤

SELECT from_number, to_number
    FROM sms_server.messages10
    WHERE app_id = aae22284-04ee-11eb-9391-bb67d1e2f833
    AND number_list_frozen contains '1111111111';
select * from messages
    where  app_id = aae22284-04ee-11eb-9391-bb67d1e2f833
    and numbers_map contains '111111111111' and numbers_map contains '222222222222' ALLOW FILTERING;
最后是我的问题

  • 选项#5似乎是最干净的,并且不需要重复数据(因为从、到已删除)-是否可以在不需要允许筛选的情况下进行查询,或者我不应该担心这一点,因为它们位于同一个分区键中
  • 是否有一种本地方式,使用列表(选项1)或冻结列表(选项2)通过
    =
    包含
    进行查询,而不使用允许筛选
  • 如果#1的答案是否定的,那么在选项1和选项2中,允许过滤对性能的实际影响是什么。这是否意味着Cassandra必须加载所有数据,然后在启用“允许筛选”时在内存中进行筛选?在这种情况下,如果启用“允许筛选”,使用列表或冻结列表是否有任何好处
  • 与冻结列表相比,使用连接字符串(选项3)是否具有更好/更差的性能
  • 最后,是否有其他更好的方法使用原生Cassandra开源工具
    • 注意-我知道使用物化视图可能会获得相同的结果,但我正计划转向AWS托管的Cassandra解决方案(Keyspaces),该解决方案不支持MVs
    **还了解ApacheSpark和Ellasandra或同等产品,但对目前的额外开销/成本不感兴趣

    谢谢你的帮助