0

为了获得某种度量的分布,我们在 Cassandra 中使用计数器,即类似于 mysql 中的 group by。但是,如果我想要测量的唯一分布 - 我该怎么做?

假设我需要访问网页的用户的每日分布 - 计数器非常方便。键是天,值是计数器。但是对于同一个网页 - 如果我需要唯一的用户分布,我如何使用 Cassandra 来实现?

我可以通过各种方式实现它 - 写前读取、离线处理等。我还听说过位图/超级日志日志计数器等。我可以在 Cassandra 中/上使用的最简单的解决方案是什么,以获得独特的每日用户分布. 我每天有数百万个事件。

例子:

在 25/08/2013 上说 - 这是我的网页点击次数 - user1, user2, user1, user3

2013 年 8 月 26 日 - 用户 1,用户 2

2013 年 8 月 27 日 - 用户 2、用户 3、用户 4

2013 年 8 月 28 日 - 用户 1、用户 2、用户 1、用户 3

我的输出应该是

25/08/2013 - 3 个独立用户

26/08/2013 - 2 个独立用户

27/08/2013 - 3 个独立用户

28/08/2013 - 3 个独立用户

即,天数与独立用户数。

谢谢

4

3 回答 3

0

很大程度上取决于性能要求、一致性保证、系统数量等(几乎是一个标准)。也就是说,如果愿意让它具有概率性,我确实有一个建议,并且你不需要它立即不断更新。正如您所提到的,HyperLogLog 是一个不错的选择。

每台服务器都可以在内存中保留一个,以便在插入数据时更新并定期(即每分钟一次)推送到 cassandra ......或其他一些存储。由于 HyperLogLog 的性质,当您想要查询它时,您可以对服务器的超日志进行列切片并将它们组合起来。

ColumnFamilyHyperLogLogs: {
  someMetricsCardinalityRow20130828: {
    Server1: HyperLogLogBlob,
    Server2: HyperLogLogBlob,
    Server3: HyperLogLogBlob
  }
}

我会推荐对我们非常有用的 clearsprings 库:

https://github.com/clearspring/stream-lib/blob/master/src/main/java/com/clearspring/analytics/stream/cardinality/HyperLogLog.java

它具有转换为字节数组的功能,可用于序列化和反序列化,并具有可用于组合它们的方法。

或者,需要更多空间的事情是你可以为每件事设置一行,就像你说的唯一用户一样。

ColumnFamilyName {
  uniqueUserOn20130828: {
   "user1" : null,
   "user2" : null,
   ...
  }
}

然后,您只需调用该行的计数,它就会为您提供唯一用户的确切数量。这更直接,更容易实现,但会占用更多空间,但还有额外的好处,您可以查看当天实际用户在哪里。使用 CQL3 和集合可能很容易做到这一点

于 2013-08-29T02:08:53.047 回答
0

表定义

CREATE TABLE user_day(
  day TEXT,
  user_id TEXT,
  user_count COUNTER,
  PRIMARY KEY (day,user_id));

更新如下:

UPDATE user_day SET user_count = user_count + 1  WHERE day = '20130829' AND user_id = 'USER-1';
UPDATE user_day SET user_count = user_count + 1  WHERE day = '20130829' AND user_id = 'USER-1';
UPDATE user_day SET user_count = user_count + 1  WHERE day = '20130829' AND user_id = 'USER-2';
UPDATE user_day SET user_count = user_count + 1  WHERE day = '20130829' AND user_id = 'USER-2';
UPDATE user_day SET user_count = user_count + 1  WHERE day = '20130829' AND user_id = 'USER-1';
UPDATE user_day SET user_count = user_count + 1  WHERE day = '20130829' AND user_id = 'USER-3';

然后会给两者:

SELECT * FROM user_day;

 day      | user_id | user_count
----------+---------+------------
 20130829 |  USER-1 |          4
 20130829 |  USER-2 |          2
 20130829 |  USER-3 |          1

和 :

SELECT COUNT(*) FROM user_day WHERE day = '20130829';


 count
-------
     3

WRT 评论,您正在寻找的是 Cassandra 不支持的 GROUP BY 功能。您可以查看付费选项,例如AcunuDatastax Enterprise 产品。如果您正在寻找免费选项,那么像amplabs spark 和 Shark 之类的东西非常适合临时查询,尽管我没有亲自将它们与 Cassandra 一起使用,但我知道它已经完成了。

于 2013-08-29T10:09:20.063 回答
0

没有特定于 Cassandra,但如果此数据的建模如下所示

date       user_id

25Aug2013    1
25Aug2013    2
25Aug2013    1
25Aug2013    3

26Aug2013    1
26Aug2013    2

27Aug2013    2
27Aug2013    3
27Aug2013    4

28Aug2013    1
28Aug2013    2
28Aug2013    1
28Aug2013    3

您可以通过执行按天或按月或任何其他日期格式获取唯一性

select count(DISTINCT user_id), date from <table_name> where date_trunc(date, 'month') =8 order by user_id, format(date, 'DDMMYYY) DESC/ASC

日期格式是可选的。您应该能够在没有它的情况下跨表查询,然后添加适当的过滤器。

于 2013-08-29T07:33:41.187 回答