中文模糊搜索
什麼是模糊搜索?為什麼要使用模糊搜索?相信大家都知道這些,我就不講了。今天只講怎麼使用模糊搜索。
一 LIKE。大名鼎鼎的like字句,使用方便,兼容性好,易維護,但效率奇低。大家都會用,不多介紹。
二 MYSQL 原生支持的全文索引(FULLTEXT index)。
實現方式:首先給目標字段添加索引,索引的類型是FULLTEXT,然後查詢的時候,在sql語句的where條件後面使用against()去指定關鍵字就好了。
而網上很多文章對這個理解卻有很多誤區,認為FULLTEXT不支持中文,或者Linux下全文索引不支持中文,然後說要把中文轉為拼音就好了。事實上不是這樣的,重點是在於分詞,因為中文沒有自然分詞,不像英文每個單詞都有空格隔開,而轉為拼音之後,每個字對應的拼音之間也像單詞一樣空格隔開,所以才有了“FULLTEXT不支持中文,要把中文轉為拼音”這一說法。
其實,轉拼音也行、按照分詞規則把一個個詞組用空格隔開也好、甚至簡單粗暴的每個字空格隔開都可以,然後把這些用空格隔開的文本存入都數據庫的一個特定字段裡面,也就是數據庫裡面要一份信息要存兩個字段,一段原始文本/一段分詞之後的文本。注意,FULLTEXT 索引要設置在分詞之後的那個字段上面。
優點:與使用like字句相比,更加高效,且MYSQL 原生支持。
缺點:要額外維護一個字段,而且需要自行分詞。使用復雜,有多復雜?請見下文(FULLTEXT全文索引的幾個關鍵點)
三 使用第三方組件,(Coreseek)sphinx、迅搜……
實現方式:把數據中需要搜索的字段連同Id,一起導入到這些第三方組件中去,搜索的時候,調用這些第三方組件提供的api去搜索,得到返回的Id,再根據Id去數據庫查詢。
優點:比上面兩種方案都要高效,且不需要自行分詞。
缺點:需要額外維護這個第三方組件,並且每次更新數據庫都要同時更新它。
而我選擇了方案三,至於維護與同步,都交給了定時任務去做了。
-- FULLTEXT全文索引的幾個關鍵點
1. 表的存儲引擎需要是MyISAM,聽說MYSQL5.6也支持全文索引了;
2. 字段類型:char、varchar和text;
3. MySQL全文索引查詢關鍵詞最小長度限制;
=> ft_min_word_len,默認是4,建議改為1,不然against()對應的關鍵字就只能是4個以上的字符,查不了單個字符,也查不了單個漢字.
=> my.ini配置文件中添加
[mysqld]
ft_min_word_len = 1
=> 設置 ft_min_word_len 之後,要重啟MySQL服務,然後執行 SHOW VARIABLES 查看 ft_min_word_len設置成功沒有;
=> 重新設置配置後,已經設置的索引需要重新設置生成索引,不然有可能報錯,
我在update某些記錄的時候就報錯了: Incorrect key file for table './webm/temp.MYI';try to repair it.
後來, 我執行了 mysql> repair table 表名; 就好了;
5. match(索引名),match()的參數是索引名,不是字段名;
=> MATCH(title, content)裡的參數必須和FULLTEXT(title, content)裡的參數一模一樣。
6. match(singername,songname),可以同時在多個索引名裡面查找關鍵字;
7. 如果一個關鍵詞在50%的數據出現,那麼這個詞會被當做無效詞,可以使用against('關鍵字'IN BOOLEAN MODE)繞過無效設定;
8. 如果搜索多個詞,請用空格或者逗號隔開,如下
=> SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST ('a x');
=> SELECT * FROM `temp` WHERE MATCH(`char`) AGAINST ('a,x');
=> AGAINST('關鍵字1 關鍵字2'),使用逗號或空格隔開多個關鍵字,使用的是or規則.
9. 每次更新表都會重構索引,索引使用了全文索引會拖慢insert和update;
10. 搜索語法規則;
=> + 一定要有(不含有該關鍵詞的數據條均被忽略)。
=> - 不可以有(排除指定關鍵詞,含有該關鍵詞的均被忽略)。
=> " " 用雙引號將一段句子包起來表示要完全相符,不可拆字。