全文檢索、文檔、倒排索引與分詞
今天還是概念性的內(nèi)容,但是這些概念卻是整個搜索引擎中最重要的概念。可以說,所有的搜索引擎就是實(shí)現(xiàn)了類似的概念才能稱之為搜索引擎。而且今天的內(nèi)容其實(shí)都是相關(guān)聯(lián)的,所以不要以為標(biāo)題上有四個名詞就感覺好像內(nèi)容很多一樣,其實(shí)它們都是聯(lián)系緊密的,一環(huán)套一環(huán)的。
全文檢索
先來看看啥叫 全文檢索 。
全文檢索是指計(jì)算機(jī)索引程序通過掃描文章中的每一個詞,對每一個詞建立一個索引,指明該詞在文章中出現(xiàn)的次數(shù)和位置,當(dāng)用戶查詢時,檢索程序就根據(jù)事先建立的索引進(jìn)行查找,并將查找的結(jié)果反饋給用戶的檢索方式。這個過程類似于通過字典中的檢索字表查字的過程。全文搜索搜索引擎數(shù)據(jù)庫中的數(shù)據(jù)。
又是百科上的定義。但是,不管是 XS 還是 ES ,我們有時也都會叫它們?yōu)?全文檢索引擎 。現(xiàn)在知道了吧,搜索引擎組件,最核心的功能其實(shí)就在于全文檢索的能力。而在全文檢索的過程中,最核心的又是索引的建立,在上面概念中那句:通過字典中的檢索字表查字的過程。就是對于索引這個概念的一般性描述。
在學(xué)習(xí) ES 的過程中,會提到兩個概念,我覺得這兩個概念也是非常重要的。那就是 精確值 和 全文本 。
精確值:那些不需要建立索引、不需要分詞的確定值,比如說 ID、時間、數(shù)字,也就是我們在 MySQL 中不會用到 Like 的字段。
全文本:需要分詞,需要對內(nèi)容建立索引的值,比如文章標(biāo)題、關(guān)鍵字、內(nèi)容、描述等,一般都是 Text 類型,是我們搜索時主要面對的內(nèi)容,也是我們在 MySQL 中需要進(jìn)行 Like 查詢的字段。
有了這兩個概念之后,以后我們在建立索引時,就可以根據(jù)字段的不同情況,來決定字段是否應(yīng)該分詞建索引。如果不管任何字段都建立索引的話,會導(dǎo)致索引巨大,帶來額外的存儲及性能開銷。
在全文檢索中,還有兩個概念,那就是 按字檢索 和 按詞檢索 。
對于英文來說,搜索分詞其實(shí)并不困難。因?yàn)橛⑽脑跁鴮憰r天生就有空格分隔。即使是一些簡寫,比如 I'm ,也可以直接劃分為整個詞,或者做成 I am 的替換詞或近意詞。但中文就不一樣了。就像這一段話,你覺得要怎么切分呢?能切出來多少詞呢?用程序怎么實(shí)現(xiàn)?
這就是中文分詞的難點(diǎn)。如果說 按字檢索 ,就會導(dǎo)致索引巨大。每一個字,每一個字和后面的句子的連接,都要建立索引。比如“我愛北京天安門”,如果按字分詞檢索,需要切分成:
我
愛
北
京
天
安
門
看著還好是吧?但是換成一整篇文章呢?再換成上百萬篇文章呢?
那么按詞分詞檢索呢?我們就可以把上面那句話切分成:
我愛
北京
天安門
先不說查詢,至少存儲空間就能節(jié)約不少吧。后面我們馬上就會詳細(xì)地說分詞這件事。
文檔
文檔在搜索引擎中,就是實(shí)際的存儲的數(shù)據(jù)單元。說直白點(diǎn),就是我們在 MySQL 的那一行數(shù)據(jù),將一行數(shù)據(jù)放到搜索引擎中,就是一篇文檔。只不過這個文檔是結(jié)構(gòu)化的,有結(jié)構(gòu)屬性的,有字段名和值,可以被查詢檢索出來的數(shù)據(jù)。在搜索引擎中,文檔是一個重要的概念,我們增、刪、改、查操作的都是文檔。而文檔在進(jìn)行上述操作時,又會關(guān)聯(lián)到索引的建立。
在 XS 中,使用 PHP SDK 時,專門的 XSDocument 是貫穿我們學(xué)習(xí)始終的一個對象。同樣地,在 ES 中,所有數(shù)據(jù)只有一個 type 類型,就是 _doc 類型。這個不用多解釋了吧,doc 就是文檔的意思。
或者再換句話說,我們上面所說的全文檢索引擎,以及我們這個系列要學(xué)習(xí)的搜索引擎,這兩個概念,最終都會落在 文檔搜索引擎 這個概念上。因?yàn)椴还茏侄螌傩匀绾?,我們其?shí)一直都是在搜索文檔。
倒排索引
到我們的重點(diǎn)概念咯,這也是常見的面試題。那就是啥是倒排索引?
要理解倒排索引(反向索引),我們就先要了解一下正排索引(正向索引)是啥。這個其實(shí)不用多說了吧,普通關(guān)系型數(shù)據(jù)庫的索引都是正排索引嘛。我們?yōu)槟硞€字段建立索引,然后形成一顆 B+樹 。大概長這樣。
典型的一個 MySQL InnoDB B+樹索引圖,數(shù)據(jù)有三個字段,id、name、age ,然后 id 上有主鍵索引,name 和 age 做了聯(lián)合索引。在關(guān)系型數(shù)據(jù)庫中,索引上存儲的是字段具體的值,然后索引根據(jù)這些值排序。這樣在搜索查找時就可以利用類似于二分查找的方式快速找到與查找值匹配的索引項(xiàng)目。如果是普通索引,則會找到最終的主鍵 ID ,進(jìn)而再使用主鍵 ID 通過主鍵索引(聚集索引)返表查詢出實(shí)際的數(shù)據(jù)。
這一套內(nèi)容大家在學(xué)習(xí)數(shù)據(jù)庫相關(guān)知識的時候應(yīng)該都會看到,這個不是我們的重點(diǎn)內(nèi)容,畢竟咱們現(xiàn)在是要講搜索引擎呀。那么搜索引擎里的倒排索引是啥意思呢?還是看圖來說。
不得不說,倒排索引的圖還好畫一些。在這個圖中,我們假設(shè)全文本字段為 subject 和 message ,那么我們就需要對這兩個字段中的內(nèi)容進(jìn)行分詞,根據(jù)分詞結(jié)果形成一個倒排表。各位大佬一眼就明白了吧,每個詞項(xiàng)對應(yīng)記錄的就是這個詞所在的文檔的 ID 。當(dāng)然,實(shí)際上的倒排索引內(nèi)容可能不止這兩個字段,還會包括關(guān)鍵字在文檔中的位置等信息。這里就是簡單地以最核心的單詞和文檔的關(guān)系來講解。
是的,這就是倒排索引。其實(shí)最終,它獲得的結(jié)果和 B+樹 的普通索引是類似的,最終都是保存著一份主鍵 ID ,但 B+樹 索引的值是整個表行字段的值,最終記錄是在所有分枝之后的一個葉子節(jié)點(diǎn)上,而且只有一個值。而倒排索引保存的值是一個一個的詞項(xiàng),相同詞項(xiàng)只會有一份,最終記錄是一組 ID 。
要說一個比較實(shí)際點(diǎn)的例子的話,請唱出《孤勇者》的三句歌詞和請說出歌詞中包含包含“我愛你”的三首歌名,這種“根據(jù)題目查找內(nèi)容”和“根據(jù)關(guān)鍵字查找題目”的形式其實(shí)是完全相反的,分別代表的就是正排索引(整個字段建立索引,就像是個題目)和倒排索引(將內(nèi)容分成單詞變成一個字典,通過字典查找內(nèi)容和題目)。(極客時間:檢索核心技術(shù)20講,關(guān)于倒排索引的解釋)
如果數(shù)據(jù)非常多,而且也都是大篇文章,那么其實(shí)這個詞項(xiàng)列表的內(nèi)容也不少。這時候,大部分搜索引擎其實(shí)會在詞項(xiàng)上再次運(yùn)用 B+樹 ,也就是通過二分法能夠快速定位詞項(xiàng)。這樣,就可以最快(最理想狀態(tài)下)通過 O(logn) + O(1) 的速度定位到包含某一個詞的全部文檔 ID 。
如果我們同時搜索多個關(guān)鍵詞,則會在獲得所有關(guān)鍵詞對應(yīng)的文檔 ID 后,再進(jìn)行歸并或多路歸并排序的方法遍歷兩個單詞中所有的文檔 ID 所對應(yīng)的內(nèi)容,從而達(dá)到 O(m+n) 的速度,這里的 m 和 n 指的是單詞對應(yīng)文檔 ID 列表,而不是正排索引中的全文檔搜索的 n 。因此,它的效率還是可以接受的。(極客時間:檢索核心技術(shù)20講及百度查詢相關(guān)資料)具體的算法原理已經(jīng)不是我能達(dá)到的水平的,各位感興趣的大佬們還是自己再查找資料進(jìn)行深入的學(xué)習(xí)吧。
那么如果是傳統(tǒng)關(guān)系型數(shù)據(jù)庫的 Like 呢?首先,如果是大型的文章內(nèi)容,索引會非常大,空間極度浪費(fèi)。其次,如果是前后都模糊,也就是 like '%項(xiàng)目%'
這種,索引會失效。因?yàn)槲覀円枰饌€文字比較,然后再逐個文檔匹配,性能可想而知。
再換個角度用生活中的例子來理解,最典型的就是圖書目錄。我們最常見的那個圖書目錄,就是根據(jù)章節(jié)標(biāo)題的一個正排索引。而有的書,特別是一些專業(yè)型的大型經(jīng)典圖書,就是特別厚的那種。往往在這些書的最后還會有一些詞匯表,有的詞匯表不僅有詞匯的解釋,還有這些詞匯在哪些章節(jié)出現(xiàn)過,甚至是具體的頁號。這種帶章節(jié)號或者頁號的詞匯表就是倒排索引。比如下面這本計(jì)算機(jī)經(jīng)典黑皮書《數(shù)據(jù)庫系統(tǒng)概念》中最后的索引部分的內(nèi)容。加微信或者公眾號,可以找我要到很多電子書哦,其中就包括這本書。
好了,從倒排索引這里,我們可以看到 分詞 真的是對倒排索引非常重要的一個概念,那么我們就再來理解一下什么叫分詞。
分詞
顧名思義,分詞,就是將一句話,一個段落或者一整篇文章中的單詞分解出來。對應(yīng)到我們的數(shù)據(jù)中,其實(shí)就是將文檔中,需要全文本分析的字段內(nèi)容進(jìn)行分詞處理,然后將獲取到的分詞加入到倒排索引表。
前面我們就說過,英文分詞會相對來說簡單一些,中文分詞要復(fù)雜一些。因此,我們平常不管是使用 ES ,還是 Solr、Sphinx 之類的搜索引擎,都需要同時配置一個中文分詞器?,F(xiàn)在最流行的,一個是 Jieba ,Python 領(lǐng)域非常出名也是現(xiàn)在整個開發(fā)領(lǐng)域都比較流行的分詞器。另一個是 IK ,這個是最經(jīng)典的配合 ES 的分詞器,當(dāng)然,Jieba 也有 ES 的插件。
雖說這兩個現(xiàn)在很流行,很出名,但咱們的 XS 所使用的 SCWS ,則是還沒有它們的時候就已經(jīng)存在的,通過 C/C++ 開發(fā)的一款優(yōu)秀分詞器。最早,甚至 ES 還沒發(fā)布的時候,大概 2011 年左右(ES最早是2010年發(fā)布的)。我所在的公司使用 Solr 作為搜索引擎,而當(dāng)時配合 Solr 的分詞器就是 SCWS 。
還有更早的,我剛畢業(yè)時做過一年 C# ,也就是 ASP.NET 開發(fā),大概是 ?2009 年。當(dāng)時的公司使用的是 Lucene.NET 配合 Pangu 分詞。
可以看到,不管你是用什么搜索引擎,要在中文世界里使用,分詞器都是必不可少的。同時,分詞器也不是你理解的就是切分個單詞就完了,它還要考慮詞性,比如動、名、形容詞。這些詞性又會影響到詞頻和逆文檔詞頻分?jǐn)?shù)以及是否索引。再比如助詞、語氣詞:嗯、啊、哈,這些,大部分分詞工具直接就會給過濾掉,因?yàn)樗鼈儗τ谡Z義搜索沒啥用。
怎么又來一堆名詞了?還能不能愉快的玩耍了?
別急別急,這些內(nèi)容我們后面就可以貫穿在與之相關(guān)的內(nèi)容中一起學(xué)習(xí)了。現(xiàn)在先有個大概的了解就好了。
所幸,上面的那些分詞器,Jieba、IK,以及我們主要要學(xué)習(xí)的 SCWS ,在形式、功能上都非常相似。就和搜索引擎一樣,不管是 ES 還是 XS ,最終都是要實(shí)現(xiàn)全文檢索的,也要做倒排索引的。因此,學(xué)完 XS 的分詞以及 SCWS 的分詞相關(guān)內(nèi)容后,再看 Jieba 或者 IK 都能很快上手的。
另外,在擴(kuò)展部分,我們會簡單地學(xué)習(xí)使用 TNTSearch + PHP JIEBA ,到時就會告訴大家,語言實(shí)現(xiàn)都是其次的,核心的概念原理才是最重要的,PHP 一樣可以實(shí)現(xiàn)完整的、純 PHP 的 搜索引擎+分詞 系統(tǒng),從而實(shí)現(xiàn)純 PHP 的搜索引擎解決方案。
學(xué)到這里,不得不提一句。碼農(nóng)們都喜歡抬G貶B。這里的 G 和 B 就不用多做解釋了吧,其實(shí) Baidu 的中文搜索很強(qiáng)的,李彥宏大佬“超鏈分析”相關(guān)的論文也對 G 站 PR(PageRank)有重要的影響。中文分詞與語義處理,從技術(shù)角度和搜索結(jié)果來說,Baidu 確實(shí)是比 G 站強(qiáng)的。只不過滿屏廣告影響用戶體驗(yàn),而且碼農(nóng)們喜歡直接復(fù)制英文報(bào)錯信息去 G 站搜索,獲得的內(nèi)容更全面(你懂得),從而讓大家覺得 G 站更好。
那么 Baidu 這些大公司,使用的分詞器、搜索框架,是我們常見的這些嗎?這個我也不知道,但我知道核心原理和概念與我們今天學(xué)習(xí)到的這些內(nèi)容都不會相差太遠(yuǎn)。假如有幸有 Baidu 的大佬看到這篇文章,或者你對這一塊有更深入的了解,也歡迎評論區(qū)留言賜教哦!
與關(guān)系型數(shù)據(jù)庫的對比
最后,我們再來根據(jù)今天的知識,將學(xué)到的內(nèi)容與關(guān)系型數(shù)據(jù)庫中的相關(guān)名詞做一個對比,方便大家的記憶。
關(guān)系型數(shù)據(jù)庫 | XS | ES |
---|---|---|
表 Table | 索引 Index | 索引 Index |
行 Row | 文檔 Document | 文檔 Document |
列 Column | 字段 Field | 字段 Field |
表結(jié)構(gòu) Schema | 索引配置 ini 文件,XSFieldScheme對象 | 字段映射 mapping |
查詢語言 SQL 語法 | 無(只能通過 SDK) | DSL+RESTFul+Json語法 |
索引 B+Tree | B+Tree、倒排索引 | B+Tree、倒排索引、分布式 |
總結(jié)
通過今天的學(xué)習(xí),相信大家就能夠理解為啥上篇文章中使用“項(xiàng)”這個單字無法搜索到結(jié)果了吧。不管是 XS 的 SCWS 還是 ES 的 IK ,都不會將“項(xiàng)”作為一個單詞拆分出來加入到倒排表中。如果要實(shí)現(xiàn)可以索引這個單字的話,那么就需要做成單字倒排索引。試想百萬級的文章量,每個文章又是少則幾百、多則幾萬字的內(nèi)容,那么這個索引量有多恐怖。
當(dāng)然,如果你只是一些內(nèi)容很少的,重復(fù)度很高的電商產(chǎn)品、訂單搜索、內(nèi)部管理系統(tǒng)OA、HR、項(xiàng)目管理系統(tǒng)之類的,倒是可以嘗試單字索引。但通常來說,并不推薦。還是那句話,掌握搜索引擎的概念,我們是做分詞語義搜索的,不是 Like 。
具體的分詞算法不是我們學(xué)習(xí)的主要內(nèi)容,而且這部分內(nèi)容也非常高級和復(fù)雜,包括 NPL 其實(shí)也是在加上了 AI 相關(guān)的技術(shù)之后做得更強(qiáng)大的語義分詞以及語法詞法分析,也就是說,我們要學(xué)習(xí)到的以及常用的這些開源分詞器,大部分都只是基于普通算法+字典組合的分詞器,可以算是 NPL 中的一小部分內(nèi)容。有興趣的小伙伴可以自行查閱和學(xué)習(xí)更深入的資料。
今天的內(nèi)容是基于自己的學(xué)習(xí)與理解,參考資料非常多就不一一列舉了,如有紕漏希望您能抽出寶貴時間隨時批評指正。文章來源:http://www.zghlxwxcb.cn/news/detail-775335.html
下篇文章開始,我們正式進(jìn)入 XS 的系統(tǒng)與開發(fā)學(xué)習(xí)。文章來源地址http://www.zghlxwxcb.cn/news/detail-775335.html
到了這里,關(guān)于【迅搜03】全文檢索、文檔、倒排索引與分詞的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!