1. 程式人生 > >什麽是全文檢索

什麽是全文檢索

郵件 log logstash 關系型 innodb 可見 p2p ava 管理

Logstash我們每個人解除互聯網都是從互聯網搜索開始的,雖然大家常用的搜索引擎可能不同,搜索的關鍵詞也可能不同,但是我們習慣經常在網上搜索的方式來快速學習技術並解決日常工作中所遇到的各種技術問題,如果沒有互聯網搜索引擎,那麽恐怕我們將會有很多的人要失業了。如何在海量的網頁信息中準確且快速的找到包含我們所搜索關鍵字的所有網頁並合理的排序展示,這的確是一個很有挑戰的問題。

除了我們生活中搜索引擎,大量的互聯網應用離不開關鍵字搜索功能。不能提供關鍵字搜索功能的互聯網應用基本沒有生存的可能性。但奇怪的是,很多人從業多年。可能從來沒有研究,學習過關鍵字搜索功能背後的實現技術,卻天天將分布式事物這種古老又神秘的術語掛在嘴邊。要理解關鍵字搜索的價值,我們需要先了解關系型數據庫索引的極限性。我們在SQL查詢語句中使用like "%keyword%" 這種查詢條件時,數據庫索引是不起作用的。此時,搜索過程就變成了類似於一頁一頁翻書的遍歷過程了,幾乎全部是I/O操作,因此對性能的危害是極大的。如果需要對多個關鍵字進行模糊匹配。比如like ‘%keyword1%’ and like ‘%keyword2%’,此時查詢效率也就可想而知了。關鍵字檢索也稱為全文檢索,本質上是將一系列文本文件內容以“詞組(關鍵字)”為單位進行分析並生成對應的索引記錄,索引存儲了關鍵字到文章的映射關系,映射關系中記錄了關鍵字所在的文章編號、出現次數等關鍵信息,甚至包括了關鍵詞在文章中出現的起始位置,於是我們有機會看到關鍵字“高亮顯示”的查詢結果頁面。

關鍵字檢索的第一步對整個文檔進行分詞,得到文本中的每一個詞。這對於英文來說毫無困難,因為英文詞中的單詞之間是通過空格天然分開的,但是中文語句中的字與詞是兩個概念,所以中文分詞就成了一個很大的問題,比如對“北京天安門”如何分詞呢?是“北京、天安門”還是“北、京、天安、門”?解決這個問題的最好辦法是采用中文詞庫配合中文分詞法,配合開源Lucene使用的比較知名的中文分詞有IK(IKAnalyzer)或庖丁(PaodingAnalyzer),直接配置就可以使用了。

2、Lucene

java生態圈裏面最有名的全文檢索開源項目是Apache Lucene,他已經超過17歲了(2001年成為Apache開源項目),目前Apache官方維護的Lucene相關的開源項目有如下幾個。

1.Lucene Core:用java編寫的核心類,提供了全文檢索功能的API與SDK。

2.solr:基於Lucene Core開發的高性能搜索服務,提供了REST API的高層封裝接口。還提供了一個web管理界面。

3.PyLucene:一個Python版的Lucene Core 的高仿實現。

為了對一個文檔進行索引,Lucene提供了5個基礎類,分別是Document,Field,Index Writer,Analyzer和Directory。

首先,Document用來描述任何待搜索的文檔,列如Html頁面,電子郵件或者文本文件。我們知道一個文檔可能有多個屬性。比如一封電子郵件有接收日期。發件人,收件人,主題。內容等屬性,每個屬性可以用一個Field對象來描述,此外我們也可以把一個Document對象想象成數據庫中的一條記錄,而每個Field對象就是這條記錄的一個字段。

其次,在一個Document能被查詢之前,我們需要對文檔內容進行分詞以找到文檔包含的關鍵字。這部分工作由Analyzer對象來實現的。Analyzer把分詞後的內容交給IndexWriter建立索引。IndexWriter是Lucene用來創建索引的(Index)的核心類之一,它的作用是把每個Document對象加入到索引中來。並且把索引對象持久化保存到Directory中,Directory代表Lucene索引的存儲位置。目前有兩個實現:第一個FSDirectory,表示在文件系統中存儲,第二個RAMDirectory,表示在內存系統中存儲。

Lucene編程的整個流程如下圖所示:

技術分享圖片

整個流程可以總結為三個獨立步驟:

1.建模:根據被索引文檔(原始文檔)的結構與信息。建模對應的Document對象與相關的Lucene的索引字段(可以有多個索引),這一步類似於數據庫建模。關鍵點之一是確定原始文檔中有哪些信息需要作為Field存儲到Document對象中。通常文檔中的ID或全路徑文件名是要保留的(Filed.Store.YES)。以便檢索出結果後能讓用戶查看或下載原始文檔。

