Elasticsearch分享

Elasticsearch是什麼

Elasticsearch是一個基於Apache Lucene(TM)的開源搜索引擎。不管在開源仍是專有領域,Lucene能夠被認爲是迄今爲止最早進、性能最好的、功能最全的搜索引擎庫html

可是,Lucene只是一個庫。想要使用它,你必須使用Java來做爲開發語言並將其直接集成到你的應用中,更糟糕的是,Lucene很是複雜,你須要深刻了解檢索的相關知識來理解它是如何工做的。sql

Elasticsearch也使用Java開發並使用Lucene做爲其核心來實現全部索引和搜索的功能,可是它的目的是經過簡單的RESTful API來隱藏Lucene的複雜性,從而讓全文搜索變得簡單數據庫

因此,能夠理解成Elasticsearch(如下簡稱Elastic)對Lucene進行了封裝,讓它變得好用api

簡化的描述:緩存

  • 文檔數據庫
  • 分佈式的實時分析搜索引擎

Elastic的主要運用領域

Elastic是一個很是著名的開源搜索和分析系統,目前被普遍應用於互聯網多種領域中,尤爲是如下三個領域特別突出。架構

  • 搜索領域,成爲不少搜索系統的不二之選,好比全文檢索;
  • Json文檔數據庫,相對於MongoDB(筆者未作比較,感興趣能夠比較一下),讀寫性能更佳,並且支持更豐富的地理位置查詢以及數字、文本的混合查詢等;
  • 時序數據分析處理,目前是日誌處理、監控數據的存儲、分析和可視化方面作得很是好,好比我們公司裏面使用的api訪問日誌的就是Elastic了,而後使用Kibana可視化日誌,感受仍是很方便的

Elastic的一些基本概念的介紹

  • 節點(Node):物理概念,一個運行的Elasticearch實例,通常是一臺機器上的一個進程,好比咱們在本身的機器上面起了兩個Elastic,就至關因而兩個節點了。
  • 索引(Index),邏輯概念,包括配置信息settings和mapping和倒排正排數據文件,一個索引的數據文件可能會分佈於一臺機器,也有可能分佈於多臺機器。索引的另一層意思是建立一條數據,索引一個文件的意思。
  • 類型(type):是屬於index下一層級的概念,index下面的mapping,映射關係,字段集合等,能夠理解成相似Mysql的表結構,而後index理解成庫;
  • 分片(Shard):爲了支持更大量的數據,索引通常會按某個維度分紅多個部分,每一個部分就是一個分片,分片被節點(Node)管理。一個節點(Node)通常會管理多個分片,這些分片多是屬於同一份索引,也有可能屬於不一樣索引,可是爲了可靠性和可用性,同一個索引的分片儘可能會分佈在不一樣節點(Node)上,不然一個節點崩了,整個index都無法使用了。分片有兩種,主分片和副本分片。
  • 副本(Replica):同一個分片(Shard)的備份數據,一個分片可能會有0個或多個副本,這些副本中的數據保證強一致或最終一致
  • 文檔(doc): 在Elastic中,一條數據稱爲一個文檔,就是相似Mysql裏面的一行數據了。

elastic的各個版本差別較大,這也是比較坑的地方,有些默認配置可能會不太同樣,好比在早期的elastic版本中,一個index裏面能夠有多個type,可是多個type裏面若是有相同的字段,則這些字段的類型必須同樣,可是在elastic 6.x版本里面,好比,咱們當前使用的是elastic 6.7版本,一個index裏面只能夠定義一個type;
因此若是沒有特別說明,全文的elastic表示6.7版本,在這個版本下面,一個index默認有5個主分片和1個副本分片,而後統一主分片和副本分片不能夠在同一個節點下面app

  • number_of_shards, 主分片數量,索引一旦建立,不能夠更改
  • number_of_replicas, 副本分片數量,默認爲1, 這個能夠更改

avatar

Elastic的寫操做流程

Elastic總體上採用的是一主多副的架構
avatar異步

  1. 先根據_routing規則選擇發給哪一個Shard, 集羣中找出出該Shard的Primary節點
    Index Request中能夠設置使用哪一個Filed的值做爲路由參數,若是沒有設置,則使用Mapping中的配置,若是mapping中也沒有配置,則使用_id做爲路由參數,而後經過_routing的Hash值選擇出Shard
  2. 請求接着會發送給Primary Shard
  3. 在Primary Shard上執行成功後, 再從Primary Shard上將請求同時發送給多個Replica Shard
  4. 請求在多個Replica Shard上執行成功並返回給Primary Shard
  5. 寫入請求執行成功,返回結果給客戶端

須要說明的一點是,寫入成功,是指寫入到Lucene,並不包含refresh的操做完成,這個後面會涉及到在實際工做中出現的一個bugelasticsearch

