2017-05-22 56 views
0

我已經構建了一個程序來爲文本文件中的關鍵字建立索引並將它們放到數據庫中。根據關鍵字的優先順序返回大多數匹配結果

我的表很簡單:

FILE_ID|Name 
------------ 
1  | a.txt 
2  | b.txt 
3  | c.txt 

KEYWORD_ID|FILE_ID|Hits 
----------------------- 
1   | 1  | 55 
2   | 1  | 10 
3   | 1  | 88 
1   | 2  | 44 
2   | 2  | 15 
1   | 3  | 199 
2   | 3  | 1 
3   | 3  | 4 

有此表沒有主鍵。我沒有發現它是必要的。

現在我想搜索哪些文件對特定關鍵字的點擊次數最多。

如果我只有一個關鍵詞很容易:

select top 10 * 
from words 
where keyword_id=1 
order by hits desc 

可以說,我想搜索的關鍵詞中1和3個文件(兩者都必須存在,並且第一關鍵字具有最高的重要性)。幾個小時後,我來到這裏:

select top 10 k.* 
from 
(
    select file_id, 
    max(hits) as maxhits 
    from words 
    where keyword_id=3 
    group by file_id 
) as x 
inner join keyword as k 
    on (k.file_id = x.file_id 
     and k.keyword=1) 
order by k.hits desc 

如何使正確嗎?特別是如果我想用N個關鍵字進行搜索。它會更好地使用臨時表和工作?

如果與關鍵字1和3搜索我想要FILE_ID 3和1回,順序(因爲3 FILE_ID有關鍵字1更高的命中次數)

+0

根據樣本數據,什麼是預期的輸出,如果'搜索文件與關鍵字1和3'? –

+0

如果使用關鍵字1和3進行搜索,我希望以此順序返回FILE_ID 3和1(因爲file_id 3對關鍵字1的命中計數較高)。 – itix

+0

@itix請檢查我的答案 – DhruvJoshi

回答

0

這裏有一種方法......如果你只是想看看您指定的行數爲KEYWORD_ID,只需在底部添加WHERE CLAUSE即可。 INNER JOINFILE_ID限制爲包含兩者的那些KEYWORD_ID您通過檢查不同計數是否等於關鍵字數量來指定。因此,在下面的例子中,我們限制在2 KEYWORD_ID結果集和檢查,以確保每個FILE_ID有關聯的2個不同的KEYWORD_ID,與HAVING條款

declare @words table (KEYWORD_ID int, [FILE_ID] int, HITS int) 
insert into @words 
values 
(1,1,55), 
(2,1,10), 
(3,1,88), 
(1,2,44), 
(2,2,15), 
(1,3,199), 
(2,3,1), 
(3,3,4) 

select top 10 w.* 
from @words w 
inner join 
    (select [FILE_ID] 
    from @words 
    where KEYWORD_ID in (1,3) 
    group by [FILE_ID] 
    having count(distinct KEYWORD_ID) = 2 
    ) x on x.[FILE_ID] = w.[FILE_ID] 
order by HITS desc 
+0

啊,實際上有一個小問題:它應該更喜歡關鍵字順序。 @DhruvJoshi給了我一個想法如何完成。 – itix

1

不知道,但(根據您的評論)可能這是你需要的嗎?

(我使用@scsimon回答表聲明)

declare @words table (KEYWORD_ID int, [FILE_ID] int, HITS int) 
insert into @words 
values 
(1,1,55), 
(2,1,10), 
(3,1,88), 
(1,2,44), 
(2,2,15), 
(1,3,199), 
(2,3,1), 
(3,3,4) 

select [FILE_ID] from (
    select *, row_number() over(partition by KEYWORD_ID order by HITS desc) rn from @words 
    where KEYWORD_ID in(1,3) 
)t 
where rn = 1 
order by hits desc 
+0

這就是我所要求的,並且在*子句的where子句中可以通過二級(或三級等)關鍵字對結果進行排序。 – itix

0

您可以使用頂部(N)與您的查詢如下關係:

declare @n int = 10 --10 in your scenario 
select top (@n) with ties * 
from (
    select w.*, f.name from #words w inner join #files f 
     on w.[FILE_ID] = f.[file_id] 
    ) a 
    order by (row_number() over (partition by a.[file_id] order by hits desc)-1)/@n +1 
+0

這是計算所有關鍵字。我不得不限制查詢來只計算指定的關鍵字。 – itix

1

假設所有相關的關鍵字是發現儲存在表KTable其中有兩列IDKEYWORD_ID

然後查詢應該是

SELECT 
    FileID, 
    SUM(Hits) NetHits, 
    SUM(Hits/K.ID) WeightedHits 
FROM 
    Words w JOIN Ktable K 
    on w.KEYWORD_ID= K.KEYWORD_ID 
GROUP BY FileID 
HAVING count(1) = (SELECT COUNT(1) FROM Ktable) 
ORDER BY 2 DESC,3 DESC 

使用同一查詢窗口函數將

SELECT 
DISTINCT 
FileID, 
NetHitsPerFile 
FROM 
(
SELECT 
    FileID, 
    SUM(Hits) OVER (PARTITION BY FileID ORDER BY K.ID ASC) NetHitsPerFile, 
    SUM(FileID) OVER(PARTITION BY K.ID) Files, 
    SUM(Hits/K.ID) OVER (PARTITION BY FileID ORDER BY K.ID ASC) weightedHits 

FROM 
    Words w JOIN Ktable K 
    on w.KEYWORD_ID= K.KEYWORD_ID 
)T 
    WHERE Files= (SELECT COUNT(1) FROM Ktable) 
    ORDER BY NetHitsPerFile, weightedHits 
在你的問題
+0

這個我喜歡。我創建了臨時表* declare @ktable表(ID float,KEYWORD_ID int)*其中關鍵字存儲在查詢中,這對我有很大的幫助。 – itix

+0

雖然您的後一個示例不起作用:它不返回任何結果。子句* WHERE Files =(SELECT COUNT(1)FROM Ktable)*未按預期工作... – itix

相關問題