mysql全文索引中文问题的解决(转)
生活随笔
收集整理的這篇文章主要介紹了
mysql全文索引中文问题的解决(转)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
MySQL從3.23.23開始就逐漸支持全文索引和搜尋。?
全文索引就是建index,全文搜尋就是去查index。?
LIKE是用Regular Expression去做查詢。?
MySQL全文索引是一種index type:FULLTEXT。?
全文索引的index只能用在MyISAM表格的char、varchar和text的字段上。?
全文索引的index可以在create table、alter table和create index時產(chǎn)生。?
create table...?
CREATE TABLE article (?
?? id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,?
??? title VARCHAR(200),?
??? body TEXT,?
??? FULLTEXT(title, body)?
) TYPE=MYISAM;?
alter table...?
create index...?
要倒大量的數(shù)據(jù)到有全文索引index的table速度會很慢,建議先拿掉全文索引index再倒數(shù)據(jù),倒完后再加上全文索引index。?
全文搜尋的語法:?
MATCH (col1, col2,...) AGAINST (expr [search_modifier])?
三種搜尋方式:?
IN BOOLEAN MODE?
IN NATURAL LANGUAGE MODE?
IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION / WITH QUERY EXPANSION?
IN NATURAL LANGUAGE MODE?
expr就是要搜尋的字符串。?
沒有特殊字符。?
套用Stopwords。?
剔除一半row以上都有的字,譬如說,每個row都有mysql這個字的話,那用mysql去查時,會找不到任何row,這在row的數(shù)量無敵多時很有用,因為把所有row都找出來是沒有意義的,這時,mysql幾乎被當作是stopword;但是當row只有兩筆時,是啥鬼也查不出來的,因為每個字都出現(xiàn)50%以上,要避免這種狀況,請用IN BOOLEAN MODE。?
預設的搜尋方式。?
SELECT *?
FROM article?
WHERE MATCH(title, body)?
AGAINST ('xxx' IN NATURAL LANGUAGE MODE);?
預設搜尋是不分大小寫,若要分大小寫,columne的character set要從utf8改成utf8_bin。?
預設MATCH...AGAINST是以相關性排序,由高到低。?
MATCH...AGAINST可以跟所有MySQL語法搭配使用,像是JOIN或是加上其他過濾條件。?
-- 第一種count?
SELECT COUNT(*)?
FROM article?
WHERE MATCH(title, body)?
AGAINST ('xxx' IN NATURAL LANGUAGE MODE);?
-- 第二種count?
SELECT COUNT(IF(MATCH(title, body) AGAINST ('xxx' IN NATURAL LANGUAGE MODE), 1, NULL)) AS count?
FROM article?
當符合的筆數(shù)較多時,第一種count比較慢,因為MATCH...AGAINST會先依相關性排序。?
當符合的筆數(shù)較少時,第二種count比較慢,因為第二種count會掃過所有數(shù)據(jù)。?
MATCH(title, body)里的字段必須和FULLTEXT(title, body)里的字段一模一樣,如果只要單查title或body一個字段,那得另外再建一個FULLTEXT(title)或FULLTEXT(body),也因為如此,MATCH()的字段一定不能跨table,但是另外兩種搜尋方式好像可以。?
SELECT id, MATCH(title, body) AGAINST ('xxx' IN NATURAL LANGUAGE MODE) as score?
FROM article;?
這樣可以取得相關值,而且也因為沒有WHERE和ORDER BY,所以不會排序。?
SELECT id, MATCH(title, body) AGAINST ('xxx' IN NATURAL LANGUAGE MODE) as score?
FROM article?
WHERE MATCH(title, body)?
AGAINST ('xxx' IN NATURAL LANGUAGE MODE);?
排序又取得相關性,雖然MATCH...AGAINST用了兩次,但是MySQL知道這兩個MATCH...AGAINST是一樣的,所以只會用一次。?
SELECT id, MATCH(title, body) AGAINST ('xxx' IN NATURAL LANGUAGE MODE) as score?
FROM article?
ORDER BY score desc;?
為啥不這樣用就好??
MySQL的FULLTEXT怎么斷字:?
字母、數(shù)字、底線的組合視為一個字,不會把底線斷字。?
會被斷字的字符:空白、逗號(,)與點(.),但不用這些斷字的語言,如中文,就得自行手動斷字。?
可以自行實做一個斷字的外掛來取代內建的斷字parser。?
接受一個單引號,如aaa'bbb視為一個字,但是aaa''bbb就是兩個字。?
前綴或字尾的單引號會被去掉,如'aaa或aaa'。?
全文搜尋時,stopword與少于四個字符的字符串會被忽略。?
可以覆寫內建的stopword清單。?
可以修改最少四個字符的設定。?
IN BOOLEAN MODE?
expr里有特殊字符輔助特殊的搜尋語法。?
SELECT *?
FROM article?
WHERE MATCH(title, body)?
AGAINST ('+mysql -yoursql' IN BOOLEAN MODE);?
一定要有msysql,且不要有yoursql。?
IN BOOLEAN MODE的特色:?
不剔除50%以上符合的row。?
不自動以相關性反向排序。?
可以對沒有FULLTEXT index的字段進行搜尋,但會非常慢。?
限制最長與最短的字符串。?
套用Stopwords。?
搜尋語法:?
+:一定要有。?
-:不可以有,但這個「不可以有」指的是在符合的row里不可以有指定的字符串,所以不能只下「-yoursql」這樣是查不到任何row的,必須搭配其他語法使用。?
:(什么都沒)預設用法,表示可有可無,有的話排比較前面,沒有的排后面。?
>:提高該字的相關性。?
<:降低相關性。?
( ):條件可以巢狀。?
+aaa +(>bbb <ccc) // 找到有aaa和bbb,或者aaa和ccc,然后aaa&bbb排在aaa&ccc前面?
~:將其相關性由正轉負,表示擁有該字會降低相關性,但不像「-」將之排除,只是排在較后面。?
*:萬用字,不像其他語法放在前面,這個要接在字符串后面。?
" ":用雙引號將一段句子包起來表示要完全相符,不可拆字。?
IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION?
也可以用WITH QUERY EXPANSION。?
IN NATURAL LANGUAGE MODE的衍生版。?
先用IN NATURAL LANGUAGE MODE做搜尋,得到最相關的字段的字再加到原expr里,再查一次。?
神奇功能之一:可以用database查出mysql或oracle,第一次查詢用databae得到一些結果,從這些結果里抽取字符串,此時得到mysql與oracle的機率相當高,最后用database和這些出取出來的字符串做一次查詢。?
神奇功能之二:無法拼出正確字符串時,第一次用「相似」的錯誤字符串查詢,很有可以得到正確的字符串,再用正確的字符串急可以得到想要的結果。?
因為這種查詢方式會讓「噪聲」爆增,所以建議第一次的查詢字符串盡量精簡。?
Stopwords請參考http://dev.mysql.com/doc/refman/5.1/en/fulltext-stopwords.html。?
全文搜尋的限制:?
只能用在MyISAM表格上。?
支援UTF-8。?
中文支持問題:?
MySQL不會斷中文字:MySQL內建的字依據(jù)是空白、逗號和點,對此內建機制的白癡解法是,存中文字時自行塞入空白斷字,但是還是有下面的限制。?
查詢字符串最少四個字符的限制:所以一二三個中文字都不能查,必須將ft_min_word_len從預設的4改成1。?
雖然同一個表格可以有不同字符集的字段,但是同一個FULLTEXT index里的字段必須是同一個字符集與collation。?
MATCH里的字段必須和FULLTEXT里的一模一樣,IN BOOLEAN MODE允許不一樣,甚至使用未FULLTEXT index的字段,但速度很慢。?
AGAINST里必須是字符串,不可以是變量或域名。?
全文搜尋使index hint受限。?
MySQL全文搜尋設定:?
大部分的參數(shù)都是啟動參數(shù),也就是修改后必須重新啟動MySQL。?
有些參數(shù)修改必須重新產(chǎn)生索引文件。?
mysql> SHOW VARIABLES LIKE 'ft%';?
ft_boolean_syntax??? + -><()~*:""&|?
ft_min_word_len??? 4?
ft_max_word_len??? 84?
ft_query_expansion_limit?? 20 ft_stopword_file??? (built-in)?
ft_min_word_len:最短的索引字符串,默認值為4,修改后必須重建索引文件。?
ft_max_word_len:最長的索引字符串,默認值因版本而不同,余同上一點。?
[mysqld]?
ft_min_word_len=1?
ft_stopword_file:stopword檔案路徑,若留空白不設定表示要停用stopword過濾,修改后必須重新啟動MySQL和重建索引;stopword檔案內容可以用分行空白與逗號區(qū)隔stopword,但底線和單引號視為合法的字符串字符。?
50%的門坎限制:配置文件在storage/myisam/ftdefs.h,將 #define GWS_IN_USE GWS_PROB 改為 #define GWS_IN_USE GWS_FREQ,然后重新編譯MySQL,因為近低門坎會影響數(shù)據(jù)的精準度,所以不建議如此,可用IN BOOLEAN MODE即可以避開50%的限制。?
ft_boolean_syntax:改變IN BOOLEAN MODE的查詢字符,不用重新啟動MySQL也不用重建索引。?
修改字符串字符的認定,譬如說將「-」認定為字符串的合法字符:?
方法一:修改storage/myisam/ftdefs.h的true_word_char()與misc_word_char(),然后重新編譯MySQL,最后重建索引。?
方法二:修改字符集檔,然后在FULLTEXT index的字段使用該字符集,最后重建索引。?
重建索引:?
每個有FULLTEXT index的表格都要這么做。?
mysql> REPAIR TABLE tbl_name QUICK;?
要注意如果用過myisamchk,會導致上述的設定值回復成默認值,因為myisamchk不是用MySQL的設定值。?
解法一:將修改過得設定值加到myisamchk的參數(shù)里。?
shell> myisamchk --recover --ft_min_word_len=1 tbl_name.MYI?
解法二:兩邊都要設定。?
[mysqld]?
ft_min_word_len=1?
[myisamchk]?
ft_min_word_len=1?
解法三:用REPAIR TABLE、ANALYZE TABLE、OPTIMIZE TABLE與ALTER TABLE取代myisamchk語法,因為這些語法是由MySQL執(zhí)行的。?
全文索引就是建index,全文搜尋就是去查index。?
LIKE是用Regular Expression去做查詢。?
MySQL全文索引是一種index type:FULLTEXT。?
全文索引的index只能用在MyISAM表格的char、varchar和text的字段上。?
全文索引的index可以在create table、alter table和create index時產(chǎn)生。?
create table...?
CREATE TABLE article (?
?? id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,?
??? title VARCHAR(200),?
??? body TEXT,?
??? FULLTEXT(title, body)?
) TYPE=MYISAM;?
alter table...?
create index...?
要倒大量的數(shù)據(jù)到有全文索引index的table速度會很慢,建議先拿掉全文索引index再倒數(shù)據(jù),倒完后再加上全文索引index。?
全文搜尋的語法:?
MATCH (col1, col2,...) AGAINST (expr [search_modifier])?
三種搜尋方式:?
IN BOOLEAN MODE?
IN NATURAL LANGUAGE MODE?
IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION / WITH QUERY EXPANSION?
IN NATURAL LANGUAGE MODE?
expr就是要搜尋的字符串。?
沒有特殊字符。?
套用Stopwords。?
剔除一半row以上都有的字,譬如說,每個row都有mysql這個字的話,那用mysql去查時,會找不到任何row,這在row的數(shù)量無敵多時很有用,因為把所有row都找出來是沒有意義的,這時,mysql幾乎被當作是stopword;但是當row只有兩筆時,是啥鬼也查不出來的,因為每個字都出現(xiàn)50%以上,要避免這種狀況,請用IN BOOLEAN MODE。?
預設的搜尋方式。?
SELECT *?
FROM article?
WHERE MATCH(title, body)?
AGAINST ('xxx' IN NATURAL LANGUAGE MODE);?
預設搜尋是不分大小寫,若要分大小寫,columne的character set要從utf8改成utf8_bin。?
預設MATCH...AGAINST是以相關性排序,由高到低。?
MATCH...AGAINST可以跟所有MySQL語法搭配使用,像是JOIN或是加上其他過濾條件。?
-- 第一種count?
SELECT COUNT(*)?
FROM article?
WHERE MATCH(title, body)?
AGAINST ('xxx' IN NATURAL LANGUAGE MODE);?
-- 第二種count?
SELECT COUNT(IF(MATCH(title, body) AGAINST ('xxx' IN NATURAL LANGUAGE MODE), 1, NULL)) AS count?
FROM article?
當符合的筆數(shù)較多時,第一種count比較慢,因為MATCH...AGAINST會先依相關性排序。?
當符合的筆數(shù)較少時,第二種count比較慢,因為第二種count會掃過所有數(shù)據(jù)。?
MATCH(title, body)里的字段必須和FULLTEXT(title, body)里的字段一模一樣,如果只要單查title或body一個字段,那得另外再建一個FULLTEXT(title)或FULLTEXT(body),也因為如此,MATCH()的字段一定不能跨table,但是另外兩種搜尋方式好像可以。?
SELECT id, MATCH(title, body) AGAINST ('xxx' IN NATURAL LANGUAGE MODE) as score?
FROM article;?
這樣可以取得相關值,而且也因為沒有WHERE和ORDER BY,所以不會排序。?
SELECT id, MATCH(title, body) AGAINST ('xxx' IN NATURAL LANGUAGE MODE) as score?
FROM article?
WHERE MATCH(title, body)?
AGAINST ('xxx' IN NATURAL LANGUAGE MODE);?
排序又取得相關性,雖然MATCH...AGAINST用了兩次,但是MySQL知道這兩個MATCH...AGAINST是一樣的,所以只會用一次。?
SELECT id, MATCH(title, body) AGAINST ('xxx' IN NATURAL LANGUAGE MODE) as score?
FROM article?
ORDER BY score desc;?
為啥不這樣用就好??
MySQL的FULLTEXT怎么斷字:?
字母、數(shù)字、底線的組合視為一個字,不會把底線斷字。?
會被斷字的字符:空白、逗號(,)與點(.),但不用這些斷字的語言,如中文,就得自行手動斷字。?
可以自行實做一個斷字的外掛來取代內建的斷字parser。?
接受一個單引號,如aaa'bbb視為一個字,但是aaa''bbb就是兩個字。?
前綴或字尾的單引號會被去掉,如'aaa或aaa'。?
全文搜尋時,stopword與少于四個字符的字符串會被忽略。?
可以覆寫內建的stopword清單。?
可以修改最少四個字符的設定。?
IN BOOLEAN MODE?
expr里有特殊字符輔助特殊的搜尋語法。?
SELECT *?
FROM article?
WHERE MATCH(title, body)?
AGAINST ('+mysql -yoursql' IN BOOLEAN MODE);?
一定要有msysql,且不要有yoursql。?
IN BOOLEAN MODE的特色:?
不剔除50%以上符合的row。?
不自動以相關性反向排序。?
可以對沒有FULLTEXT index的字段進行搜尋,但會非常慢。?
限制最長與最短的字符串。?
套用Stopwords。?
搜尋語法:?
+:一定要有。?
-:不可以有,但這個「不可以有」指的是在符合的row里不可以有指定的字符串,所以不能只下「-yoursql」這樣是查不到任何row的,必須搭配其他語法使用。?
:(什么都沒)預設用法,表示可有可無,有的話排比較前面,沒有的排后面。?
>:提高該字的相關性。?
<:降低相關性。?
( ):條件可以巢狀。?
+aaa +(>bbb <ccc) // 找到有aaa和bbb,或者aaa和ccc,然后aaa&bbb排在aaa&ccc前面?
~:將其相關性由正轉負,表示擁有該字會降低相關性,但不像「-」將之排除,只是排在較后面。?
*:萬用字,不像其他語法放在前面,這個要接在字符串后面。?
" ":用雙引號將一段句子包起來表示要完全相符,不可拆字。?
IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION?
也可以用WITH QUERY EXPANSION。?
IN NATURAL LANGUAGE MODE的衍生版。?
先用IN NATURAL LANGUAGE MODE做搜尋,得到最相關的字段的字再加到原expr里,再查一次。?
神奇功能之一:可以用database查出mysql或oracle,第一次查詢用databae得到一些結果,從這些結果里抽取字符串,此時得到mysql與oracle的機率相當高,最后用database和這些出取出來的字符串做一次查詢。?
神奇功能之二:無法拼出正確字符串時,第一次用「相似」的錯誤字符串查詢,很有可以得到正確的字符串,再用正確的字符串急可以得到想要的結果。?
因為這種查詢方式會讓「噪聲」爆增,所以建議第一次的查詢字符串盡量精簡。?
Stopwords請參考http://dev.mysql.com/doc/refman/5.1/en/fulltext-stopwords.html。?
全文搜尋的限制:?
只能用在MyISAM表格上。?
支援UTF-8。?
中文支持問題:?
MySQL不會斷中文字:MySQL內建的字依據(jù)是空白、逗號和點,對此內建機制的白癡解法是,存中文字時自行塞入空白斷字,但是還是有下面的限制。?
查詢字符串最少四個字符的限制:所以一二三個中文字都不能查,必須將ft_min_word_len從預設的4改成1。?
雖然同一個表格可以有不同字符集的字段,但是同一個FULLTEXT index里的字段必須是同一個字符集與collation。?
MATCH里的字段必須和FULLTEXT里的一模一樣,IN BOOLEAN MODE允許不一樣,甚至使用未FULLTEXT index的字段,但速度很慢。?
AGAINST里必須是字符串,不可以是變量或域名。?
全文搜尋使index hint受限。?
MySQL全文搜尋設定:?
大部分的參數(shù)都是啟動參數(shù),也就是修改后必須重新啟動MySQL。?
有些參數(shù)修改必須重新產(chǎn)生索引文件。?
mysql> SHOW VARIABLES LIKE 'ft%';?
ft_boolean_syntax??? + -><()~*:""&|?
ft_min_word_len??? 4?
ft_max_word_len??? 84?
ft_query_expansion_limit?? 20 ft_stopword_file??? (built-in)?
ft_min_word_len:最短的索引字符串,默認值為4,修改后必須重建索引文件。?
ft_max_word_len:最長的索引字符串,默認值因版本而不同,余同上一點。?
[mysqld]?
ft_min_word_len=1?
ft_stopword_file:stopword檔案路徑,若留空白不設定表示要停用stopword過濾,修改后必須重新啟動MySQL和重建索引;stopword檔案內容可以用分行空白與逗號區(qū)隔stopword,但底線和單引號視為合法的字符串字符。?
50%的門坎限制:配置文件在storage/myisam/ftdefs.h,將 #define GWS_IN_USE GWS_PROB 改為 #define GWS_IN_USE GWS_FREQ,然后重新編譯MySQL,因為近低門坎會影響數(shù)據(jù)的精準度,所以不建議如此,可用IN BOOLEAN MODE即可以避開50%的限制。?
ft_boolean_syntax:改變IN BOOLEAN MODE的查詢字符,不用重新啟動MySQL也不用重建索引。?
修改字符串字符的認定,譬如說將「-」認定為字符串的合法字符:?
方法一:修改storage/myisam/ftdefs.h的true_word_char()與misc_word_char(),然后重新編譯MySQL,最后重建索引。?
方法二:修改字符集檔,然后在FULLTEXT index的字段使用該字符集,最后重建索引。?
重建索引:?
每個有FULLTEXT index的表格都要這么做。?
mysql> REPAIR TABLE tbl_name QUICK;?
要注意如果用過myisamchk,會導致上述的設定值回復成默認值,因為myisamchk不是用MySQL的設定值。?
解法一:將修改過得設定值加到myisamchk的參數(shù)里。?
shell> myisamchk --recover --ft_min_word_len=1 tbl_name.MYI?
解法二:兩邊都要設定。?
[mysqld]?
ft_min_word_len=1?
[myisamchk]?
ft_min_word_len=1?
解法三:用REPAIR TABLE、ANALYZE TABLE、OPTIMIZE TABLE與ALTER TABLE取代myisamchk語法,因為這些語法是由MySQL執(zhí)行的。?
轉載于:https://www.cnblogs.com/macula7/archive/2011/05/18/2050525.html
總結
以上是生活随笔為你收集整理的mysql全文索引中文问题的解决(转)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [转]const使用详解
- 下一篇: SQL 语句 - Select(1):