針對上面的寫入的方式,寫入操做的延時就等於latency = Latency(Primary Write) + Max(Replicas Write),缺點是寫入效率比較低,除了寫入主分片,還須要寫入全部副本分片,好處也很明顯,經過副本分片能夠拓展讀性能,由於讀的時候,僅僅須要任一副本分片就能夠讀取數據,除此以外,就是避免在某個分片所在的節點崩了以後,數據不會丟失。分佈式

Elastic的TransLog

是爲了減小磁盤的IO來保證讀寫性能,同時也爲了保證對於那些已經寫入內存可是還沒寫進磁盤的數據在發生宕機的時候,數據不會丟失。

avatar

針對上圖,須要說明的幾點是:

  • refresh表示將Lucene內存中的對象轉化爲完整的Segment以後,才能夠被搜索到,這個時間通常是1秒,因此咱們通常寫入Elastic的數據,1秒以後才能夠被搜索到,Elasticsearch在搜索方面是NRT(Near Real Time)近實時的系統
  • 可是Elastic還有做爲NoSQL的一面,若是咱們按照GetById方法查詢,這個時候就變成了RT系統,這是由於這種查詢方式是直接查詢TransLog(上面那個),這個是能夠直接被查到的,這個也是我後面纔看到了,因此當時的那個問題,我並無採用這種方式
  • 每隔一段時間以後,Lucene會將內存中的Segment flush到磁盤上,此時數據被持久化了,歷史的Translog就會被清理掉。

Elastic的讀操做

Elasticsearch中每一個Shard都會有多個Replica,主要是爲了保證數據可靠性,除此以外,還能夠增長讀能力,由於寫的時候雖然要寫大部分Replica Shard,可是查詢的時候只須要查詢Primary和Replica中的任何一個就能夠了。
avatat

而後針對上面說的GetById的查詢方式和普通的Search,下面有個示意圖
avatar

整體而言讀的流程就是

  • 在全部分片中根據篩選條件找出docid(主分片和副本分片只須要一個),query
  • 而後根據docid取出完整的文檔,fetch
  • 搜索裏面有一種算分邏輯是根據TF(Term Frequency)和IDF(Inverse Document Frequency)計算基礎分
  • 上面的三個步驟都是在一個shard裏面進行的,最後一步將全部內容彙總,根據評分排名,取出部分數據

PS:從上面能夠看到Elastic不太適合深度分頁,深度分頁會比較慢,若是須要獲取因此數據,可使用scan,裏面是使用的scroll

TF:目標詞在字段中出現的次數,加分
IDF:目標詞在全部文檔中出現的次數,減分

Elastic在使用中的出現的問題和須要注意的地方

索引index按照日期分組

  • 代碼實例
class Record(Document):
    class Index:
        name = "purifier-record-*"
        
    def save(self, **kwargs):
        kwargs['index'] = self.date_created.strftime('purifier-record-%Y%m%d')
        return super(Record, self).save(**kwargs)
  • 按照日期分index的緣由:index一旦創建,主分片的數量是不能夠改變的,至關因而沒法水平拓展,若是後期數據量比較大,有可能會致使一臺機器空間不足,(PS: 若是你要說有錢,加機器硬件,當我沒說,可是一個機器的性能畢竟有限,特別是面對海量日誌之類的東西的時候),全部咱們對index進行切分了,按照月份也能夠:
  • 致使的問題:咱們在使用Elastic搜索的時候,沒有指定index,因此最後至關因而全量搜索es,速度很慢,常常接口超時,lambda是15秒,後來咱們查詢的時候加上了時間做爲篩選項,快了不少,基本都是100ms如下吧

Elastic默認的返回數量是10條,

這個須要注意,不然有可能會遇到明明數據庫存在,都是就是查找不出來的狀況,坑過

Elastic做爲搜索引擎是近乎實時的

這個須要主要,以前我遇到過剛寫入數據,而後立馬更新緩存或者執行異步任務的時候,緩存更新的是以前的數據,異步任務裏面沒有搜到剛纔那條數據,多是我搜索方式不對,以後可使用GetbyId的方式,我試試看

docid做爲其餘type的字段時候

假如說在Record裏面的_id,保存在Task裏面爲record_id,而後咱們使用record_id查詢進行filter過濾的的時候,要使用keyword查詢,就是不分析,由於docid默認的裏面有大寫字母,而後進行搜索的時候,若是沒有配置分詞器的話,使用默認的standard分詞器,會將大寫所有變爲小寫,因此就查不到了。

最後放上學習資料
Elastic權威指南,版本比較老,看看一些思想,有些操做在新版本須要修改或者廢棄了

Elasticsearch技術探討,阿里的技術人寫的一些分享

最後極客時間,前兩天新上了Elasticsearch視頻課,我先試試毒,買課如山倒,看課如抽絲

相關文章
相關標籤/搜索