2014-06-30 24 views
5

Ho una tabella di sessioni giornaliere con colonne user_id e data. Mi piacerebbe tracciare grafici DAU/MAU (utenti attivi giornalieri/utenti mensili attivi) su base giornaliera. Per esempio:Interrogazione di DAU/MAU nel tempo (giornalmente)

Date   MAU  DAU  DAU/MAU 
2014-06-01 20,000 5,000 20% 
2014-06-02 21,000 4,000 19% 
2014-06-03 20,050 3,050 17% 
...   ...  ...  ... 

Calcolo attivi quotidiana è semplice da calcolare, ma il calcolo dei principi attivi mensili per esempio il numero di utenti che hanno effettuato l'accesso alla data-30 giorni sta causando problemi. Come si ottiene questo risultato senza un join di sinistra per ogni giorno?

Modifica: sto utilizzando Postgres.

+0

Che database stai usando, MySQL o Postgres? –

+0

È in Postgres. –

risposta

6

Supponendo di avere valori per ciascun d ay, è possibile ottenere i conteggi totali con una sottoquery e range between:

with dau as (
     select date, count(userid) as dau 
     from dailysessions ds 
     group by date 
    ) 
select date, dau, 
     sum(dau) over (order by date rows between -29 preceding and current row) as mau 
from dau; 

Purtroppo, penso che si desidera che gli utenti distinti piuttosto che solo i conteggi degli utenti. Ciò rende il problema molto più difficile, soprattutto perché Postgres non supporta count(distinct) come funzione finestra.

Penso che devi fare una sorta di auto join per questo. Ecco un metodo:

with dau as (
     select date, count(distinct userid) as dau 
     from dailysessions ds 
     group by date 
    ) 
select date, dau, 
     (select count(distinct user_id) 
     from dailysessions ds 
     where ds.date bewteen date - 29 * 'interval 1 day' and date 
     ) as mau 
from dau; 
1

Lei non ci ha mostrato la sua definizione tabella completa, ma forse qualcosa di simile:

select date, 
     count(*) over (partition by date_trunc('day', date) order by date) as dau, 
     count(*) over (partition by date_trunc('month', date) order by date) as mau 
from sessions 
order by date; 

per ottenere la percentuale senza ripetere le funzioni finestra, proprio avvolgere questo in una tabella derivata:

select date, 
     dau, 
     mau, 
     dau::numeric/(case when mau = 0 then null else mau end) as pct 
from (
    select date, 
      count(*) over (partition by date_trunc('day', date) order by date) as dau, 
      count(*) over (partition by date_trunc('month', date) order by date) as mau 
    from sessions 
) t 
order by date; 

Ecco un esempio di output:

 
postgres=> select * from sessions; 
session_date | user_id 
--------------+--------- 
2014-05-01 |  1 
2014-05-01 |  2 
2014-05-01 |  3 
2014-05-02 |  1 
2014-05-02 |  2 
2014-05-02 |  3 
2014-05-02 |  4 
2014-05-02 |  5 
2014-06-01 |  1 
2014-06-01 |  2 
2014-06-01 |  3 
2014-06-02 |  1 
2014-06-02 |  2 
2014-06-02 |  3 
2014-06-02 |  4 
2014-06-03 |  1 
2014-06-03 |  2 
2014-06-03 |  3 
2014-06-03 |  4 
2014-06-03 |  5 
(20 rows) 

