elasticSearch -- (文档,类型,索引)
問題:大規模數據如何檢索
- 數據庫選擇—mysql, sybase,oracle,mongodb,hbase…
- 單點故障如何解決—lvs, F5,A10,Zookeeper,MQ
- 如何保證數據安全----熱備,冷備,異地多活
- 如何解決檢索難題—數據庫中間件mysql-proxy,sharding, cobar, MaxScale
- 如何積極統計分析問題—離線計算,近實時
- 通過主從備份解決數據安全性問題
- 通過數據庫代理中間件心跳檢測,解決單點故障問題
- 通過代理中間件將查詢語句分發到每個slave節點查詢,并且匯總結果
- 通過副本備份積極數據安全性問題
- 通過節點競選機制解決單點問題
- 先從配置庫檢索分片信息,讓后請求分發到各個節點,最后由路由節點合并匯總結果。
- 不可能完全在內存中放所有數據,單達到PB級別的時候,每個節點按256G,在內存完全裝滿情況下我們需要如下個機器 1PB = 1024T = 1024*1024G,節點1024 * 4 = 4096個,加上備份的數據,節點應該會超過4096 * 2 = 8192個,太費錢
- 不管是否全部放內存都不能完全解決問題,用一下方式
- 存儲數據按有序存儲
- 將數據和索引分離、
- 壓縮數據
luncene與 ES
- luncene只是一個檢索庫,要想使用必須用java開發并且集成到你項目中,并且luncene非常復雜,需要深入了解檢索的相關知識來理解他是如何工作的。
- Elasticsearch使用luncene作為底層查詢,用java開發,通過RESTful api來隱藏Lucene的復雜性,使用只需關注api就行,降低接入成本以及復雜度。
ES主要解決問題
- 檢索相關數據
- 返回統計結果
- 速度快
原理
- 當ElasticSearch的節點啟動后,會利用多播(multicast)或者單播(配置修改)尋找集群中其他節點,并且建立連接,過程如下:
核心概念
- 集群:ES可以作為獨立的搜索服務器,不過處理的數據局限于單點存儲功能,可以通過多借點相互合作的多服務器上,實現大小數據集檢索,實現容錯和高可用。
- 分片:文檔巨大,內存限制,磁盤處理能力不足,無法足夠快的響應查詢,一個節點存儲不夠。這些情況,數據可以分開成多個較小的分片,每個分片在不同的服務器上。單查詢的索引分布在多個分片上,ES會將查詢發送給每一個分片,并將結果組合起來,對應用透明。
- 副本:為提供吞吐量或者實現高可用,可以使用分片副本,副本是一個分片的Slave,每個分片可以有多個副本,ES可以有許多相同的分片,其中一個被選中更改索引操作,這種分片是主分片。單主分片丟失,集群將副本某一個提升為主分片
- 全文檢索:將內容根據詞的意義進行分詞,讓后分別創建索引例如:
- “你們的動力是因為什么事情來的” 可分為:“你們”,“動力”,“什么事情”,“來”等token,當搜索你們,或者動力時候都會講這個段搜索出來。
ES數據架構主要概念(mySql對比)
- 關系型數據庫中數據庫(DB)等價es中索引(index)
- 一個數據庫下面N張表(table),等價1個索引下N多屬性(Type)
- 一個數據庫表(table)下的數據由多行,多列組成,等價es中1個Type由多Document和多個Field組成
- 關系型數據庫里面,Schema定義了表,每個表的字段,還有表與字段直接的關系,與之對應的ES中:Mapping定義索引下的Type的字段處理規則,即索引如何建立,索引類型,是否保存原始索引JSON文檔,是否壓縮原始JSON文檔,是否需要分詞處理,如何進行分詞等。
- 數據庫中CURD操作等價ES中 增PUT/POST,刪Delete,改_update,查GET(標準RESTful)
ELK: elasticsearch+Logstash+kibana
- elasticsearch:后臺分布式存儲以及全文檢索
- logstash:日志加工,日志統計
- kibana:數據可視化展示
- ELK架構為數據分布式存儲,可視化查詢和日志解析創建了一個功能強大的管理鏈,三者相互配合完成分布式大數據處理工作。
常見的增、刪、改、查操作實現
性能esrally工具
[新浪ES 如何分析處理32億條實時日志 ]( <http://dockone.io/article/505 )
阿里ES 構建挖財自己的日志采集和分析體系
有贊ES 業務日志處理
ES實現站內搜索
特定優勢
- 分布式實時文件存儲,索引可到某個字段級別檢索
- 實時分析的分布式搜索引擎
倒排索引
- 搜索引擎通常檢索的場景是:給的幾個關鍵字,找出包含關鍵字的文檔。怎么快速找到包含某個關鍵字的文檔就成為搜索的關鍵,倒排索引源于實際應用中需要根據屬性的值來查找記錄,lucene是基于倒排索引實現的,這種索引表中的每一項都包括一個屬性值和具有改屬性值的各個記錄的地址,由于不是由記錄來確認屬性值,而是由屬性值來確定記錄的位置,所以稱為倒排索引
正排索引
- 正排索引是以文檔的ID為關鍵字,表中記錄文檔中每個字的位置信息,查找時候掃描表中每個文檔中字的信息直到找出所有包含查詢關鍵字的文檔。查詢效率相對來說不高。
總結:倒排索引記錄了某個關鍵字在那些文檔中,正排索引記錄了文檔包含了哪些關鍵字
問題:倒排索引比關系型數據庫的b-tree索引快在哪里?
文檔
- Elasticsearch是面向文檔的,那么搜索和索引數據的最小單元就是文檔,在Elasticsearch中文檔有以下幾個重要的屬性:
- 文檔是自我包含的,一篇文檔包含字段,已經他們的值
- 他可以是層次結構。比如一個JSON個是保存的文檔,他某個字段里面還是一個JSON格式,這就是層次結構
- 有靈活的結構,文檔不依賴預先定義的模式也就是非schema的形式,也就是在同一個類型下的文檔并不一定都包含改類型下的所有字段。
- 盡管我們可以隨意的添加數據和忽略數據,但是每個字段的類型在Elasticsearch 中是很重要的:某個字段是字符串,某些是整數等。這一點Elasticsearch 在添加數據的時候,會將字段和類型之間做映射這就是我們說的建立Mapping。這樣的映射具體到每個索引的每種類型上面。在Elasticsearch 中也叫作映射類型。
類型
- 類型是文檔的邏輯容器,類似表格是行的容器。不同類型中,最好放入不同結構的文檔。例如一個類型定義A分組,而另一個類型定義B
- 每個類型中字段的定義就是我們說的Mapping映射。例如name字段可以映射為String。而location中的geolocation可以映射為get_point類型。每種字段都通過不同方式進行處理。例如我們可以在name字段中搜索匹配的關鍵字,同時根據位置類搜索哪些分組離我的地理位置更近
- 問題在于Elasticsearch 是無模式非schema形式的數據,為什么文檔屬于一種類型,二每個類型都是類似模式的映射(字段):
- 因為非schema形式是針對文檔的,表示 文檔是不受模式限制。并不是每個文檔都需要包含他所在類型中的所有字段,而是類型映射應該包含他所有文檔的所有字段。這就是類型與文檔的關系。
- 同樣道理,如果一篇新的文檔添加后有一個映射不在本類型的字段中,Elasticsearch會自動的將新字段鍵入映射。為了添加這個字段,Elasticsearch需要先確定這個類型,Elasticsearch猜測類型,例如如果是一個整數7 ,他會將類型建立為整型,所以es的寫入性能是不高的,他需要刷新Mapping
- 這種實時刷新Mapping的方式確定在于,在第一次定義7 這個字段是整型后,我對字段進行搜索hello,那么索引會失敗,他不是String。對應線上的環境最安全的方式就是先導入數據,建立Mapping后在去搜索
- 類型的Mapping映射只是將文檔進行了邏輯劃分,從物理上看同一個索引中的文檔都是寫入磁盤中,而不會考慮他們所在的映射類型。
索引
- 索引是映射類型的容器。一個Elasticsearch索引就像mySql中的數據庫級別。是獨立的大量文檔數據的集合。每個索引存儲在磁盤上的同組文件中;索引存儲了所有映射的字段。還有一些設置。
- 例如每個索引有一個稱為refresh_interval的設置,定義了新進的索引的文檔對于搜索的可見的時間間隔。從性能上看,刷新的操作代價是比較大的。這也是為什么更新只能是偶爾進行。默認是一次性導入,而不是逐步的同步,Elasticsearch被稱為準實時的,就是因為有這個刷新時間
映射的定義
- 映射的定義就是Mapping建立的一個過程,我會將文檔歸類,將文檔中的每個字段歸類到每一個類型中,并且設置改文檔的每個字段的查詢設置
定義文檔字段的核心類型
- 字符串類型
- 字符串是最直接的:如果索引字符,字段就是string類型,也是查詢最豐富的的一種類型,因為映射有很多選項設置來分析他
- 解析文本,轉變文本,分解為基本元素使得搜索更為相關,這個過程就是分析
- 例如搜索的name字段,當索引到文檔的name時候,默認分析器將改文檔的內容轉為小寫,然后將字符分解為單詞
- 映射的作用就是在分析過程起作用,可以依據需求來設置映射分析的策略,例如index選項可以設置為:
- anayzed(默認):分析器將所有字符轉小寫,并且將字符串分解為單詞
- not_analyzed:分析過程被略過,整個字段需要全量匹配
- no:索引略過該字段。
- 數值類型
- 包括byte,short, int, long數值型 float, double浮點型
- 這些對于的java原始數據類型,顯然字段選擇會影響索引的大小,在存儲數據的索引中,字符占用內存越大,數據量也就越大,最好選擇合適的數據類型
- 日期類型
分析數據
- 分析(analysis)是在文檔被發送并加入倒排索引之前,Elasticsearch在其數據上進行的一個處理。
- 數據添加到索引前做的事情:
- 字符過濾: 使用字符過濾器轉變字符
- 文本切分成詞組: 將文本切分成單個的單詞
- 分詞過濾: 使用分詞過濾轉變每個分詞
- 分詞索引: 將這些分詞存儲到索引中。
- 整個流程如下圖:
字符過濾
- Elasticsearch運行字符過濾器,將特定字符列轉換為其他字符序列。可以將HTML從文本中剝離,或者將任意字符轉化為其他字符(例如“ I LOVE u 2” 轉為 “i love you too”)如上我們設置特殊的將&符合轉為 and
切分為分詞
- 文本需要被分割成可以操作的片段。Lucene自己不會對大塊的字符串數據進行操作,他直接處理被稱為分詞(token)的數據。分詞是從文本片段生成的,可以產生任意數量,
分詞過濾器
- 被分詞后得到的token,Elasticsearch會將每個分詞運用分詞過濾器,他可以將一個分詞作為輸入,然后更具需要進行修改,添加,刪除。最有用的和常用的分詞過濾器是小寫分詞過濾器將輸入分詞轉為小寫,這樣我們早修改noSql的時候也可以同時發現NoSql的聚合。
分詞索引
- 當溫度經過0~n個分詞過濾器后,將發送到lucene進行文檔索引。
- 以上所有的不同組件部分組成了一個分析器(analyzer),Elasticsearch提供了很多這種分析器可以直接使用而不用構建自己的分析器
內置分析器
- 一個分析器包括一個可選的字符過濾器,一個單個分詞器,0個或者多個分詞過濾器
- 如下有幾種分析器,每種功能都不同
- 標準分析器:文本的默認分析器包括 標準分析器,標準分詞過濾器,小寫轉換分詞過濾器和停用分詞過濾器
- 簡單分析器:只永小寫轉換分詞器
- 空白分析器:什么都不做,值更具空包將文本進行拆分
- 停用詞分析器:在分詞流中過濾停用詞
- 關鍵詞分析器:將整個字段當成單獨一個分詞
- 模式分析器:
- 語言和多語言分析器:Elasticsearch能直接使用的特點語言分析器包括漢語等
- 雪球分析器
分詞器
-
以上說過,分詞器將文本分解成小塊token,Elasticsearch 內部也包含了一些內置的分詞器
- 標準分詞器:基于語法的分詞器,針對英語等歐洲語法
- 關鍵詞分詞器:簡單的將文本作為單個的單詞提供給分詞過濾器,但我們不想在拆分的時候可以用
- 字母分詞器:更具妃子們的符號,將文本切分為分詞,去掉符號等
- 小寫分詞器:結合了常規字母分詞器和小寫分詞過濾器,功能結合提升性能
- 空白分詞器:通過空白分割不同分詞,空白包括:空格,制表符,換行符
- 模式分詞器:
- UAX URL 電子郵件分詞器
- 路勁層次分詞器
分詞過濾器
- Elasticsearch中有很多分詞過濾器,如下圖三個簡單的分詞過濾
- 標準分詞過濾器:什么都沒做
- 小寫分詞過濾器:將任何進過的分詞轉小寫
- 長度分詞過濾器:將長度不符合配置范圍內的單詞過濾,可設置
- 停用詞分詞過濾器:將停用詞從分詞中刪除,針對英文的過濾
- 截斷分詞過濾器,修剪分詞過濾器和限制分詞數量過濾器:
- 截斷分詞過濾器:運行通過盯著配置中length參數,截斷超過一定長度分詞,默認配置是階段多余10個字符的部分
- 修剪分詞過濾器:刪除一個分詞中所有空包
- 限制分詞數量分詞過濾器:現在某個字段可能包含分詞的最大數量,比如文本太長,限制8 ,那么就只會有8個分詞被索引
- 顛倒分詞過濾器:允許一個分詞流并且顛倒每個單詞
- 唯一分詞過濾器:
- ASCII折疊分詞過濾器
- 同義詞分詞過濾器:在分詞流中的同樣位移處,用關鍵詞的同義詞取代原始詞
Mapping構建總結
- ElasticSearch 的查詢是基于 luncene實現的,但是luncene只是一個檢索庫,他能處理的數據單元并非是整個文檔類型,lucene是基于倒排索引實現的,這種索引表的結構特點在于,表中的每個屬性都對應各個記錄的具體文檔位置,這樣可以直接通過查詢屬性key來找到對應的文檔集合。
- ElasticSearch對數據的處理就是要將普通的文檔 處理成 (屬性-- 結果地址)這種數據字典,同時對字段進行一些特殊設置這就是Mapping建立過程
- 在文檔添加的時候,將結構相似的文檔歸為同一個類型下,該類型包含了所有文檔中的每個屬性
- 在添加到文檔之前,文檔需要經過ElasticSearch分析器的處理,它包括字符過濾器,分詞器,分詞過濾器,分別是字符過濾,分詞,特定功能呢過濾的能力,每個功能都內置了不同功能的插件,可以依據業務的需要選擇,也可以選擇外部插件,例如中文IK分詞器就是在分詞階段起作用。最后將得到的分詞存儲到索引中。如下圖示意流程
- 每個索引可能有多個分類,而每個分類下是包含本類別文檔的所有分詞信息,這樣就得到了如下模式的一個數據結構
倒排索引性能總結
- 在為屬性(field)構建倒排索引后,此時,本類別中包含了所有文檔中所有字段的一個 分詞(term) 文檔id對應關系的字典信息
- 通過倒排索引,我們可以迅速找到符合添加的文檔,例如peace在文檔 2,3,4 中。
- 當我們進行Elasticsearch查詢,為了能快速找到某個term,ElasticSearch 將類型中所有的term進行排序,然后通過二分法查找term,時間復雜度能達到 logN的查找效率,就像通過字典查找一樣,這就是Term Dictionary
- 同時參照 B-Tree通過減少磁盤尋道次數來提高查詢性能,Elasticsearch也是采用同樣的思路,直接通過內存查找term,將term Dictionary這個構建的Mapping存放在內存中。但是如果term太多,term dictionary也會很大,放內存不現實,于是有了Term Index,就像字典里的索引頁一樣,A開頭的有哪些term,分別在哪頁,可以理解term index是一顆樹如下圖:
-
如上圖中數據結構是字典樹,同時也叫tire樹, 有如下結構特性:
- 根節點不包含字符,除根節點外每一個節點都只包含一個字符。
- 從根節點到某一節點,路徑上經過的字符連接起來,為該節點對應的字符串。
- 每個節點的所有子節點包含的字符都不相同。
-
如上第二點中每個節點都只包含一個字符,如圖中te 是結合了第一個節點t, 和本節點e,得到的一個結果是te,本節點此時值存儲了一個字符e
-
字典樹平均時間復雜度:復雜度為O(n*len),實際查詢的復雜度也只是O(len)。(Trie樹的平均高度h為len,所以Trie樹的查詢復雜度為O(h)=O(len)
-
樹節點存儲的是term的前綴信息,通過前綴查詢關鍵字在term Dictionary中的偏移量,然后在遍歷對應的Term Dictionary 對應的這段數據找到具體的term, 存儲的是Term前綴 與 Term Dictionary 的block之間的映射關系
-
在此基礎上在對內存中的Term index進行數據壓縮,這樣的話用時間換空間,的方式減少內存的占用,這樣就可以完全在內存中找到對應的文檔id,最后去磁盤讀取對應的文檔信息。磁盤隨機讀的次數
-
額外的知識:
- MySql Innodb存儲引擎在1.2版本后也支持了全文檢索,通MyISam存儲引擎一樣,在創建全文檢索所有后,mysql會將對應字段進行分詞
- 分詞后的分詞,文檔id字典信息存儲在六張表中
- 同樣的,MySql全文檢索為了優化查詢,將全文檢索索引(也就是字典)緩存在內存中,也同樣的是通過內存區查詢
- MySql此時也同樣用來前綴存儲的方法去減少內存的占用,但是這里MySql并不是和es一樣用的term index的字典表,有MySql用的紅黑樹來存儲term directionary
- 并且MySql還做了數據壓縮處理,在紅黑樹中得到的前綴是sab,找到對應字段offset后的所有對應的數據存儲的方式是將sab省略的后半部分,以這種方式來減少磁盤的占用
- MySql 還對全文索引對應的字段的insert, delete操作進行了優化,因為我們真正查詢的時候是用的字典,并不是全文檢索本文
- 當insert的時候,MySql對全文索引字段進行分詞,此時并不會直接將新的字段數據更新到字典表,而是直接更新全文檢索索引緩存,只有在正在用到索引緩存進行數據查詢的時候,才會真正更新到對應的字典表中
- MySql對刪除有同樣的處理,當我們刪除一個文檔時候,MySql會將文檔id添加到一張刪除記錄表中,并且更新對應的索引緩存,還是在查詢的時候,更新字典表。
- 紅黑樹查詢平均時間復雜度是O(logn)
總結
以上是生活随笔為你收集整理的elasticSearch -- (文档,类型,索引)的全部內容,希望文章能夠幫你解決所遇到的問題。