グループ見学活動

グループ訪問アクティビティ

私はグループのアクティビティを調査するクエリの作成に取り組んでいます。

  • 一意の訪問者数
  • 総訪問数
  • モバイル対デスクトップ訪問数
  • グループメンバーの訪問割合
  • 訪問あたりの平均読了時間
  • 訪問あたりの平均投稿読了数
  • メンバーあたりの平均読了時間
  • メンバーあたりの平均投稿読了数

質問

  1. user_visits テーブルは、visited_at が DATETIME または TIMESTAMP ではなく DATE であるため、1 日に複数回、複数のデバイスタイプから訪問した場合でも、1 日の 1 人の一意の user_id につき 1 件のレコードのみを記録しているのではないかと疑っています。DAY 単位でクエリを実行すると、一意のメンバーの総数が訪問数の総数と一致しています。私の仮定が正しいか確認していただけませんか? もしそうであれば、次の質問は、ユーザーが 1 日にラップトップ、デスクトップ、そして順不同で携帯電話から 3 回訪問した場合、mobile の値はどうなるのかということです。
  2. 奇妙なことに、AVG(uv.posts_read) の値が SUM(uv.posts_read)/COUNT(DISTINCT(uv.user_id)) と一致しないことも確認しました。私のクエリがどこで誤っているのか、あるいは user_visits テーブルやフィールドの解釈を間違えているのか、興味があります。それらの 2 つの計算の違いについてご意見をお聞かせください。

クエリ:

サマリー
-- [params]
-- null string :group_name = YourGroupName
-- date :start_date = 2019/09/01
-- date :end_date = 2019/10/01
-- null string :frame = day

with mobile as (
SELECT uv.id,
    count(DISTINCT(uv.user_id)) as UniqueMobile,
    date_part(:frame, uv.visited_at::date) as Day,
    g.name as GroupName
from user_visits uv
join users u on uv.user_id = u.id
join group_users gu on gu.user_id = u.id
join groups g on g.id = gu.group_id
where mobile = true
    and uv.visited_at >= :start_date::date
    and uv.visited_at < :end_date::date
    and g.name = :group_name
GROUP BY GroupName, Day, uv.id
    ), 
    
desktop as (
SELECT uv.id,
    count(DISTINCT(uv.user_id)) as UniqueDesktop,
    date_part(:frame, uv.visited_at::date) as Day,
    g.name as GroupName
from user_visits uv
join users u on uv.user_id = u.id
join group_users gu on gu.user_id = u.id
join groups g on g.id = gu.group_id
where mobile = false
    and uv.visited_at >= :start_date::date
    and uv.visited_at < :end_date::date
    and g.name = :group_name
GROUP BY GroupName, Day, uv.id
    )

   SELECT 
    date_part(:frame, uv.visited_at::date) as VisitDate,
    count(DISTINCT(uv.user_id)) as UniqueMembers, 
    count(uv.id) as AllVisits,
    count(m.UniqueMobile) as MobileVisits,
    count(d.UniqueDesktop) as DesktopVisits,
    round((count(DISTINCT(uv.user_id)) * 100.0) / groups.user_count, 2) as Percent,
    round(avg(uv.posts_read),2) as "Posts Read (avg Visit)",
    (interval '1' minute * ROUND((cast(AVG(uv.time_read) as decimal)/60), 2)) as "Read Time (avg Visit)",
    (SUM(uv.posts_read)/count(DISTINCT(uv.user_id))) as "Posts Read (avg Member)",
    date_trunc('second',(interval '1' minute * (ROUND((cast(SUM(uv.time_read) as decimal)/60), 2)/(count(DISTINCT(uv.user_id)))))) as "Read Time (avg Member)"

FROM users
join group_users on group_users.user_id = users.id
join groups on group_users.group_id = groups.id
LEFT join user_visits uv on uv.user_id = users.id
LEFT JOIN mobile m ON m.id = uv.id
LEFT JOIN desktop d ON d.id = uv.id
    where groups.name = :group_name
    AND uv.visited_at::date >= :start_date
    and uv.visited_at::date < :end_date
    
group by VisitDate, groups.user_count 

order by VisitDate asc
「いいね!」 2

はい、その通りです。

ユーザーが新しいデバイスから投稿を読み込んだ場合、mobile カラムは最後にアクセスしたデバイスに基づいて更新されます。例えば、ユーザーが 1 日の始めにデスクトップブラウザで 2 件の投稿を読み、そのユーザー ID に対して posts_read が 2、mobilefalse に設定された user_visits エントリが作成されるとします。その後、ユーザーがモバイルデバイスでログインしてさらに 3 件の投稿を読んだ場合、その日の user_visits エントリは posts_read: 5mobile: true に更新されます。これはデータエクスプローラーでテストできますが、ユーザーがまだ読んでいない投稿を読んでいることを確認する必要があります。

「いいね!」 3

ありがとうございます。最後の質問について何かご存知ですか?私は良いデータの方が悪いデータより好きです。ご説明いただいた通り、user_visits において uv.visited_at ごとに uv.user_id に対して uv.id が一つしかないという前提のもと、似ているのに同じではないという事実は、特に眉をひそめさせるものです。

あまり参考にならないかもしれませんが、私のデータからのサンプルを以下に示します:

訪問日 投稿読了数(平均訪問) 読了数(平均メンバー)
13 1.18 1
14 4.15 4
15 7.18 7
16 6.15 6

整数で除算を行うと、PostgreSQL は整数を返します。SUM(posts_read)::float / COUNT(DISTINCT(user_id)) のように試して、まだ違いが見られるか確認してみてください。結果を小数点以下 2 位に丸める必要があるかもしれません。

「いいね!」 2