2009-09-10 30 views
5

Sử dụng Stack Overflow dữ liệu công cộng bãi, tôi đã tạo ra ba bảng đơn giản:Số lần xem trang xấp xỉ trên mỗi thẻ (hoặc nhóm thẻ) mỗi tháng có dữ liệu hạn chế?

  • câu hỏi (Question_Id, VIEW_COUNT, CREATION_DATE)
  • Tags (TAG_NAME)
  • QuestionTags (Question_Id, TAG_NAME)

Bảng Câu hỏi có hàng trăm nghìn hàng với Creation_Date trải rộng từ một năm trước cho tới hôm nay. Nhìn qua các dữ liệu, có hai xu hướng đáng chú ý:

  • Số câu hỏi Tăng bởi Thời gian - ví dụ, đã có nhiều câu hỏi trong tháng này so với ba tháng trước
  • Câu hỏi xem có một cái đuôi dài - bằng cách xem các lượt xem dựa trên các tuần mở, chúng ta có thể thấy rằng hầu hết các lượt xem của câu hỏi xảy ra trong tuần đầu tiên; số tiền ít hơn trong lần thứ hai và thứ ba; và đuôi dài, liên tục trong các tuần tiếp theo

Nếu không có yếu tố nào trong số này phát sinh, nó sẽ khá tầm thường để ước tính lưu lượng truy cập cho một thẻ (hoặc nhóm thẻ) nhất định trong một tháng:

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 

Nhưng vì các yếu tố nói trên (đặc biệt là đuôi dài), tôi không chắc chắn cách xem gần đúng. Suy nghĩ của tôi là tạo ra một hàm, sử dụng công thức đuôi dài, sẽ tính toán lượt xem trong một tháng dựa trên số lượt xem hiện tại và tuần mở.

Đây là những gì tôi đã đưa ra để tìm đuôi:

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 

Làm thế nào tôi nên tiến hành để tạo ra truy vấn SQL này?

Mục tiêu cuối cùng là Nguyên tắc được lưu trữ sẽ nhập một chuỗi CSV và kích hoạt lượt xem trang trong sáu tháng qua cho các thẻ đó.

CẬP NHẬT Sau khi "kiếm" huy hiệu tumbleweed, tôi đã nhận ra đó là thời gian cho tiền thưởng!

Trả lời

5

Bạn sẽ cần phải xem xét một đường cong Lần sâu mũ, một cái gì đó tương tự như sau - http://en.wikipedia.org/wiki/Exponential_decay

Những gì chúng ta cần ở đây diện tích dưới đường cong tối đa thời gian mong muốn (trong ngày) là.

Nếu bạn làm toán, bạn sẽ đi đến một kết quả

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

t (ngày tạo - ngày hôm nay - 1)

V là đếm xem chúng ta có

λ có thể là 2ln2/T hoặc 1.4/T

T có thể là thời gian sống lớn như 5 ngày hoặc 7 ngày. Cho phép lấy nó 5.

Chúng tôi đang tạo ra rất nhiều giả định ở đây vì tính chất động của SO. Nhưng tôi tích cực rằng nó mang lại kết quả tốt đẹp.

Tất cả những gì bạn phải làm bây giờ là thay thế các giá trị thích hợp và nhận số lượt xem.

+0

Điều này trông rất gần với những gì tôi đang tìm kiếm; đối với tính chất động ... tất cả đều trung bình, đặc biệt là khi chúng ta bỏ các câu hỏi "quái dị" như http: // stackoverflow.com/questions/84556/whats-your-yêu thích-lập trình-phim hoạt hình –

+0

Bạn có thể phải tinh chỉnh công thức, đặc biệt là V và tỷ lệ phân rã λ. Tỷ lệ phân rã cho các câu hỏi như vậy là rất thấp (1/25?). –

2

Tôi nghĩ đến phương pháp này để ước lượng đuôi:

cho một danh sách các thẻ, cho mỗi câu hỏi trong các thẻ cho tháng 1 sau khi CREATION_DATE 80% VIEW_COUNT cho tháng thứ 2 sau khi CREATION_DATE 10 % của View_Count chia đều 10% giữa các tháng còn lại cho đến ngày hôm nay

tất nhiên 80%, 10% chỉ là lựa chọn của tôi, chúng có thể được tính chính xác hơn dựa trên dữ liệu thực. Ngoài ra, tháng thứ hai 10% có thể bị loại bỏ. Tất cả logic đó nằm trong phần: CASE WHEN diff ....

bạn có được ước tính VIEW_COUNT/câu hỏi/tháng

sau đó tất cả các bạn phải làm là tổng VIEW_COUNT mỗi tháng và nếu bạn muốn có một cửa sổ thời gian thêm một điều kiện về tháng

Tôi tạo ra một thủ tục lưu trữ có thể làm điều này, nhưng bạn phải tạo một thẻ #tags tạm thời (Tag_name), nơi bạn đặt các thẻ mong muốn.

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 

Nếu tôi chạy thủ tục này với các dữ liệu sau:

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# 

cư #tags với '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 

cư #tags với 'C#'

GetTagViews '20090501', '20091001' 

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

điền #tags với cả '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 

(bạn thấy rằng đỉnh cho (sql, C#) so với chỉ (sql) cho 2009-08, đó là do sự C# câu hỏi được đặt tháng đó.)

NB : rouding của ước tính dẫn của tôi đến một sự khác biệt của một số quan điểm (~ 1) nếu bạn tổng hợp các quan điểm chi tiết và so sánh với các dữ liệu ban đầu cho một câu hỏi nhất định!

+0

này là rất tốt đẹp, nhờ; Tôi sẽ cung cấp cho nó một shot –

0

Để mô phỏng đuôi dài chỉ giới thiệu một hằng số. Hoặc sử dụng hàm logarit.

your_formula(delta_t) + C 

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

(hệ số được bỏ qua)

Các vấn đề liên quan