百度二面,MySQL 怎么做權(quán)重搜索?
考慮這樣一個(gè)搜索需求,有一個(gè) MySQL 表,表中很多個(gè)列存放著不同的內(nèi)容,希望用戶通過(guò)關(guān)鍵詞進(jìn)行搜索的時(shí)候,能夠模糊匹配多個(gè)列,比如有 t1 列、t2 列、t3 列,同時(shí)還希望 t1 列的匹配權(quán)重最高,t3 列的匹配權(quán)重最低。簡(jiǎn)單說(shuō)就是如果有一個(gè)關(guān)鍵詞同時(shí)出現(xiàn)在記錄 A 的 t1 列 和里記錄 B 的 t2 列,那么記錄 A 應(yīng)該優(yōu)先展示,排序是在前面的。
注意這里是 MySQL,不是 ES,搜索引擎做這種搜索需求當(dāng)然得天獨(dú)厚,但是這種在 MySQL 中進(jìn)行權(quán)重搜索的需求也不是沒(méi)有,業(yè)務(wù)初期數(shù)據(jù)量還不大的時(shí)候大概率不會(huì)考慮上 ES,這時(shí)候在 MySQL 中先簡(jiǎn)單跑通邏輯才是最重要的。
思考下該如何做?
模糊匹配
首先模糊匹配大家最常用的就是 like
:
SELECT * FROM test
WHERE t1 LIKE '%標(biāo)題%'
or t2 LIKE '%內(nèi)容%'
or t3 LIKE '%注釋%''
當(dāng)只需要簡(jiǎn)單的模式匹配時(shí) like
確實(shí)往往是更好的選擇。而在需要進(jìn)行復(fù)雜匹配,如同一字段中包含多個(gè)模式,進(jìn)行分組匹配等,REGEXP
則表現(xiàn)更為突出,Mysql 支持對(duì)列的正則表達(dá)式方式查詢,使用方式如下:
SELECT * FROM test
WHERE t1 regexp '標(biāo)題'
or t2 regexp '內(nèi)容'
or t3 regexp '注釋'
權(quán)重搜索
權(quán)重搜索涉及到幾個(gè) Mysql 函數(shù)。
LOCATE('標(biāo)題', test.t1)
: 查詢 "標(biāo)題" 在 test.t1 列出現(xiàn)的位置,0 表示未找到。否則返回 坐標(biāo)位置,坐標(biāo)位置從 1 開(kāi)始。IF( 表達(dá)式, 1, 0)
:判斷表達(dá)式結(jié)果,TRUE 則返回 1,F(xiàn)ALSE 則返回 0
下面我們來(lái)看如何基于這兩個(gè)函數(shù)來(lái)實(shí)現(xiàn)文章開(kāi)頭的需求:
SELECT *, (
IF(LOCATE('標(biāo)題',test.t1), 1, 0)
+ IF(LOCATE('內(nèi)容',test.t2) , 1, 0)
+ IF(LOCATE('注釋',test.t3) , 1, 0)
) AS weight
FROM test
WHERE test.t1 regexp '標(biāo)題'
or test.t2 regexp '內(nèi)容'
or test.t3 regexp '注釋'
order by weight desc
上面的查詢中,每個(gè)關(guān)鍵詞的權(quán)重都是 1,所以,在這 t1\t2\t3 三列中,關(guān)鍵詞出現(xiàn)次數(shù)最多的記錄將出現(xiàn)在搜索結(jié)果的第一位。
如果權(quán)重增加,那么權(quán)重高的關(guān)鍵詞將會(huì)影響排序規(guī)則。如下例子,將 t1 列的搜索權(quán)重改為 7:
SELECT *, (
IF(LOCATE('標(biāo)題',test.t1), 7, 0)
+ IF(LOCATE('內(nèi)容',test.t2) , 2, 0)
+ IF(LOCATE('注釋',test.t3) , 1, 0)
) AS weight
FROM test
WHERE test.t1 regexp '標(biāo)題'
or test.t2 regexp '內(nèi)容'
or test.t3 regexp '注釋'
order by weight desc