整理:ElasticSearch 2 (10) - 在ElasticSearch之下(深入理解Shard和Lucene Index)

ElasticSearch 2 (10) - 在ElasticSearch之下(深入理解Shard和Lucene Index)

摘要

從底層介紹ElasticSearch Shard的內部原理,以及回答爲什麼使用ElasticSearch有必要了解Lucene的內部工作方式?

  • 瞭解ElasticSearch API的代價

    • 構建快速的搜索應用
    • 不要任何時候都commit
    • 何時使用Stored Fields和Document Values
    • Lucene可能不是一個合適的工具
  • 瞭解索引的存儲方式

    • term vector是索引大小的1/2
    • 我移除了20%的文件,但是索引佔用空間並未發生任何變化

版本

elasticsearch版本: elasticsearch-2.2.0

內容

索引

毫不誇張的說,如果不瞭解Lucene索引的工作方式,可以說完全不瞭解Lucene,對於ElasticSearch更是如此。

  • 可以使搜索更快速

    • 可以冗餘信息
    • 根據查詢(queries)建立索引
  • 在更新速度與查詢速度間妥協

    需要注意的是搜索的應用場景

    • Grep vs. 全文檢索(full-text indexing)
    • Prefix queries vs. edge n-grams
    • Phrase queries vs shingles

    如果是進行前綴查詢(右模糊匹配)或者是短語查詢(phrase queries),ElasticSearch可能不合適,需要做特殊的優化。(在2.x中,ES對以上應用場景都有支持,具體使用方式可以參考:Search in Depth

  • Lucene索引的速度

創建索引

以兩個簡單的文件爲例:Lucene in action和Databases。

假設Lucene in action裏有單詞

{index, term, data, Lucene}

Databases裏有單詞

{sql, index, data}
  • 樹形結構(Tree structure)

    對於range query有序
    查詢的時間複雜度爲O(log(n))

    一般的關係型數據庫大致結構可能是上面這樣的一顆B、B+樹,但是Lucene是另外一種存儲結構。

  • 倒排索引(或反向索引Inverted Index)

    對於Lucene來說,其主要的存儲結構是一個反向索引,它是一個數組,數組裏面是一個有序的數據字典。

    這樣一個存儲結構存在與LuceneSegment裏。

    • term ordinal —— 是一個詞的序號
    • term dict —— 是詞的內容
    • postings list —— 存放包含詞的文件的id序列
    • doc id —— 是每個文件的唯一標識
    • document —— 存放每個文件的內容

    這兩種結構的一個重要區別是:在增加或刪除文件時,系統會樹形結構頻繁操作,這個結構是一直變化的,而反向索引可以維持不變(Immutable)。????

  • 插入?

    • 插入 即 創建一個新的segment

    • 當有很多segment時,系統會合並segment
      這個過程本質上是一個merge sort,做的事情就是

      • 連接文件
      • 合併字典
      • 合併postings lists

  • 刪除?

    • 刪除要做的只是置一個標誌位
    • 搜索及merge的時候系統會忽略被刪除的文件
    • 當有很多刪除發生時,系統會自動運行merge
    • 被標記爲已刪除的文件會在merge完成後回收其所佔用的存儲空間

  • 孰優孰劣?

    • 當更新一個文件的時候,我們實際上是創建了一個新的segment,因此

      • 單個文件的更新代價高昂,我們需要使用bulk更新
      • 所有的寫操作都是順序執行的
    • Segments永遠不會被修改

      • 文件系統緩存友好
      • 不會出現鎖的問題
    • Terms 高度去重

      • 節省大量高頻詞所佔用的空間
    • 文件本身由唯一序號標識

      • 跨API通信的時候非常方便
      • Lucene可以在單個Query下使用多個索引index
    • Terms 由唯一序號標識

      • 對於排序非常重要,只需要比較數字,而非字符串
      • 對於faceting(分面搜索)非常重要
  • Lucene Index的強大之處(Index intersection)???

    很多數據庫不支持同時使用多個索引,但是Lucene支持

    • Lucene爲postings lists 維護一個skip list(Wiki),如果要搜索如上例子中的“red shoe”,系統參考skip list裏的信息可以跳躍檢索(“leap-frog”)

    • 對於很多數據庫,它們會挑選最主要的索引(most selective),而忽略其他

    關於詳細的index intersection算法以及如何使用skip list的可以參照(nlp.standford.edu

更多索引

  • 術語向量(Term vectors)

    • 爲每個文件都會創建一個反向索引(Inverted Index)
    • 適用場景:搜索更相似的內容
    • 也可以用作高亮搜索結果

  • 文件值(Document Values)???

    • 以文件字段爲單位進行列式存儲
    • 適用場景:排序、權重記分

  • 有序(集合)文件值???

    • 文件有序、字段有序

      • 單字段:排序
      • 多字段:分面搜索

  • 分面搜索(Faceting)???

    分面是指事物的多維度屬性。例如一本書包含主題、作者、年代等分面。而分面搜索是指通過事物的這些屬性不斷篩選、過濾搜索結果的方法。可以將分面搜索看成搜索和瀏覽的結合。分面搜索作爲一種有效的搜索方式,已經被用在電子商務、音樂、旅遊等多個方面。

    例如,谷歌音樂的挑歌頁面,將歌曲分爲節奏、聲調、音色、年代、流派等分面

    • 根據文件與搜索匹配的情況計數

      • 例如,電商網站根據衣服的款式、衣長、尺碼、顏色等分面。
    • 簡單(naive)方案

      • 利用哈希表計數(value to count)
      • O(#docs) ordinal 查找
      • O(#doc) value 查找
    • Lucene方案

      • 哈希表(ord to count)
      • 最後統計值
      • O(#docs) ordinal 查找
      • O(#values) value 查找

    因爲ordinal是密集的,所以可以簡單用數組array來表示。

  • 如何使用API?

    ElasticSearch高級API 都是基於Lucene API構建的,這些基礎的API包括:

      -----------------------------------------------------------------------------------------------
      	API					|	用途									|	方法
      -----------------------------------------------------------------------------------------------	
      	Inverted index		| Term -> doc ids, positions, offsets	|	AtomicReader.fields
      -----------------------------------------------------------------------------------------------	
      	Stored fields		| Summaries of search results			|	IndexReader.document
      -----------------------------------------------------------------------------------------------	
      	Live docs			| Ignoring deleted docs					|	AtomicReader.liveDocs
      -----------------------------------------------------------------------------------------------		
      	Term vectors		| More like this						|	IndexReader.termVectors
      -----------------------------------------------------------------------------------------------
      	Doc values/Norms	| Sorting/faceting/scoring				|	AtomicReader.get*Values
      -----------------------------------------------------------------------------------------------		
    
  • 小結

    • 數據有四份重複,只是結構各不相同

      • 絕不是浪費空間
      • 感謝immutable使數據易於管理
    • Stored Fields和Document Values

      • 兩種結構爲不同的使用場景優化

        1. 少量文件獲取多個字段:Stored Fields
        2. 大量文件獲取少量字段:Document Values

文件格式的祕密

  • 不能忘的規則

    • 保存文件的句柄

      不要爲每個字段每個文件使用文件

    • 避免磁盤尋址

      磁盤尋址的時間大概爲~10ms

    • 不要忽略文件系統的緩存

      隨機訪問小文件還是可以的

    • 使用輕壓縮

      • 更少I/O
      • 更小索引
      • 文件系統緩存友好
  • 編碼解碼

  • 合適的壓縮技術

    • Bit packing / vlnt encoding

      • postings lists
      • numeric doc values
    • LZ4

    • FSTs

      • Map<String, ?>
      • 鍵共享前綴(prefix)和後綴(suffix)
      • terms index
  • TermQuery的背後

    1. Terms Index

      在索引中查找相應的詞

      • 在內存中FST存儲了詞的前綴prefix
      • 提供詞在字典中的偏移量
      • 在不存在時可以快速失敗

    2. Terms Dictionary

      • 跳到字典偏移的位置

        壓縮是基於共享前綴的,與“BlockTree term dict”類似

      • 順序讀取直到找到特定的Term

    3. Postings List

      • 跳到postings list偏移量對應位置

      • 用改進的FOR(Frame of Reference)進行增量編碼

        1. 增量編碼
        2. 將塊拆分爲N=128個值的大小
        3. 每個塊使用位壓縮(bit packing)
        4. 如果有剩餘文檔,使用vlnt壓縮

    4. Stored Fields

      • 對一個子集的doc id,索引存於內存中

        高效內存(monotonic)壓縮

        二分查找

      • 字段

        順序存儲

        使用16KB塊存儲壓縮

  • 查詢過程小結

    • 每個字段2次磁盤尋址

    • 每個文件1次磁盤尋址(Stored Fields)

    • terms dict/postings lists都在文件系統的緩存中

      此時不會發生磁盤尋址

    • “脈衝”優化

      • 對於唯一的term,postings list存儲在Terms dict中
      • 1次磁盤尋址
      • 永遠作爲主鍵

性能

上圖中系統性能出現兩次下降,可能的情況是

  1. 索引增長超過文件系統緩存的大小

    Stored Fields不再全部存儲於緩存中

  2. Terms dict/Postings lists不全在緩存中

參考

參考來源:

SlideShare: What is in a Lucene index?

Youtube: What is in a Lucene index? Adrien Grand, Software Engineer, Elasticsearch

SlideShare: Elasticsearch From the Bottom Up

Youtube: Elasticsearch from the bottom up

Wiki: Document-term matrix

Wiki: Search engine indexing

Skip list

Standford Edu: Faster postings list intersection via skip pointers

分面搜索(Faceted Search)

StackOverflow: how an search index works when querying many words?

StackOverflow: how does lucene calculate intersection of documents so fast?

Lucene and its magical indexes

結束

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章