什么是全文檢索?
什么叫做全文檢索呢?這要從我們生活中的數(shù)據(jù)說(shuō)起。我們生活中的數(shù)據(jù)總體分為兩種:
結(jié)構(gòu)化數(shù)據(jù):指具有固定格式或有限長(zhǎng)度的數(shù)據(jù),如數(shù)據(jù)庫(kù),元數(shù)據(jù)等。
非結(jié)構(gòu)化數(shù)據(jù)(也叫全文數(shù)據(jù)) :指不定長(zhǎng)或無(wú)固定格式的數(shù)據(jù),如郵件,word文檔等。
半結(jié)構(gòu)化數(shù)據(jù):如XML,HTML等,當(dāng)根據(jù)需要可按結(jié)構(gòu)化數(shù)據(jù)來(lái)處理,也可抽取出純文本按非結(jié)構(gòu)化數(shù)據(jù)來(lái)處理。
按照數(shù)據(jù)的分類,搜索也分為兩種:
對(duì)結(jié)構(gòu)化數(shù)據(jù)的搜索 :如對(duì)數(shù)據(jù)庫(kù)的搜索,用SQL語(yǔ)句。再如對(duì)元數(shù)據(jù)的搜索,如利用windows搜索對(duì)文件名,類型,修改時(shí)間進(jìn)行搜索等。
對(duì)非結(jié)構(gòu)化數(shù)據(jù)的搜索 :如利用windows的搜索也可以搜索文件內(nèi)容,Linux下的grep命令,再如用Google和百度可以搜索大量?jī)?nèi)容數(shù)據(jù)。
對(duì)非結(jié)構(gòu)化數(shù)據(jù)也即對(duì)全文數(shù)據(jù)的搜索主要有兩種方法:
順序掃描法 (Serial Scanning)
所謂順序掃描,比如要找內(nèi)容包含某一個(gè)字符串的文件,就是一個(gè)文檔一個(gè)文檔的看,對(duì)于每一個(gè)文檔,從頭看到尾,如果此文檔包含此字符串,則此文檔為我們要找的文件,接著看下一個(gè)文件,直到掃描完所有的文件。如利用windows的搜索也可以搜索文件內(nèi)容,只是相當(dāng)?shù)穆?。如果你有一個(gè)80G硬盤,如果想在上面找到一個(gè)內(nèi)容包含某字符串的文件,不花他幾個(gè)小時(shí),怕是做不到。Linux下的grep命令也是這一種方式。
這種方法比較原始,但對(duì)于小數(shù)據(jù)量的文件,這種方法還是最直接,最方便的。但是對(duì)于大量的文件,這種方法就很慢了。
全文檢索
將非結(jié)構(gòu)化數(shù)據(jù)中的一部分信息提取出來(lái),重新組織,使其變得有一定結(jié)構(gòu),然后對(duì)此有一定結(jié)構(gòu)的數(shù)據(jù)進(jìn)行搜一個(gè)索,從而達(dá)到搜索相對(duì)較快的目的。
Apache Lucene是什么?
Apache Lucene其實(shí)就是apache提供的一個(gè)開(kāi)源關(guān)于搜索引擎的類庫(kù),囊括了較為全面的有關(guān)搜索引擎相關(guān)的技術(shù)解決思路,使得現(xiàn)如今的soler以及ElasticSearch尤為的火爆,不管是在互聯(lián)網(wǎng)項(xiàng)目中以及大數(shù)據(jù)領(lǐng)域占據(jù)了不可多得的地位。
索引
正排索引

為什么順序掃描的速度慢:其實(shí)是由于我們想要搜索的信息和非結(jié)構(gòu)化數(shù)據(jù)中所存儲(chǔ)的信息不一致造成的。
倒排索引
非結(jié)構(gòu)化數(shù)據(jù)中所存儲(chǔ)的信息是每個(gè)文件包含哪些字符串,也即已知文件,欲求字符串相對(duì)容易,也即是從文件到字符串的映射。而我們想搜索的信息是哪些文件包含此字符串,也即已知字符串,欲求文件,也即從字符串到文件的映射。兩者恰恰相反。于是如果索引總能夠保存從字符串到文件的映射,則會(huì)大大提高搜索速度。

