获取每天活动用户的列表

chy5wohz  于 2021-07-24  发布在  Java
关注(0)|答案(3)|浏览(511)

我有一个数据集,它有一个每隔15分钟连接到服务器的用户列表,例如。

  1. May 7, 2020, 8:09 AM user1
  2. May 7, 2020, 8:09 AM user2
  3. ...
  4. May 7, 2020, 8:24 AM user1
  5. May 7, 2020, 8:24 AM user3
  6. ...

我希望每天都有大量的活跃用户,例如。

  1. May 7, 2020 71
  2. May 8, 2020 83

现在,棘手的部分。如果活动用户在过去7天中80%或更多时间处于连接状态,则定义该用户。这意味着,如果一周中有672个15分钟的间隔(1440/15 x 7),那么用户必须显示538次(672 x 0.8)。
到目前为止,我的代码是:

  1. SELECT
  2. DATE_TRUNC('week', ts) AS ts_week
  3. ,COUNT(DISTINCT user)
  4. FROM activeusers
  5. GROUP BY 1

它只提供每周连接的唯一用户列表。

  1. July 13, 2020, 12:00 AM 435
  2. July 20, 2020, 12:00 AM 267

但是我想实现活动的用户定义,并得到每天的结果,而不仅仅是星期一。

kjthegm6

kjthegm61#

我为设备监控报告做了类似的工作。我从来没有想出一个解决方案,不涉及建立一个日历和交叉连接到一个独特的设备列表( user 价值观)。
这个故意冗长的查询构建交叉连接,获取每个连接的活动计数 user 以及 ddate ,执行运行 sum() 超过七天,然后统计给定 ddate 在那之后的七天里,有538个或更多的活动 ddate .

  1. with drange as (
  2. select min(ts) as start_ts, max(ts) as end_ts
  3. from activeusers
  4. ), alldates as (
  5. select (start_ts + make_interval(days := x))::date as ddate
  6. from drange
  7. cross join generate_series(0, date_part('day', end_ts - start_ts)::int) as gs(x)
  8. ), user_dates as (
  9. select ddate, "user"
  10. from alldates
  11. cross join (select distinct "user" from activeusers) u
  12. ), user_date_counts as (
  13. select u.ddate, u."user",
  14. sum(case when a.user is null then 0 else 1 end) as actives
  15. from user_dates u
  16. left join activeusers a
  17. on a."user" = u."user"
  18. and a.ts::date = u.ddate
  19. group by u.ddate, u."user"
  20. ), running_window as (
  21. select ddate, "user",
  22. sum(actives) over (partition by user
  23. order by ddate
  24. rows between 6 preceding
  25. and current row) seven_days
  26. from user_date_counts
  27. ), flag_active as (
  28. select ddate, "user",
  29. seven_days >= 538 as is_active
  30. from running_window
  31. )
  32. select ddate, count(*) as active_users
  33. from flag_active
  34. where is_active
  35. group by ddate
  36. ;
展开查看全部
s5a0g9ez

s5a0g9ez2#

因为您需要每天的活动用户,但要按周确定,所以我认为您可以使用交叉应用程序来复制每天的计数。查询的from部分将给出天数和用户,交叉应用将限制为活动用户。你可以在最后指定你想要的用户或日期。

  1. SELECT users.UserName, users.LogDate
  2. FROM (
  3. SELECT UserName, CAST(ts AS DATE) AS LogDate
  4. FROM activeusers
  5. GROUP BY CAST(ts AS DATE)
  6. ) AS users
  7. CROSS APPLY (
  8. SELECT UserName, COUNT(1)
  9. FROM activeusers AS a
  10. WHERE a.UserName = users.UserName AND CAST(ts AS DATE) BETWEEN DATEADD(WEEK, -1, LogDate) AND LogDate
  11. GROUP BY UserName
  12. HAVING COUNT(1) >= 538
  13. ) AS activeUsers
  14. WHERE users.LogDate > '2020-01-01' AND users.UserName = 'user1'

这是sql server,您可能需要对postgresql进行修订。交叉应用可以转换为左连接横向(…)为真。

展开查看全部
mqxuamgl

mqxuamgl3#

由此产生的特殊困难是,如果用户在前6天内连接充分,他们可能有资格在没有任何连接的情况下工作。
这使得使用窗口函数变得更加困难。聚集在一个 LATERAL 子查询是显而易见的选择:

  1. WITH daily AS ( -- granulate daily
  2. SELECT ts::date AS the_day
  3. , "user"
  4. , count(*)::int AS daily_cons
  5. FROM activeusers
  6. GROUP BY 1, 2
  7. )
  8. SELECT d.the_day, count("user") AS active_users
  9. FROM ( -- time frame
  10. SELECT generate_series (timestamp '2020-07-01'
  11. , LOCALTIMESTAMP
  12. , interval '1 day')::date
  13. ) d(the_day)
  14. LEFT JOIN LATERAL (
  15. SELECT "user"
  16. FROM daily d
  17. WHERE d.the_day >= d.the_day - 6
  18. AND d.the_day <= d.the_day
  19. GROUP BY "user"
  20. HAVING sum(daily_cons) >= 538 --
  21. ) sum7 ON true
  22. ORDER BY d.the_day;

① cte daily 是可选的,但是从每日聚合开始应该对性能有很大帮助。
② 你得确定一下时间范围。我选择了当年。替换为您的选择。要使用表中的总范围,请改用:

  1. SELECT generate_series (min(the_day)::timestamp
  2. , max(the_day)::timestamp
  3. , interval '1 day')::date AS the_day
  4. FROM daily

请考虑以下基本问题:
在postgresql中生成两个日期之间的时间序列
这也克服了上述“特殊困难”。
③ 天气状况 HAVING 子句将消除过去7天(包括“今天”)中连接不足的所有行。
相关:
按月累计值之和,填写缺失月份
在rails+postgres中按任意时间间隔统计记录的最佳方法
每周记录总数
旁白:
您不会真正使用保留字“user”作为标识符。

展开查看全部

相关问题