围绕电子邮件系统的 Cassandra 数据建模

Posted

技术标签:

【中文标题】围绕电子邮件系统的 Cassandra 数据建模【英文标题】:Cassandra data-modelling around email-system 【发布时间】:2015-04-27 18:29:36 【问题描述】:

我需要数据建模帮助,因为我还没有找到解决相同问题的资源。

用户案例类似于电子邮件系统。我想存储用户收到的所有电子邮件的时间线,然后用三种不同的方式取回它们:

    曾经收到的所有电子邮件 用户已阅读的邮件 用户仍未阅读的邮件

我目前的模型如下:

CREATE TABLE TIMELINE (
    userID varchar,
    emailID varchar,
    timestamp bigint,
    read boolean,
    PRIMARY KEY (userID, timestamp)
) WITH CLUSTERING ORDER BY (timestamp desc);

CREATE INDEX ON TIMELINE (userID, read);

我需要支持的查询是:

SELECT * FROM TIMELINE where userID = 12;
SELECT * FROM TIMELINE where userID = 12 order by timestamp asc;
SELECT * FROM TIMELINE where userID = 12 and read = true;
SELECT * FROM TIMELINE where userID = 12 and read = false;
SELECT * FROM TIMELINE where userID = 12 and read = true order by timestamp asc;
SELECT * FROM TIMELINE where userID = 12 and read = false order by timestamp asc;

我的查询是:

    我是否应该继续阅读作为我的二级索引,因为它会经常更新并且可以创建墓碑 - 每个 http://docs.datastax.com/en/cql/3.1/cql/ddl/ddl_when_use_index_c.html 这是一个问题。

    我们可以对二级索引进行不等式检查吗,因为我发现二级索引上应该存在至少一个相等条件

    如果这不是正确的建模方式,请就如何支持上述查询提出建议。维护三个不同的表格让我担心插入的数量(对于已读/未读),因为用户数量 * 每天查看的电子邮件将是巨大的。

【问题讨论】:

【参考方案1】:

您的索引 (userID) 具有高基数 - 您可能希望将其作为您手动与应用程序同步的第二个(或第三个)CF 进行管理。

可能是这样的

CREATE TABLE READ_TIMELINE (
    userID varchar,
    emailID varchar,
    timestamp bigint,
    PRIMARY KEY (userID, timestamp)
) WITH CLUSTERING ORDER BY (timestamp desc);

CREATE TABLE UNREAD_TIMELINE (
    userID varchar,
    emailID varchar,
    timestamp bigint,
    PRIMARY KEY (userID, timestamp)
) WITH CLUSTERING ORDER BY (timestamp desc);

这使您能够满足以下查询:

SELECT * FROM READ_TIMELINE where userID = 12;
SELECT * FROM UNREAD_TIMELINE where userID = 12;
SELECT * FROM READ_TIMELINE where userID = 12 order by timestamp asc;
SELECT * FROM UNREAD_TIMELINE where userID = 12 order by timestamp asc;

也就是说,您使用 ORDER BY 的自然聚类顺序,并且您可以通过简单的批处理(一个 DELETE,一个 INSERT)将电子邮件从 UNREAD 移动到 READ

现在,当您将电子邮件标记为已读时,您最终可能会在 UNREAD 表中出现大量墓碑。将 GCGS 设置得较低并使用频繁的压缩可以在一定程度上有所帮助,但是如果您有成千上万的电子邮件飞入并标记为已读,您可能还希望分解这些分区以避免墓碑压倒性问题。

【讨论】:

好答案杰夫。我也在想同样的事情。 这里有一个非常现实的潜在墓碑问题,不容忽视,但我认为这可能是正确的方向。 @JeffJirsa 感谢您的回答和解释。我仍然有一个查询:渲染所有电子邮件时间线 - 我会在 cassandra 上触发两个查询,然后进行内存合并,对吗? 否 - 您将针对 TIMELINE 表执行一次查询,并且仅在需要 WHERE 子句中的读取状态时才使用 READ_TIMELINE 和 UNREAD_TIMELINE。 @JeffJirsa 好的。因此,我们为单个用户维护三个不同的时间线。谢谢。实施后如有更多问题会回复。

以上是关于围绕电子邮件系统的 Cassandra 数据建模的主要内容,如果未能解决你的问题,请参考以下文章

Cassandra中的数据建模简单表不起作用

Apache Cassandra:为小表建模

Cassandra表定义/分区/建模

Cassandra 数据建模分区键

cassandra 中的数据建模和查询

Cassandra 中的数据建模冲突