倒排索引一般表示為一個(gè)關(guān)鍵詞,然后是它的頻度(出現(xiàn)的次數(shù)),位置(出現(xiàn)在哪一篇文章或網(wǎng)頁(yè)中,及有關(guān)的日期,作者等信息),它相當(dāng)于為互聯(lián)網(wǎng)上幾千億頁(yè)網(wǎng)頁(yè)做了一個(gè)索引,好比一本書的目錄、標(biāo)簽一般。想看哪一個(gè)主題相關(guān)的章節(jié),直接根據(jù)目錄即可找到相關(guān)的頁(yè)面。不必再?gòu)臅牡谝豁?yè)到最后一頁(yè),一頁(yè)一頁(yè)的查找。
例如:
| 文章 | head | content |
|---|---|---|
| 文章1 | 超級(jí)塞亞人 | 我是超級(jí)塞亞人我喜歡吃蘋果,我不是天朝的人,也不是地球人 |
| 文章2 | 天朝大國(guó) | 我大天朝威武,我大天朝13億人,我大天朝 |
| 文章3 | 游泳 | 游泳有很多好方法 |
| 文章4 | 動(dòng)畫片 | 喜歡看動(dòng)畫片,尤其是七龍珠,因?yàn)槔锩嬗腥麃喨?,而且塞亞人喜歡吃蘋果,他們不是地球人 |
| 文章5 | 運(yùn)動(dòng) | 喜歡運(yùn)動(dòng),喜歡跑步,喜歡游泳,喜歡健身,喜歡 |
| 文章6 | 打炮 | 我喜歡打游戲,我最幸福的時(shí)光就是在天朝吃著蘋果玩打炮游戲 |
關(guān)鍵字:塞亞人 蘋果 天朝 地球 七龍珠 游泳 喜歡
| 關(guān)鍵詞 | 索引 |
|---|---|
| 塞亞人 | 文章1[1],文章4[2], n n n |
| 蘋果 | 文章1[1],文章4[1],文章6[1], n n n |
| 天朝 | 文章1[1],文章2[2],文章6[1], n n n n |
| 地球 | 文章1[1],文章4[1], n n |
| 游泳 | 文章3[1],文章5[1], n n |
| 七龍珠 | 文章4[1], n |
| 喜歡 | 文章1[1],文章4[2],文章5[4],文章6[1], n n n n n n n n |
倒排索引2個(gè)重要構(gòu)成:
1.倒排文件(inverted file):存儲(chǔ)倒排索引的物理文件
2.倒排索引組成:?jiǎn)卧~詞典和倒排文件。
何為倒排索引
核心術(shù)語(yǔ)

Index
Lucene的索引(Index)是由多個(gè)文件組成,這些文件被存放在同一目錄下。
Token
詞元(Token)在Lucene與在自然語(yǔ)言處理(NLP)中的概念相同,表示“詞元”。詞元即自然語(yǔ)言中的基本單位:在中文表現(xiàn)為一個(gè)獨(dú)立的字或詞,在英文中表現(xiàn)為一個(gè)單詞。
Term
經(jīng)過(guò)分詞和語(yǔ)言處理后得到的字符串,它是索引的最小單位。
Field
不同的域可以指定不同的索引方式,比如指定不同的分詞方式,是否構(gòu)建索引,是否存儲(chǔ)等。
Document
文檔是索引的基本單位,代表一些域(Field)的集合。在Lucene中,Document是一種邏輯文件。可以近似地認(rèn)為它表示的是計(jì)算機(jī)中的一個(gè)文件。這個(gè)Document是一種抽象的表示,它從各種維度來(lái)描述一個(gè)數(shù)據(jù)源中的每一條數(shù)據(jù)。
可以使用關(guān)系型數(shù)據(jù)庫(kù)中的記錄來(lái)理解Document,數(shù)據(jù)庫(kù)的每一條記錄可以表示為一個(gè)Document,而每一列可以用Field來(lái)表示。但不同的是,Document并非結(jié)構(gòu)化的,并沒(méi)有schema的約束。不同的文檔保存在不同的段中的,一個(gè)段中可以包含多篇文檔。新添加的文檔被單獨(dú)保存在一個(gè)新生成的段中,隨著段的合并,不同的文檔會(huì)合并到至相同的段中。
Segment
一個(gè)Lucene的索引(Index)由多個(gè)段組成,段與段之間是獨(dú)立的。當(dāng)添加索引時(shí)會(huì)生成新的Document,但并不是把新的Document 立即添加到同一個(gè)索引文件,而是把它們先被寫入到不同的小文件(Segment),當(dāng)小文件的個(gè)數(shù)達(dá)到閾值(段的個(gè)數(shù),段中包含的文件數(shù)等)時(shí),然后再合并成一個(gè)大索引文件(不同的段可以合并)。
Directory
Lucene索引的存放位置。
文檔模型
| 文檔名稱 | 擴(kuò)展名 | 說(shuō)明 |
|---|---|---|
| Segments File | segments_N | 保存提交點(diǎn)的信息 |
| Lock File | write.lock | 寫文件鎖,用于防止多個(gè)IndexWriters同時(shí)寫一個(gè)文件 |
| Segment Info | .si | 保存段的元數(shù)據(jù)信息 |
| Compound File | .cfs, .cfe | 采用混合格式下該文件包括其他所有格式的文件 |
| Fields | .fnm | 保存域信息 |
| Field Index | .fdx | 保存指向域數(shù)據(jù)的指針 |
| Field Data | .fdt | 保存域數(shù)據(jù) |
| Term Dictionary | .tim | 保存詞項(xiàng)信息 |
| Term Index | .tip | Term Dictionary的索引信息 |
| Frequencies | .doc | 記錄文檔信息,以及文檔中詞項(xiàng)對(duì)應(yīng)的詞頻 |
| Positions | .pos | 記錄詞項(xiàng)的位置信息 |
| Payloads | .pay | 全文索引的字段,使用了一些像payloads的高級(jí)特性會(huì)有該文件,保存了term在doc中的一些高級(jí)特性 |
| Norms | .nvd, .nvm | 文件保存索引字段加權(quán)數(shù)據(jù) |
| Per-Document Values | .dvd, .dvm | lucene的docvalues文件,即數(shù)據(jù)的列式存儲(chǔ),用作聚合和排序 |
| Term Vector Index | .tvx | 記錄文檔數(shù)據(jù)記錄中的偏移量 |
| Term Vector Documents | .tvd | 記錄有詞項(xiàng)向量的文檔的信息 |
| Term Vector Fields | .tvf | 詞項(xiàng)向量的域級(jí)別信息 |
| Live Documents | .liv | 存活文件的信息 |
| Point values | .dii, .dim | 記錄被索引的點(diǎn) |
Segment_N
Segments_N為段的元數(shù)據(jù)信息文件。保存了此索引包含多少個(gè)段,每個(gè)段包含多少篇文檔等信息。

