全文檢索引擎Solr系列—–全文檢索基本原理

場景:小時候我們都使用過新華字典,媽媽叫你翻開第38頁,找到“坑爹”所在的位置,此時你會怎麼查呢?毫無疑問,你的眼睛會從38頁的第一個字開始從頭至尾地掃描,直到找到“坑爹”二字爲止。這種搜索方法叫做順序掃描法。對於少量的數據,使用順序掃描是夠用的。但是媽媽叫你查出坑爹的“坑”字在哪一頁時,你要是從第一頁的第一個字逐個的掃描下去,那你真的是被坑了。此時你就需要用到索引。索引記錄了“坑”字在哪一頁,你只需在索引中找到“坑”字,然後找到對應的頁碼,答案就出來了。因爲在索引中查找“坑”字是非常快的,因爲你知道它的偏旁,因此也就可迅速定位到這個字。

那麼新華字典的目錄(索引表)是怎麼編寫而成的呢?首先對於新華字典這本書來說,除去目錄後,這本書就是一堆沒有結構的數據集。但是聰明的人類善於思考總結,發現每個字都會對應到一個頁碼,比如“坑”字就在第38頁,“爹”字在第90頁。於是他們就從中提取這些信息,構造成一個有結構的數據。類似數據庫中的表結構:

word    page_no
---------------
坑        38
爹        90
...       ...

這樣就形成了一個完整的目錄(索引庫),查找的時候就非常方便了。對於全文檢索也是類似的原理,它可以歸結爲兩個過程:1.索引創建(Indexing)2. 搜索索引(Search)。那麼索引到底是如何創建的呢?索引裏面存放的又是什麼東西呢?搜索的的時候又是如何去查找索引的呢?帶着這一系列問題繼續往下看。

索引

Solr/Lucene採用的是一種反向索引,所謂反向索引:就是從關鍵字到文檔的映射過程,保存這種映射這種信息的索引稱爲反向索引

inverted_index_thumb.jpg

  • 左邊保存的是字符串序列
  • 右邊是字符串的文檔(Document)編號鏈表,稱爲倒排表(Posting List)

字段串列表和文檔編號鏈表兩者構成了一個字典。現在想搜索”lucene”,那麼索引直接告訴我們,包含有”lucene”的文檔有:2,3,10,35,92,而無需在整個文檔庫中逐個查找。如果是想搜既包含”lucene”又包含”solr”的文檔,那麼與之對應的兩個倒排表去交集即可獲得:3、10、35、92。

索引創建

假設有如下兩個原始文檔:
文檔一: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.
創建過程大概分爲如下步驟:
index-build

一:把原始文檔交給分詞組件(Tokenizer)
分詞組件(Tokenizer)會做以下幾件事情(這個過程稱爲:Tokenize),處理得到的結果是詞彙單元(Token)

  1. 將文檔分成一個一個單獨的單詞
  2. 去除標點符號
  3. 去除停詞(stop word)
    • 所謂停詞(Stop word)就是一種語言中沒有具體含義,因而大多數情況下不會作爲搜索的關鍵詞,這樣一來創建索引時能減少索引的大小。英語中停詞(Stop word)如:”the”、”a”、”this”,中文有:”的,得”等。不同語種的分詞組件(Tokenizer),都有自己的停詞(stop word)集合。經過分詞(Tokenizer)後得到的結果稱爲詞彙單元(Token)。上例子中,便得到以下詞彙單元(Token)
      "Students","allowed","go","their","friends","allowed","drink","beer","My","friend","Jerry","went","school","see","his","students","found","them","drunk","allowed"

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

  1. 變爲小寫(Lowercase)。
  2. 將單詞縮減爲詞根形式,如”cars”到”car”等。這種操作稱爲:stemming。
  3. 將單詞轉變爲詞根形式,如”drove”到”drive”等。這種操作稱爲:lemmatization。

語言處理組件(linguistic processor)處理得到的結果稱爲詞(Term),例子中經過語言處理後得到的詞(Term)如下:

"student","allow","go","their","friend","allow","drink","beer","my","friend","jerry","go","school","see","his","student","find","them","drink","allow"。

經過語言處理後,搜索drive時drove也能被搜索出來。Stemming 和 lemmatization的異同:

  • 相同之處:
    1. Stemming和lemmatization都要使詞彙成爲詞根形式。
  • 兩者的方式不同:
    1. Stemming採用的是”縮減”的式:”cars”到”car”,”driving”到”drive”。
    2. Lemmatization採用的是”轉變”的方式:”drove”到”drove”,”driving”到”drive”。
  • 兩者的算法不同:
    1. Stemming主要是採取某種固定的算法來做這種縮減,如去除”s”,去除”ing”加”e”,將”ational”變爲”ate”,將”tional”變爲”tion”。
    2. Lemmatization主要是採用事先約定的格式保存某種字典中。比如字典中有”driving”到”drive”,”drove”到”drive”,”am, is, are”到”be”的映射,做轉變時,按照字典中約定的方式轉換就可以了。
    3. Stemming和lemmatization不是互斥關係,是有交集的,有的詞利用這兩種方式都能達到相同的轉換。

