3

数年にわたるアクティビティ ログがあります。アプリケーションの各ユーザーの毎週のエンゲージメントを計算するように依頼されました。私はエンゲージメントを、特定の週に記録された 1 つ以上のアクティビティを実行するユーザーとして定義します。

これらのアクティビティをグループ化し、ユーザーごとに週ごとにカウントするにはどうすればよいですか? 私はさまざまな投稿をたくさん読みましたが、ruby​​ メソッドsql、または arel 構文のどれが最適かについて議論があるようです。私は 500 人を超えるユーザーを持っていないので、パフォーマンスは簡潔なものほど重要ではありません。

私はこれをうまく試しました:

user = User.first.activity_logs.group_by { |m| m.created_at.beginning_of_week } 
       # => {Mon, 11 Mar 2013 00:00:00 EDT -04:00=>
             [#<ActivityLog id: 12345, user_id: 429, ... ]}

次に、エラーなしで何かを返すことができる唯一の次のステップ:

user.map { |week| week.count } => [2, 2, 2, 2, 2, 2, 2, 2]

だから私はこれを複雑にしすぎているようです。アクティビティの数を週ごとに簡潔にカウントし、それを各ユーザーに対して行うにはどうすればよいですか?

マネージャー向けのヒート マップやその他のグラフを作成するために、最終的にスプレッドシート (たとえば、以下) に貼り付けることができるものが欲しいだけです。

| User          | Week            | Activity|
| ------------- | :-------------: | -------:|
| jho           | 2013-1          | 20      |
| bmo           | 2013-1          | 5       |
| jlo           | 2013-1          | 11      |
| gdo           | 2013-2          | 2       |
| gdo           | 2013-5          | 3       |
| jho           | 2013-6          | 5       |

編集

他の参考資料として:
Rails 3.1
Using PostgreSQL 9.1.4 これ
は ruby​​ on rails のスキーマ ファイルです。

create_table "activity_logs", :force => true do |t|
  t.integer  "user_id"
  t.string   "activity_type"
  t.datetime "created_at"
  t.datetime "updated_at"
end

| ------+| --------+| ----------------+| ----------------+ | ----------------+ | 
| id     | user_id  | activity_type    | created_at        | updated_at        | 
| ------+| --------+| ----------------+| ----------------+ | ----------------+ | 
| 28257  | 8        | User Signin      | 2013-02-14 1...   | 2013-02-14 1...   | 
| 25878  | 7        | Password Res...  | 2013-02-03 1...   | 2013-02-03 1...   | 
| 25879  | 7        | User Signin      | 2013-02-03 1...   | 2013-02-03 1...   | 
| 25877  | 8        | Password Res...  | 2013-02-03 1...   | 2013-02-03 1...   | 
| 19325  | 8        | Created report   | 2012-12-16 0...   | 2012-12-16 0...   | 
| 19324  | 9        | Added product    | 2012-12-16 0...   | 2012-12-16 0...   | 
| 18702  | 8        | Added event      | 2012-12-15 1...   | 2012-12-15 1...   | 
| 18701  | 1        | Birthday Email   | 2012-12-15 0...   | 2012-12-15 0...   | 
| ------+| --------+| ----------------+| ----------------+ | ----------------+ | 

解決

@Erwin Brandstetter のコマンドを変更すると、コマンド ラインで次のように目的の結果が得られました。

ActivityLogs.find_by_sql("
  SELECT user_id, to_char(created_at, 'YYYY-WW') AS week, count(*) AS activity
  FROM   activity_logs
  GROUP  BY 1, 2
  ORDER  BY 1, 2;")
4

2 に答える 2

2

@ideamotor からテスト テーブルを借りて単純化しました。活動の種類は関係なく、各活動を1次のように数えます。

CREATE TEMP TABLE log(usr text, day date);
INSERT INTO log VALUES 
  ('bob' , '2012-01-01')
 ,('bob' , '2012-01-02')
 ,('bob' , '2012-01-14')
 ,('susi', '2012-01-01')
 ,('susi', '2012-01-14');

クエリ (これ以上簡潔にはなりません):

SELECT usr, to_char(day, 'YYYY-WW') AS week, count(*) AS activity
FROM   log
GROUP  BY 1, 2
ORDER  BY 1, 2;

結果:

usr  | week     | activity
-----+----------+---------
bob  | 2012-01  | 2
bob  | 2012-02  | 1
susi | 2012-01  | 1
susi | 2012-02  | 1

to_char()これを非常に簡単にします。ここでマニュアルを引用します:

WW 年の週番号 (1 ~ 53) (最初の週は年の最初の日から始まります。)

別の方法として、次のことを考慮してください。

IW年の ISO 週番号 (01 から 53。新年の最初の木曜日は第 1 週です。)

于 2013-03-22T01:23:26.790 に答える
1

これは Postgresql にあります。ここでのコツは、year-weekofyear 値を生成する必要があることです。ここでは、日付から情報を取り出して連結しています。

ここでは、「2012-01-01」が 52 週目としてカウントされないようにしています。私は標準をオーバーライドしています。週の定義方法によっては、この関数を変更する必要がある場合があります。

create temp table daily_log(person character varying, activity numeric, 
    dayof date);
insert into daily_log values 
     ('bob'    ,1,'2012-01-01')
    ,('bob'    ,1,'2012-01-02')
    ,('bob'    ,0,'2012-01-14')
    ,('charlie',1,'2012-01-01')
    ,('charlie',1,'2012-01-14')

select person 
 ,extract('year' from dayof) || '-' || 
    case when extract('week' FROM dayof) >= 52 
         and extract('month' FROM dayof) = 1 
    then 1 
 else extract('week' FROM dayof) end as weekof
,sum(activity) as activity_cnt
from daily_log
group by weekof, person
order by person, weekof;

それはあなたを得るでしょう:

| person        | weekof          | activity_cnt|
| -------------:| :--------------:| -----------:|
| bob           | 2012-1          | 2           |
| bob           | 2012-2          | 0           |
| charlie       | 2012-1          | 1           |
| charlie       | 2012-2          | 1           |

なぜ 2012 年を使用したのかはわかりません。

週の抽出について postgresl マニュアルに記載されている内容は次のとおりです ( http://www.postgresql.org/docs/9.2/static/functions-datetime.html )。

「その日が含まれる年の週の番号。定義 (ISO 8601) により、年の最初の週にはその年の 1 月 4 日が含まれます。(ISO-8601 の週は月曜日に始まります。) 言い換えれば、年の最初の木曜日は、その年の第 1 週です (タイムスタンプ値のみ)。

このため、1 月上旬の日付が前年の第 52 週または第 53 週の一部になる可能性があります。たとえば、2005-01-01 は 2004 年の第 53 週の一部であり、2006-01-01 は 2005 年の第 52 週の一部です。

于 2013-03-22T00:53:59.903 に答える