Skip to content

Commit

Permalink
SOLR-16989: Optimize and consolidate reuse of DocValues iterators for…
Browse files Browse the repository at this point in the history
… value retrieval (#1938)

(cherry picked from commit dafbe80)
  • Loading branch information
magibney committed Sep 26, 2023
1 parent 43a6161 commit dae7872
Show file tree
Hide file tree
Showing 14 changed files with 660 additions and 256 deletions.
1 change: 1 addition & 0 deletions solr/CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ Optimizations

* SOLR-16265: reduce memory usage of ContentWriter based requests in Http2SolrClient (Alex Deparvu, Kevin Risden, David Smiley)

* SOLR-16989: Optimize and consolidate reuse of DocValues iterators for value retrieval (Michael Gibney)

Bug Fixes
---------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.search.DocList;
import org.apache.solr.search.DocValuesIteratorCache;
import org.apache.solr.search.QueryUtils;
import org.apache.solr.search.ReturnFields;
import org.apache.solr.search.SolrDocumentFetcher;
Expand Down Expand Up @@ -238,6 +239,7 @@ public void process(ResponseBuilder rb) throws IOException {

boolean opennedRealtimeSearcher = false;
BytesRefBuilder idBytes = new BytesRefBuilder();
DocValuesIteratorCache reuseDvIters = null;
for (String idStr : reqIds.allIds) {
fieldType.readableToIndexed(idStr, idBytes);
// if _route_ is passed, id is a child doc. TODO remove in SOLR-15064
Expand Down Expand Up @@ -348,7 +350,11 @@ public void process(ResponseBuilder rb) throws IOException {
searcherInfo.getSearcher().doc(docid, rsp.getReturnFields().getLuceneFieldNames());
SolrDocument doc = toSolrDoc(luceneDocument, core.getLatestSchema());
SolrDocumentFetcher docFetcher = searcherInfo.getSearcher().getDocFetcher();
docFetcher.decorateDocValueFields(doc, docid, docFetcher.getNonStoredDVs(true));
if (reuseDvIters == null) {
reuseDvIters = new DocValuesIteratorCache(searcherInfo.getSearcher());
}
docFetcher.decorateDocValueFields(
doc, docid, docFetcher.getNonStoredDVs(true), reuseDvIters);
if (null != transformer) {
if (null == resultContext) {
// either first pass, or we've re-opened searcher - either way now we setContext
Expand Down Expand Up @@ -575,7 +581,11 @@ private static SolrDocument mergePartialDocWithFullDocFromIndex(
if (!doc.containsKey(VERSION_FIELD)) {
searcher
.getDocFetcher()
.decorateDocValueFields(doc, docid, Collections.singleton(VERSION_FIELD));
.decorateDocValueFields(
doc,
docid,
Collections.singleton(VERSION_FIELD),
new DocValuesIteratorCache(searcher, false));
}

long docVersion = (long) doc.getFirstValue(VERSION_FIELD);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@
import org.apache.lucene.util.BytesRef;
import org.apache.solr.common.MapWriter;
import org.apache.solr.schema.FieldType;
import org.apache.solr.search.DocValuesIteratorCache;

class BoolFieldWriter extends StringFieldWriter {
public BoolFieldWriter(String field, FieldType fieldType) {
super(field, fieldType);
public BoolFieldWriter(
String field,
FieldType fieldType,
DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache) {
super(field, fieldType, docValuesCache);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,58 +17,19 @@

package org.apache.solr.handler.export;

import com.carrotsearch.hppc.IntObjectHashMap;
import java.io.IOException;
import java.util.Date;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.NumericDocValues;
import org.apache.solr.common.MapWriter;
import org.apache.solr.search.DocValuesIteratorCache;

class DateFieldWriter extends FieldWriter {
private String field;
private IntObjectHashMap<NumericDocValues> docValuesCache = new IntObjectHashMap<>();

public DateFieldWriter(String field) {
this.field = field;
class DateFieldWriter extends LongFieldWriter {
public DateFieldWriter(
String field, DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache) {
super(field, docValuesCache);
}

@Override
public boolean write(
SortDoc sortDoc, LeafReaderContext readerContext, MapWriter.EntryWriter ew, int fieldIndex)
throws IOException {
Long val;
SortValue sortValue = sortDoc.getSortValue(this.field);
if (sortValue != null) {
if (sortValue.isPresent()) {
val = (long) sortValue.getCurrentValue();
} else { // empty-value
return false;
}
} else {
// field is not part of 'sort' param, but part of 'fl' param
int readerOrd = readerContext.ord;
NumericDocValues vals = null;
if (docValuesCache.containsKey(readerOrd)) {
NumericDocValues numericDocValues = docValuesCache.get(readerOrd);
if (numericDocValues.docID() < sortDoc.docId) {
// We have not advanced beyond the current docId so we can use this docValues.
vals = numericDocValues;
}
}

if (vals == null) {
vals = DocValues.getNumeric(readerContext.reader(), this.field);
docValuesCache.put(readerOrd, vals);
}

if (vals.advance(sortDoc.docId) == sortDoc.docId) {
val = vals.longValue();
} else {
return false;
}
}
ew.put(this.field, new Date(val));
return true;
protected void doWrite(MapWriter.EntryWriter ew, long val) throws IOException {
ew.put(field, new Date(val));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,57 +17,46 @@

package org.apache.solr.handler.export;

import com.carrotsearch.hppc.IntObjectHashMap;
import java.io.IOException;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.NumericDocValues;
import org.apache.solr.common.MapWriter;
import org.apache.solr.search.DocValuesIteratorCache;

class DoubleFieldWriter extends FieldWriter {
private String field;
private IntObjectHashMap<NumericDocValues> docValuesCache = new IntObjectHashMap<>();
private final String field;
private final DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache;

public DoubleFieldWriter(String field) {
public DoubleFieldWriter(
String field, DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache) {
this.field = field;
this.docValuesCache = docValuesCache;
}

@Override
public boolean write(
SortDoc sortDoc, LeafReaderContext readerContext, MapWriter.EntryWriter ew, int fieldIndex)
throws IOException {
double val;
SortValue sortValue = sortDoc.getSortValue(this.field);
if (sortValue != null) {
if (sortValue.isPresent()) {
double val = (double) sortValue.getCurrentValue();
ew.put(this.field, val);
return true;
val = (double) sortValue.getCurrentValue();
} else { // empty-value
return false;
}
} else {
// field is not part of 'sort' param, but part of 'fl' param
int readerOrd = readerContext.ord;
NumericDocValues vals = null;
if (docValuesCache.containsKey(readerOrd)) {
NumericDocValues numericDocValues = docValuesCache.get(readerOrd);
if (numericDocValues.docID() < sortDoc.docId) {
// We have not advanced beyond the current docId so we can use this docValues.
vals = numericDocValues;
}
}

if (vals == null) {
vals = DocValues.getNumeric(readerContext.reader(), this.field);
docValuesCache.put(readerOrd, vals);
}
if (vals.advance(sortDoc.docId) == sortDoc.docId) {
long val = vals.longValue();
ew.put(this.field, Double.longBitsToDouble(val));
return true;
NumericDocValues vals =
docValuesCache.getNumericDocValues(
sortDoc.docId, readerContext.reader(), readerContext.ord);
if (vals != null) {
val = Double.longBitsToDouble(vals.longValue());
} else {
return false;
}
}
ew.put(this.field, val);
return true;
}
}
44 changes: 29 additions & 15 deletions solr/core/src/java/org/apache/solr/handler/export/ExportWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
import org.apache.solr.schema.SchemaField;
import org.apache.solr.schema.SortableTextField;
import org.apache.solr.schema.StrField;
import org.apache.solr.search.DocValuesIteratorCache;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.search.SortSpec;
import org.apache.solr.search.SyntaxError;
Expand All @@ -99,6 +100,14 @@ public class ExportWriter implements SolrCore.RawWriter, Closeable {

public static final int DEFAULT_BATCH_SIZE = 30000;
public static final int DEFAULT_QUEUE_SIZE = 150000;
private static final FieldWriter EMPTY_FIELD_WRITER =
new FieldWriter() {
@Override
public boolean write(
SortDoc sortDoc, LeafReaderContext readerContext, EntryWriter out, int fieldIndex) {
return false;
}
};

private OutputStreamWriter respWriter;
final SolrQueryRequest req;
Expand Down Expand Up @@ -480,6 +489,7 @@ public FieldWriter[] getFieldWriters(String[] fields, SolrIndexSearcher searcher
throws IOException {
IndexSchema schema = searcher.getSchema();
FieldWriter[] writers = new FieldWriter[fields.length];
DocValuesIteratorCache dvIterCache = new DocValuesIteratorCache(searcher, false);
for (int i = 0; i < fields.length; i++) {
String field = fields[i];
SchemaField schemaField = null;
Expand All @@ -501,47 +511,51 @@ public FieldWriter[] getFieldWriters(String[] fields, SolrIndexSearcher searcher
schemaField + " Must have useDocValuesAsStored='true' to be used with export writer");
}

if (fieldType instanceof IntValueFieldType) {
DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache = dvIterCache.getSupplier(field);

if (docValuesCache == null) {
writers[i] = EMPTY_FIELD_WRITER;
} else if (fieldType instanceof IntValueFieldType) {
if (multiValued) {
writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true);
writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true, docValuesCache);
} else {
writers[i] = new IntFieldWriter(field);
writers[i] = new IntFieldWriter(field, docValuesCache);
}
} else if (fieldType instanceof LongValueFieldType) {
if (multiValued) {
writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true);
writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true, docValuesCache);
} else {
writers[i] = new LongFieldWriter(field);
writers[i] = new LongFieldWriter(field, docValuesCache);
}
} else if (fieldType instanceof FloatValueFieldType) {
if (multiValued) {
writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true);
writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true, docValuesCache);
} else {
writers[i] = new FloatFieldWriter(field);
writers[i] = new FloatFieldWriter(field, docValuesCache);
}
} else if (fieldType instanceof DoubleValueFieldType) {
if (multiValued) {
writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true);
writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true, docValuesCache);
} else {
writers[i] = new DoubleFieldWriter(field);
writers[i] = new DoubleFieldWriter(field, docValuesCache);
}
} else if (fieldType instanceof StrField || fieldType instanceof SortableTextField) {
if (multiValued) {
writers[i] = new MultiFieldWriter(field, fieldType, schemaField, false);
writers[i] = new MultiFieldWriter(field, fieldType, schemaField, false, docValuesCache);
} else {
writers[i] = new StringFieldWriter(field, fieldType);
writers[i] = new StringFieldWriter(field, fieldType, docValuesCache);
}
} else if (fieldType instanceof DateValueFieldType) {
if (multiValued) {
writers[i] = new MultiFieldWriter(field, fieldType, schemaField, false);
writers[i] = new MultiFieldWriter(field, fieldType, schemaField, false, docValuesCache);
} else {
writers[i] = new DateFieldWriter(field);
writers[i] = new DateFieldWriter(field, docValuesCache);
}
} else if (fieldType instanceof BoolField) {
if (multiValued) {
writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true);
writers[i] = new MultiFieldWriter(field, fieldType, schemaField, true, docValuesCache);
} else {
writers[i] = new BoolFieldWriter(field, fieldType);
writers[i] = new BoolFieldWriter(field, fieldType, docValuesCache);
}
} else {
throw new IOException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,58 +17,46 @@

package org.apache.solr.handler.export;

import com.carrotsearch.hppc.IntObjectHashMap;
import java.io.IOException;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.NumericDocValues;
import org.apache.solr.common.MapWriter;
import org.apache.solr.search.DocValuesIteratorCache;

class FloatFieldWriter extends FieldWriter {
private String field;
private IntObjectHashMap<NumericDocValues> docValuesCache = new IntObjectHashMap<>();
private final String field;
private final DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache;

public FloatFieldWriter(String field) {
public FloatFieldWriter(
String field, DocValuesIteratorCache.FieldDocValuesSupplier docValuesCache) {
this.field = field;
this.docValuesCache = docValuesCache;
}

@Override
public boolean write(
SortDoc sortDoc, LeafReaderContext readerContext, MapWriter.EntryWriter ew, int fieldIndex)
throws IOException {
float val;
SortValue sortValue = sortDoc.getSortValue(this.field);
if (sortValue != null) {
if (sortValue.isPresent()) {
float val = (float) sortValue.getCurrentValue();
ew.put(this.field, val);
return true;
val = (float) sortValue.getCurrentValue();
} else { // empty-value
return false;
}
} else {
// field is not part of 'sort' param, but part of 'fl' param
int readerOrd = readerContext.ord;
NumericDocValues vals = null;
if (docValuesCache.containsKey(readerOrd)) {
NumericDocValues numericDocValues = docValuesCache.get(readerOrd);
if (numericDocValues.docID() < sortDoc.docId) {
// We have not advanced beyond the current docId so we can use this docValues.
vals = numericDocValues;
}
}

if (vals == null) {
vals = DocValues.getNumeric(readerContext.reader(), this.field);
docValuesCache.put(readerOrd, vals);
}

if (vals.advance(sortDoc.docId) == sortDoc.docId) {
int val = (int) vals.longValue();
ew.put(this.field, Float.intBitsToFloat(val));
return true;
NumericDocValues vals =
docValuesCache.getNumericDocValues(
sortDoc.docId, readerContext.reader(), readerContext.ord);
if (vals != null) {
val = Float.intBitsToFloat((int) vals.longValue());
} else {
return false;
}
}
ew.put(this.field, val);
return true;
}
}
Loading

0 comments on commit dae7872

Please sign in to comment.