Change ParentFieldSubFetchPhase to create doc values iterator once per segment (#26815)

This commit is contained in:
Jim Ferenczi 2017-09-28 16:24:05 +02:00 committed by GitHub
parent 0358bb5f34
commit aade2f6d63
1 changed files with 52 additions and 17 deletions

View File

@ -20,43 +20,79 @@
package org.elasticsearch.search.fetch.subphase; package org.elasticsearch.search.fetch.subphase;
import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.ReaderUtil;
import org.apache.lucene.index.SortedDocValues; import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.common.document.DocumentField; import org.elasticsearch.common.document.DocumentField;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.ParentFieldMapper; import org.elasticsearch.index.mapper.ParentFieldMapper;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.fetch.FetchSubPhase; import org.elasticsearch.search.fetch.FetchSubPhase;
import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.internal.SearchContext;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set;
public final class ParentFieldSubFetchPhase implements FetchSubPhase { public final class ParentFieldSubFetchPhase implements FetchSubPhase {
@Override @Override
public void hitExecute(SearchContext context, HitContext hitContext) { public void hitsExecute(SearchContext context, SearchHit[] hits) throws IOException {
if (context.storedFieldsContext() != null && context.storedFieldsContext().fetchFields() == false) { if (context.storedFieldsContext() != null && context.storedFieldsContext().fetchFields() == false) {
return ; return ;
} }
ParentFieldMapper parentFieldMapper = context.mapperService().documentMapper(hitContext.hit().getType()).parentFieldMapper();
hits = hits.clone(); // don't modify the incoming hits
Arrays.sort(hits, Comparator.comparingInt(SearchHit::docId));
MapperService mapperService = context.mapperService();
Set<String> parentFields = new HashSet<>();
for (SearchHit hit : hits) {
ParentFieldMapper parentFieldMapper = mapperService.documentMapper(hit.getType()).parentFieldMapper();
if (parentFieldMapper.active()) {
parentFields.add(parentFieldMapper.name());
}
}
int lastReaderId = -1;
Map<String, SortedDocValues> docValuesMap = new HashMap<>();
for (SearchHit hit : hits) {
ParentFieldMapper parentFieldMapper = mapperService.documentMapper(hit.getType()).parentFieldMapper();
if (parentFieldMapper.active() == false) { if (parentFieldMapper.active() == false) {
return; continue;
} }
int readerId = ReaderUtil.subIndex(hit.docId(), context.searcher().getIndexReader().leaves());
String parentId = getParentId(parentFieldMapper, hitContext.reader(), hitContext.docId()); LeafReaderContext subReaderContext = context.searcher().getIndexReader().leaves().get(readerId);
if (parentId == null) { if (lastReaderId != readerId) {
docValuesMap.clear();
for (String field : parentFields) {
docValuesMap.put(field, subReaderContext.reader().getSortedDocValues(field));
}
lastReaderId = readerId;
}
int docId = hit.docId() - subReaderContext.docBase;
SortedDocValues values = docValuesMap.get(parentFieldMapper.name());
if (values != null && values.advanceExact(docId)) {
BytesRef binaryValue = values.binaryValue();
String value = binaryValue.length > 0 ? binaryValue.utf8ToString() : null;
if (value == null) {
// hit has no _parent field. Can happen for nested inner hits if parent hit is a p/c document. // hit has no _parent field. Can happen for nested inner hits if parent hit is a p/c document.
return; continue;
} }
Map<String, DocumentField> fields = hit.fieldsOrNull();
Map<String, DocumentField> fields = hitContext.hit().fieldsOrNull();
if (fields == null) { if (fields == null) {
fields = new HashMap<>(); fields = new HashMap<>();
hitContext.hit().fields(fields); hit.fields(fields);
}
fields.put(ParentFieldMapper.NAME, new DocumentField(ParentFieldMapper.NAME, Collections.singletonList(value)));
}
} }
fields.put(ParentFieldMapper.NAME, new DocumentField(ParentFieldMapper.NAME, Collections.singletonList(parentId)));
} }
public static String getParentId(ParentFieldMapper fieldMapper, LeafReader reader, int docId) { public static String getParentId(ParentFieldMapper fieldMapper, LeafReader reader, int docId) {
@ -72,5 +108,4 @@ public final class ParentFieldSubFetchPhase implements FetchSubPhase {
throw ExceptionsHelper.convertToElastic(e); throw ExceptionsHelper.convertToElastic(e);
} }
} }
} }