2009-09-10 6 views
5

Utilisation de la décharge de données publiques débordement de pile, j'ai créé trois tables simples:Approximation des vues de page par balise (ou groupe de balises) par mois avec des données limitées?

  • Questions (question_id, view_count, creation_date)
  • Tags (TAG_NAME)
  • QuestionTags (question_id, TAG_NAME)

La table Questions contient des centaines de milliers de lignes avec Creation_Date depuis l'année dernière jusqu'à aujourd'hui. Donnant sur les données, il y a deux tendances notables:

  • Nombre de questions Augmentation par période - par exemple, il y avait plus de questions posées ce mois-ci il y a trois mois
  • Questions Vues ont une longue queue - en regardant les vues basées sur les semaines ouvertes, nous pouvons voir que la plupart des vues d'une question se produisent dans la première semaine; un montant moindre dans la deuxième et la troisième; et une longue queue constante dans les semaines suivantes

Si aucun de ces facteurs sont venus pour jouer, ce serait assez trivial d'estimer le trafic pour un tag donné (ou groupe d'étiquettes) plus d'un mois:

SELECT YEAR(Q.Creation_Date) 
     ,MONTH(Q.Creation_Date) 
     ,SUM(Q.View_Count/DATEDIFF(m,Q.Creation_Date,GETDATE())) 
    FROM Questions Q 
     JOIN QuestionTags QT 
     ON Q.Question_Id = QT.Question_Id 
WHERE QT.Tag_Name IN ('c#','.net', ...) 
GROUP BY YEAR(Q.Creation_Date), MONTH(Q.Creation_Date) 
ORDER BY 1,2 

Mais en raison des facteurs mentionnés ci-dessus (en particulier la longue queue), je ne suis pas sûr comment approcher les vues. Mes pensées sont de créer une fonction qui, en utilisant la formule longue queue, calcule les vues pour un mois en fonction du nombre actuel de vues et de semaines ouvertes.

Voici ce que je suis venu avec pour trouver la queue:

DECLARE @SDTE DATETIME, @EDTE DATETIME 
SELECT @SDTE = '2009-01-11' -- after new years holiday 
     ,@EDTE = CAST(MAX([Creation_Date]) AS INT) 
    FROM [Questions] 


SELECT [DaysOpen_Count] 
     ,AVG([WView_Count]) 
     FROM 
    (
    SELECT QT.[Tag_Name], 
     Q.[View_Count], 
     [DaysOpen_Count] = DATEDIFF(DAY, Q.[Creation_Date], @EDTE), 
     [WView_Count] = CAST(Q.[View_Count]/(DATEDIFF(DAY, Q.[Creation_Date], @EDTE)/7.0) AS INT) 
    FROM [Questions] Q 
     INNER JOIN [QuestionTags] QT 
     ON Q.[Question_Id] = QT.[Question_Id] 
    WHERE [Tag_Name] IN ('c#','.net',...) 
    AND [Creation_Date] < @EDTE 
) Q 
GROUP BY [DaysOpen_Count] 
ORDER BY 1,2 

Comment dois-je procéder pour créer cette requête SQL?

L'objectif final est une procédure stockée qui introduit une chaîne CSV de balises et crache les pages vues des six derniers mois pour ces balises. Après avoir gagné le badge tumbleweed, j'ai pensé qu'il était temps pour une prime!

Répondre

5

Vous devez considérer une courbe exponentielle de décroissance des vues, quelque chose de similaire à ce - http://en.wikipedia.org/wiki/Exponential_decay

Ce que nous avons besoin est la région ici sous la courbe jusqu'à temps désiré (en jours).

Si vous faites le calcul, vous arriverez à un résultat

Views = V/λ[1 - e^(-λt)] 

t est (date de création - la date d'aujourd'hui - 1)

V est le nombre de visionnages, nous avons

λ peut être 2ln2/T ou 1,4/T

T peut être une durée de vie importante comme 5 jours ou 7 jours. Prenons-le 5.

Nous faisons beaucoup de suppositions ici, par exemple, de la nature dynamique du SO. Mais je suis certain que cela donne de bons résultats.

Tout ce que vous avez à faire maintenant est de substituer les valeurs appropriées et obtenir des vues.

+0

Cela ressemble très près à ce que je cherchais; quant à la nature dynamique ... tout est moyen, surtout quand on laisse tomber les questions "bizarres" comme http: // stackoverflow.com/questions/84556/whats-your-favorite-programmer-cartoon –

+0

Vous devrez peut-être affiner la formule, en particulier le V et le taux de décroissance λ. Le taux de décroissance pour de telles questions est très faible (1/25?). –

2

Je pensais que cette méthode d'estimation de la queue:

pour une liste de tags, pour chaque question dans ces balises donnent le 1er mois après creation_date 80% de view_count donnent le 2ème mois après creation_date 10 % of View_Count divisé 10% de manière égale entre les mois restants jusqu'à aujourd'hui

