全文檢索的基本原理


什么是全文檢索?

我們生活中的數據總體分為兩種:結構化數據和非結構化數據。

* 結構化數據:指具有固定格式或有限長度的數據,如數據庫,元數據等。
* 非結構化數據:指不定長或無固定格式的數據,如郵件,word文檔等。

當然有的地方還會提到第三種,半結構化數據,如XML,HTML等,當根據需要可按結構化數據來處理,也可抽取出純文本按非結構化數據來處理。
非結構化數據又一種叫法叫全文數據。

按照數據的分類,搜索也分為兩種:

* 對結構化數據的搜索:如對數據庫的搜索,用SQL語句。再如對元數據的搜索,如利用windows搜索對文件名,類型,修改時間進行搜索等。
* 對非結構化數據的搜索:如利用windows的搜索也可以搜索文件內容,Linux下的grep命令,再如用Google和百度可以搜索大量內容數據。

非結構化數據搜索方法

順序掃描法(Serial Scanning)

所謂順序掃描,比如要找內容包含某一個字符串的文件,就是一個文檔一個文檔的看,對於每一個文檔,從頭看到尾,如果此文檔包含此字符串,則此文檔為我們要找的文件,接着看下一個文件,直到掃描完所有的文件。
如利用windows的搜索也可以搜索文件內容,只是相當的慢。如果你有一個80G硬盤,如果想在上面找到一個內容包含某字符串的文件,不花他幾個小時,怕是做不到。
Linux下的grep命令也是這一種方式。大家可能覺得這種方法比較原始,但對於小數據量的文件,這種方法還是最直接,最方便的。但是對於大量的文件,這種方法就很慢了。

全文索引

全文檢索的基本思路:將非結構化數據中的一部分信息提取出來,重新組織,使其變得有一定結構,然后對此有一定結構的數據進行搜索,從而達到搜索相對較快的目的。
這部分從非結構化數據中提取出的然后重新組織的信息,我們稱之索引。
這種先建立索引,再對索引進行搜索的過程就叫全文檢索(Full-text Search)。

字典示例

比如字典,字典的拼音表和部首檢字表就相當於字典的索引,對每一個字的解釋是非結構化的,如果字典沒有音節表和部首檢字表,在茫茫辭海中找一個字只能順序掃描。
然而字的某些信息可以提取出來進行結構化處理,比如讀音,就比較結構化,分聲母和韻母,分別只有幾種可以一一列舉,於是將讀音拿出來按一定的順序排列,每一項讀音都指向此字的詳細解釋的頁數。
搜索時按結構化的拼音搜到讀音,然后按其指向的頁數,便可找到我們的非結構化數據——也即對字的解釋。

全文檢索的一般過程

圖來自《Lucene in action》
全文檢索大體分兩個過程,索引創建(Indexing)和搜索索引(Search)。

* 索引創建:將現實世界中所有的結構化和非結構化數據提取信息,創建索引的過程。
* 搜索索引:就是得到用戶的查詢請求,搜索創建的索引,然后返回結果的過程。

於是全文檢索就存在三個重要問題:

  1. 索引里面究竟存些什么?(Index)
  2. 如何創建索引?(Indexing)
  3. 如何對索引進行搜索?(Search)

索引存些什么?

為什么順序掃描的速度慢?是由於要搜索的信息和非結構化數據中所存儲的信息不一致造成的。
非結構化數據中所存儲的信息是每個文件包含哪些字符串,也即已知文件,欲求字符串相對容易,也即是從文件到字符串的映射。
而我們想搜索的信息是哪些文件包含此字符串,也即已知字符串,欲求文件,也即從字符串到文件的映射。

反向索引

兩者恰恰相反。於是如果索引總能夠保存從字符串到文件的映射,則會大大提高搜索速度。
由於從字符串到文件的映射是文件到字符串映射的反向過程,於是保存這種信息的索引稱為反向索引。

反向索引保存的信息(詞典-倒排表)

假設我的文檔集合里面有100篇文檔,為了方便表示,我們為文檔編號從1到100,得到下面的結構

左邊保存的是一系列字符串,稱為詞典。
每個字符串都指向包含此字符串的文檔(Document)鏈表,此文檔鏈表稱為倒排表(Posting List)。
有了索引,便使保存的信息和要搜索的信息一致,可以大大加快搜索的速度。

反向索引查詢示例

比如說,我們要尋找既包含字符串“lucene”又包含字符串“solr”的文檔,我們只需要以下幾步:

  1. 取出包含字符串“lucene”的文檔鏈表。
  2. 取出包含字符串“solr”的文檔鏈表。
  3. 通過合並鏈表,找出既包含“lucene”又包含“solr”的文件。

反向索引的優缺點

  1. 缺點:加上新建索引的過程,全文檢索不一定比順序掃描快,尤其是在數據量小的時候更是如此。而對一個很大量的數據創建索引也是一個很慢的過程。
  2. 優點:順序掃描是每次都要掃描,而全文索引可一次索引,多次使用;檢索速度快。

如何創建索引?

全文檢索的索引創建過程一般有以下幾步:

待索引的原文檔(Document)

將原文檔(Document)傳給分詞組件(Tokenizer)

分詞組件(Tokenizer)會做以下幾件事情(此過程稱為Tokenize):

  1. 將文檔分成一個一個單獨的單詞;
  2. 去除標點符號;
  3. 去除停用詞(Stop word);
    所謂停用詞(Stop word)就是一種語言中最普通的一些單詞,由於沒有特別的意義,因而大多數情況下不能成為搜索的關鍵詞,因而創建索引時,這種詞會被去掉而減少索引的大小。
    英語中挺詞(Stop word)如:“the”,“a”,“this”等。
    對於每一種語言的分詞組件(Tokenizer),都有一個停詞(stop word)集合。
    經過分詞(Tokenizer)后得到的結果稱為詞次(Token)。

將詞次(Token)傳給語言處理組件(Linguistic Processor)

語言處理組件(linguistic processor)主要是對得到的詞次(Token)做一些同語言相關的處理。
對於英語,語言處理組件(Linguistic Processor)一般做以下幾點:

  1. 變為小寫(Lowercase)。
  2. 將單詞縮減為詞根形式,如“cars”到“car”等。這種操作稱為:stemming。
  3. 將單詞轉變為詞根形式,如“drove”到“drive”等。這種操作稱為:lemmatization。
    語言處理組件(linguistic processor)的結果稱為詞元(Term)。

將詞元(Term)傳給索引組件(Indexer)

索引組件(Indexer)主要做以下幾件事情:

  1. 利用得到的詞(Term)創建一個字典(Term-DocumentID)

  2. 對字典按字母順序進行排序。

  3. 合並相同的詞元(Term)成為文檔倒排(Posting List)鏈表。
    在此表中,有幾個定義:

    • Document Frequency 即文檔頻次,表示總共有多少文件包含此詞(Term)。
    • Frequency 即詞頻率,表示此文件中包含了幾個此詞(Term)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM