尝试为我们的场景定义正确的架构/表:我们有几百个电子商务站点,每个站点都有独特的siteId
。
每个站点都有自己的最终用户,每月最多可达1000万个唯一身份用户。每个用户都有独特的userId
。
每个最终用户都与网站进行交互:查看产品,将产品添加到购物车并购买产品(我们称之为用户事件)。我想存储过去30天的活动(如果可能,则存储180天)。
需要考虑的事项:
+--------+---------+------------+-----------+-----------+-----------+
| siteId | userId | timestamp | eventType | productId | other ... |
+--------+---------+------------+-----------+-----------+-----------+
| 1 | Value 2 | 1501234567 | view | abc | |
| 1 | cols | 1501234568 | purchase | abc | |
+--------+---------+------------+-----------+-----------+-----------+
我的查询是:获取特定用户的所有事件(及其元数据)。正如我上面所假设的,大约有100个事件。
编辑2:我想这不清楚,但用户的唯一性是每个网站,如果他们在不同的网站上,两个不同的用户可能具有相同的ID
如果要查询userid,则userid应该是复合主键的第一部分(这是分区键)。使用复合主键创建可以查询以返回排序结果的列。我会建议以下架构:
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));
这种方法的“缺点”是您始终必须提供用户和站点ID。但我想这是你必须做的事情,对吧?
指出一件事。分区键(也称为行id)标识一行。一行将保留在特定节点上。出于这个原因,最好让行或多或少具有相同的大小。具有几千或几十列的行不是真正的问题。如果您有一些包含数百万列的行和其他只有10-20列的行,您将会遇到问题。这将导致集群失衡。此外,它使行缓存效率降低。在您的示例中,我建议避免将site_id作为分区键(行键)。
这对你有意义吗?也许这篇文章的优秀答案会给你一些更多的内容:difference between partition-key, composite-key and clustering-key。此外,仔细看看datastax documentation的这一部分提供了更多细节。
希望有所帮助。
我的查询是:获取特定用户的所有事件(及其元数据)。正如我上面所假设的,大约有100个事件。
所以,你想要给定用户的所有事件。由于每个用户在站点上都有唯一的ID,因此您可以使用userid
和site_id
作为主键并使用timestamp
作为聚类键来构建表。这是表结构:
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>;
希望这能解决你的问题。