bien sûr 80%, 10% est juste un choix du mien, ils peuvent être calculés plus précisément sur la base de données réelles. De plus, le deuxième mois 10% peut être éliminé. Toute cette logique est dans la partie: CASE WHEN diff ....

-vous d'obtenir estimé view_count/question/mois

tout ce que vous avez à faire est somme view_count par mois et si vous voulez une fenêtre de temps ajouter une condition sur le mois

J'ai créé une procédure stockée cela peut faire cela, mais vous devez d'abord créer une table temporaire #tags (Tag_name) où vous mettez les balises désirées.

CREATE PROCEDURE GetTagViews @startDate datetime, @endDate datetime 
As 

IF exists (SELECT null FROM sysobjects WHERE name = '#months' and type = 'U') 
    DROP TABLE #MONTHS 

CREATE TABLE #MONTHS 
(
    month datetime 
) 

DECLARE @currMonth datetime 
SELECT @currMonth = MIN(Creation_Date) FROM Questions 

-- Populate #MONTHS with all the months from the oldest 
-- question creation_date to Today 
WHILE @currMonth < getdate() 
BEGIN 
    -- insert date starting at the beginning og the month 
    INSERT INTO #MONTHS select @currMonth - day(@currMonth) + 1 
    SELECT @currMonth = dateadd(m, 1, @currMonth) -- advance 1 month 
END 

SELECT YEAR(month) y, MONTH(month) m, SUM(curr_month_views) Views FROM (
SELECT Q1.month, Q1.diff, round(
CASE WHEN diff = dmin and diff = dmax THEN View_Count 
    WHEN diff = dmin and diff < dmax THEN 0.8*View_Count 
    WHEN diff = dmin+1 and diff < dmax THEN 0.1*View_Count 
    WHEN diff = dmin+1 and diff = dmax THEN 0.2*View_Count 
    WHEN diff >= dmin+2 THEN 0.1/(dmax - (dmin+2) + 1)*View_Count 
    ELSE 0 
END, 0) curr_month_views 
FROM (
SELECT Q.question_id, m.month, 
    DATEDIFF(m, Q.Creation_Date, m.month) diff, 
    Q.View_Count, dmin, dmax 
FROM Questions Q, 
    #MONTHS m, 
    (SELECT MIN(DATEDIFF(m, Q.Creation_Date, m.month)) [dmin], 
      MAX(DATEDIFF(m, Q.Creation_Date, m.month)) [dmax] 
     FROM Questions Q,#MONTHS m 
     WHERE DATEDIFF(m, Q.Creation_Date, m.month) >= 0) MINMAX 
) Q1 join QuestionTags QT on Q1.question_id = QT.question_id 
    join #tags on #tags.Tag_Name = QT.Tag_Name 
) b WHERE month >= @startDate - day(@startDate) + 1 
     AND month <= @enddate - day(@enddate) + 1 
GROUP BY Year(month), Month(month) 
ORDER BY 1, 2 

Si je lance cette procédure avec les données suivantes:

Question_Id View_Count Creation_Date     tag_name   
----------- ----------- ------------------------------ ---------- 
0   42   2009-09-10 00:00:00.000  sql 
1   326   2008-08-04 00:00:00.000  sql 
2   377   2008-08-04 00:00:00.000  sql 
3   568   2008-08-03 00:00:00.000  sql 
4   839   2008-08-01 00:00:00.000  sql 
5   228   2009-03-01 00:00:00.000  sql 
6   178   2009-03-11 00:00:00.000  sql 
7   348   2009-08-11 00:00:00.000  c# 

#tags avec peupler 'sql'

GetTagViews '20090501', '20091001' 

    y   m   Views          
    ----------- ----------- --------------- 
    2009  5   21.000000000000 
    2009  6   21.000000000000 
    2009  7   21.000000000000 
    2009  8   21.000000000000 
    2009  9   55.000000000000 

#tags avec peupler 'C#'

GetTagViews '20090501', '20091001' 

    y   m   Views          
    ----------- ----------- ---------------------------------------- 
    2009  5   .000000000000 
    2009  6   .000000000000 
    2009  7   .000000000000 
    2009  8   278.000000000000 
    2009  9   35.000000000000 

remplir #tags avec les deux 'sql' & 'C#'

GetTagViews '20090501', '20091001' 

    y   m   Views          
    ----------- ----------- ---------------- 
    2009  5   21.000000000000 
    2009  6   21.000000000000 
    2009  7   21.000000000000 
    2009  8   299.000000000000 
    2009  9   90.000000000000 

(vous voyez ce pic pour (sql, C#) comparer seulement (sql) pour 2009-08, il est dû au C# question posée ce mois.)

NB : le classement des estimations conduit à une différence de quelques vues (~ 1) si vous résumez des vues détaillées et comparez aux données originales pour une question donnée!

+0

ce qui est très agréable, merci; Je vais donner un coup de feu –

0

Pour émuler des queues longues, il suffit d'introduire une constante. Ou utilisez la fonction logarithmique.

your_formula(delta_t) + C 

1/(1 + log(1 + delta_t)) 

(coefficients sont omis)

Questions connexes