Cassandra table 定义/分区/建模
Cassandra table definition / partitioning / modeling
尝试为我们的场景定义正确的架构/table:
我们有数百个电子商务网站,每个网站都有独特的 siteId
.
每个站点都有自己的最终用户,每月最多 1000 万独立用户。每个用户都有唯一的 userId
.
每个最终用户都与站点交互:查看产品、将产品添加到购物车和购买产品(我们称之为用户事件)。我想存储过去 30 天(或 180 天,如果可能的话)的活动。
需要考虑的事项:
- 站点大小不同!我们有一些 "heavy" 个拥有 1000 万最终用户的网站,但我们也有 "light" 个拥有少数 hundreds/thousands 用户的网站。
- 事件没有唯一 ID。
- 用户一次可以有多个事件,例如,他们可以查看包含多个产品的页面(但为了简化我们可以没有这种限制)。
- 粗略估计:100 位客户 x 1000 万最终用户 x 100 次交互 = 100,000,000,000 行(每月)
- 实时写入(当事件到达服务器时)。读取次数少得多(事件的 1%)。
- 事件有更多的元数据,不同的事件 (view/purchase/..) 有不同的元数据。
- 使用 Keyspace 分隔站点,并管理每个站点的 table 与一个 table 中的所有客户。
这里的key怎么定义?
+--------+---------+------------+-----------+-----------+-----------+
| siteId | userId | timestamp | eventType | productId | other ... |
+--------+---------+------------+-----------+-----------+-----------+
| 1 | Value 2 | 1501234567 | view | abc | |
| 1 | cols | 1501234568 | purchase | abc | |
+--------+---------+------------+-----------+-----------+-----------+
我的查询是:获取特定用户的所有事件(及其元数据)。正如我上面假设的那样,大约有 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,因此您可以使用 userid
和 site_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>;
希望这能解决您的问题。
尝试为我们的场景定义正确的架构/table:
我们有数百个电子商务网站,每个网站都有独特的 siteId
.
每个站点都有自己的最终用户,每月最多 1000 万独立用户。每个用户都有唯一的 userId
.
每个最终用户都与站点交互:查看产品、将产品添加到购物车和购买产品(我们称之为用户事件)。我想存储过去 30 天(或 180 天,如果可能的话)的活动。
需要考虑的事项:
- 站点大小不同!我们有一些 "heavy" 个拥有 1000 万最终用户的网站,但我们也有 "light" 个拥有少数 hundreds/thousands 用户的网站。
- 事件没有唯一 ID。
- 用户一次可以有多个事件,例如,他们可以查看包含多个产品的页面(但为了简化我们可以没有这种限制)。
- 粗略估计:100 位客户 x 1000 万最终用户 x 100 次交互 = 100,000,000,000 行(每月)
- 实时写入(当事件到达服务器时)。读取次数少得多(事件的 1%)。
- 事件有更多的元数据,不同的事件 (view/purchase/..) 有不同的元数据。
- 使用 Keyspace 分隔站点,并管理每个站点的 table 与一个 table 中的所有客户。
这里的key怎么定义?
+--------+---------+------------+-----------+-----------+-----------+ | siteId | userId | timestamp | eventType | productId | other ... | +--------+---------+------------+-----------+-----------+-----------+ | 1 | Value 2 | 1501234567 | view | abc | | | 1 | cols | 1501234568 | purchase | abc | | +--------+---------+------------+-----------+-----------+-----------+
我的查询是:获取特定用户的所有事件(及其元数据)。正如我上面假设的那样,大约有 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,因此您可以使用 userid
和 site_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>;
希望这能解决您的问题。