2009-09-10 11 views
5

Utilizando el volcado de datos pública de desbordamiento de pila, he creado tres tablas simples:Aprox. Páginas vistas por etiqueta (o grupo de etiquetas) por mes con datos limitados?

  • Preguntas (question_id, view_count, creation_date)
  • Etiquetas (TAG_NAME)
  • QuestionTags (question_id, TAG_NAME)

La tabla de Preguntas tiene cientos de miles de filas con Creation_Date desde hace un año hasta hoy. Mirando por encima de los datos, hay dos tendencias notables:

  • número de preguntas incrementará en un período de - por ejemplo, hubo más Preguntas este mes que hace tres meses
  • Preguntas Vistas tienen una larga cola: al observar las vistas en función de las semanas abiertas, podemos ver que la mayoría de las vistas de una pregunta ocurren en la primera semana; una cantidad menor en el segundo y el tercero; y una cola larga, constante en las siguientes semanas

Si ninguno de estos factores se introdujo para jugar, sería bastante trivial para estimar el tráfico de una determinada etiqueta (o grupo de etiquetas) más de un mes:

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 

Pero debido a los factores antes mencionados (especialmente la cola larga), no estoy seguro de cómo aproximar las vistas. Mi idea es crear una función que, usando la fórmula de cola larga, calcule las vistas de un mes en función del número actual de vistas y semanas abiertas.

Esto es lo que se me ocurrió para encontrar la cola:

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 

¿Cómo debo proceder para crear esta consulta SQL?

El objetivo final es un proceso almacenado que ingresa una cadena CSV de etiquetas y escupe las vistas de las últimas seis páginas de esas etiquetas.

ACTUALIZACIÓN Después de "ganar" la insignia de tumbleweed, ¡pensé que era hora de una recompensa!

Respuesta

5

Usted tendrá que considerar una curva de caída exponencial Vistas, algo similar a esto - http://en.wikipedia.org/wiki/Exponential_decay

Lo que necesitamos aquí es el área bajo la curva hasta el tiempo deseado (en días).

Si se hacen las cuentas, podrás llegar a un resultado

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

t es (fecha de creación - la fecha de hoy - 1)

V es el recuento de visión que se tiene

λ puede ser 2ln2/T o 1.4/T

T puede ser una gran vida útil, como 5 días o 7 días. Vamos a tomarlo 5.

Estamos haciendo muchas suposiciones aquí, porque la naturaleza dinámica de SO. Pero estoy seguro de que produce buenos resultados.

Todo lo que tienes que hacer ahora es sustituir los valores apropiados y obtener vistas.

+0

Esto se ve muy cerca de lo que estaba buscando; en cuanto a la naturaleza dinámica ... todo promedia, especialmente una vez que dejamos caer las preguntas "freak" como http: // stackoverflow.com/questions/84556/whats-your-favorite-programmer-cartoon –

+0

Puede que tenga que afinar la fórmula, especialmente la V y la tasa de desintegración λ. La tasa de caries para tales preguntas es muy baja (1/25?). –

2

pensé de este método para la estimación de la cola:

para una lista de etiquetas, para cada pregunta en estas etiquetas dan la primera mes después creation_date 80% de view_count dar el segundo mes después de creation_date 10 % de View_Count dividido 10% por igual entre los meses restantes hasta hoy

por supuesto 80%, 10% es solo una opción mía, se pueden calcular con mayor precisión sobre la base de datos reales. Además, el segundo mes 10% puede eliminarse. Toda esa lógica está en la parte: CASE WHEN diff ....

a obtener estimaste view_count/pregunta/mes

entonces todo lo que tiene que hacer es suma view_count por mes y si quieres una ventana de tiempo de agregar una condición en el mes

he creado un procedimiento almacenado eso puede hacer esto, pero primero debe crear una tabla temporal #tags (Tag_name) donde coloca las etiquetas deseadas.

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 funciono este procedimiento con los siguientes datos:

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# 

pueblan con #tags '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 

pueblan #tags con 'C#'

GetTagViews '20090501', '20091001' 

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

llene #tags con 'sql' & 'de 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 

(que ver que el pico de (sql, # c) comparar a solamente (SQL) para 2009-08, que es debido a la C# pregunta que se hace de ese mes.)

NB : el enrutamiento de las estimaciones me lleva a una diferencia de algunas vistas (~ 1) si resume las vistas detalladas y las compara con los datos originales de una pregunta determinada.

+0

esto es muy bonito, gracias; Voy a darle una oportunidad –

0

Para emular colas largas solo introduce una constante. O usa la función logarítmica.

your_formula(delta_t) + C 

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

(se omiten los coeficientes)