一、前言
(知識搬運工
走近 ElasticSearch (一)——基本概念與架構設計
走近 ElasticSearch (二)——Document概念、倒排索引原理與分詞
走近 ElasticSearch (三)——Mapping設計與Search API 介紹
二、Document 介紹
1. Document 數據類型
Json Object,由字段(Field)組成,常見數據類型如下:
- 字符串: text, keyword
- 數值型: long, integer, shot, byte, double, float,haf_float, scaled_float
- 布爾: boolean
- 日期: date
- 二進制: binary
- 範圍類型: integer_range, float_range, long_range, double_range, date_range, ip_range
- 還有其他數據類型:
- 嵌套類型: nested
- 對象類型: object
- 數組類型: Array
- 地理類型: geo_point, geo_shape
- 自動補全類型: completion
- 多字段特性:multi-fields
2. Document 創建
每個文檔有唯一的 id 標示。兩種方式:自行指定;es自動生成
以es自動生成索引爲例:
文檔元數據解釋:
- _index: 文檔所在的索引名
- _type: 文檔所在的類型名
- _id: 文檔唯一id
- _uid: 組合 id, 由 _type 和 _id 組成(6.x _type 不再起作用, 同_id一樣)
- _source: 文檔的原始 Json 數據,可以從這裏獲取每個字段的內容
- _all: 整合所有字段內容到該字段,默認禁用
注意:創建文檔時,如果索引不存在,es 會自動創建對應的 index 和 type。建議在創建索引時,定義 mapping。
使用 POST _bulk
一次創建多個文檔,從而減少網絡傳輸開銷,提升寫入速率
3. Document 查詢
指定要查詢的文檔id
搜索索引文檔,用到_search
:
三、倒排索引與分詞
1. 倒排索引
1.1 概念
倒排索引是搜索引擎到核心,主要包括兩部分:
- 單詞詞典(Term Dictionary)
- 記錄所有文檔的單詞,一般都比較大
- 記錄單詞到倒排列表的關聯信息(文檔ID)
- 倒排列表(Posting List):
- 記錄了單詞對應的文檔集合,由倒排索引項(Posting)組成
單詞詞典的實現一般是 B+ Tree:
倒排索引項(Posting)主要包含如下信息:
- 文檔Id,用於獲取原始信息
- 單詞頻率(TF, Term Frequency),記錄該單詞在該文檔中的出現次數,用於後續相關性算法
- 位置(Position),記錄單詞在文檔中的分詞位置(多個),用於做詞語搜索(Phrase Query)
- 偏移(Offset),記錄單詞在文檔的開始和結束位置,用於做高亮顯示
1.2 索引的位置與粒度
倒排索引的位置:
Cluster->Node->Shard->segment->Index
爲了優化搜索,segment不僅只提供了倒排,還提供了document values field cache 解決:排序、聚合等問題
對於索引的構建粒度,是按照字段來構建的,即:每個字段會有自己的倒排索引,類似下圖:
1.3 ES集羣中操作索引過程
ES引擎把文檔數據寫入到倒排索引(Inverted Index)的數據結構中,建立起 分詞 (Term)—> 文檔(Document) 映射關係。
然後這些倒排索引會存放在段(segment)中,段的寫入會落盤,緩存buffer會實時更新。
具體的操作可分爲寫操作、讀操作、更新操作:
- 寫操作: 寫操作必須在primary shard完全成功後才能拷貝至其對應的replicas上,默認情況下主分片。等待所有備份完成索引後才返回客戶端。
1、客戶端向Node1 發送索引文檔請求
2、Node1 根據文檔ID(_id字段)計算出該文檔應該屬於shard0,然後請求路由到Node3的P0分片上
3、Node3在P0上執行了請求。如果請求成功,則將請求並行的路由至Node1,Node2的R0上。當所有的Replicas報告成功後,Node3向請求的Node(Node1)發送成功報告,Node1再報告至Client。
當客戶端收到執行成功後,操作已經在Primary shard和所有的replica shards上執行成功了 - 讀操作: 一個文檔可以在primary shard和所有的replica shard上讀取
1.客戶端發送Get請求到NODE1。
2.NODE1根據文檔ID(_id字段)計算出該文檔應該屬於shard0,且shard 0的所有拷貝存在於所有3個節點上。這次,它將請求路由至NODE2。
3.NODE2將文檔返回給NODE1,NODE1將文檔返回給客戶端。 對於讀請求,請求節點(NODE1)將在每次請求到來時都選擇一個不同的replica shard來達到負載均衡。使用輪詢策略輪詢所有的replica shards。 - 更新操作,結合了以上的兩個操作:讀、寫
1.客戶端發送更新操作請求至NODE1
2.NODE1將請求路由至NODE3,Primary shard所在的位置
3.NODE3從P0讀取文檔,改變source字段的JSON內容,然後試圖重新對修改後的數據在P0做索引。如果此時這個文檔已經被其他的進程修改了,那麼它將重新執行3步驟,這個過程如果超過了retryon_conflict設置的次數,就放棄。
4.如果NODE3成功更新了文檔,它將並行的將新版本的文檔同步到NODE1和NODE2的replica shards重新建立索引。一旦所有的replica shards報告成功,NODE3向被請求的節點(NODE1)返回成功,然後NODE1向客戶端返回成功。
2. 分詞
分詞是指將文本轉換成一系列單詞(term or token)的過程,也可以叫做文本分析,在 es 裏面成爲 Analysis,如下圖所示:
2.1 分詞器組成
分詞器是 es 中專門處理分詞的組建,英文爲 Analyzer,它的組成如下:
- Character Filters:針對原始文本進行處理,比如去除 html 特殊標記符
- Tokenizer:將原始文本按照一定規則切分爲單詞
- Token Filters:針對 tokenizer 處理的單詞再加工,比如轉小寫,刪除或新增等處理
分詞器調用順序:
2.2 調參:測試我們配置的分詞器
es 提供了一個測試分詞的 api 接口,方便驗證分詞效果,endpoint 是 _analyze。
對此我們可以使用三種方式進行測試:
- 直接指定 analyzer 進行測試,接口如下:
- 直接指定索引中的字段進行測試,接口如下:
- 自定義分詞器進行測試,接口如下:
2.3 分詞器種類
es自帶如下的分詞器:Standard、Simple、Whitespace、Stop、Keyword(不分詞,直接將輸入作爲一個單詞輸出)、Pattern、Language
常用中文分詞器:
- ik(下載地址)
- 可自定義詞庫,支持熱更新分詞詞典
- jieba(下載地址)
- 支持繁體分詞、自定義詞典、並行分詞等。python 中最流行的分詞系統,支持分詞和詞性標註
基於自然語言處理的分詞系統
- 支持繁體分詞、自定義詞典、並行分詞等。python 中最流行的分詞系統,支持分詞和詞性標註
- Hanlp:由一系列模型與算法組成的Java工具包,目標是普及自然語言處理在生成環境中的應用
- THULAC:清華大學自然語言處理實驗室推出的一套中文詞法分析工具包,具有中文分詞和詞性標註功能
2.4 分詞器使用說明
分詞會在如下兩個時機使用:
- 創建或更新文檔時(Index Time),會對相應的文檔進行分詞處理
- 查詢時(Search Time),會對查詢語句進行分詞
對於創建或更新索引:我們可以通過配置 Index Mapping 中每個字段的 analyzer 屬性實現指定分詞器(默認 standar 分詞器);
對於查詢時分詞,通過 index mapping 設置 search_analyzer 實現