2.收錄:編寫一段程序掃描每個待檢索的目標文檔。將其轉換成對應的目標Document對象。並且創建相關的索引。最後存儲到Lucene的索引倉庫(Directory)中。這一步可以類比為初始化數據步驟(批量數據導入)。

3.檢索:使用類似於SQL查詢的Lucene API來編寫我們的全文檢索條件,從Lucene的索引倉庫中查詢符合條件的Document並且輸出給用戶。這一步瓦全類似於SQL查詢。

Lucene還普遍與網絡爬蟲技術相結合,提供基於互聯網資源的全文檢索的功能,比如不少提供商品比較和最優購物的信息網站通過爬蟲去抓起各個電商平臺上的商品信息並錄入到Lucene庫裏。然後提供用戶檢索服務。如下圖所示為此類型系統的一個典型的架構圖。

技術分享圖片

3、Solr

如果我們把Lucene與Mysql做對比,你會發現Lucene像MySql的某個存儲引擎。比如InnoDB或者MyISAM。Lucene只提供了最基本的全文檢索相關的API,這不是一個獨立中間件。功能也不夠豐富。Api比較復雜。不大方便使用。除此之外。Lucene還缺乏一個更為關鍵性分布式。當我們需要檢索的文檔數量特別大的時候。必然會遭受到宕機的瓶頸。所以有了後來的solr和ElasticSearch。他們都基於Lucene的功能豐富的分布式全文檢索中間件。

如下圖所示為Solr的架構示意圖,我們可以看到Solr在Lucene的基礎上開發了很多企業級增強功能。

1.提供了一套強大的Data Schema來方便用戶定義Document的結構;

2.增加了高效靈活的緩存功能;

3.增加了基於web的管理界面以提供集中的配置管理功能。

4.此外solr索引數據還可以分片存儲到多個節點上。並且通過多副本復制的方式來提高系統的可靠性。

技術分享圖片

solr的分布式集群模式也被稱為SolrCloud,這是一個靈活的分布式索引和檢索系統。SolrCloud也是一種去中心化思想的分布式集群,集群中沒有特殊的Master節點。而是依靠ZooKeeper來協調集群。SolrCloud中一個索引的數據(Collection)可以被劃分成為多個分片(Shard)並存儲在不同的節點上(Solr Core或者Core)。在索引數據分片的同時,SolrCloud也可以實現分片的復制。(Replication)功能以提升集群的可用性。SolrCloud集群的所有狀態信息都放在ZooKeeper中統一維護,客戶端訪問SolrCloud集群時,首先要向ZooKeeper查詢索引數據(Collection)所在的Core節點的地址列表。然後就可以連接到任意Core節點上來完成索引的所有操作的(CRUD)了。

如下圖所示給出了一個SolrCloud參考部署方案。本方案的索引數據(Collection)被分為兩個分片,同時每個Shard分片的數據有3份。其中一份所在Core節點被稱為Leader,其它兩個Core,節點被稱為Replica。所有的索引數據分布在8個Core中,他們位於3臺獨立的服務器上。所以其中一臺機器宕機。都不會影響系統的可用性。如果某個服務器在運行中宕機。那麽SolrCloud會自動觸發Leader的重新選舉行為。具體通過ZooKeeper提供的分布式鎖功能來實現的。

技術分享圖片

之前我們說到SolrCloud中的每個Shard分片都是由一個Leader和N個Replica所組成的,而卻客戶端可以連接到任意一個Core節點上進行索引的數據操作,那麽,此時索引數據是如何實現多副本同步的內?下面給出了背後的答案。

技術分享圖片

1.如果客戶端連接的Core不是Leader,此時節點會把請求轉發給所在的Shard分片的Leader節點。

2.Leader會把數據(Document),路由到所在Shard分片的每個Replica節點上。

3.如果文檔分片路由規則計算出目標Shard分片是另外一個分片。則leader會把數據轉發給該分片對應的leader 節點去處理。

SolrCloud采用了什麽算法進行索引數據分片Shard呢?為了選擇何時的分片的算法。SolrCloud提供了一個兩個關鍵要求。

1.分片算法的計算速度就必須快,因為建立索引及訪問索引的過程中都頻繁用到分片算法。

