
doc_values - 預設情況下,大部分字段是索引的,這樣讓這些字段可被搜尋。反向索引(inverted index)允許查詢請求在詞項清單中查找搜尋項(search term),并立即獲得包含該詞項的文檔清單。
doc_values
預設情況下,大部分字段是索引的,這樣讓這些字段可被搜尋。反向索引(inverted index)允許查詢請求在詞項清單中查找搜尋項(search term),并立即獲得包含該詞項的文檔清單。
反向索引(inverted index):
如果我們想要獲得所有包含 brown 的文檔的詞的完整清單,我們會建立如下查詢:
GET /my_index/_search
{
"query" : {
"match" : {
"body" : "brown"
}
},
"aggs" : {
"popular_terms": {
"terms" : {
"field" : "body"
}
}
}
反向索引是根據詞項來排序的,是以我們首先在詞項清單中找到 brown,然後掃描所有列,找到包含 brown 的文檔。我們可以快速看到 Doc_1 和 Doc_2 包含 brown 這個 token。
然後,對于聚合部分,我們需要找到 Doc_1 和 Doc_2 裡所有唯一的詞項。用反向索引做這件事情代價很高: 我們會疊代索引裡的每個詞項并收集 Doc_1 和 Doc_2 列裡面 token。這很慢而且難以擴充:随着詞項和文檔的數量增加,執行時間也會增加。
Doc values 通過轉置兩者間的關系來解決這個問題。反向索引将詞項映射到包含它們的文檔,doc values 将文檔映射到它們包含的詞項:
當資料被轉置之後,想要收集到 Doc_1 和 Doc_2 的唯一 token 會非常容易。獲得每個文檔行,擷取所有的詞項,然後求兩個集合的并集。
Doc values 可以使聚合更快、更高效并且記憶體友好。Doc values 的存在是因為反向索引隻對某些操作是高效的。
反向索引的優勢:在于查找包含某個項的文檔,而對于從另外一個方向的相反操作并不高效,即:确定哪些項是否存在單個文檔裡,聚合需要這種通路模式。
在 Elasticsearch 中,Doc Values 就是一種列式存儲結構,預設情況下每個字段的 Doc Values 都是激活的,Doc Values 是在索引時建立的。當字段索引時,Elasticsearch 為了能夠快速檢索,會把字段的值加入反向索引中,同時它也會存儲該字段的 `Doc Values`。
Elasticsearch 中的 Doc Values 常被應用到以下場景:
對一個字段進行排序
對一個字段進行聚合
某些過濾,比如地理位置過濾
某些與字段相關的腳本計算
因為文檔值(doc values)被序列化到磁盤,我們可以依靠作業系統的幫助來快速通路。當 working set 遠小于節點的可用記憶體,系統會自動将所有的文檔值儲存在記憶體中,使得其讀寫十分高速;當其遠大于可用記憶體,作業系統會自動把 Doc Values 加載到系統的頁緩存中,進而避免了 jvm 堆記憶體溢出異常。
是以,搜尋和聚合是互相緊密纏繞的。搜尋使用反向索引查找文檔,聚合操作收集和聚合 doc values 裡的資料。
doc values 支援大部分字段類型,但是text 字段類型不支援(因為analyzed)。
(1) status_code 字段預設啟動 doc_values 屬性;
(2) session_id 顯式設定 doc_values = false,但是仍然可以被查詢;
如果确信某字段不需要排序或者聚合,或者從腳本中通路字段值,那麼我們可以設定 doc_values = false,這樣可以節省磁盤空間。
fielddata
與 doc values 不同,fielddata 建構和管理 100% 在記憶體中,常駐于 JVM 記憶體堆。這意味着它本質上是不可擴充的。
fielddata可能會消耗大量的堆空間,尤其是在加載高基數(high cardinality)text字段時。一旦fielddata已加載到堆中,它将在該段的生命周期内保留。此外,加載fielddata是一個昂貴的過程,可能會導緻使用者遇到延遲命中。這就是預設情況下禁用fielddata的原因。
如果需要對 text 類型字段進行排序、聚合、或者從腳本中通路字段值,則會出現如下異常:
Fielddata is disabled on text fields by default. Set fielddata=true on [your_field_name] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory.
但是,在啟動fielddata 設定之前,需要考慮為什麼針對text 類型字段進行排序、聚合、或腳本呢?通常情況下,這是不太合理的。
text字段在索引時,例如New York,這樣的詞會被分詞,會被拆成new、york 2個詞項,這樣當搜尋new 或 york時,可以被搜尋到。在此字段上面來一個terms的聚合會傳回一個new的bucket和一個york的bucket,但是你可能想要的是一個單一new york的bucket。
怎麼解決這一問題呢?
你可以使用 text 字段來實作全文本查詢,同時使用一個未分詞的 keyword 字段,且啟用doc_values,來處理聚合操作。
(1) 使用my_field 字段用于查詢;
(2) 使用my_field.keyword 字段用于聚合、排序、或腳本;
可以使用 PUT mapping API 在現有text 字段上啟用 fielddata,如下所示:
《Elasticsearch 7.x從入門到精通》專欄會通過理論與實踐相結合的方式,帶領你一步一步走進Elasticsearch的世界,使你輕松掌握Elasticsearch的基本概念,學習Elasticsearch的服務搭建,了解Elasticsearch的常用技巧,并通過案例項目讓你擁有實際的應用能力。 同時,也會講解Elastic Stack中其他相關元件,如Logstash、Beats和Kibana等等。