我给出的用例非常简单:为给定用户存储事件,并允许在以后的给定时间范围内为每个用户计算这些事件。
可能事件的数量相当小(<1k),用户数量(<10k)也是如此。插入件的数量约为1k / sec。查询是以用户为中心的,因此基本上在给定时间范围内为给定用户选择所有或特定事件。
关键栏目是:
目前我的模型看起来像这个列将被用作:
(username, (timestamp, event, uuid))
因此,用户名将是分区键,大多数查询只能通过查询一个节点来完成。一个非常常见的查询可能如下:
select * from user_events where username=? and timestamp>? and timestamp<?
我进一步考虑使用计数器列而不是添加单独的uuid列,以防同一用户的同一事件在同一毫秒内发生。
因此,表格也会保持较小。
如果有人可以分享他/她对这个模型的想法,我将不胜感激。
更新
我创建了以下主表来存储用户事件
CREATE TABLE IF NOT EXISTS events.events_by_user(
user text,
added_week int,
added_timestamp timestamp,
event text,
uuid uuid,
PRIMARY KEY((user, added_week), added_timestamp, event))
WITH CLUSTERING ORDER BY(added_timestamp DESC)
这很好用,我开始通过这样的查询查询表:
SELECT event,added_timestamp FROM events_by_user WHERE user=? AND added_week=? AND added_timestamp>=? AND added_timestamp<?;
之后我创建了第二个查询以过滤掉特定事件:
SELECT event,added_timestamp FROM events_by_user WHERE user=? AND added_week=? AND added_timestamp>=? AND added_timestamp<? AND event IN ?;
这个虽然不起作用,因为我不允许在对时间戳执行gte和lt查询之后添加一个in子句,并带有以下消息:
无法限制聚类列“事件”(在列之前 “added_timestamp”受非EQ关系的限制)
答案 0 :(得分:2)
您有两个相互矛盾的要求:您希望执行username
中心查询,但您不想要宽行...此处没有太多的操作空间......
我先解决宽行问题。你真的不想要宽行,他们只会杀了你(r节点)。所以,你需要找到与username
结合的东西。从我看到的情况来看,由于您的大多数查询都基于username
和timestamp
,因此我会选择一个良好的时间粒度来控制行的宽度。
你说
可能事件的数量相当小(<1k),用户数量(<10k)也是如此。插入物的数量约为~1k / sec
但是,您没有指定事件数量每个用户,并且您没有指定插入频率是否适用于所有用户 (我假设他们从现在开始)。
基于此,您希望每天有86M个事件,这意味着每个用户平均有8600个事件。在我看来,这是一个不错的粒度级别,所以我会在yyyy-mm-dd
格式中添加一个时间戳作为分区键:
CREATE TABLE myevents (
username text,
day timestamp,
timestamp timestamp,
event int
uuid uuid,
...
PRIMARY KEY ((username, day), timestamp, event, uuid)
);
这使您可以在特定日期查询属于特定用户的所有事件的完美情况。如果您需要跨多天查询,则需要执行多个查询(每天一个),然后通过将第一天的结果与第二天的结果相关联,在应用程序中重建结果,然后附加结果第三天......依此类推。我说追加是因为结果按群集密钥timestamp
排序。
您可以通过更改day
值来选择最适合您需求的粒度级别。如果您希望小时粒度将格式更改为yyyy-mm-dd HH:00
,则可以使用较小的行,但是您需要执行24次查询才能获取一天的数据。或者你可以选择两天的步骤,现在你的行数是你的两倍,但你执行了一半的查询。
现在一切都取决于您的需求和群集。鉴于高C *可伸缩性功能,我会使用更多查询和更小的行,即使这意味着在应用程序级别执行更多编码。它可以让你更好地扩展。