mysql中文全文搜尋
Elasticsearch 是全文搜尋的首選,但是對於資金沒有那麼充足,或者資料量沒有那麼多的團隊,MySQL 提供的全文搜尋已經可以滿足需求。
MySQL 的全文搜尋預設不支援中文,如果要支援中文,要在配置里加入
[mysqld] ngram_token_size=2
這個時候 MySQL 可以搜尋至少兩個字的關鍵詞,1個字還是不能搜尋的。然後在建索引的時候要設定 WITH PARSER ngram
mysql> USE test; mysql> CREATE TABLE articles ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), body TEXT, FULLTEXT (title,body) WITH PARSER ngram ) ENGINE=InnoDB CHARACTER SET utf8mb4; mysql> SET NAMES utf8mb4; INSERT INTO articles (title,body) VALUES ('資料庫管理','在本教程中我將向你展示如何管理資料庫'), ('資料庫應用開發','學習開發資料庫應用程式');
對於已存在的表,這樣建立索引
CREATE TABLE articles ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), body TEXT ) ENGINE=InnoDB CHARACTER SET utf8; ALTER TABLE articles ADD FULLTEXT INDEX ft_index (title,body) WITH PARSER ngram; # Or: CREATE FULLTEXT INDEX ft_index ON articles (title,body) WITH PARSER ngram;
現在可以這樣搜尋
SELECT * FROM articles WHERE MATCH(title,body) AGAINST('資料庫教程');
注意這裡不管是索引還是關鍵詞“資料庫教程”,我都沒有做分詞,MySQL都自動處理了。
高階
IN NATURAL LANGUAGE MODE
預設的搜尋方式是 IN NATURAL LANGUAGE MODE,即全部匹配關鍵詞,使用如下
mysql> SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('database' IN NATURAL LANGUAGE MODE); +----+-------------------+------------------------------------------+ | id | title| body| +----+-------------------+------------------------------------------+ |1 | MySQL Tutorial| DBMS stands for DataBase ...| |5 | MySQL vs. YourSQL | In the following database comparison ... | +----+-------------------+------------------------------------------+ 2 rows in set (0.00 sec)
即使不加 IN NATURAL LANGUAGE MODE 也是這個結果
IN BOOLEAN MODE
BOOLEAN MODE 提供高階搜尋方法,使用如下
mysql> SELECT * FROM articles WHERE MATCH (title,body) AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE); +----+-----------------------+-------------------------------------+ | id | title| body| +----+-----------------------+-------------------------------------+ |1 | MySQL Tutorial| DBMS stands for DataBase ...| |2 | How To Use MySQL Well | After you went through a ...| |3 | Optimizing MySQL| In this tutorial we will show ...| |4 | 1001 MySQL Tricks| 1. Never run mysqld as root. 2. ... | |6 | MySQL Security| When configured properly, MySQL ... | +----+-----------------------+-------------------------------------+
這裡關鍵詞裡面的
- +表示必須有
- -表示必須沒有
- 不加符號表示可有可沒有
- @表示距離,即關鍵詞必須在某距離內,例如 MATCH(col1) AGAINST(‘“word1 word2 word3” @8’ IN BOOLEAN MODE)
- < > 這兩個符號表示關鍵詞權重,> 提升權重,< 降低權重
- ( ) 表示表示式優先順序
- ~ 表示關鍵詞可以沒有,如果有,則降低權重
- *匹配以關鍵詞開始的詞(見下面例子)
- “ 匹配完整的詞
例子:
-
‘apple banana’
包含至少一個詞
-
‘+apple + juice’
必須包含兩個詞
-
‘+apple macintosh’
包含”apple”,如果也包含“macintosh”則提高優先順序
-
‘+apple -macintosh’
包含’apple’但是不能包含 ‘macintosh’
-
‘+apple ~macintosh’
包含’apple’,如果也包含’macintosh’,則降低優先順序
-
‘+apple +(>turnover <strudel)’
包含 ‘apple’ 和 ‘turnover’,或者 ‘apple’ 和 ‘strudel’(順序不限),前者比後者優先順序高
-
‘apple*’
匹配所有’apple’開頭的詞,如’apples’,’applesauce’,或’applet’
-
‘“some words”‘
匹配完整的詞,例如匹配”some words of wisdom”,但不匹配”some noise words”
最佳實踐
- 如果索引是 (title,body),則不能只搜尋 title 或 body
- 有時候我們要去掉表裡的某一行,不是刪除,而是做一個標記,例如 isDeleted。由於全文索引是單獨的索引,不能同時包含 isDeleted 列,所以資料量大的話,建議單獨建表來存放,而不是在原表上建立索引
參考資料:
MySQL中文支援設定https://dev.mysql.com/doc/refman/5.7/en/fulltext-search-ngram.html
BOOLEAN MODEhttps://dev.mysql.com/doc/refman/5.7/en/fulltext-boolean.html