在Cassandra中建立一对多关系的最佳方法是什么?

时间:2017-07-10 20:26:53

标签: cassandra one-to-many composite-key nosql

假设我想设计一个用户可以创建帖子的系统,其中每个帖子属于一个用户,但用户可能有多个帖子。还假设我想支持找到给定userID的所有帖子,除了简单地通过postId查找帖子。我还想存储特定于用户的帐户详细信息,例如帐户创建日期。

对此进行建模的一种方法如下:

CREATE TABLE user (
   userId int,
   name varchar,
   userDetail1,
   userDetail2,
   ...,
   PRIMARY KEY(userId)
);

CREATE TABLE post (
   postId int,
   postDetail1,
   postDetail2,
   ...,
   userId int,
   PRIMARY KEY(postId)
);

从我读过的内容来看,这应该不是最佳的,因为查询特定用户发布的帖子会降低内存效率。它是否正确?并且Cassandra不支持在userId上索引post表的原因是什么?

理想的解决方案如下所示?

CREATE TABLE user (
   userId int,
   name varchar,
   userDetail1,
   userDetail2,
   ...,
   PRIMARY KEY(userId)
);

CREATE TABLE post (
   postId int,
   postDetail1,
   postDetail2,
   ...,
   userId int,
   PRIMARY KEY(postId)
);

CREATE TABLE user_to_post (
   userId int,
   postId int,
   userDetail1,
   userDetail2,
   ...,
   postDetail1,
   postDetail2,
   ...,
   PRIMARY KEY(userId, postId)
);

使用复合键,查询特定用户的帖子效率更高。但是通过这种设计,有一个特定的帖子表是多余的吗?同样,在此设计中,我希望查找特定用户发布的帖子,并且还希望快速链接到给定帖子的特定用户。我已经做了很多阅读,但我很困惑如何在Cassandra中精确设计一对多的关系。

1 个答案:

答案 0 :(得分:3)

这完全取决于您尝试实现的所有要求。如果我理解正确,您希望能够:

  1. 按ID ID
  2. 获取特定用户
  3. 获取用户的帖子列表
  4. 我将从DataStax的优秀页面Basic Rules of Cassandra Data Modeling中获得大部分建议。你必须先了解这个问题没有明确的答案。它高度依赖于您尝试运行的查询,以及您准备做出的权衡。例如:您是否希望特定用户的帖子数量真正高(数千或数百万)?什么是最常见的查询(即模拟数据的那个)?

    • 第一个模型似乎打破了规则2:最小化分区读取次数。 posts表的分区键是帖子ID(我将假设是随机的,例如UUID),结果将是帖子分布在整个群集中。因此,假设您拥有特定用户的帖子列表(实际上需要非常低效的群集扫描),如果每个用户的帖子数量足够大,您的请求将必须命中群集中的每个服务器。这是最糟糕的情况,绝对不是你想要的。

    • 第二个模型本质上更好,因为每个请求都可以使用单个请求来实现。您正在交易存储以获取读取性能,这通常是一件非常好的事情。我可能只是建议看Materialized Views(Cassandra 3.0+),这对你来说维护这样一个表有很大的帮助 - 虽然完全按照你的建议使用MV很复杂,因为你只能提供一个表作为视图源(即帖子)。

    我还可以建议一个替代模型,它修复了第一个提案中的设计缺陷而没有数据重复(这也就是问题),这里的关键是将用户ID用作分区键的帖子,并将帖子ID作为聚类键。这允许特定用户的所有帖子存储在同一节点上,因此提供了从特定用户请求帖子的良好性能。

    CREATE TABLE user (
       userId int,
       name varchar,
       userDetail1,
       userDetail2,
       ...,
       PRIMARY KEY(userId)
    );
    
    CREATE TABLE post (
       userId int,
       postId int,
       postDetail1,
       postDetail2,
       PRIMARY KEY(userId, postId)
    );
    

    此解决方案的主要缺点是它略微复杂化了检索单个帖子的过程:除了帖子ID之外,您还必须知道用户ID。这可能不是问题,因为两者本质上是相关联的。

    再一次记住,除了非常简单的情况之外,在计算机科学中做任何事情的最佳方式都不太可能存在。这取决于您尝试最大化的指标集,您准备做出的权衡,更重要的是存储系统,您将要运行的工作量。