postgres=> select session_date, 
postgres->  dau, 
postgres->  mau, 
postgres->  round(dau::numeric/(case when mau = 0 then null else mau end),2) as pct 
postgres-> from (
postgres(>  select session_date, 
postgres(>   count(*) over (partition by date_trunc('day', session_date) order by session_date) as dau, 
postgres(>   count(*) over (partition by date_trunc('month', session_date) order by session_date) as mau 
postgres(>  from sessions 
postgres(>) t 
postgres-> order by session_date; 
session_date | dau | mau | pct 
--------------+-----+-----+------ 
2014-05-01 | 3 | 3 | 1.00 
2014-05-01 | 3 | 3 | 1.00 
2014-05-01 | 3 | 3 | 1.00 
2014-05-02 | 5 | 8 | 0.63 
2014-05-02 | 5 | 8 | 0.63 
2014-05-02 | 5 | 8 | 0.63 
2014-05-02 | 5 | 8 | 0.63 
2014-05-02 | 5 | 8 | 0.63 
2014-06-01 | 3 | 3 | 1.00 
2014-06-01 | 3 | 3 | 1.00 
2014-06-01 | 3 | 3 | 1.00 
2014-06-02 | 4 | 7 | 0.57 
2014-06-02 | 4 | 7 | 0.57 
2014-06-02 | 4 | 7 | 0.57 
2014-06-02 | 4 | 7 | 0.57 
2014-06-03 | 5 | 12 | 0.42 
2014-06-03 | 5 | 12 | 0.42 
2014-06-03 | 5 | 12 | 0.42 
2014-06-03 | 5 | 12 | 0.42 
2014-06-03 | 5 | 12 | 0.42 
(20 rows) 

postgres=> 
+1

Sembra fantastico - domanda: è il mese del calendario MAU o il mese precedente a ogni giorno? L'ideale è il mese precedente a quel giorno. –

+0

Ho eseguito questa query e non funziona. La MAU aumenta da 0 all'inizio del mese al totale cumulativo di utenti alla fine del mese. Inoltre, il wrapper ha bisogno di un gruppo per data, dau, mau. –

+0

@DavidBailey: quindi è necessario fornire ulteriori dettagli, in particolare la struttura della tabella e un po 'più di dati di esempio. E no, il wrapper non ha bisogno di un gruppo dato che sto usando una funzione di finestra che genera un conteggio cumulativo. Sfortunatamente SQL Fiddle non funziona al momento, perché allora avrei fornito un esempio "live". Ho aggiunto una trascrizione da una sessione di psql per mostrarti la mia tabella di esempio. –

2

Questo si usa conteggio distinto per ottenere il rotolamento 30 giorni DAU/MAU:

(coinvolgimento degli utenti calcolo di reddit in BigQuery - ma l'SQL è abbastanza standard da utilizzare su altri basi di dati)

SELECT day, dau, mau, INTEGER(100*dau/mau) daumau 
FROM (
    SELECT day, EXACT_COUNT_DISTINCT(author) dau, FIRST(mau) mau 
    FROM (
    SELECT DATE(SEC_TO_TIMESTAMP(created_utc)) day, author 
    FROM [fh-bigquery:reddit_comments.2015_09] 
    WHERE subreddit='AskReddit') a 
    JOIN (
    SELECT stopday, EXACT_COUNT_DISTINCT(author) mau 
    FROM (SELECT created_utc, subreddit, author FROM [fh-bigquery:reddit_comments.2015_09], [fh-bigquery:reddit_comments.2015_08]) a 
    CROSS JOIN (
     SELECT DATE(SEC_TO_TIMESTAMP(created_utc)) stopday 
     FROM [fh-bigquery:reddit_comments.2015_09] 
     GROUP BY 1 
    ) b 
    WHERE subreddit='AskReddit' 
    AND SEC_TO_TIMESTAMP(created_utc) BETWEEN DATE_ADD(stopday, -30, 'day') AND TIMESTAMP(stopday) 
    GROUP BY 1 
) b 
    ON a.day=b.stopday 
    GROUP BY 1 
) 
ORDER BY 1 

sono andato ulteriormente a How to calculate DAU/MAU with BigQuery (engagement)

1

ho scritto su questo su my blog.

La DAU è facile, come hai notato. È possibile risolvere il MAU creando prima una vista con valori booleani per quando un utente attiva e disattiva, in questo modo:

CREATE OR REPLACE VIEW "vw_login" AS 
SELECT * 
    , LEAST (LEAD("date") OVER w, "date" + 30) AS "activeExpiry" 
    , CASE WHEN LAG("date") OVER w IS NULL THEN true ELSE false AS "activated" 
    , CASE 
WHEN LEAD("date") OVER w IS NULL THEN true 
WHEN LEAD("date") OVER w - "date" > 30 THEN true 
ELSE false 
END AS "churned" 
    , CASE 
WHEN LAG("date") OVER w IS NULL THEN false 
WHEN "date" - LAG("date") OVER w <= 30 THEN false 
WHEN row_number() OVER w > 1 THEN true 
ELSE false 
END AS "resurrected" 
    FROM "login" 
    WINDOW w AS (PARTITION BY "user_id" ORDER BY "date") 

Questo crea valori booleani per utente al giorno quando queste diventano attive, quando si agitano e quando si riattivano.

poi fare un aggregato quotidiana dello stesso:

CREATE OR REPLACE VIEW "vw_activity" AS 
SELECT 
    SUM("activated"::int) "activated" 
    , SUM("churned"::int) "churned" 
    , SUM("resurrected"::int) "resurrected" 
    , "date" 
    FROM "vw_login" 
    GROUP BY "date" 
    ; 

E infine calcolare i totali in esecuzione di MAUs attiva calcolando le somme cumulative sopra le colonne. È necessario unirsi a vw_activity due volte, poiché il secondo viene aggiunto al giorno in cui l'utente diventa inattivo (vale a dire 30 giorni dall'ultimo accesso).

Ho incluso una serie di date per garantire che tutti i giorni siano presenti nel set di dati.Ne puoi fare anche a meno, ma potresti saltare alcuni giorni nel tuo set di dati.

SELECT 
d."date" 
, SUM(COALESCE(a.activated::int,0) 
    - COALESCE(a2.churned::int,0) 
    + COALESCE(a.resurrected::int,0)) OVER w 
, d."date", a."activated", a2."churned", a."resurrected" FROM 
generate_series('2010-01-01'::date, CURRENT_DATE, '1 day'::interval) d 
LEFT OUTER JOIN vw_activity a ON d."date" = a."date" 
LEFT OUTER JOIN vw_activity a2 ON d."date" = (a2."date" + INTERVAL '30 days')::date 
WINDOW w AS (ORDER BY d."date") ORDER BY d."date"; 

Ovviamente si può fare questo in una singola query, ma questo aiuta a capire meglio la struttura.

Problemi correlati