Cassandra table 定义/分区/建模

Cassandra table definition / partitioning / modeling

尝试为我们的场景定义正确的架构/table: 我们有数百个电子商务网站,每个网站都有独特的 siteId.

每个站点都有自己的最终用户,每月最多 1000 万独立用户。每个用户都有唯一的 userId.

每个最终用户都与站点交互:查看产品、将产品添加到购物车和购买产品(我们称之为用户事件)。我想存储过去 30 天(或 180 天,如果可能的话)的活动。

需要考虑的事项:

我的查询是:获取特定用户的所有事件(及其元数据)。正如我上面假设的那样,大约有 100 个事件。

Edit2:我猜不是很清楚,但是用户的唯一性是每个站点的,两个不同的用户如果在不同的站点上可能有相同的id

如果您想查询用户 ID,那么用户 ID 应该是复合主键的第一部分(这是分区键)。使用复合主键创建可以查询 return 排序结果的列。我会建议以下架构:

CREATE TABLE user_events (
       userid long,
       timestamp timestamp,
       event_type text,
       site_id long,
       product_id long,
PRIMARY KEY (userid, site_id, timestamp, product_id));

那应该像

这样的查询
SELECT * FROM user_events WHERE user_id = 123 and site_id = 456;

相当高效。通过将时间戳添加到 PK,您还可以轻松地限制您的查询以仅获取前(最新)1000 个(无论您需要什么)事件,而不会因为高活跃用户(或机器人)具有很长的历史而导致性能问题。

有一点要记住:我建议使用 user_id 或 user_id、site_id 的组合作为分区键(主键的第一部分) .这将防止您的行变得太大。

因此替代设计如下所示:

CREATE TABLE user_events (
       userid long,
       timestamp timestamp,
       event_type text,
       site_id long,
       product_id long,
PRIMARY KEY ( (userid, site_id), timestamp, product_id));

此方法的 "downside" 是您始终必须提供用户和 site-id。但我想这是你无论如何都必须做的事情,对吧?

指出一件事。分区键(也称为行 ID)标识一行。一行将保留在特定节点上。出于这个原因,让行的大小大致相同是个好主意。一行有几千或 10ks 的列并不是真正的问题。如果您有一些行有数百万列而其他行只有 10-20 列,您将会遇到问题。这将导致集群不平衡。此外,它还降低了行缓存的效率。在您的示例中,我建议避免将 site_id 作为分区键(行键)。

你觉得这有意义吗?也许对此 post 的出色回答会为您提供更多内幕:difference between partition-key, composite-key and clustering-key. Furthermore a closer look at this part of the datastax documentation 提供了更多详细信息。

希望对您有所帮助。

My query is: Get all events (and their metadata) of specific user. As I assumed above, around 100 events.

因此,您需要给定用户的所有事件。由于每个用户在站点上都有一个唯一的 ID,因此您可以使用 useridsite_id 作为主键并使用 timestamp 作为聚类键来形成 table。这是 table 结构:

    CREATE TABLE user_events_by_time (
         userid bigint,
         timestamp timestamp,
         event_type text,
         product_id bigint,
         site_id bigint,
         PRIMARY KEY ((site_id,userid), timestamp)
    ) WITH CLUSTERING ORDER BY (timestamp DESC) ;

现在您可以使用以下查询查询给定时间内用户的所有事件:

SELECT * from user_events_by_time WHERE site_id= <site_id> and userid = <user_id> and timestamp > <from_time> and timestamp < <to_time>;

希望这能解决您的问题。