Приближение просмотров страниц по тегу (или группе тегов) за месяц с ограниченными данными? - PullRequest
5 голосов
/ 10 сентября 2009

Используя публичный дамп данных переполнения стека, я создал три простые таблицы:

  • Вопросы (вопрос, идентификатор, количество просмотров, дата создания),
  • Теги (Tag_Name)
  • QuestionTags (Question_Id, Tag_Name)

Таблица «Вопросы» содержит сотни тысяч строк с Creation_Date, охватывающей год назад и сегодня. Просматривая данные, можно выделить две заметные тенденции:

  • Количество вопросов увеличилось на период - например, в этом месяце было задано больше вопросов, чем три месяца назад
  • Представления вопросов имеют длинный хвост - просмотрев представления, основанные на открытых неделях, мы можем увидеть, что большинство представлений вопроса происходит в первую неделю; меньшее количество во втором и третьем; и длинный, постоянный хвост в последующие недели

Если в игру не вошел ни один из этих факторов, было бы довольно тривиально оценить трафик для данного тега (или группы тегов) за месяц:

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

Но из-за вышеупомянутых факторов (особенно длинного хвоста) я не уверен, как приблизить взгляды. Мои мысли состоят в том, чтобы создать функцию, которая, используя формулу длинного хвоста, будет вычислять просмотры за месяц на основе текущего количества просмотров и открытых недель.

Вот что я придумал, чтобы найти хвост:

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

Как мне приступить к созданию этого SQL-запроса?

Конечной целью является Stored PRocedure, которая вводит CSV-строку тегов и выплевывает просмотры страниц за последние шесть месяцев для этих тегов.

ОБНОВЛЕНИЕ После того, как я "заработал" значок с камышами, я решил, что пришло время щедрости!

Ответы [ 3 ]

5 голосов
/ 18 сентября 2009

Вам нужно будет рассмотреть экспоненциальную кривую затухания просмотров, что-то похожее на это - http://en.wikipedia.org/wiki/Exponential_decay

Здесь нам нужна область под кривой до желаемого времени (в днях).

Если вы выполните математику, вы получите результат

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

t is (дата создания - сегодняшняя дата - 1)

V - это количество просмотров, которое у нас есть

λ может быть 2ln2 / T или 1,4 / T

T может быть основным временем жизни, например, 5 дней или 7 дней. Давайте возьмем 5.

Мы делаем здесь много предположений, потому что динамическая природа SO. Но я уверен, что это дает хорошие результаты.

Все, что вам нужно сделать сейчас, это заменить соответствующие значения и получить представления.

2 голосов
/ 18 сентября 2009

Я думал об этом методе оценки хвоста:

для списка тегов, за каждый вопрос в этих тегах дать 1-й месяц после создания_даты 80% от View_Count дать 2-й месяц после создания_даты 10% от View_Count разделить 10% поровну между оставшимися месяцами до сегодняшнего дня

конечно 80%, 10% - это только мой выбор, они могут быть более точно рассчитаны на основе реальных данных. Также за второй месяц 10% могут быть исключены. Вся эта логика в: CASE WHEN diff ... части.

Вы получаете приблизительное количество просмотров / вопрос / месяц

тогда все, что вам нужно сделать, это сумма view_count в месяц и, если вы хотите, чтобы окно времени добавляло условие для месяца

Я создал хранимую процедуру, которая может сделать это, но сначала нужно создать временную таблицу #tags (Tag_name), в которую вы поместите нужные теги.

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

Если я запускаю эту процедуру со следующими данными:

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 '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 'c #'

GetTagViews '20090501', '20091001'

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

заполнить #tags обоими '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

(вы видите, что пик для (sql, c #) по сравнению только с (sql) для 2009-08, это из-за вопроса c #, задаваемого в этом месяце.)

N.B .: приблизительные оценки могут привести к разнице некоторых представлений (~ 1), если вы подытожите подробные представления и сравните их с исходными данными для данного вопроса!

0 голосов
/ 19 сентября 2009

Чтобы подражать длинным хвостам, просто введите константу. Или используйте логарифмическую функцию.

your_formula(delta_t) + C

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

(коэффициенты опущены)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...