全文索引

概念
通過數(shù)值比較义钉、范圍過濾等就可以完成絕大多數(shù)我們需要的查詢,但是规肴,如果希望通過關(guān)鍵字的匹配來進行查詢過濾捶闸,那么就需要基于相似度的查詢,而不是原來的精確數(shù)值比較拖刃。全文索引就是為這種場景設(shè)計的删壮。

你可能會說,用 like + % 就可以實現(xiàn)模糊匹配了兑牡,為什么還要全文索引央碟?like + % 在文本比較少時是合適的,但是對于大量的文本數(shù)據(jù)檢索均函,是不可想象的硬耍。全文索引在大量的數(shù)據(jù)面前,能比 like + % 快 N 倍边酒,速度不是一個數(shù)量級,但是全文索引可能存在精度問題狸窘。

你可能沒有注意過全文索引墩朦,不過至少應(yīng)該對一種全文索引技術(shù)比較熟悉:各種的搜索引擎。雖然搜索引擎的索引對象是超大量的數(shù)據(jù)翻擒,并且通常其背后都不是關(guān)系型數(shù)據(jù)庫氓涣,不過全文索引的基本原理是一樣的。

版本支持
開始之前陋气,先說一下全文索引的版本劳吠、存儲引擎、數(shù)據(jù)類型的支持情況

MySQL 5.6 以前的版本巩趁,只有 MyISAM 存儲引擎支持全文索引痒玩;
MySQL 5.6 及以后的版本,MyISAM 和 InnoDB 存儲引擎均支持全文索引;
只有字段的數(shù)據(jù)類型為 char、varchar蠢古、text 及其系列才可以建全文索引奴曙。
測試或使用全文索引時,要先看一下自己的 MySQL 版本草讶、存儲引擎和數(shù)據(jù)類型是否支持全文索引洽糟。

操作全文索引
索引的操作隨便一搜都是,這里還是再啰嗦一遍堕战。

