在 Cassandra 中模拟一对多关系的最佳方式是什么?

What is the optimal way to model one-to-many relationships in Cassandra?

假设我想设计一个用户可以创建 post 的系统,其中每个 post 属于一个用户,但一个用户可能有多个 post。还假设除了通过 postId 简单地查找 post 之外,我还想支持查找所有给定用户 ID 的 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)
);

根据我的阅读,这应该不是最佳的,因为查询特定用户创建的 posts 会导致内存效率低下。这个对吗?这就是 Cassandra 不支持索引 userId 上的 post table 的原因吗?

那么理想的解决方案是否如下?

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)
);

使用复合键,查询特定用户的 post 会更有效率。但是对于这种设计,将 table 用于 post 是否特别多余?同样,在这个设计中,我想要查找由特定用户进行的 post,并且还想快速 link 到给定 post 的特定用户。我读了很多书,但对如何在 Cassandra 中准确设计一对多关系感到非常困惑。

这在很大程度上取决于您要实现的所有请求。如果我理解正确,你希望能够:

  1. 通过 ID 获取特定用户
  2. 获取用户post的列表

我的大部分建议都来自 DataStax 的优秀页面 Basic Rules of Cassandra Data Modeling。您必须首先了解该问题没有明确的答案。这在很大程度上取决于您尝试 运行 的查询,以及您准备做出的权衡。例如:您是否预计特定用户的 post 数量 真的 高(数千或数百万)?最频繁的查询是什么(即围绕数据建模的查询)?

  • 第一个模型似乎违反了规则2:最小化分区读取次数。 posts table 的分区键是 post ID(我假设它是随机的,例如 UUID),结果将是 posts分布在集群中。因此,假设您有特定用户的 post 列表(这实际上需要非常低效的集群扫描),如果 post每个用户的 s 足够大。这是最坏的情况,绝对不是你想要的。

  • 第二种模式本质上更好,因为每个请求都可以使用单个请求来实现。您正在用存储换取读取性能,这通常是一件非常好的事情。我可能只是建议查看 Materialized Views (Cassandra 3.0+),它确实有助于为您维护这样的 table – 尽管完全按照您的建议使用 MV 很复杂,因为您只能提供一个 table 作为查看源(即 posts)。

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

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)
);

此解决方案的主要缺点是它使检索单个 post 的过程稍微复杂化:除了 post ID 之外,您还必须传递已知的用户 ID。这可能不是问题,因为两者存在内在联系。

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

的工作负载