MySQL實現多關鍵詞模糊搜索,搜索結果按照匹配關鍵詞的多寡來排序
目前在做“Brick4.com - 國產積木索引表”這個小工具。它是當作“工具書”而存在的,必然需要一個靠譜的檢索功能。按主題和品牌這些即有的篩選就不說了,今天把我的摸索過程整理一下,說說如何用 MySQL 實現多關鍵詞站內“模糊查找”。
拿一個簡化的小表兒做例子
表名叫:article
字段有:title、subtitle、tag、text……
涉及到查找的字段有三個:title、subtitle、tag
像我這種初學者,首先想到的肯定是 LIKE ,關鍵詞是“車”的話,就這樣:
SELECT * FROM article WHERE
title LIKE "%車%"
OR subtitle LIKE "%車%"
OR tag LIKE "%車%"
怎么樣?LIKE 是萬能的,用一個 LIKE 解決不了的事情就多用幾個 LIKE 。於是多關鍵詞就這樣搞:
SELECT * FROM article WHERE
(
title LIKE "%車%"
OR subtitle LIKE "%車%"
OR tag LIKE "%車%"
) OR (
title LIKE "%摩托%"
OR subtitle LIKE "%摩托%"
OR tag LIKE "%摩托%"
) OR (
title LIKE "%紅色%"
OR subtitle LIKE "%紅色%"
OR tag LIKE "%紅色%"
) OR (
title LIKE "%美國%"
OR subtitle LIKE "%美國%"
OR tag LIKE "%美國%"
) OR (
title LIKE "%2006%"
OR subtitle LIKE "%2006%"
OR tag LIKE "%2006%"
)
雖然很工整,不過能不能簡潔一點?當然行!看我變形!我們可以用正則:
SELECT * FROM article WHERE
title REGEXP "車|摩托|紅色|美國|2006"
OR subtitle REGEXP "車|摩托|紅色|美國|2006"
OR tag REGEXP "車|摩托|紅色|美國|2006"
怎么樣?意外不意外?驚喜不驚喜?其實咱們還可以更進一步,把幾個字段合並起來:
SELECT * FROM article WHERE
CONCAT_WS(" ", title, subtitle, tag) REGEXP "車|摩托|紅色|美國|2006"
這一句話,和前面洋洋灑灑那一大坨是等同的。
之所以用 CONCAT_WS()
而不是 CONCAT()
,是因為后者在某字段為 NULL 的情況下會導致合並結果為 NULL,萬無一失嘛,我們用前者。
要求不高的話,到這其實就可以了。但是總感覺找到的文章似有關聯又東一榔頭西一杵,所以咱們要排序。我希望“按照匹配關鍵詞的多寡來排序”,匹配關鍵詞越多的文章越靠前,咋辦呢?
SELECT *,
(
(IF( CONCAT_WS(" ", title, subtitle, tag) LIKE "%車%", 1, 0))
+ (IF( CONCAT_WS(" ", title, subtitle, tag) LIKE "%摩托%", 1, 0))
+ (IF( CONCAT_WS(" ", title, subtitle, tag) LIKE "%紅色%", 1, 0))
+ (IF( CONCAT_WS(" ", title, subtitle, tag) LIKE "%美國%", 1, 0))
+ (IF( CONCAT_WS(" ", title, subtitle, tag) LIKE "%2006%", 1, 0))
) AS keyweight
FROM article WHERE
CONCAT_WS(" ", title, subtitle, tag) REGEXP "車|摩托|紅色|美國|2006"
ORDER BY keyweight DESC
“通過一組關鍵詞站內模糊搜索,按照匹配關鍵詞的多寡來排序。”這個需求,目標達成!撒花撒花~
最終的語句扔在這里,相信你一看就懂了。關鍵是思路,我可是瀝瀝拉拉摸索了好幾天啊……
在今天的例子里 title、subtitle、tag 三個字段同等重要,所以直接合並起來,如果你希望有權重的概念,比如 主標題 大於 副標題 大於 標簽,思考一下,其實也不復雜。
最后再打個廣告:Brick4.com - 最實用的國產積木索引表 更好用了!感興趣的小伙伴快來支持一下!!
2017-09-13 更新
發現 Brick4 搜索的關鍵詞開始區分大小寫了。探究源頭是因為最近把一個數據類型為 INT 的字段納入了檢索,區分大小寫正是因此造成的。
舉個例子,比如 time 的數據類型是數字,title 是文本,直接這樣寫就會區分大小寫:
SELECT * FROM article WHERE
CONCAT_WS("", time, title) REGEXP "關鍵詞"
要是把數字轉成字符串再拼合就沒事了:
SELECT * FROM article WHERE
CONCAT_WS("", CHAR(time), title) REGEXP "關鍵詞"
上述轉自:
http://lao.si/120
============================================================================
今天一同事碰到一奇葩需求。
多個模糊查詢結果 優先按照某一個模糊查詢匹配
思路一:優先的模糊查詢先查 union 其他的模糊查詢結果 再分頁,但是花費時間*2
思路二:產品角度考慮,既然優先某一個模糊查詢,可以分為兩個查詢頁面/采用tab頁形式,,
ok sql級別的模糊查詢就這樣了。。多個角度優化