三:得到的詞(Term)傳遞給索引組件(Indexer)

  1. 利用得到的詞(Term)創建一個字典
    Term    Document ID
    student     1
    allow       1
    go          1
    their       1
    friend      1
    allow       1
    drink       1
    beer        1
    my          2
    friend      2
    jerry       2
    go          2
    school      2
    see         2
    his         2
    student     2
    find        2
    them        2
    drink       2
    allow       2
  2. 對字典按字母順序排序:
    Term    Document ID
    allow       1
    allow       1
    allow       2
    beer        1
    drink       1
    drink       2
    find        2
    friend      1
    friend      2
    go          1
    go          2
    his         2
    jerry       2
    my          2
    school      2
    see         2
    student     1
    student     2
    their       1
    them        2
  3. 合併相同的詞(Term)成爲文檔倒排(Posting List)鏈表postlist
    • Document Frequency:文檔頻次,表示多少文檔出現過此詞(Term)
    • Frequency:詞頻,表示某個文檔中該詞(Term)出現過幾次

對詞(Term) “allow”來講,總共有兩篇文檔包含此詞(Term),詞(Term)後面的文檔鏈表總共有兩個,第一個表示包含”allow”的第一篇文檔,即1號文檔,此文檔中,”allow”出現了2次,第二個表示包含”allow”的第二個文檔,是2號文檔,此文檔中,”allow”出現了1次

至此索引創建完成,搜索”drive”時,”driving”,”drove”,”driven”也能夠被搜到。因爲在索引中,”driving”,”drove”,”driven”都會經過語言處理而變成”drive”,在搜索時,如果您輸入”driving”,輸入的查詢語句同樣經過分詞組件和語言處理組件處理的步驟,變爲查詢”drive”,從而可以搜索到想要的文檔。

搜索步驟

搜索”microsoft job”,用戶的目的是希望在微軟找一份工作,如果搜出來的結果是:”Microsoft does a good job at software industry…”,這就與用戶的期望偏離太遠了。如何進行合理有效的搜索,搜索出用戶最想要得結果呢?搜索主要有如下步驟:

一:對查詢內容進行詞法分析、語法分析、語言處理

  1. 詞法分析:區分查詢內容中單詞和關鍵字,比如:english and janpan,”and”就是關鍵字,”english”和”janpan”是普通單詞。
  2. 根據查詢語法的語法規則形成一棵樹
    grammer_tree.jpg
  3. 語言處理,和創建索引時處理方式是一樣的。比如:leaned–>lean,driven–>drive

二:搜索索引,得到符合語法樹的文檔集合
三:根據查詢語句與文檔的相關性,對結果進行排序

我們把查詢語句也看作是一個文檔,對文檔與文檔之間的相關性(relevance)進行打分(scoring),分數高比較越相關,排名就越靠前。當然還可以人工影響打分,比如百度搜索,就不一定完全按照相關性來排名的。

如何評判文檔之間的相關性?一個文檔由多個(或者一個)詞(Term)組成,比如:”solr”, “toturial”,不同的詞可能重要性不一樣,比如solr就比toturial重要,如果一個文檔出現了10次toturial,但只出現了一次solr,而另一文檔solr出現了4次,toturial出現一次,那麼後者很有可能就是我們想要的搜的結果。這就引申出權重(Term weight)的概念。

權重表示該詞在文檔中的重要程度,越重要的詞當然權重越高,因此在計算文檔相關性時影響力就更大。通過詞之間的權重得到文檔相關性的過程叫做空間向量模型算法(Vector Space Model)

影響一個詞在文檔中的重要性主要有兩個方面:

  • Term Frequencey(tf),Term在此文檔中出現的頻率,ft越大表示越重要
  • Document Frequency(df),表示有多少文檔中出現過這個Trem,df越大表示越不重要
    物以希爲貴,大家都有的東西,自然就不那麼貴重了,只有你專有的東西表示這個東西很珍貴,權重的公式:

空間向量模型

文檔中詞的權重看作一個向量

Document = {term1, term2, …… ,term N}
Document Vector = {weight1, weight2, …… ,weight N}

把欲要查詢的語句看作一個簡單的文檔,也用向量表示:

Query = {term1, term 2, …… , term N}
Query Vector = {weight1, weight2, …… , weight N}

把搜索出的文檔向量及查詢向量放入N維度的空間中,每個詞表示一維:

夾角越小,表示越相似,相關性越大

參考:http://www.cnblogs.com/guochunguang/articles/3641008.html

關於作者: 劉志軍

程序員,關注 Java、Python、雲計算,移動互聯網。(新浪微博:@_Zhijun

查看劉志軍的更多文章 >>


原文出處:
http://www.importnew.com/12707.html

發佈了84 篇原創文章 · 獲贊 135 · 訪問量 41萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章