ES的官方文檔中關於 檢索和排序的關係說得特別好:程序員
Search needs to answer the question "Which documents contain this term?", while sorting and aggregations need to answer a different question: "What is the value of this field for this document?".
搜索要解決的問題是: "哪些文檔包含給定的關鍵詞?"
排序和聚合要解決的問題是: 「這個文檔中對應字段的值是多少?」json
一樣,以需求爲出發點: "檢索的結果按時間排序" 這個需求在商品搜索和日誌分析系統中是很是廣泛的。 衆所周知,Lucene是經過倒排索引解決了「檢索的問題」,那麼「排序的問題」 怎麼處理呢?app
最開始,Lucene是經過FieldCache來解決這個需求。就是經過FieldCache創建docId - value
的映射關係。 可是FieldCache有個兩個致命的問題: 堆內存消耗 和 首次加載耗時 。 如過索引更新頻率較高,這兩個問題引起的GC和超時致使系統不穩定估計是程序員的噩夢。elasticsearch
從Lucene4.0開始,引入了新的組件IndexDocValues,就是咱們常說的doc_value
。ide
它有兩個亮點: ui
1. 索引數據時構建 doc-value的映射關係。注: 倒排索引構建的是value-doc的映射關係。 2. 列式存儲
這基本上就是「空間換時間」和「按需加載」的典型實踐了。 並且,列式存儲基本上是全部高效NoSQL的標配,Hbase, Hive 都有列式存儲的身影。this
IndexDocValues跟FieldCache同樣解決了「經過doc_id
查詢value」的問題, 同時也解決了FieldCache的兩個問題。 日誌
ES基於doc_value
構建了fielddata
, 用於排序和聚合兩大功能。 因此,能夠絕不客氣地說, doc_value
是ES aggregations
的基石。code
那麼在ES中, fielddata
如何使用呢? 以binary類型爲例,參考: org.elasticsearch.index.fielddata.BinaryDVFieldDataTests
orm
s1: 建mappings時須要特殊處理
String mapping = XContentFactory.jsonBuilder().startObject().startObject("test") .startObject("properties") .startObject("field") .field("type", "binary") .startObject("fielddata").field("format", "doc_values").endObject() .endObject() .endObject() .endObject().endObject().string();
s2: 經過leafreader構建doc_values
LeafReaderContext reader = refreshReader(); IndexFieldData<?> indexFieldData = getForField("field"); AtomicFieldData fieldData = indexFieldData.load(reader); SortedBinaryDocValues bytesValues = fieldData.getBytesValues();
s3: 定位到指定文檔, 用setDocument()
方法。
/** * A list of per-document binary values, sorted * according to {@link BytesRef#getUTF8SortedAsUnicodeComparator()}. * There might be dups however. */ public abstract class SortedBinaryDocValues { /** * Positions to the specified document */ public abstract void setDocument(int docId); /** * Return the number of values of the current document. */ public abstract int count(); /** * Retrieve the value for the current document at the specified index. * An index ranges from {@code 0} to {@code count()-1}. * Note that the returned {@link BytesRef} might be reused across invocations. */ public abstract BytesRef valueAt(int index); }
注意,若是reader是組合的,也就是有多個,須要用到docBase + reader.docId
。 這裏是容易採坑的。
s4: 獲取文檔的指定field的value,使用 valueAt()
方法。
最後總結一下, 本文簡述了lucene的doc_value
和 es的fielddata
的關係, 簡要描述了一下doc_value
的基本思想。最後給出了在ES中使用fielddata的基本方法。這對於本身開發plugin是比較有用的。