Elasticsearch 是分布式搜索和分析引擎,是滿足搜索和聚合需求的最受歡迎的選擇。
【資料圖】
Elasticsearch 提供了 2 種數據類型來存儲字符串值:
Text:- 在存儲到倒排索引之前對這些內容進行分析,并針對全文搜索進行優化。 文本字段不允許聚合Keyword:- 它們按原樣存儲在倒排索引中,如果需要,可以在查詢期間進行分析。 這些針對聚合進行了優化,因為它們也以柱狀方式存儲(稱為 doc values),以便可以引用單個字段,而無需在內存中加載完整文檔有關 text 及 keyword 搜索的更多比較,請參閱我之前的文章 “Elasticsearch:Text vs. Keyword - 它們之間的差異以及它們的行為方式”。
Elasticsearch 將 keyword 存儲為 doc values 中的序數,以獲得更緊湊的表示。 這種映射的工作原理是根據每個術語的字典順序為每個術語分配一個增量整數或“序數(ordinal)”。 該字段的 doc values 僅存儲每個文檔的序數而不是原始術語,并具有單獨的查找結構來在序數和術語之間進行轉換。
在聚合期間使用時,序數可以極大地提高性能。 作為術語(terms)聚合的示例,依賴于序數將文檔分組到分片級別的存儲桶中,然后在跨分片組合結果時將序數轉換回其原始術語值。
每個分片包含多個 “段(segements)”,其中一個段就是一個倒排索引。 分片中的搜索將依次搜索每個片段,然后將其結果合并到該分片的最終結果中。 當你為文檔建立索引時,Elasticsearch 將它們收集在內存中(為了安全起見,收集在 trasaction log 中),然后每隔一秒左右將一個新的小段寫入磁盤,并 “刷新” 搜索。這使得新段中的數據對搜索可見(即它們是 “可搜索的”)
每個段都定義自己的序數映射,但聚合會跨整個分片收集數據。 因此,為了能夠使用序數(ordinals)進行聚合等分片級操作,Elasticsearch 創建了一個稱為全局序數(global ordinals)的統一映射。 全局序數映射建立在段序數之上,并通過維護每個段的從全局序數到局部序數的映射來工作。
必須先構建全局序數映射,然后才能在搜索過程中使用序數。 默認情況下,第一次需要全局序數時會在搜索過程中加載映射。 通常,全局序數在加載時間和內存使用方面不會產生很大的開銷。 但是,對于具有大分片的索引,或者如果字段包含大量唯一術語值,則加載全局序數可能會很昂貴。 由于全局序號為分片上的所有段提供了統一的映射,因此當新段可見時,它們也需要完全重建。
聚合提供了一個參數 execution_hint,有助于控制存儲桶的收集方式。 它默認為 global_ordinals,但可以設置為 map 來直接使用術語值。 這避免了創建全局序數的麻煩并提高了性能,但僅當很少有文檔與查詢匹配時才應考慮,否則基于序數的執行模式會明顯更快。 默認情況下,僅在對腳本運行聚合時使用 map,因為它們沒有序數。它可以指定如下:
"aggs": { "make": { "terms": { "field": "make", "execution_hint": "map", "size": 10 } } }
我們還可以使用 eager_global_ordinals,在這種情況下,全局序數是在刷新分片時構建的。 Elasticsearch 總是在公開索引內容的更改之前加載它們。 這將構建全局序數的成本從搜索時間轉移到索引時間。 可以為字段啟用它,如下所示:
PUT my-index-000001/_mapping{ "properties": { "tags": { "type": "keyword", "eager_global_ordinals": true } }}
可以通過更新 eager_global_ordinals 設置隨時禁用預加載:
PUT my-index-000001/_mapping{ "properties": { "tags": { "type": "keyword", "eager_global_ordinals": false } }}
關鍵詞: