海量資料搜尋---demo展示百度、谷歌搜尋引擎的實現

宜信技術學院發表於2019-09-06

在我們平常的生活工作中,百度、谷歌這些搜尋網站已經成為了我們受教解惑的學校,俗話說得好,“有問題找度娘”。那麼百度是如何在海量資料中找到自己需要的資料呢?為什麼它搜尋的速度如此之快?我們都知道是因為百度的搜尋引擎,那麼搜尋引擎到底是個什麼東西呢?可能有的程式設計師會想到es,但是es並不能代表搜尋引擎,它只是其中的一種工具,不過這種工具確實好用,效率很高。

本文會向大家講述搜尋引擎的基本知識以及中文分詞的一些方法、然後會做一個小的demo來嘗試資料檢索。讓大家初步瞭解搜尋引擎的實現。

一、搜尋引擎介紹

1.1 搜尋引擎是什麼

這裡引用百度百科的介紹:

搜尋引擎(Search Engine)是指根據一定的策略、運用特定的計算機程式從網際網路上搜集資訊,在對資訊進行組織和處理後,為使用者提供檢索服務,將使用者檢索相關的資訊展示給使用者的系統。

1.2 搜尋引擎分類

搜尋引擎包括全文索引、目錄索引、元搜尋引擎、垂直搜尋引擎、集合式搜尋引擎、門戶搜尋引擎與免費連結列表等。

本文主要介紹全文索引,即百度使用的搜尋引擎分類。

全文索引

首先是資料庫中資料的蒐集,搜尋引擎的自動資訊蒐集功能分兩種:

  • 一種是定期搜尋,即每隔一段時間(比如Google一般是28天),搜尋引擎主動派出“蜘蛛”程式,對一定IP地址範圍內的網際網路網站進行檢索,一旦發現新的網站,它會自動提取網站的資訊和網址加入自己的資料庫。
  • 另一種是提交網站搜尋,即網站擁有者主動向搜尋引擎提交網址,它在一定時間內(2天到數月不等)定向向你的網站派出“蜘蛛”程式,掃描你的網站並將有關資訊存入資料庫,以備使用者查詢。

當使用者以關鍵詞查詢資訊時,搜尋引擎會在資料庫中進行搜尋,如果找到與使用者要求內容相符的網站,便採用特殊的演算法——通常根據網頁中關鍵詞的匹配程度、出現的位置、頻次、連結質量——計算出各網頁的相關度及排名等級,然後根據關聯度高低,按順序將這些網頁連結返回給使用者。這種引擎的特點是搜全率比較高。

1.3 搜尋引擎能解決什麼問題

  • 高效查詢資料(運用多種演算法查詢資料,查詢速率是毫秒級別,無論是千萬條資料還是上億的資料)

  • 比較容易,將普通的資料庫切換成搜尋引擎比較容易。

  • 大資料量、時效性、高併發等等。

1.4 搜尋引擎的應用場景

  • 資料庫達到百萬資料級別的時候
  • 要求檢索時效性、效能要求高,Ms級響應

1.5 Solr

接下來看在平常的網際網路中搜尋引擎的應用Solr。那麼什麼是Solr呢?它和es相比有什麼優點和不足呢?

我們先來簡單地介紹一下solr:

Solr是一個基於Lucene的全文搜尋伺服器。同時對其進行了擴充套件,提供了比Lucene更為豐富的面向使用的查詢語言,同時實現了可配置、可擴充套件並對查詢效能進行了優化,並且提供了一個完善的功能管理介面。它支援Xml/Http協議,支援JSONAPI介面。

它具有如下特點:

  • 可擴充套件性:Solr可以把建立索引和查詢處理的運算分佈到一個叢集內的多臺伺服器上。

  • 快速部署:Solr是開源軟體,安裝和配置都很方便,可以根據安裝包內的Sample配置直接上手,可分為單機和叢集模式。

  • 海量資料:Solr是針對億級以上的海量資料處理而設計的,可以很好地處理海量資料檢索。

  • 優化的搜尋功能:Solr搜尋速度夠快,對於複雜的搜尋查詢Solr可以做到毫秒級的處理,通常,幾十毫秒就能處理完一次複雜查詢。

二、分詞介紹

接下來,我們將瞭解分詞是如何實現的。那麼,我們為什麼要去分詞呢,這和搜尋引擎有什麼關係呢?我們在搜尋框裡輸入的幾個詞或者一段話是如何拆成多個關鍵字的呢?

大家聽說過哪些分詞器嗎?比如lucene自帶的中文分詞器smartcn,還有最常用的IK分詞器等等,今天我們主要講一下IK分詞器。

2.1 IK分詞器

IK分詞器首先會維護幾個詞典來記錄一些常用的詞,如主詞表:main2012.dic、量詞表quantifier.dic、停用詞stopword.dic。

Dictionary為字典管理類中,分別載入了這個詞典到記憶體結構中。具體的字典程式碼,位於org.wltea.analyzer.dic.DictSegment。 這個類實現了一個分詞器的一個核心資料結構,即Tire Tree。

Tire Tree(字典樹)是一種結構相當簡單的樹型結構,用於構建詞典,通過字首字元逐一比較對方式,快速查詢詞,所以有時也稱為字首樹。具體的例子如下。

舉例

比如:我是北京海淀區中關村的中國人民。

我們設定的詞典是:北京、海淀區、中關村、中國、中國人民,那麼根據詞典組成的字典樹如圖所示:

然後我們根據這個字典樹來對這段話進行詞語切分。IK分詞器中,基本可以分為兩種模式:一種是smart模式、一種是非smart模式,可以在程式碼中初始化的時候去配置。

我們其實不用解釋這兩種模式的字面含義,直接列印兩種模式的結果就可以看出來:

  • 原句:我是北京海淀區中關村的中國人民

  • smart模式:北京、海淀區、中關村、中國人民

  • 非smart模式:北京、海淀區、中關村、中國、中國人民

顯而易見,非smart模式是將能夠分出來的詞全部輸出;smart模式是根據內在的方法輸出一個合理的分詞結果,這就涉及到了歧義判斷。

舉例

舉個更有代表性的例子:張三說的確實在理。

根據正向匹配可能的詞元鏈:

  • L1:{張三,張,三}
  • L2:{說}
  • L3:{的確,的,確實,確,實在,實,在理,在,理}

首來看一下最基本的一些元素結構類:

public class Lexeme implements Comparable{  
    ……  
   
    //詞元的起始位移  
    private int offset;  
    //詞元的相對起始位置  
    private int begin;  
    //詞元的長度  
    private int length;  
    //詞元文字  
    private String lexemeText;  
    //詞元型別  
    private int lexemeType;  
     ……  
}

這裡的Lexeme(詞元),可以理解為是一個詞語或單詞。其中的begin,是指其在輸入文字中的位置。注意,它是實現Comparable的,起始位置靠前的優先,長度較長的優先,這可以用來決定一個詞在一條分詞結果的詞元鏈中的位置,可以用於得到上面例子中分詞結果中的各個詞的順序。    

/* 
* 詞元在排序集合中的比較演算法
* @see java.lang.Comparable#compareTo(java.lang.Object) 
*/  
public int compareTo(Lexeme other) {  
//起始位置優先  
    if(this.begin < other.getBegin()){  
        return -1;  
    }else if(this.begin == other.getBegin()){  
     //詞元長度優先  
     if(this.length > other.getLength()){  
         return -1;  
     }else if(this.length == other.getLength()){  
         return 0;  
     }else {//this.length < other.getLength()  
         return 1;  
     }  
        
    }else{//this.begin > other.getBegin()  
     return 1;  
    }  
}

smart模式歧義消除演算法:  

  • 詞元位置權重比較(詞元長度積),含義是選取長的詞元位置在後的集合
  • L31:{的,確實,在理}1*1+2*2+3*2=11
  • L32:{的確,實,在理} 1*2+2*1+3*2=10
  • L33:{的確,實在,理} 1*2+2*2+3*1=9
  • 最後的分詞結果:張三,說,的,確實,在理

分詞就介紹這麼多,大家可以去讀一下IK分詞器的原始碼,深入地瞭解一下,原始碼地址:https://github.com/quentinxxz/Search/tree/master/IKAnalyzer2012FF_hf1_source/

三、倒排索引演算法

3.1 介紹

我們可以把倒排索引演算法想象成查字典時的目錄一樣,我們知道需要查的字的目錄後,就會很快地查詢到。如果用專業的語言解釋的話就是:

倒排索引源於實際應用中需要根據屬性的值來查詢記錄。這種索引表中的每一項都包括一個屬性值和具有該屬性值的各記錄的地址。由於不是由記錄來確定屬性值,而是由屬性值來確定記錄的位置,因而稱為倒排索引(inverted index)。帶有倒排索引的檔案我們稱為倒排索引檔案,簡稱倒排檔案(inverted file)。

倒排檔案(倒排索引),索引物件是文件或者文件集合中的單詞等,用來儲存這些單詞在一個文件或者一組文件中的儲存位置,是對文件或者文件集合的一種最常用的索引機制。

搜尋引擎的關鍵步驟就是建立倒排索引,倒排索引一般表示為一個關鍵詞,然後是它的頻度(出現的次數),位置(出現在哪一篇文章或網頁中,及有關的日期,作者等資訊),它相當於為網際網路上幾千億頁網頁做了一個索引,好比一本書的目錄、標籤一般。讀者想看哪一個主題相關的章節,直接根據目錄即可找到相關的頁面。不必再從書的第一頁到最後一頁,一頁一頁地查詢。

3.2 Lucene倒排索引原理

