如何在cassandra中模拟用户事件日志?
How to model user event log in cassandra?
我给定的用例非常简单:为给定用户存储事件,并允许稍后在给定时间范围内为每个用户计算这些事件。
可能事件的数量相当少 (<1k),用户数量也很少 (<10k)。插入次数约为 ~1k/sec。查询以用户为中心,因此基本上是在给定时间范围内为给定用户选择所有或特定事件。
关键列是:
- 用户名
- 时间戳
- 事件
目前我的模型看起来像这样使用此列:
(username, (timestamp, event, uuid))
因此,用户名将是分区键,大多数查询只需查询一个节点即可完成。一个非常常见的查询可能如下所示:
select * from user_events where username=? and timestamp>? and timestamp<?
我进一步考虑使用计数器列而不是添加单独的 uuid 列,以防同一用户的同一事件在同一毫秒内发生。
因此,table 也会保持较小。
如果有人可以分享 his/her 对此模型的想法,我将不胜感激。
更新
我创建了以下 main table 来存储用户事件
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)
这工作得很好,我开始通过这样的查询来查询 table:
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 查询后添加子句:
Clustering column "event" cannot be restricted (preceding column
"added_timestamp" is restricted by a non-EQ relation)
您有两个相互矛盾的要求:您想要执行 username
中心查询,但您不想要宽行...这里没有太多操作 space...
我会先解决宽行问题。你真的不想要宽行,他们只会杀了你(r 节点)。所以,你需要找到一些东西来配合 username
。据我所知,由于您的大部分查询都基于 username
和 timestamp
,我会 select 一个很好的时间粒度来控制行的宽度。
你说
The number of possible events is rather small (<1k) and so is the number of users (<10k). The number of inserts is approximately ~1k/sec
但是您没有指定事件数是否是每个用户,并且您没有指定插入频率是否适用于所有用户(我假设他们从现在开始)。
基于此,您预计每天有 8600 万个事件,这意味着每个用户平均有 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
值来 select 最适合您需要的粒度级别。如果您希望小时粒度将格式更改为 yyyy-mm-dd HH:00
,这将允许您拥有更小的行,但您需要执行 24 次查询来获取一天的数据。或者您可以选择采用两天的步骤,现在您的行数增加了一倍,但您将执行一半的查询。
现在一切都取决于您的需求和您的集群。考虑到 C* 的高可伸缩性特性,我会选择更多的查询和更小的行,即使这意味着在应用程序级别执行更多的编码。它会让你更好地扩展。
我给定的用例非常简单:为给定用户存储事件,并允许稍后在给定时间范围内为每个用户计算这些事件。
可能事件的数量相当少 (<1k),用户数量也很少 (<10k)。插入次数约为 ~1k/sec。查询以用户为中心,因此基本上是在给定时间范围内为给定用户选择所有或特定事件。
关键列是:
- 用户名
- 时间戳
- 事件
目前我的模型看起来像这样使用此列:
(username, (timestamp, event, uuid))
因此,用户名将是分区键,大多数查询只需查询一个节点即可完成。一个非常常见的查询可能如下所示:
select * from user_events where username=? and timestamp>? and timestamp<?
我进一步考虑使用计数器列而不是添加单独的 uuid 列,以防同一用户的同一事件在同一毫秒内发生。
因此,table 也会保持较小。
如果有人可以分享 his/her 对此模型的想法,我将不胜感激。
更新
我创建了以下 main table 来存储用户事件
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)
这工作得很好,我开始通过这样的查询来查询 table:
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 查询后添加子句:
Clustering column "event" cannot be restricted (preceding column "added_timestamp" is restricted by a non-EQ relation)
您有两个相互矛盾的要求:您想要执行 username
中心查询,但您不想要宽行...这里没有太多操作 space...
我会先解决宽行问题。你真的不想要宽行,他们只会杀了你(r 节点)。所以,你需要找到一些东西来配合 username
。据我所知,由于您的大部分查询都基于 username
和 timestamp
,我会 select 一个很好的时间粒度来控制行的宽度。
你说
The number of possible events is rather small (<1k) and so is the number of users (<10k). The number of inserts is approximately ~1k/sec
但是您没有指定事件数是否是每个用户,并且您没有指定插入频率是否适用于所有用户(我假设他们从现在开始)。
基于此,您预计每天有 8600 万个事件,这意味着每个用户平均有 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
值来 select 最适合您需要的粒度级别。如果您希望小时粒度将格式更改为 yyyy-mm-dd HH:00
,这将允许您拥有更小的行,但您需要执行 24 次查询来获取一天的数据。或者您可以选择采用两天的步骤,现在您的行数增加了一倍,但您将执行一半的查询。
现在一切都取决于您的需求和您的集群。考虑到 C* 的高可伸缩性特性,我会选择更多的查询和更小的行,即使这意味着在应用程序级别执行更多的编码。它会让你更好地扩展。