2

尝试为我们的场景定义正确的模式/表:我们有数百个电子商务站点,每个站点都有唯一的siteId.

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

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

需要考虑的事项:

  • 网站大小不一样!我们有一些拥有 1000 万最终用户的“重度”网站,但我们也有拥有数百/数千用户的“轻量”网站。
  • 事件没有唯一的 ID。
  • 用户一次可以有多个事件,例如,他们可以查看包含多个产品的页面(但我们可以不受限制以简化)。
  • 粗略估计:100 个客户 x 10M 最终用户 x 100 次交互 = 100,000,000,000 行(每月)
  • 实时写入(当事件到达服务器时)。读取完成的次数要少得多(1% 的事件)。
  • 事件有更多的元数据,不同的事件(查看/购买/..)有不同的元数据。
  • 使用 Keyspace 在站点之间进行分隔,并管理每个站点的表与一张表中的所有客户。
  • 如何在这里定义密钥?

    +--------+---------+------------+-----------+-----------+-----------+
    | siteId | userId  | timestamp  | eventType | productId | other ... |
    +--------+---------+------------+-----------+-----------+-----------+
    |      1 | Value 2 | 1501234567 | view      | abc       |           |
    |      1 | cols    | 1501234568 | purchase  | abc       |           |
    +--------+---------+------------+-----------+-----------+-----------+
    

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

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

4

2 回答 2

2

如果要查询用户 ID,则用户 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));

这应该使查询像

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)标识一行。一行将停留在特定节点上。出于这个原因,最好让行的大小或多或少相同。具有数千或 10ks 列的行并不是真正的问题。如果某些行有数百万列,而其他行只有 10-20 列,则会出现问题。这将导致集群不平衡。此外,它还降低了行缓存的效率。在您的示例中,我建议避免将 site_id 作为分区键(行键)。

这对你有意义吗?也许这篇文章的优秀答案会给你更多的内幕:partition-key、c​​omposite -key 和 clustering-key 之间的区别。此外,仔细查看datastax 文档的这一部分会提供更多详细信息。

希望有帮助。

于 2018-03-02T21:25:27.197 回答
2

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

因此,您需要给定用户的所有事件。由于每个用户在站点上都有一个唯一的 ID,因此您可以使用useridsite_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>;

希望这可以解决您的问题。

于 2018-03-03T07:21:15.443 回答