|
@@ -7,6 +7,7 @@
|
|
|
*/
|
|
*/
|
|
|
package org.elasticsearch.search.lookup;
|
|
package org.elasticsearch.search.lookup;
|
|
|
|
|
|
|
|
|
|
+import org.apache.lucene.codecs.StoredFieldsReader;
|
|
|
import org.apache.lucene.index.LeafReader;
|
|
import org.apache.lucene.index.LeafReader;
|
|
|
import org.apache.lucene.index.LeafReaderContext;
|
|
import org.apache.lucene.index.LeafReaderContext;
|
|
|
import org.elasticsearch.ElasticsearchParseException;
|
|
import org.elasticsearch.ElasticsearchParseException;
|
|
@@ -15,6 +16,7 @@ import org.elasticsearch.common.bytes.BytesReference;
|
|
|
import org.elasticsearch.common.lucene.index.SequentialStoredFieldsLeafReader;
|
|
import org.elasticsearch.common.lucene.index.SequentialStoredFieldsLeafReader;
|
|
|
import org.elasticsearch.common.xcontent.XContentHelper;
|
|
import org.elasticsearch.common.xcontent.XContentHelper;
|
|
|
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
|
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
|
|
|
|
+import org.elasticsearch.core.MemoizedSupplier;
|
|
|
import org.elasticsearch.core.Nullable;
|
|
import org.elasticsearch.core.Nullable;
|
|
|
import org.elasticsearch.core.Tuple;
|
|
import org.elasticsearch.core.Tuple;
|
|
|
import org.elasticsearch.index.fieldvisitor.FieldsVisitor;
|
|
import org.elasticsearch.index.fieldvisitor.FieldsVisitor;
|
|
@@ -26,13 +28,14 @@ import java.util.Collection;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
import java.util.Set;
|
|
import java.util.Set;
|
|
|
|
|
+import java.util.function.Supplier;
|
|
|
|
|
|
|
|
import static java.util.Collections.emptyMap;
|
|
import static java.util.Collections.emptyMap;
|
|
|
|
|
|
|
|
public class SourceLookup implements Map<String, Object> {
|
|
public class SourceLookup implements Map<String, Object> {
|
|
|
|
|
|
|
|
private LeafReader reader;
|
|
private LeafReader reader;
|
|
|
- CheckedBiConsumer<Integer, FieldsVisitor, IOException> fieldReader;
|
|
|
|
|
|
|
+ private CheckedBiConsumer<Integer, FieldsVisitor, IOException> fieldReader;
|
|
|
|
|
|
|
|
private int docId = -1;
|
|
private int docId = -1;
|
|
|
|
|
|
|
@@ -104,19 +107,23 @@ public class SourceLookup implements Map<String, Object> {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public void setSegmentAndDocument(LeafReaderContext context, int docId) {
|
|
public void setSegmentAndDocument(LeafReaderContext context, int docId) {
|
|
|
|
|
+ // if we are called with the same document, don't invalidate source
|
|
|
if (this.reader == context.reader() && this.docId == docId) {
|
|
if (this.reader == context.reader() && this.docId == docId) {
|
|
|
- // if we are called with the same document, don't invalidate source
|
|
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // only reset reader and fieldReader when reader changes
|
|
|
if (this.reader != context.reader()) {
|
|
if (this.reader != context.reader()) {
|
|
|
this.reader = context.reader();
|
|
this.reader = context.reader();
|
|
|
- // only reset reader and fieldReader when reader changes
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // All the docs to fetch are adjacent but Lucene stored fields are optimized
|
|
|
|
|
+ // for random access and don't optimize for sequential access - except for merging.
|
|
|
|
|
+ // So we do a little hack here and pretend we're going to do merges in order to
|
|
|
|
|
+ // get better sequential access.
|
|
|
if (context.reader()instanceof SequentialStoredFieldsLeafReader lf) {
|
|
if (context.reader()instanceof SequentialStoredFieldsLeafReader lf) {
|
|
|
- // All the docs to fetch are adjacent but Lucene stored fields are optimized
|
|
|
|
|
- // for random access and don't optimize for sequential access - except for merging.
|
|
|
|
|
- // So we do a little hack here and pretend we're going to do merges in order to
|
|
|
|
|
- // get better sequential access.
|
|
|
|
|
- fieldReader = lf.getSequentialStoredFieldsReader()::visitDocument;
|
|
|
|
|
|
|
+ // Avoid eagerly loading the stored fields reader, since this can be expensive
|
|
|
|
|
+ Supplier<StoredFieldsReader> supplier = new MemoizedSupplier<>(lf::getSequentialStoredFieldsReader);
|
|
|
|
|
+ fieldReader = (d, v) -> supplier.get().visitDocument(d, v);
|
|
|
} else {
|
|
} else {
|
|
|
fieldReader = context.reader()::document;
|
|
fieldReader = context.reader()::document;
|
|
|
}
|
|
}
|