創(chuàng)建
創(chuàng)建表時創(chuàng)建全文索引
create table fulltext_test (
id int(11) NOT NULL AUTO_INCREMENT,
content text NOT NULL,
tag varchar(255),
PRIMARY KEY (id),
FULLTEXT KEY content_tag_fulltext(content,tag) // 創(chuàng)建聯(lián)合全文索引列
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

在已存在的表上創(chuàng)建全文索引
create fulltext index content_tag_fulltext
on fulltext_test(content,tag);

通過 SQL 語句 ALTER TABLE 創(chuàng)建全文索引
alter table fulltext_test
add fulltext index content_tag_fulltext(content,tag);

修改
修改個 O整吆,直接刪掉重建黄伊。

刪除
直接使用 DROP INDEX 刪除全文索引
drop index content_tag_fulltext
on fulltext_test;

通過 SQL 語句 ALTER TABLE 刪除全文索引
alter table fulltext_test
drop index content_tag_fulltext;

使用全文索引
和常用的模糊匹配使用 like + % 不同,全文索引有自己的語法格式,使用 match 和 against 關(guān)鍵字务荆,比如

select * from fulltext_test
where match(content,tag) against('xxx xxx');

注意: match() 函數(shù)中指定的列必須和全文索引中指定的列完全相同,否則就會報錯皂冰,無法使用全文索引贿讹,這是因為全文索引不會記錄關(guān)鍵字來自哪一列。如果想要對某一列使用全文索引伐谈,請單獨為該列創(chuàng)建全文索引烂完。

測試全文索引
添加測試數(shù)據(jù)
有了上面的知識,就可以測試一下全文索引了诵棵。

首先創(chuàng)建測試表抠蚣,插入測試數(shù)據(jù)

create table test (
id int(11) unsigned not null auto_increment,
content text not null,
primary key(id),
fulltext key content_index(content)
) engine=MyISAM default charset=utf8;

insert into test (content) values ('a'),('b'),('c');
insert into test (content) values ('aa'),('bb'),('cc');
insert into test (content) values ('aaa'),('bbb'),('ccc');
insert into test (content) values ('aaaa'),('bbbb'),('cccc');

按照全文索引的使用語法執(zhí)行下面查詢

select * from test where match(content) against('a');
select * from test where match(content) against('aa');
select * from test where match(content) against('aaa');

根據(jù)我們的慣性思維,應(yīng)該會顯示 4 條記錄才對履澳,然而結(jié)果是 1 條記錄也沒有嘶窄,只有在執(zhí)行下面的查詢時

select * from test where match(content) against('aaaa');

才會搜到 aaaa 這 1 條記錄。

為什么距贷?這個問題有很多原因柄冲,其中最常見的就是 最小搜索長度 導(dǎo)致的。另外插一句忠蝗,使用全文索引時现横,測試表里至少要有 4 條以上的記錄,否則阁最,會出現(xiàn)意想不到的結(jié)果戒祠。

MySQL 中的全文索引,有兩個變量速种,最小搜索長度和最大搜索長度姜盈,對于長度小于最小搜索長度和大于最大搜索長度的詞語,都不會被索引配阵。通俗點就是說馏颂,想對一個詞語使用全文索引搜索示血,那么這個詞語的長度必須在以上兩個變量的區(qū)間內(nèi)。

這兩個的默認值可以使用以下命令查看

show variables like '%ft%';

可以看到這兩個變量在 MyISAM 和 InnoDB 兩種存儲引擎下的變量名和默認值

// MyISAM
ft_min_word_len = 4;
ft_max_word_len = 84;

// InnoDB
innodb_ft_min_token_size = 3;
innodb_ft_max_token_size = 84;

可以看到最小搜索長度 MyISAM 引擎下默認是 4饱亮,InnoDB 引擎下是 3矾芙,也即,MySQL 的全文索引只會對長度大于等于 4 或者 3 的詞語建立索引近上,而剛剛搜索的只有 aaaa 的長度大于等于 4剔宪。

配置最小搜索長度
全文索引的相關(guān)參數(shù)都無法進行動態(tài)修改,必須通過修改 MySQL 的配置文件來完成壹无。修改最小搜索長度的值為 1葱绒,首先打開 MySQL 的配置文件 /etc/my.cnf,在 [mysqld] 的下面追加以下內(nèi)容

[mysqld]
innodb_ft_min_token_size = 1
ft_min_word_len = 1

然后重啟 MySQL 服務(wù)器斗锭,并修復(fù)全文索引地淀。注意,修改完參數(shù)以后岖是,一定要修復(fù)下索引帮毁,不然參數(shù)不會生效。

兩種修復(fù)方式豺撑,可以使用下面的命令修復(fù)

repair table test quick;

或者直接刪掉重新建立索引烈疚,再次執(zhí)行上面的查詢,a聪轿、aa爷肝、aaa 就都可以查出來了。

但是陆错,這里還有一個問題灯抛,搜索關(guān)鍵字 a 時,為什么 aa音瓷、aaa对嚼、aaaa 沒有出現(xiàn)結(jié)果中,講這個問題之前绳慎,先說說兩種全文索引纵竖。

兩種全文索引
自然語言的全文索引
默認情況下,或者使用 in natural language mode 修飾符時偷线,match() 函數(shù)對文本集合執(zhí)行自然語言搜索,上面的例子都是自然語言的全文索引沽甥。

自然語言搜索引擎將計算每一個文檔對象和查詢的相關(guān)度声邦。這里,相關(guān)度是基于匹配的關(guān)鍵詞的個數(shù)摆舟,以及關(guān)鍵詞在文檔中出現(xiàn)的次數(shù)亥曹。在整個索引中出現(xiàn)次數(shù)越少的詞語邓了,匹配時的相關(guān)度就越高。相反媳瞪,非常常見的單詞將不會被搜索骗炉,如果一個詞語的在超過 50% 的記錄中都出現(xiàn)了,那么自然語言的搜索將不會搜索這類詞語蛇受。上面提到的句葵,測試表中必須有 4 條以上的記錄,就是這個原因兢仰。

這個機制也比較好理解乍丈,比如說,一個數(shù)據(jù)表存儲的是一篇篇的文章把将,文章中的常見詞轻专、語氣詞等等,出現(xiàn)的肯定比較多察蹲,搜索這些詞語就沒什么意義了请垛,需要搜索的是那些文章中有特殊意義的詞,這樣才能把文章區(qū)分開洽议。

布爾全文索引
在布爾搜索中宗收,我們可以在查詢中自定義某個被搜索的詞語的相關(guān)性,當編寫一個布爾搜索查詢時绞铃,可以通過一些前綴修飾符來定制搜索镜雨。

MySQL 內(nèi)置的修飾符,上面查詢最小搜索長度時儿捧,搜索結(jié)果 ft_boolean_syntax 變量的值就是內(nèi)置的修飾符荚坞,下面簡單解釋幾個,更多修飾符的作用可以查手冊

  • 必須包含該詞
  • 必須不包含該詞

提高該詞的相關(guān)性菲盾,查詢的結(jié)果靠前
< 降低該詞的相關(guān)性颓影,查詢的結(jié)果靠后
(*)星號 通配符,只能接在詞后面
對于上面提到的問題懒鉴,可以使用布爾全文索引查詢來解決诡挂,使用下面的命令,a临谱、aa璃俗、aaa、aaaa 就都被查詢出來了悉默。

select * test where match(content) against('a*' in boolean mode);

總結(jié)
好了城豁,差不多寫完了,又到了總結(jié)的時候抄课。

MySQL 的全文索引最開始僅支持英語唱星,因為英語的詞與詞之間有空格雳旅,使用空格作為分詞的分隔符是很方便的。亞洲文字间聊,比如漢語攒盈、日語、漢語等哎榴,是沒有空格的型豁,這就造成了一定的限制。不過 MySQL 5.7.6 開始叹话,引入了一個 ngram 全文分析器來解決這個問題偷遗,并且對 MyISAM 和 InnoDB 引擎都有效。

事實上驼壶,MyISAM 存儲引擎對全文索引的支持有很多的限制氏豌,例如表級別鎖對性能的影響、數(shù)據(jù)文件的崩潰热凹、崩潰后的恢復(fù)等泵喘,這使得 MyISAM 的全文索引對于很多的應(yīng)用場景并不適合。所以般妙,多數(shù)情況下的建議是使用別的解決方案纪铺,例如 Sphinx、Lucene 等等第三方的插件碟渺,亦或是使用 InnoDB 存儲引擎的全文索引鲜锚。

幾個注意點
使用全文索引前,搞清楚版本支持情況苫拍;
全文索引比 like + % 快 N 倍芜繁,但是可能存在精度問題;
如果需要全文索引的是大量數(shù)據(jù)绒极,建議先添加數(shù)據(jù)骏令,再創(chuàng)建索引;
對于中文垄提,可以使用 MySQL 5.7.6 之后的版本榔袋,或者第三方插件。
————————————————
版權(quán)聲明:本文為CSDN博主「潛心做事GG」的原創(chuàng)文章铡俐,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議凰兑,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/mrzhouxiaofei/article/details/79940958

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末审丘,一起剝皮案震驚了整個濱河市吏够,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖稿饰,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異露泊,居然都是意外死亡喉镰,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門惭笑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來侣姆,“玉大人,你說我怎么就攤上這事沉噩∞嘧冢” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵川蒙,是天一觀的道長蚜厉。 經(jīng)常有香客問我,道長畜眨,這世上最難降的妖魔是什么昼牛? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮康聂,結(jié)果婚禮上贰健,老公的妹妹穿的比我還像新娘。我一直安慰自己恬汁,他們只是感情好伶椿,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著氓侧,像睡著了一般脊另。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上甘苍,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天尝蠕,我揣著相機與錄音,去河邊找鬼载庭。 笑死看彼,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的囚聚。 我是一名探鬼主播靖榕,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼顽铸!你這毒婦竟也來了茁计?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤谓松,失蹤者是張志新(化名)和其女友劉穎星压,沒想到半個月后践剂,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡娜膘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年逊脯,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片竣贪。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡军洼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出演怎,到底是詐尸還是另有隱情匕争,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布爷耀,位于F島的核電站甘桑,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏歹叮。R本人自食惡果不足惜扇住,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望盗胀。 院中可真熱鬧艘蹋,春花似錦、人聲如沸票灰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽屑迂。三九已至浸策,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惹盼,已是汗流浹背庸汗。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留手报,地道東北人蚯舱。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像掩蛤,于是被迫代替她去往敵國和親枉昏。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348