2.分片算法必須保證索引數據能均勻的分布到每個分片上。SolrCloud的查詢同時先後匯總了的過程。如果某個分片中的索引文檔。(Document的數量遠遠大於其他分片。那麽查詢此分片同時花的時間就會明顯多於其他分片。片大於其他分片。也就是說慢分片的查詢速度決定了整體的查詢的速度。

基於兩點考慮。SolrCloud選擇了一致性hash算法來實現索引分片。

Solr為了提供更實時的檢索能力,提供了Soft Commit的新模式,在這種模式中不僅把數據提交到內存中。此時沒有寫入到磁盤索引文件中,但是索引index可見。solr會打開新的Searcher從而使得新的Document可見。同時,Solr會進行預熱緩存以及查詢以使得緩存的數據也是可見的。為了保證數據最終會持久化到磁盤上。可以每1-10分鐘自動觸發Hard Commit而每秒鐘自動觸發Soft Commit。Soft Commit也是一把雙刃劍,一方面Commit越頻繁,查詢實時性越高。但同時增加solr的負荷。因為Commity越頻繁越會生成小或者多的索引段。於是Solr Mange的行為會更加頻繁。在實際項目中建議根據業務的需求和忍受。來確定Soft Commit的頻率。

4、ElasticSearch

ElasticSearch簡稱ES,它並不是Apache出品的。和Solr類似,也是基於Lucene的一個分布式索引的中間件。在日誌分析領域,以ElasticSearch為核心的ELK三件套(ELK Stack)成為事實上的標準。ELK其實並不是一款軟件。而是一套解決方案。是三款軟件ElasticSearch,Logstash和Kibana首字母的縮寫,這三款軟件都是開源軟件。通常是配合使用的。又先後歸於Elastic.co公司名下,故稱為ELK Stack。在當前流行的日誌管理平臺,而在流行的基於Docker與Kubernetes的Pass平臺中,ELK也是標配之一。非Apache出品的ES之所以能後來居上,與ELK的流行和影響力有著千絲萬縷的聯系。

如下圖所示是ELK Stack的一個架構組成圖。

技術分享圖片

Logstash是一個有實時管道能力的數據收集引擎。用來收集日誌並且作為索引數據寫入到集群中。我們可以開發自定義的日誌采集探頭。並按照ELK的日誌索引格式寫入到ES集群找那個。

Kibana則為ES提供了數據分析以及數據可視化的web平臺。它可以在ES的索引中查找數據並生成各種維度的標圖。

ES通過簡單的RESTful API來隱藏Lucene的復雜性。從而讓全文檢索變得簡單。它提供了近時的索引,搜索,分析等功能。我們可以這樣理解和描述ES。

1.分布式實時文檔存儲,文檔中的每個字段都可被索引並搜索。

2.分布式實時分析搜索索引。

3.可以擴展到上百臺服務器,處理器PB級結構化或非結構化數據。

ES中增加了Type這個概念,如果我們把index這個類比為Database ,那麽Type就相當於Table。但是這個比喻又不是很恰當。因為我們知道不同的Table的表結構不同。而一個index中所有的Document的結構的高度一致的。ES中的Type其實就是Document中的一段特殊的字段。用來查詢時過濾不同的Document.,比如我們在一個B2C的電商平臺時,需要對每個店鋪進行索引。而可以用Type區分不同的商鋪,實際上。Type的使用場景非常少。這是我們需要註意的地方。

與SolrCloud一樣。ES也是分布式系統,但是ES並沒有采用ZooKeeper作為集群的協調者,而是自己實現了一套被稱為Zen Directory的模塊,該模塊主要負責集群中節點自動發現和Master節點的選舉,Master節點維護集群的全局狀態,比如節點加入和離開時進行Shard的重新分配。而集群的節點之間則使用P2P的方式進行直接通信。不存在單點故障問題。我們需要重視一個參數是discovery.zen.minimum_master_nodes,他決定了在選舉Master的過程中需要有多少個節點通信,一個基本原則是要設置成N/2+1,N是集群中節點的數量。

ES集群與SolrCloud還有一個重大區別,即ES集群中的節點類型不止一種,有以下幾種類型。

1.Master節點:它有資格被選舉為主節點,控制整個集群。

2.Data節點:該節點保存索引數據並執行相關操作,列如,增,刪,改,查,搜索以及聚合。

3.Load balance節點:該節點只能處理路由信息,處理搜索及分發索引操作等,從本質上來說該節點的表現等同於智能負載平衡器。Load balance節點在較大的集群中是非常有用的,Load balance節點加入集群後可以得到集群的狀態,並可以根據集群的狀態直接路由請求。

4.Tribe節點:這是一個特殊的Load balance節點,他可以鏈接多個集群,在所有鏈接的集群上執行搜索和其他操作。

5.Ingest節點:是ES5.0新增的節點類型,該節點大大簡化了以往ES集群中添加數據的復雜度。

如下所示是Tribe節點鏈接多個ES集群展示日誌的ELK部署方案。據說魅族就采用了這種方案來解決各個IDC機房日誌的集中展示問題。

什麽是全文檢索