天天看點

ElasticSearch底層搜尋引擎Lucene原理剖析

  Apache官方定義:Lucene是一個高效的,基于Java的全文檢索庫;開源免費

  先來談什麼叫全文檢索?

  全文檢索主要針對非結構化資料,主要有兩種方法:

  (1)、順序掃描法

  比如我們想要在成千上萬的文檔中,查找包含某一字元串的所有文檔,順序掃描法就必須逐個的掃描每個文檔,并且每個文檔都要從頭看到尾,如果找到,就繼續找下一個,直至周遊所有的文檔;這種方法通常應用于資料量較小的場景,比如經常使用的grep指令就是這種查找方式

  (2)、全文檢索

  試想一下結構化資料的查詢方式,例如資料庫的查找方式,我們知道在資料庫中建構索引可以極大程度的提高查詢速度,這是因為結構化資料有一定程度固定的結構使得我們可以采取某些搜尋算法加速查詢速度,那既然如此,為什麼我們不可以嘗試在非結構化資料中,将一部分結構化資訊抽取出來,重新組織,然後針對這部分有結構的資料進行索引建立,進而達到加速查詢的目的;

  上述想法很天然,但卻構成了全文檢索的基本思路

  從非結構化資料中抽取部分結構化資料,并建立索引,再對索引進行搜尋的過程,我們成為全文索引

  從上面我們可以看出,全文檢索分為兩步:

  第一步:索引建立

  第二步:搜尋索引

  從上述思路中,可以印出來三個問題:

  1、索引裡究竟存了些什麼?

  2、如何建立索引

  3、如何對索引進行搜尋?

  針對上述問題,我們逐個探讨:

  問題1:索引裡究竟存了些什麼?

  想要知道索引裡究竟存了些什麼?我們必須先來了解一下正向索引和反向索引

  正向索引:從文檔中查找字元串 關系型資料庫使用的是正向索引

  反向索引:從字元串查找文檔 搜尋引擎lucene使用的是反向索引

  反向索引的解釋如下:

  

ElasticSearch底層搜尋引擎Lucene原理剖析

  如上圖所示,假如我有100個文檔,對他們從1-100進行編号;

  左邊儲存的是一系列的字元串,也可以了解為詞,我們稱這些字元串集合為詞典;

  右邊儲存的是包含左邊字元串的文檔連結清單,此文檔連結清單成為倒排表

  在上面中,我們對詞典中包含的字元串建立索引,而這些字元串也正是我們搜尋的資訊,是以可以大大加快查詢速度

  比如說我們要查找同時包含lucene和hadoop的文檔,我們隻需以下幾步:

  第一步:取出包含lucene的文檔連結清單

  第二步:取出包含hadoop的文檔連結清單

  第三步:合并連結清單,取出交集

  

ElasticSearch底層搜尋引擎Lucene原理剖析

  疑問:全文檢索的确加快了搜尋的速度,但是多了索引的過程,兩者加起來不一定有順序掃描快。這種說法的确有一定道理,在資料量小的情況下,順序掃描未必比全文檢索慢,但全文檢索設計的初衷就是用于大資料量的業務環境中。

  解答:全文檢索和順序掃描的差別在于:順序掃描每次都必須從頭至尾掃描全部資料,但全文檢索的索引建立過程隻需一次,以後查詢無需再次建立,但卻可以一直為搜尋所用。

  總結:全文檢索相對于順序掃描的優勢在于一次索引建立,多次使用

  問題2:如何建立索引?

  索引的建立一般分為以下幾步:

  第一步:将文檔交給切詞元件(Tokenizer)進行切詞處理

  第二步:将得到的詞元(Token)交給語言處理元件

  第三步:将得到的詞(Term)交給索引元件

  第四步:由索引元件針對詞建立索引

  針對上述步驟,我們給出2個示例文檔,加以詳細說明

  Document 1:Students should be allowed to go out with their friends, but not allowed to drink beer.

  Document 2:My friend Jerry went to school to see his students but found them drunk which is not allowed.

  第一步:切詞元件處理

  上述2個文檔會被交給切詞元件,切詞元件主要針對文檔進行切割,将文檔中的單詞一個一個切割出來,同時消除一些無意義的詞,比如标點符号、英文中的the和is、中文中的的等。因為标點符号和一些形容詞,在實際的搜尋中是很少會被搜尋的,是以在該步驟會剃掉這些詞語,減少索引的大小

  經過切割以後,可能會被切分成以下詞元:

  “Students”,“allowed”,“go”,“their”,“friends”,“allowed”,“drink”,“beer”,“My”,“friend”,“Jerry”,“went”,“school”,“see”,“his”,“students”,“found”,“them”,“drunk”,“allowed”

  第二步:語言處理元件處理

  該步驟主要針對第一步生成的詞元進行自然語言同化處理,比如針對cars詞元,同時生成新的詞car;Student詞元中的大寫字母小寫化,這樣能夠實作一個student搜尋,可以同時搜尋處理像Student、STUDENT、stuDENT等多種情況,經過該步驟處理後,可能會被切分成以下詞:

  “student”,“allow”,“go”,“their”,“friend”,“allow”,“drink”,“beer”,“my”,“friend”,“jerry”,“go”,“school”,“see”,“his”,“student”,“find”,“them”,“drink”,“allow”

  正因為有了自然語言處理元件,才能使得搜尋drove,drive也能被搜出來

  第三步:将得到的詞交給索引元件建立索引

  索引元件主要做以下幾件事情:

  (1)、利用得到的詞建立一個詞典

  

