Database 用户聊天的Cassandra表设计

Database 用户聊天的Cassandra表设计,database,database-design,cassandra,nosql,Database,Database Design,Cassandra,Nosql,我想在Cassandra中为用户聊天创建一个表,最后我完成了这项工作 CREATE TABLE sample.user_messages ( user_id INT, second_user_id INT, id TIMEUUID, author_id INT, message TEXT, PRIMARY KEY ((user_id), second_user_id, id) ) WITH CLUSTERING ORDER BY (second_u

我想在Cassandra中为用户聊天创建一个表,最后我完成了这项工作

CREATE TABLE sample.user_messages (
    user_id INT,
    second_user_id INT,
    id TIMEUUID,
    author_id INT,
    message TEXT,
    PRIMARY KEY ((user_id), second_user_id, id)
) WITH CLUSTERING ORDER BY (second_user_id ASC, id DESC);
我有两种类型的查询

  • 获取此表设计满足的两个用户之间的聊天
    。。。其中user_id=100,second_user_id=200

  • 获取此表设计不适合的特定用户的所有聊天信息,我不知道该怎么办,为此我应该使用两个查询,1-
    。。。其中用户id=100'
    2-
    其中second_user_id=100
    哪一个第二个查询不好,是否有任何方法可以只使用一个查询


  • 我建议对第二个用户id使用二级索引,如下所示:

    在sample.user消息(第二个用户id)上创建索引索引第二个用户id

    现在您的第一个查询将保持不变

    您的第二个查询将拆分为两个单独的关于用户id和第二个用户id的查询,如下所示

    1) select * from "user_messages" where user_id=100;
    2) select * from "user_messages" where second_user_id=100;
    

    这应该很有帮助。

    您的表允许您按用户id获取所有聊天记录,因此您只需在该表中插入两次数据,但在第二次插入时更改用户id

    为第一个用户放置消息:

    UPDATE user_messages SET .... second_user_id = 200 WHERE user_id = 100;
    
    并为第二个用户发送相同的消息:

    UPDATE user_messages SET .... second_user_id = 100 WHERE user_id = 200;
    
    现在,您可以为每个用户获取所有聊天记录:

    Select * from user_messages where user_id = 100;
    Select * from user_messages where user_id = 200;
    
    获取两个用户之间的聊天:

    Select * from user_messages where user_id = 100 and second_user_id = 200;
    
    反之亦然:

    Select * from user_messages where user_id = 200 and second_user_id = 100;
    
    这种方法会复制数据,但对于Cassandra来说,这是一种支付读取速度的常见方法

    [编辑]大分区问题


    如果您期望每个用户有太多的消息,您应该选择另一个分区键,而不是用户id。例如,您可以使用一个由用户id和日期组成的复合分区键,在这种情况下,每个分区只包含一天的消息,但您每天都有单独的分区。这种技术通常被称为“bucketing”,您可以使用反向ID为两个用户创建两条记录:

    记录1:user_id=1和second_user_id=2

    记录2:user_id=2和second_user_id=1

    显然,两条记录必须相同的
    id
    作者id
    消息

    所以你的第二个查询是有效的

    SELECT * FROM sample.user_messages WHERE user_id = 1
    
    此外,您的第一个查询可能在所有情况下都有效,因为无论您在查询中提供的ID顺序如何:

    SELECT * FROM sample.user_messages WHERE user_id = 1 AND second_user_id = 2
    SELECT * FROM sample.user_messages WHERE user_id = 1 AND second_user_id = 2
    

    两个查询将提供相同的结果。

    我不建议使用这种设计,因为当您具有高键基数时,C*二级索引无法正常工作,因为每个副本都保留自己的本地索引。如果您具有高键基数,那么很可能每个查询都需要访问每个副本集,这是非常昂贵的。参考:非常感谢,我搜索了一下,发现你的解决方案很好,如果我想存储数十亿的数据,它需要重复的空间和。。。这是唯一的解决方案吗?在Cassandra中,您应该只关心分区大小,因为单个分区不能拆分并放置在不同的节点上,但不同的分区将分布在集群上。因此,在您的情况下,针对不同用户的消息将分布在集群上,但是如果一个用户有太多的消息,那么可能会有太大的分区。我更新了关于大分区问题的答案。