Lucerne是一個開放原始碼的高效能的基於java的全文檢索引擎工具包,不是一個完整的全文檢索引擎,而是一個全文檢索引擎的架構,提供了完整的查詢引擎和索引引擎,部分文字分析引擎。目的是為軟體開發人員提供一個簡單易用的工具包,以方便在目標系統中實現全文檢索的功能,或者以此為基礎建立起完整的全文檢索引擎。

假設有兩篇文章1和2:

文章1的內容為: Jack lives in BeiJing,I live in BeiJing too.    文章2的內容為: He lived in Taiyuan.

1)取得關鍵詞 

首先我們要用我們之前講的方式分詞,然後由於英文的原因,我們需要將in、on、of這些沒用實際意義的詞過濾掉,然後將第三人稱單數加s或者過去式加ed這些詞還原回去,如lived變回live,lives變回live,然後把不需要的標點符號也去掉。經過上面的處理之後,剩下的關鍵字為:

文章1的所有關鍵詞為:[Jack] [live] [BeiJing] [i] [live] [BeiJing]    

文章2的所有關鍵詞為:[he] [live] [Taiyuan]

2)建立倒排索引

關鍵詞            文章號[出現頻率]              出現位置   
BeiJing             1[2]                      3,6   
he                  2[1]                      1   
i                   1[1]                      4   
live                1[2]                      2,5, 
                    2[1]                      2   
Taiyuan             2[1]                      3   
tom                 1[1]                      1

  以上就是lucene索引結構中最核心的部分。我們注意到關鍵字是按字元順序排列的(lucene沒有使用B樹結構),因此lucene可以用二元搜尋演算法快速定位關鍵詞。  

3.3 實現

實現時,lucene將上面三列分別作為詞典檔案(Term Dictionary)、頻率檔案(frequencies)、位置檔案 (positions)儲存。其中詞典檔案不僅儲存有每個關鍵詞,還保留了指向頻率檔案和位置檔案的指標,通過指標可以找到該關鍵字的頻率資訊和位置資訊。  

3.4 壓縮演算法

為了減小索引檔案的大小,Lucene對索引還使用了壓縮技術。

首先,對詞典檔案中的關鍵詞進行了壓縮,關鍵詞壓縮為<字首長度,字尾>,例如:當前詞為“阿拉伯語”,上一個詞為“阿拉伯”,那麼“阿拉伯語”壓縮為<3,語>。

其次大量用到的是對數字的壓縮,數字只儲存與上一個值的差值(這樣可以減小數字的長度,進而減少儲存該數字需要的位元組數)。例如當前文章號是16389(不壓縮要用3個位元組儲存),上一文章號是16382,壓縮後儲存7(只用一個位元組)。

3.5 使用原因

假設要查詢單詞 “live”,lucene先對詞典二元查詢、找到該詞,通過指向頻率檔案的指標讀出所有文章號,然後返回結果。詞典通常非常小,因而,整個過程的時間是毫秒級的。   

而用普通的順序匹配演算法,不建索引,而是對所有文章的內容進行字串匹配,這個過程將會相當緩慢,當文章數目很大時,時間往往是無法忍受的。

四、solr基本配置以及使用

我們在windows系統中安裝solr。

下載地址 http://lucene.apache.org/solr/downloads.html

解壓後:

cmd 進入solr的bin目錄,使用命令 solr start(為了更方便,可以配置solr的環境變數,配好後可以直接在cmd中使用solr命名)

看到這個介面,說明solr服務啟動成功,埠號為 8983,訪問 http://localhost:8983,會自動跳轉到http://localhost:8983/solr/#/

在這個頁面會顯示 solr的基本資訊,lucene資訊,Java資訊等

然後我們介紹一個solr的指令: solr -h 可以看到solr的基本資訊

配置solr

配置核心core

solr create -c mycore -d baisc_configs:-c引數指定定義的核心名稱,-d引數指定配置目錄

執行該命令後,會多出一個test目錄。

訪問Solr Admin頁面:http://localhost:8983/,檢視core,多了一個 test

在\solr-6.3.0\server\solr\test目錄下有conf和data目錄,分別對應配置和資料。

給core新增資料

開啟目錄:\solr-6.3.0\server\solr\test\conf,新增一個欄位:

<field name="name" type="string" indexed="false" stored="true" required="true" multiValued="false" />

然後重啟solr: solr restart -p 8983

到Solr Admin頁面,選擇core-test-document,在Document(s)中填寫資料:

{
"id":"1",
"name":"寶馬"
}

點選submit,返回Status: success,則代表新增資料成功。

多加幾條後,點選Query,查詢資料:

查詢介面的 q,代表 查詢條件,如輸入:name:"寶馬",再次執行查詢

也可以直接get方式訪問url:http://localhost:8983/solr/test/select?q=name:寶馬

作者:楊亨

來源: 宜信技術學院


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69918724/viewspace-2656201/,如需轉載,請註明出處,否則將追究法律責任。

相關文章