倒排索引與ElasticSearch


 

1 Mysql中的索引

在MySQL中,索引屬於存儲引擎級別的概念,不同存儲引擎對索引的實現方式是不同的,本文主要討論MyISAM和InnoDB兩個存儲引擎的索引實現方式。

1.1 MyISAM索引實現

MyISAM表的索引和數據是分離的,索引保存在”表名.MYI”文件內,而數據保存在“表名.MYD”文件內。

MyISAM的索引方式也叫做“非聚集”的,之所以這么稱呼是為了與InnoDB的聚集索引區分。

1.2 InnoDB索引實現

雖然InnoDB也使用B+Tree作為索引結構,但具體實現方式卻與MyISAM截然不同。

上圖是InnoDB主索引(同時也是數據文件)的示意圖,可以看到葉節點包含了完整的數據記錄。這種索引叫做聚集索引。因為InnoDB的數據文件本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,則MySQL系統會自動選擇一個可以唯一標識數據記錄的列作為主鍵,如果不存在這種列,則MySQL自動為InnoDB表生成一個隱含字段作為主鍵,這個字段長度為6個字節,類型為長整形。

這里以英文字符的ASCII碼作為比較准則。聚集索引這種實現方式使得按主鍵的搜索十分高效,但是輔助索引搜索需要檢索兩遍索引:首先檢索輔助索引獲得主鍵,然后用主鍵到主索引中檢索獲得記錄。

了解不同存儲引擎的索引實現方式對於正確使用和優化索引都非常有幫助,例如知道了InnoDB的索引實現后,就很容易明白為什么不建議使用過長的字段作為主鍵,因為所有輔助索引都引用主索引,過長的主索引會令輔助索引變得過大。再例如,用非單調的字段作為主鍵在InnoDB中不是個好主意,因為InnoDB數據文件本身是一顆B+Tree,非單調的主鍵會造成在插入新記錄時數據文件為了維持B+Tree的特性而頻繁的分裂調整,十分低效,而使用自增字段作為主鍵則是一個很好的選擇。

傳統關系型數據庫大部分采用B-Tree/B+Tree這樣的數據結構。我們知道二叉樹的查找效率是logN,同時寫入更新新的節點不必移動全部節點,所以樹型結構存儲索引,能同時兼顧寫入和查詢性能。當我們不需要支持快速的更新的時候,則可以用預先排序等方式換取更小的存儲空間,更快的檢索速度等好處,其代價就是更新慢。

2 倒排索引

Elasticsearch使用一種稱為倒排索引的結構,它適用於快速的全文搜索。 

一個倒排索引由文檔中所有不能重復詞的列表構成,對於其中每個詞,有一個包含它的文檔列表。

倒排索引包含:文檔的列表、文檔的數量、詞條在每個文檔中出現的次數、出現的位置、每個文檔的長度、所有文檔的平均長度。

索引不可變的原因:不需要鎖,提升並發性能;可以一直保存在緩存中(filter,過濾查詢可以體現,詳情查看:Elasticsearch 過濾查詢);節省cpu和io開銷 。

一個例子:

ID是Elasticsearch自建的文檔id,那么Elasticsearch建立的索引如下:

Name:

Age:

Sex:

Posting List:

Elasticsearch分別為每個field都建立了一個倒排索引,Kate, John, 24, Female這些叫term,而[1,2]就是Posting List。Posting list就是一個int的數組,存儲了所有符合某個term的文檔id。

看到這里,不要認為就結束了,精彩的部分才剛開始...

通過posting list這種索引方式似乎可以很快進行查找,比如要找age=24的同學,愛回答問題的小明馬上就舉手回答:我知道,id是1,2的同學。但是,如果這里有上千萬的記錄呢?如果是想通過name來查找呢?

Term Dictionary:

Elasticsearch為了能快速找到某個term,將所有的term排個序,二分法查找term,logN的查找效率,就像通過字典查找一樣,這就是Term Dictionary。現在再看起來,似乎和傳統數據庫通過B-Tree的方式類似啊,為什么說比B-Tree的查詢快呢?

Term Index:

B-Tree通過減少磁盤尋道次數來提高查詢性能,Elasticsearch也是采用同樣的思路,直接通過內存查找term,不讀磁盤,但是如果term太多,term dictionary也會很大,放內存不現實,於是有了Term Index,就像字典里的索引頁一樣,A開頭的有哪些term,分別在哪頁,可以理解term index是一顆樹:

這棵樹不會包含所有的term,它包含的是term的一些前綴。通過term index可以快速地定位到term dictionary的某個offset,然后從這個位置再往后順序查找。

所以term index不需要存下所有的term,而僅僅是他們的一些前綴與Term Dictionary的block之間的映射關系,再結合FST(Finite State Transducers)的壓縮技術,可以使term index緩存到內存中。從term index查到對應的term dictionary的block位置之后,再去磁盤上找term,大大減少了磁盤隨機讀的次數。

 

3 ElasticSearch對比關系型數據庫

Elasticsearch是面向文檔型數據庫,一條數據在這里就是一個文檔,用JSON作為文檔序列化的格式,比如下面這條用戶數據:

{
    "name" :     "John",
    "sex" :      "Male",
    "age" :      25,
    "birthDate": "1990/05/01",
    "about" :    "I love to go rock climbing",
    "interests": [ "sports", "music" ]
}

用Mysql這樣的數據庫存儲就會容易想到建立一張User表,有6個字段等,在Elasticsearch里這就是一個文檔,當然這個文檔會屬於一個User的類型,各種各樣的類型存在於一個索引當中。這里有一份簡易的將Elasticsearch和關系型數據術語對照表:

Relational DB

Databases

Tables

Rows

Columns

關系型數據庫

數據庫

Elasticsearch

Indices

Types

Documents

Fields

搜索引擎

索引

類型

文檔

域(字段)

以上表格是一一對應的關系,比如上述代碼塊中的例子,對應到關系型數據庫中就是1個數據庫6個字段,對飲到ElasticSearch中就是1個索引,6種類型。

在Elasticsearch中,所有的字段缺省都建了索引。 也就是說每一個字段都有一個倒排索引,用於快速查詢。

es支持http協議(json格式)(9200端口)、thrift、servlet、memcached、zeroMQ等的傳輸協議(通過插件方式集成),傳統關系型數據庫不支持。

es支持分片和復制,從而方便水平分割和擴展,復制保證了es的高可用與高吞吐。

 

Reference

https://blog.csdn.net/qq924862077/article/details/80382634

https://www.cnblogs.com/dreamroute/p/8484457.html

https://blog.csdn.net/zx711166/article/details/81517178


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM