2009-02-13 62 views
34

假設我有兩列,關鍵字和內容。我有一個全文索引。我想要在關鍵字中使用foo的行與內容中的foo的行關聯更多。我需要做什麼才能使MySQL對比關鍵字中的匹配更高的內容進行加權?如何操縱MySQL全文搜索相關性使一個字段比另一個字段更「有價值」?

我正在使用「match against」語法。

SOLUTION:

是能夠使這項工作方式如下:

SELECT *, 
CASE when Keywords like '%watermelon%' then 1 else 0 END as keywordmatch, 
CASE when Content like '%watermelon%' then 1 else 0 END as contentmatch, 
MATCH (Title, Keywords, Content) AGAINST ('watermelon') AS relevance 
FROM about_data 
WHERE MATCH(Title, Keywords, Content) AGAINST ('watermelon' IN BOOLEAN MODE) 
HAVING relevance > 0 
ORDER by keywordmatch desc, contentmatch desc, relevance desc 

回答

19

實際上,使用CASE語句,使一對標誌可能是一個更好的解決方案:

select 
... 
, case when keyword like '%' + @input + '%' then 1 else 0 end as keywordmatch 
, case when content like '%' + @input + '%' then 1 else 0 end as contentmatch 
-- or whatever check you use for the matching 
from 
    ... 
    and here the rest of your usual matching query 
    ... 
order by keywordmatch desc, contentmatch desc 

再次,這是隻有在所有關鍵字匹配的排名高於一切的內容,只匹配。我還假設關鍵字和內容中的匹配是最高級別。

0

據我所知,這是不是與MySQL全文搜索的支持,但是可以達到的效果通過某種方式在關鍵字字段中多次重複該單詞。 而不是關鍵字「富酒吧」,有「富酒吧富酒吧富吧」,這樣的兩個富和酒吧在關鍵字列同樣重要,並且因爲他們出現多次,他們變得更相關的MySQL。

我們在我們的網站上使用它,它的工作原理。

-4

如果指標只是說所有的關鍵字匹配都比所有內容匹配更「有價值」,那麼您可以使用行計數的聯合。沿着這些線路的東西。

​​

對於任何比這更復雜的情況,如果您想在每一行上應用實際重量,我不知道如何提供幫助。

+0

我想這一點,並結束了語法錯誤。我不認爲我知道應該通過blahblah spot發佈什麼內容。建議? – Buzz 2009-02-13 21:11:31

+0

對不起,這不是一個複製和粘貼示例。在over子句中的順序是您應用行號的順序,所以它應該是您通常會按順序排列結果的順序。 – notnot 2009-02-13 21:43:42

+0

現在我想到了,這個將複製與關鍵字和內容匹配的記錄。 – notnot 2009-02-13 21:52:45

-1

嗯,這取決於你是什麼恰恰意味着有:

我想在關鍵字 以foo一行到比在內容 富行更相關。

如果你的意思是,在關鍵字FOO行應該在內容上,然後我會做兩個單獨的查詢,一個是關鍵字,然後來到之前任何行以foo(可能懶洋洋地,只有在被請求時)另一個內容。

0

幾年前,我做了這個,但沒有全文索引。我沒有方便的代碼(前僱主),但我記得技術很好。

簡而言之,我從每列中選擇一個「重量」。例如:

select table.id, keyword_relevance + content_relevance as relevance from table 
    left join 
     (select id, 1 as keyword_relevance from table_name where keyword match) a 
    on table.id = a.id 
    left join 
     (select id, 0.75 as content_relevance from table_name where content match) b 
    on table.id = b.id 

請forrgive任何僞劣SQL這裏,因爲我需要編寫任何它已經有幾年了,我這樣做了我的頭頂部...

希望這幫助!

J.Js

68

創建三個全文索引

  • 一)一個在關鍵字列
  • B)一個在內容列
  • C)在一個關鍵字和內容列

然後,您的查詢:

