您好,登錄后才能下訂單哦!
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?".
搜索要解決的問題是: "哪些文檔包含給定的關鍵詞?"
排序和聚合要解決的問題是: “這個文檔中對應字段的值是多少?”
同樣,以需求為出發點: "檢索的結果按時間排序" 這個需求在商品搜索和日志分析系統中是非常普遍的。 眾所周知,Lucene是通過倒排索引解決了“檢索的問題”,那么“排序的問題” 怎么處理呢?
最開始,Lucene是通過FieldCache來解決這個需求。就是通過FieldCache建立docId - value
的映射關系。 但是FieldCache有個兩個致命的問題: 堆內存消耗 和 首次加載耗時 。 如過索引更新頻率較高,這兩個問題引發的GC和超時導致系統不穩定估計是程序員的噩夢。
從Lucene4.0開始,引入了新的組件IndexDocValues,就是我們常說的doc_value
。
它有兩個亮點:
1. 索引數據時構建 doc-value的映射關系。注: 倒排索引構建的是value-doc的映射關系。
2. 列式存儲
這基本上就是“空間換時間”和“按需加載”的典型實踐了。 而且,列式存儲基本上是所有高效NoSQL的標配,Hbase, Hive 都有列式存儲的身影。
IndexDocValues跟FieldCache一樣解決了“通過doc_id
查詢value”的問題, 同時也解決了FieldCache的兩個問題。
ES基于doc_value
構建了fielddata
, 用于排序和聚合兩大功能。 所以,可以毫不客氣地說, doc_value
是ES aggregations
的基石。
那么在ES中, fielddata
如何使用呢? 以binary類型為例,參考: org.elasticsearch.index.fielddata.BinaryDVFieldDataTests
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是比較有用的。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。