Lucene當(dāng)前活躍的Segment都會(huì)存在一個(gè)Segment Info文件里,也就是segments_N。如果有多個(gè)segments_N, 那么序號(hào)最大的就是最新的。
1.Format:索引文件格式的版本號(hào)。由于Lucene是在不斷開(kāi)發(fā)過(guò)程中的,不同版本的Lucene可能有不同索引文件格式,所以規(guī)定了文件格式的版本號(hào)。
2.Version:索引的版本號(hào)
3.NameCount:下一個(gè)新段的段名
4.SegCount:段的個(gè)數(shù)
[Lucece圖形化工具Luke:]{https://www.github.com/DmitryKey/luke}
域文件格式
域元數(shù)據(jù)文件(fnm)
一個(gè)段(Segment)包含多個(gè)域,每個(gè)域都有一些元數(shù)據(jù)信息,保存在.fnm文件中,.fnm文件的格式如下:

域的數(shù)據(jù)信息存儲(chǔ)在 .fdt 和 .fdx 文件中。其中,.fdx 文件中存放FieldValuesPositon,指向.fdt文件,也就是說(shuō)域的具體數(shù)據(jù)是存放在fdt文件中的。
域數(shù)據(jù)文件(fdt)
真正保存域(stored field)信息的是fdt文件。
假如在一個(gè)Segment中包含N篇文檔,那么fdt文檔中一會(huì)有N個(gè)項(xiàng),每一個(gè)項(xiàng)都保存對(duì)應(yīng)文檔的域信息。
FieldCount,表示此文檔包含的域數(shù)目
緊接著是FieldCount域信息項(xiàng),每個(gè)項(xiàng)保存一個(gè)域的信息。對(duì)于每一個(gè)域的信息:
FieldNum是域編號(hào)
接著是一個(gè)8bit的byte。根據(jù)填充值(0或1),代表不同的意義。最低一位表示此域是否分詞;倒數(shù)第二位表示此域保存的是字符串?dāng)?shù)據(jù)還是二進(jìn)制數(shù)據(jù);倒數(shù)第三位表示此域是否被壓縮。最后存儲(chǔ)的是這個(gè)存儲(chǔ)域的值。
域索引文件(fdx)
由域數(shù)據(jù)文件格式可知,每篇文檔包含的域的個(gè)數(shù)、每個(gè)存儲(chǔ)域的值都是不一樣的。
因?yàn)閟egment中會(huì)包含N篇文檔(Document),每篇文檔占用的大小也是不一樣的,那么如何快速在fdt文件中辨別每一篇文檔的起始地址和終止地址?如何能夠更快的找到第N篇文檔的存儲(chǔ)域的信息呢?
這就需要借助域索引文件。域索引文件也總共有N個(gè)項(xiàng)(如果segment中包含N篇Document),每篇文檔都對(duì)應(yīng)一個(gè)項(xiàng),每一項(xiàng)中都存儲(chǔ)一個(gè)Long型數(shù)值(大小固定),該數(shù)值代表文檔在fdt中的起始地址偏移量。