ElasticSearch底層搜尋引擎Lucene原理剖析

  (2)、對字典按字母順序進行排序

  

ElasticSearch底層搜尋引擎Lucene原理剖析

  (3)、合并相同的詞并建立倒排連結清單

  

ElasticSearch底層搜尋引擎Lucene原理剖析

  在上述表中,有幾個定義:

  Document Frequency:表示該詞出現在所有文檔的總數

  Frequency:表示在某一個文檔中該詞出現的次數

  第四步:建立索引

  針對最後生成的詞典,進行索引的建立,至此我們發現根據搜尋詞,我們可以立即找到對應的文檔;而且諸如drink、drunk等都可以找到同一個文檔

  問題3:如何對索引進行搜尋?

  搜尋可以分為以下幾步:

  第一步:使用者輸入查詢語句

  第二步:對查詢語句進行詞法分析、文法分析、語言處理

  第三步:搜尋索引,得到符合文法樹的文檔

  第四步:根據得到的文檔和查詢語句相關性,對結果進行排序予以展示

  第一步:使用者輸入語句

  查詢語句的文法根據全文檢索系統的實作而不同。

  比如使用者輸入:lucene AND learned NOT hadoop --------- 使用者想要查找包含lucene和learned,但是不包含hadoop的文檔

  第二步:對查詢語句進行詞法分析、文法分析、語言處理

  (1)、詞法分析主要用來識别單詞和關鍵字

  比如針對上述使用者的輸入,經過詞法分析,得到單詞為lucene、learned、hadoop,關鍵詞為AND、NOT

  (2)、語言分析主要根據查詢語句來生成一顆文法樹

  受限進行文法判斷,如果不滿足文法要求,則直接報錯;若滿足文法要求,則可以生成下面的文法樹:

  

ElasticSearch底層搜尋引擎Lucene原理剖析

  (3)、語言處理和索引建立過程中得語言處理幾乎一樣

  例如将learned變成learn,經過處理後得到以下結果:

  

ElasticSearch底層搜尋引擎Lucene原理剖析

  第三步:搜尋索引,得到符合文法樹得文檔

  首先,在反向索引連結清單裡,找到包含lucene、learn和hadoop得文檔

  其次,對包含lucene和learn得文檔進行求合集操作,得到同時包含兩者得文檔鍊條

  然後,将得到合集後得連結清單與hadoop得文檔連結清單進行差集操作,去除包含hadoop得文檔

  最後,此文檔連結清單就是我們要找得文檔

  第四步:根據得到的文檔和查詢語句的相關性,對結果進行排序

  此過程也是極其複雜的,比如谷歌搜尋,查詢出來的結果有幾十萬上百萬,如何排序顯示,這個過程涉及到一些自然語言的了解,過程非常複雜,在此不再贅述

  總結:Lucene是一個開源的分部署搜尋引擎的實作,ElasticSearch底層就是基于Lucene實作的,之是以能夠實作分布式搜尋,原因就在于每一個文檔在出庫入庫之前,就已經被進行切詞分析處理,針對每個詞建立索引,是一種空間換時間的做法