SELECT id, keyword, content, 
    MATCH (keyword) AGAINST ('watermelon') AS rel1, 
    MATCH (content) AGAINST ('watermelon') AS rel2 
FROM table 
WHERE MATCH (keyword,content) AGAINST ('watermelon') 
ORDER BY (rel1*1.5)+(rel2) 

問題是,rel1只是在keyword列中爲您提供查詢的相關性(因爲您僅在該列上創建索引)。 rel2也是如此,但對於content列。您現在可以將這兩個相關性分數加在一起,應用您喜歡的任何權重。

但是,您沒有在實際搜索中使用這兩個索引中的任何一個。爲此,你使用你的第三個索引,它在兩列上。

(關鍵字,內容)上的索引控制您的召回。又名,什麼是返回。

兩個單獨的索引(一個僅用於關鍵字,一個僅用於內容)控制您的相關性。你可以在這裏應用你自己的權重標準。

請注意,您可以使用任意數量的不同索引(或者根據其他因素改變您在查詢時使用的索引和權重,也許...只在關鍵字上搜索,如果查詢包含停用詞...減少如果查詢包含多於3個單詞等,則關鍵字的權重偏差)。

每個索引都佔用磁盤空間,所以索引越多,磁盤就越多。而反過來,MySQL的內存佔用更大。此外,插入將花費更長時間,因爲您有更多的索引要更新。

您應該基準性能(注意關閉mysql查詢緩存以進行基準測試,否則結果將會出現偏差)。這不是谷歌級的高效,但它非常容易和「開箱即用」,它幾乎肯定比在查詢中使用「like」要好得多。

我覺得它工作得很好。

0

在布爾模式下,MySQL支持「>」和「<」運算符來更改單詞對分配給某行的相關性值的貢獻。

我不知道這樣的事情是否會起作用?

SELECT *, 
MATCH (Keywords) AGAINST ('>watermelon' IN BOOLEAN MODE) AS relStrong, 
MATCH (Title,Keywords,Content) AGAINST ('<watermelon' IN BOOLEAN MODE) AS relWeak 
FROM about_data 
WHERE MATCH(Title, Keywords, Content) AGAINST ('watermelon' IN BOOLEAN MODE) 
ORDER by (relStrong+relWeak) desc 
0

我需要類似的東西,並使用OP的解決方案,但我注意到全文不匹配部分單詞。因此,如果'西瓜'在關鍵詞或內容中作爲單詞的一部分(如watermelonsalesmanager),它不匹配,並且由於WHERE MATCH而不包含在結果中。 所以我上當了一下週圍,並調整了OP的查詢到這一點:

SELECT *, 
CASE WHEN Keywords LIKE '%watermelon%' THEN 1 ELSE 0 END AS keywordmatch, 
CASE WHEN Content LIKE '%watermelon%' THEN 1 ELSE 0 END AS contentmatch, 
MATCH (Title, Keywords, Content) AGAINST ('watermelon') AS relevance 
FROM about_data 
WHERE (Keywords LIKE '%watermelon%' OR 
    Title LIKE '%watermelon%' OR 
    MATCH(Title, Keywords, Content) AGAINST ('watermelon' IN BOOLEAN MODE)) 
HAVING (keywordmatch > 0 OR contentmatch > 0 OR relevance > 0) 
ORDER BY keywordmatch DESC, contentmatch DESC, relevance DESC 

希望這有助於。

1

簡單的版本僅使用2全文索引(從@mintywalker採取學分):

SELECT id, 
    MATCH (`content_ft`) AGAINST ('keyword*' IN BOOLEAN MODE) AS relevance1, 
    MATCH (`title_ft`) AGAINST ('keyword*' IN BOOLEAN MODE) AS relevance2 
FROM search_table 
HAVING (relevance1 + relevance2) > 0 
ORDER BY (relevance1 * 1.5) + (relevance2) DESC 
LIMIT 0, 1000; 
相關問題