詞向量文件
詞向量信息是從索引(Index)到文檔(Document)到域(Field)到詞(Term)的正向信息,有了詞向量信息,就可以得到一篇文檔包含哪些詞的信息 。

詞向量數(shù)據(jù)文件(tvd)
首先,是此文檔包含域的個(gè)數(shù):NumFields
之后,是一個(gè)NumFields大小的數(shù)組,數(shù)組每一項(xiàng)都是域號(hào)
最后,是(NumField - 1)大小的數(shù)組。每一篇文檔的第一個(gè)域的偏移量信息存儲(chǔ)在 tvx 文件中。而其他(NumFields - 1)域的偏移量就是第一個(gè)域的偏移量加上第(NumField - 1)個(gè)數(shù)組的值。
詞向量索引文件(tvx)
一個(gè)段(segment)包含N篇文檔,此文件就有N項(xiàng),每一項(xiàng)代表一篇文檔。每一項(xiàng)包含兩部分信息:
第一部分是詞向量文檔文件(tvd)中此文檔的偏移量
第二部分是詞向量文件(tvf)中此文檔的第一個(gè)域的偏移量
詞向量域文件(tvf)
該文件包含了此段(Segment)中的所有域,并且不對(duì)文檔做區(qū)分,到底第幾個(gè)域到第幾個(gè)域是屬于那篇文件,是由tvx文件中的第一個(gè)域的偏移量以及tvd文件中的(NumField - 1)個(gè)域的偏移量來(lái)決定哪些域數(shù)據(jù)屬于哪個(gè)文檔。
對(duì)于每一個(gè)域,包含如下項(xiàng):
首先,是說(shuō)明此域中包含的多少(NumTerms)個(gè)詞(Term)
之后,是8bit的byte(最后一位指定是否保存位置信息,倒數(shù)第二位表示是否保存偏移量信息)
最后,NumTerms個(gè)項(xiàng)的數(shù)組,每一項(xiàng)代表一個(gè)詞(Term)。每一個(gè)詞,由如下幾部分構(gòu)成
詞的文本TermText
詞頻TermFreq(詞在該文檔中出現(xiàn)的次數(shù))
詞的位置
詞的偏移量
創(chuàng)建倒排索引流程

全文檢索的索引創(chuàng)建過(guò)程一般有以下幾步:
第一步(原始素材)
為了方便說(shuō)明索引創(chuàng)建過(guò)程,這里特意用兩個(gè)文件為例:
文件一:Students should be allowed to go out with their friends, but not allowed to drink beer.
文件二:My friend Jerry went to school to see his students but found them drunk which is not allowed.
第二步(分詞)
將原文檔傳給分詞器(Tokenizer),分詞器會(huì)做以下幾件事情( 此過(guò)程稱為Tokenize) :
將文檔分成一個(gè)一個(gè)單獨(dú)的單詞。
去除標(biāo)點(diǎn)符號(hào)。
去除停詞(Stop word) 。
所謂停詞(Stop word)就是一種語(yǔ)言中最普通的一些單詞,由于沒(méi)有特別的意義,因而大多數(shù)情況下不能成為搜索的關(guān)鍵詞,因而創(chuàng)建索引時(shí),這種詞會(huì)被去掉而減少索引的大小。
每一種語(yǔ)言的分詞組件(Tokenizer),都有一個(gè)停詞(stop word)集合。
經(jīng)過(guò)分詞(Tokenizer) 后得到的結(jié)果稱為詞元(Token) ,如下:
第三步(語(yǔ)言處理)
將得到的詞元(Token)傳給語(yǔ)言處理組件(Linguistic Processor),語(yǔ)言處理組件(linguistic processor)主要是對(duì)得到的詞元(Token)做一些同語(yǔ)言相關(guān)的處理。
對(duì)于英語(yǔ),語(yǔ)言處理組件(Linguistic Processor) 一般做以下幾點(diǎn):
變?yōu)樾?Lowercase) 。
將單詞縮減為詞根形式,如“cars ”到“car ”等。這種操作稱為:stemming 。
將單詞轉(zhuǎn)變?yōu)樵~根形式,如“drove ”到“drive ”等。這種操作稱為:lemmatization 。
經(jīng)過(guò)語(yǔ)言處理,得到的詞(Term)如下:
第四步(構(gòu)建索引)
至此,Lucene有關(guān)于搜索引擎以及基礎(chǔ)知識(shí)點(diǎn)還有如何創(chuàng)建索引和大家分享完,歡迎大家和我一起分享學(xué)習(xí)!