terms stats to use new field data

This commit is contained in:
Shay Banon 2013-01-20 07:10:50 +01:00
parent f1f86efed5
commit 37acba1b57
8 changed files with 158 additions and 199 deletions

View File

@ -73,4 +73,14 @@ public class HashedBytesRef {
public String toString() { public String toString() {
return bytes.toString(); return bytes.toString();
} }
public HashedBytesRef deepCopy() {
return deepCopyOf(this);
}
public static HashedBytesRef deepCopyOf(HashedBytesRef other) {
BytesRef copy = new BytesRef();
copy.copyBytes(other.bytes);
return new HashedBytesRef(copy, other.hash);
}
} }

View File

@ -26,12 +26,44 @@ import org.apache.lucene.index.AtomicReaderContext;
public interface IndexNumericFieldData<FD extends AtomicNumericFieldData> extends IndexFieldData<FD> { public interface IndexNumericFieldData<FD extends AtomicNumericFieldData> extends IndexFieldData<FD> {
static enum NumericType { static enum NumericType {
BYTE, BYTE {
SHORT, @Override
INT, public boolean isFloatingPoint() {
LONG, return false;
FLOAT, }
DOUBLE },
SHORT {
@Override
public boolean isFloatingPoint() {
return false;
}
},
INT {
@Override
public boolean isFloatingPoint() {
return false;
}
},
LONG {
@Override
public boolean isFloatingPoint() {
return false;
}
},
FLOAT {
@Override
public boolean isFloatingPoint() {
return true;
}
},
DOUBLE {
@Override
public boolean isFloatingPoint() {
return true;
}
};
public abstract boolean isFloatingPoint();
} }
NumericType getNumericType(); NumericType getNumericType();

View File

@ -54,7 +54,7 @@ public class LongArrayIndexFieldData extends AbstractIndexFieldData<LongArrayAto
@Override @Override
public NumericType getNumericType() { public NumericType getNumericType() {
return NumericType.DOUBLE; return NumericType.LONG;
} }
@Override @Override

View File

@ -23,8 +23,10 @@ import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.field.data.FieldDataType; import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.mapper.FieldMapper; import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.facet.Facet; import org.elasticsearch.search.facet.Facet;
import org.elasticsearch.search.facet.FacetCollector; import org.elasticsearch.search.facet.FacetCollector;
import org.elasticsearch.search.facet.FacetPhaseExecutionException; import org.elasticsearch.search.facet.FacetPhaseExecutionException;
@ -102,24 +104,29 @@ public class TermsStatsFacetProcessor extends AbstractComponent implements Facet
throw new FacetPhaseExecutionException(facetName, "either [value_field] or [script] are required to be set for terms stats facet"); throw new FacetPhaseExecutionException(facetName, "either [value_field] or [script] are required to be set for terms stats facet");
} }
FieldMapper keyFieldMapper = context.smartNameFieldMapper(keyField); FieldMapper keyMapper = context.smartNameFieldMapper(keyField);
if (keyFieldMapper != null) { if (keyMapper == null) {
if (keyFieldMapper.fieldDataType() == FieldDataType.DefaultTypes.LONG) { throw new FacetPhaseExecutionException(facetName, "failed to find mapping for " + keyField);
return new TermsStatsLongFacetCollector(facetName, keyField, valueField, size, comparatorType, context, scriptLang, script, params);
} else if (keyFieldMapper.fieldDataType() == FieldDataType.DefaultTypes.INT) {
return new TermsStatsLongFacetCollector(facetName, keyField, valueField, size, comparatorType, context, scriptLang, script, params);
} else if (keyFieldMapper.fieldDataType() == FieldDataType.DefaultTypes.SHORT) {
return new TermsStatsLongFacetCollector(facetName, keyField, valueField, size, comparatorType, context, scriptLang, script, params);
} else if (keyFieldMapper.fieldDataType() == FieldDataType.DefaultTypes.BYTE) {
return new TermsStatsLongFacetCollector(facetName, keyField, valueField, size, comparatorType, context, scriptLang, script, params);
} else if (keyFieldMapper.fieldDataType() == FieldDataType.DefaultTypes.DOUBLE) {
return new TermsStatsDoubleFacetCollector(facetName, keyField, valueField, size, comparatorType, context, scriptLang, script, params);
} else if (keyFieldMapper.fieldDataType() == FieldDataType.DefaultTypes.FLOAT) {
return new TermsStatsDoubleFacetCollector(facetName, keyField, valueField, size, comparatorType, context, scriptLang, script, params);
} }
IndexFieldData keyIndexFieldData = context.fieldData().getForField(keyMapper);
IndexNumericFieldData valueIndexFieldData = null;
SearchScript valueScript = null;
if (valueField != null) {
valueIndexFieldData = context.fieldData().getForField(context.smartNameFieldMapper(valueField));
} else {
valueScript = context.scriptService().search(context.lookup(), scriptLang, script, params);
} }
return new TermsStatsStringFacetCollector(facetName, keyField, valueField, size, comparatorType, context, scriptLang, script, params); if (keyIndexFieldData instanceof IndexNumericFieldData) {
IndexNumericFieldData keyIndexNumericFieldData = (IndexNumericFieldData) keyIndexFieldData;
if (keyIndexNumericFieldData.getNumericType().isFloatingPoint()) {
return new TermsStatsDoubleFacetCollector(facetName, keyIndexNumericFieldData, valueIndexFieldData, valueScript, size, comparatorType, context);
} else {
return new TermsStatsLongFacetCollector(facetName, keyIndexNumericFieldData, valueIndexFieldData, valueScript, size, comparatorType, context);
}
}
return new TermsStatsStringFacetCollector(facetName, keyIndexFieldData, valueIndexFieldData, valueScript, size, comparatorType, context);
} }
@Override @Override

View File

@ -23,13 +23,10 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.apache.lucene.index.AtomicReaderContext; import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Scorer;
import org.elasticsearch.ElasticSearchIllegalArgumentException;
import org.elasticsearch.common.CacheRecycler; import org.elasticsearch.common.CacheRecycler;
import org.elasticsearch.common.trove.ExtTDoubleObjectHashMap; import org.elasticsearch.common.trove.ExtTDoubleObjectHashMap;
import org.elasticsearch.index.cache.field.data.FieldDataCache; import org.elasticsearch.index.fielddata.DoubleValues;
import org.elasticsearch.index.field.data.FieldDataType; import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.field.data.NumericFieldData;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.script.SearchScript; import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.facet.AbstractFacetCollector; import org.elasticsearch.search.facet.AbstractFacetCollector;
import org.elasticsearch.search.facet.Facet; import org.elasticsearch.search.facet.Facet;
@ -40,67 +37,35 @@ import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map;
public class TermsStatsDoubleFacetCollector extends AbstractFacetCollector { public class TermsStatsDoubleFacetCollector extends AbstractFacetCollector {
private final TermsStatsFacet.ComparatorType comparatorType; private final TermsStatsFacet.ComparatorType comparatorType;
private final FieldDataCache fieldDataCache; private final IndexNumericFieldData keyIndexFieldData;
private final IndexNumericFieldData valueIndexFieldData;
private final String keyFieldName; private final SearchScript script;
private final String valueFieldName;
private final int size; private final int size;
private final int numberOfShards; private final int numberOfShards;
private final FieldDataType keyFieldDataType;
private NumericFieldData keyFieldData;
private final FieldDataType valueFieldDataType;
private final SearchScript script;
private final Aggregator aggregator; private final Aggregator aggregator;
public TermsStatsDoubleFacetCollector(String facetName, String keyFieldName, String valueFieldName, int size, TermsStatsFacet.ComparatorType comparatorType, private DoubleValues keyValues;
SearchContext context, String scriptLang, String script, Map<String, Object> params) {
public TermsStatsDoubleFacetCollector(String facetName, IndexNumericFieldData keyIndexFieldData, IndexNumericFieldData valueIndexFieldData, SearchScript script,
int size, TermsStatsFacet.ComparatorType comparatorType, SearchContext context) {
super(facetName); super(facetName);
this.fieldDataCache = context.fieldDataCache();
this.size = size; this.size = size;
this.comparatorType = comparatorType; this.comparatorType = comparatorType;
this.numberOfShards = context.numberOfShards(); this.numberOfShards = context.numberOfShards();
this.keyIndexFieldData = keyIndexFieldData;
MapperService.SmartNameFieldMappers smartMappers = context.smartFieldMappers(keyFieldName); this.valueIndexFieldData = valueIndexFieldData;
if (smartMappers == null || !smartMappers.hasMapper()) { this.script = script;
this.keyFieldName = keyFieldName;
this.keyFieldDataType = FieldDataType.DefaultTypes.STRING;
} else {
// add type filter if there is exact doc mapper associated with it
if (smartMappers.explicitTypeInNameWithDocMapper()) {
setFilter(context.filterCache().cache(smartMappers.docMapper().typeFilter()));
}
this.keyFieldName = smartMappers.mapper().names().indexName();
this.keyFieldDataType = smartMappers.mapper().fieldDataType();
}
if (script == null) { if (script == null) {
smartMappers = context.smartFieldMappers(valueFieldName);
if (smartMappers == null || !smartMappers.hasMapper()) {
throw new ElasticSearchIllegalArgumentException("failed to find mappings for [" + valueFieldName + "]");
}
this.valueFieldName = smartMappers.mapper().names().indexName();
this.valueFieldDataType = smartMappers.mapper().fieldDataType();
this.script = null;
this.aggregator = new Aggregator(); this.aggregator = new Aggregator();
} else { } else {
this.valueFieldName = null;
this.valueFieldDataType = null;
this.script = context.scriptService().search(context.lookup(), scriptLang, script, params);
this.aggregator = new ScriptAggregator(this.script); this.aggregator = new ScriptAggregator(this.script);
} }
} }
@ -114,17 +79,17 @@ public class TermsStatsDoubleFacetCollector extends AbstractFacetCollector {
@Override @Override
protected void doSetNextReader(AtomicReaderContext context) throws IOException { protected void doSetNextReader(AtomicReaderContext context) throws IOException {
keyFieldData = (NumericFieldData) fieldDataCache.cache(keyFieldDataType, context.reader(), keyFieldName); keyValues = keyIndexFieldData.load(context).getDoubleValues();
if (script != null) { if (script != null) {
script.setNextReader(context); script.setNextReader(context);
} else { } else {
aggregator.valueFieldData = (NumericFieldData) fieldDataCache.cache(valueFieldDataType, context.reader(), valueFieldName); aggregator.valueFieldData = valueIndexFieldData.load(context).getDoubleValues();
} }
} }
@Override @Override
protected void doCollect(int doc) throws IOException { protected void doCollect(int doc) throws IOException {
keyFieldData.forEachValueInDoc(doc, aggregator); keyValues.forEachValueInDoc(doc, aggregator);
} }
@Override @Override
@ -153,12 +118,12 @@ public class TermsStatsDoubleFacetCollector extends AbstractFacetCollector {
return new InternalTermsStatsDoubleFacet(facetName, comparatorType, size, ordered, aggregator.missing); return new InternalTermsStatsDoubleFacet(facetName, comparatorType, size, ordered, aggregator.missing);
} }
public static class Aggregator implements NumericFieldData.MissingDoubleValueInDocProc { public static class Aggregator implements DoubleValues.ValueInDocProc {
final ExtTDoubleObjectHashMap<InternalTermsStatsDoubleFacet.DoubleEntry> entries = CacheRecycler.popDoubleObjectMap(); final ExtTDoubleObjectHashMap<InternalTermsStatsDoubleFacet.DoubleEntry> entries = CacheRecycler.popDoubleObjectMap();
int missing; int missing;
NumericFieldData valueFieldData; DoubleValues valueFieldData;
final ValueAggregator valueAggregator = new ValueAggregator(); final ValueAggregator valueAggregator = new ValueAggregator();
@ -179,10 +144,14 @@ public class TermsStatsDoubleFacetCollector extends AbstractFacetCollector {
missing++; missing++;
} }
public static class ValueAggregator implements NumericFieldData.DoubleValueInDocProc { public static class ValueAggregator implements DoubleValues.ValueInDocProc {
InternalTermsStatsDoubleFacet.DoubleEntry doubleEntry; InternalTermsStatsDoubleFacet.DoubleEntry doubleEntry;
@Override
public void onMissing(int docId) {
}
@Override @Override
public void onValue(int docId, double value) { public void onValue(int docId, double value) {
if (value < doubleEntry.min) { if (value < doubleEntry.min) {

View File

@ -23,13 +23,11 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.apache.lucene.index.AtomicReaderContext; import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Scorer;
import org.elasticsearch.ElasticSearchIllegalArgumentException;
import org.elasticsearch.common.CacheRecycler; import org.elasticsearch.common.CacheRecycler;
import org.elasticsearch.common.trove.ExtTLongObjectHashMap; import org.elasticsearch.common.trove.ExtTLongObjectHashMap;
import org.elasticsearch.index.cache.field.data.FieldDataCache; import org.elasticsearch.index.fielddata.DoubleValues;
import org.elasticsearch.index.field.data.FieldDataType; import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.field.data.NumericFieldData; import org.elasticsearch.index.fielddata.LongValues;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.script.SearchScript; import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.facet.AbstractFacetCollector; import org.elasticsearch.search.facet.AbstractFacetCollector;
import org.elasticsearch.search.facet.Facet; import org.elasticsearch.search.facet.Facet;
@ -40,68 +38,35 @@ import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map;
public class TermsStatsLongFacetCollector extends AbstractFacetCollector { public class TermsStatsLongFacetCollector extends AbstractFacetCollector {
private final TermsStatsFacet.ComparatorType comparatorType; private final TermsStatsFacet.ComparatorType comparatorType;
private final FieldDataCache fieldDataCache; private final IndexNumericFieldData keyIndexFieldData;
private final IndexNumericFieldData valueIndexFieldData;
private final String keyFieldName;
private final String valueFieldName;
private final int size;
private final int numberOfShards;
private final FieldDataType keyFieldDataType;
private NumericFieldData keyFieldData;
private final FieldDataType valueFieldDataType;
private final SearchScript script; private final SearchScript script;
private final int size;
private final int numberOfShards;
private final Aggregator aggregator; private final Aggregator aggregator;
public TermsStatsLongFacetCollector(String facetName, String keyFieldName, String valueFieldName, int size, TermsStatsFacet.ComparatorType comparatorType, private LongValues keyValues;
SearchContext context, String scriptLang, String script, Map<String, Object> params) {
public TermsStatsLongFacetCollector(String facetName, IndexNumericFieldData keyIndexFieldData, IndexNumericFieldData valueIndexFieldData, SearchScript script,
int size, TermsStatsFacet.ComparatorType comparatorType, SearchContext context) {
super(facetName); super(facetName);
this.fieldDataCache = context.fieldDataCache();
this.size = size; this.size = size;
this.comparatorType = comparatorType; this.comparatorType = comparatorType;
this.numberOfShards = context.numberOfShards(); this.numberOfShards = context.numberOfShards();
this.keyIndexFieldData = keyIndexFieldData;
MapperService.SmartNameFieldMappers smartMappers = context.smartFieldMappers(keyFieldName); this.valueIndexFieldData = valueIndexFieldData;
if (smartMappers == null || !smartMappers.hasMapper()) { this.script = script;
this.keyFieldName = keyFieldName;
this.keyFieldDataType = FieldDataType.DefaultTypes.STRING;
} else {
// add type filter if there is exact doc mapper associated with it
if (smartMappers.explicitTypeInNameWithDocMapper()) {
setFilter(context.filterCache().cache(smartMappers.docMapper().typeFilter()));
}
this.keyFieldName = smartMappers.mapper().names().indexName();
this.keyFieldDataType = smartMappers.mapper().fieldDataType();
}
if (script == null) { if (script == null) {
smartMappers = context.smartFieldMappers(valueFieldName);
if (smartMappers == null || !smartMappers.hasMapper()) {
throw new ElasticSearchIllegalArgumentException("failed to find mappings for [" + valueFieldName + "]");
}
this.valueFieldName = smartMappers.mapper().names().indexName();
this.valueFieldDataType = smartMappers.mapper().fieldDataType();
this.script = null;
this.aggregator = new Aggregator(); this.aggregator = new Aggregator();
} else { } else {
this.valueFieldName = null;
this.valueFieldDataType = null;
this.script = context.scriptService().search(context.lookup(), scriptLang, script, params);
this.aggregator = new ScriptAggregator(this.script); this.aggregator = new ScriptAggregator(this.script);
} }
} }
@ -115,17 +80,17 @@ public class TermsStatsLongFacetCollector extends AbstractFacetCollector {
@Override @Override
protected void doSetNextReader(AtomicReaderContext context) throws IOException { protected void doSetNextReader(AtomicReaderContext context) throws IOException {
keyFieldData = (NumericFieldData) fieldDataCache.cache(keyFieldDataType, context.reader(), keyFieldName); keyValues = keyIndexFieldData.load(context).getLongValues();
if (script != null) { if (script != null) {
script.setNextReader(context); script.setNextReader(context);
} else { } else {
aggregator.valueFieldData = (NumericFieldData) fieldDataCache.cache(valueFieldDataType, context.reader(), valueFieldName); aggregator.valueValues = valueIndexFieldData.load(context).getDoubleValues();
} }
} }
@Override @Override
protected void doCollect(int doc) throws IOException { protected void doCollect(int doc) throws IOException {
keyFieldData.forEachValueInDoc(doc, aggregator); keyValues.forEachValueInDoc(doc, aggregator);
} }
@Override @Override
@ -155,13 +120,13 @@ public class TermsStatsLongFacetCollector extends AbstractFacetCollector {
return new InternalTermsStatsLongFacet(facetName, comparatorType, size, ordered, aggregator.missing); return new InternalTermsStatsLongFacet(facetName, comparatorType, size, ordered, aggregator.missing);
} }
public static class Aggregator implements NumericFieldData.MissingLongValueInDocProc { public static class Aggregator implements LongValues.ValueInDocProc {
final ExtTLongObjectHashMap<InternalTermsStatsLongFacet.LongEntry> entries = CacheRecycler.popLongObjectMap(); final ExtTLongObjectHashMap<InternalTermsStatsLongFacet.LongEntry> entries = CacheRecycler.popLongObjectMap();
int missing; int missing;
NumericFieldData valueFieldData; DoubleValues valueValues;
final ValueAggregator valueAggregator = new ValueAggregator(); final ValueAggregator valueAggregator = new ValueAggregator();
@ -174,7 +139,7 @@ public class TermsStatsLongFacetCollector extends AbstractFacetCollector {
} }
longEntry.count++; longEntry.count++;
valueAggregator.longEntry = longEntry; valueAggregator.longEntry = longEntry;
valueFieldData.forEachValueInDoc(docId, valueAggregator); valueValues.forEachValueInDoc(docId, valueAggregator);
} }
@Override @Override
@ -182,10 +147,14 @@ public class TermsStatsLongFacetCollector extends AbstractFacetCollector {
missing++; missing++;
} }
public static class ValueAggregator implements NumericFieldData.DoubleValueInDocProc { public static class ValueAggregator implements DoubleValues.ValueInDocProc {
InternalTermsStatsLongFacet.LongEntry longEntry; InternalTermsStatsLongFacet.LongEntry longEntry;
@Override
public void onMissing(int docId) {
}
@Override @Override
public void onValue(int docId, double value) { public void onValue(int docId, double value) {
if (value < longEntry.min) { if (value < longEntry.min) {

View File

@ -20,12 +20,11 @@
package org.elasticsearch.search.facet.termsstats.strings; package org.elasticsearch.search.facet.termsstats.strings;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.CacheRecycler; import org.elasticsearch.common.CacheRecycler;
import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.lucene.HashedBytesRef;
import org.elasticsearch.common.text.BytesText; import org.elasticsearch.common.text.BytesText;
import org.elasticsearch.common.text.Text; import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.trove.ExtTHashMap; import org.elasticsearch.common.trove.ExtTHashMap;
@ -69,8 +68,8 @@ public class InternalTermsStatsStringFacet extends InternalTermsStatsFacet {
double min; double min;
double max; double max;
public StringEntry(BytesRef term, long count, long totalCount, double total, double min, double max) { public StringEntry(HashedBytesRef term, long count, long totalCount, double total, double min, double max) {
this(new BytesText(new BytesArray(term)), count, totalCount, total, min, max); this(new BytesText(new BytesArray(term.bytes)), count, totalCount, total, min, max);
} }
public StringEntry(Text term, long count, long totalCount, double total, double min, double max) { public StringEntry(Text term, long count, long totalCount, double total, double min, double max) {

View File

@ -23,15 +23,13 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.apache.lucene.index.AtomicReaderContext; import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Scorer;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.ElasticSearchIllegalArgumentException;
import org.elasticsearch.common.CacheRecycler; import org.elasticsearch.common.CacheRecycler;
import org.elasticsearch.common.lucene.HashedBytesRef;
import org.elasticsearch.common.trove.ExtTHashMap; import org.elasticsearch.common.trove.ExtTHashMap;
import org.elasticsearch.index.cache.field.data.FieldDataCache; import org.elasticsearch.index.fielddata.DoubleValues;
import org.elasticsearch.index.field.data.FieldData; import org.elasticsearch.index.fielddata.HashedBytesValues;
import org.elasticsearch.index.field.data.FieldDataType; import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.field.data.NumericFieldData; import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.script.SearchScript; import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.facet.AbstractFacetCollector; import org.elasticsearch.search.facet.AbstractFacetCollector;
import org.elasticsearch.search.facet.Facet; import org.elasticsearch.search.facet.Facet;
@ -42,68 +40,36 @@ import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map;
public class TermsStatsStringFacetCollector extends AbstractFacetCollector { public class TermsStatsStringFacetCollector extends AbstractFacetCollector {
private final TermsStatsFacet.ComparatorType comparatorType; private final TermsStatsFacet.ComparatorType comparatorType;
private final FieldDataCache fieldDataCache; private final IndexFieldData keyIndexFieldData;
private final IndexNumericFieldData valueIndexFieldData;
private final String keyFieldName; private final SearchScript script;
private final String valueFieldName;
private final int size; private final int size;
private final int numberOfShards; private final int numberOfShards;
private final FieldDataType keyFieldDataType;
private FieldData keyFieldData;
private final FieldDataType valueFieldDataType;
private final SearchScript script;
private final Aggregator aggregator; private final Aggregator aggregator;
public TermsStatsStringFacetCollector(String facetName, String keyFieldName, String valueFieldName, int size, TermsStatsFacet.ComparatorType comparatorType, private HashedBytesValues keyValues;
SearchContext context, String scriptLang, String script, Map<String, Object> params) {
public TermsStatsStringFacetCollector(String facetName, IndexFieldData keyIndexFieldData, IndexNumericFieldData valueIndexFieldData, SearchScript valueScript,
int size, TermsStatsFacet.ComparatorType comparatorType, SearchContext context) {
super(facetName); super(facetName);
this.fieldDataCache = context.fieldDataCache(); this.keyIndexFieldData = keyIndexFieldData;
this.valueIndexFieldData = valueIndexFieldData;
this.script = valueScript;
this.size = size; this.size = size;
this.comparatorType = comparatorType; this.comparatorType = comparatorType;
this.numberOfShards = context.numberOfShards(); this.numberOfShards = context.numberOfShards();
MapperService.SmartNameFieldMappers smartMappers = context.smartFieldMappers(keyFieldName); if (script != null) {
if (smartMappers == null || !smartMappers.hasMapper()) { this.aggregator = new ScriptAggregator(valueScript);
this.keyFieldName = keyFieldName;
this.keyFieldDataType = FieldDataType.DefaultTypes.STRING;
} else { } else {
// add type filter if there is exact doc mapper associated with it
if (smartMappers.explicitTypeInNameWithDocMapper()) {
setFilter(context.filterCache().cache(smartMappers.docMapper().typeFilter()));
}
this.keyFieldName = smartMappers.mapper().names().indexName();
this.keyFieldDataType = smartMappers.mapper().fieldDataType();
}
if (script == null) {
smartMappers = context.smartFieldMappers(valueFieldName);
if (smartMappers == null || !smartMappers.hasMapper()) {
throw new ElasticSearchIllegalArgumentException("failed to find mappings for [" + valueFieldName + "]");
}
this.valueFieldName = smartMappers.mapper().names().indexName();
this.valueFieldDataType = smartMappers.mapper().fieldDataType();
this.script = null;
this.aggregator = new Aggregator(); this.aggregator = new Aggregator();
} else {
this.valueFieldName = null;
this.valueFieldDataType = null;
this.script = context.scriptService().search(context.lookup(), scriptLang, script, params);
this.aggregator = new ScriptAggregator(this.script);
} }
} }
@ -116,17 +82,17 @@ public class TermsStatsStringFacetCollector extends AbstractFacetCollector {
@Override @Override
protected void doSetNextReader(AtomicReaderContext context) throws IOException { protected void doSetNextReader(AtomicReaderContext context) throws IOException {
keyFieldData = fieldDataCache.cache(keyFieldDataType, context.reader(), keyFieldName); keyValues = keyIndexFieldData.load(context).getHashedBytesValues();
if (script != null) { if (script != null) {
script.setNextReader(context); script.setNextReader(context);
} else { } else {
aggregator.valueFieldData = (NumericFieldData) fieldDataCache.cache(valueFieldDataType, context.reader(), valueFieldName); aggregator.valueValues = valueIndexFieldData.load(context).getDoubleValues();
} }
} }
@Override @Override
protected void doCollect(int doc) throws IOException { protected void doCollect(int doc) throws IOException {
keyFieldData.forEachValueInDoc(doc, aggregator); keyValues.forEachValueInDoc(doc, aggregator);
} }
@Override @Override
@ -155,27 +121,28 @@ public class TermsStatsStringFacetCollector extends AbstractFacetCollector {
return new InternalTermsStatsStringFacet(facetName, comparatorType, size, ordered, aggregator.missing); return new InternalTermsStatsStringFacet(facetName, comparatorType, size, ordered, aggregator.missing);
} }
public static class Aggregator implements FieldData.StringValueInDocProc { public static class Aggregator implements HashedBytesValues.ValueInDocProc {
// LUCENE 4 UPGRADE: check if hashcode is not too expensive final ExtTHashMap<HashedBytesRef, InternalTermsStatsStringFacet.StringEntry> entries = CacheRecycler.popHashMap();
final ExtTHashMap<BytesRef, InternalTermsStatsStringFacet.StringEntry> entries = CacheRecycler.popHashMap();
int missing = 0; int missing = 0;
NumericFieldData valueFieldData; DoubleValues valueValues;
ValueAggregator valueAggregator = new ValueAggregator(); ValueAggregator valueAggregator = new ValueAggregator();
@Override @Override
public void onValue(int docId, BytesRef value) { public void onValue(int docId, HashedBytesRef value) {
InternalTermsStatsStringFacet.StringEntry stringEntry = entries.get(value); InternalTermsStatsStringFacet.StringEntry stringEntry = entries.get(value);
if (stringEntry == null) { if (stringEntry == null) {
// we use "unsafe" hashedBytes, and only copy over if we "miss" on the map, and need to put it there
value = value.deepCopy();
stringEntry = new InternalTermsStatsStringFacet.StringEntry(value, 0, 0, 0, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY); stringEntry = new InternalTermsStatsStringFacet.StringEntry(value, 0, 0, 0, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY);
entries.put(value, stringEntry); entries.put(value, stringEntry);
} }
stringEntry.count++; stringEntry.count++;
valueAggregator.stringEntry = stringEntry; valueAggregator.stringEntry = stringEntry;
valueFieldData.forEachValueInDoc(docId, valueAggregator); valueValues.forEachValueInDoc(docId, valueAggregator);
} }
@Override @Override
@ -183,10 +150,14 @@ public class TermsStatsStringFacetCollector extends AbstractFacetCollector {
missing++; missing++;
} }
public static class ValueAggregator implements NumericFieldData.DoubleValueInDocProc { public static class ValueAggregator implements DoubleValues.ValueInDocProc {
InternalTermsStatsStringFacet.StringEntry stringEntry; InternalTermsStatsStringFacet.StringEntry stringEntry;
@Override
public void onMissing(int docId) {
}
@Override @Override
public void onValue(int docId, double value) { public void onValue(int docId, double value) {
if (value < stringEntry.min) { if (value < stringEntry.min) {
@ -209,9 +180,11 @@ public class TermsStatsStringFacetCollector extends AbstractFacetCollector {
} }
@Override @Override
public void onValue(int docId, BytesRef value) { public void onValue(int docId, HashedBytesRef value) {
InternalTermsStatsStringFacet.StringEntry stringEntry = entries.get(value); InternalTermsStatsStringFacet.StringEntry stringEntry = entries.get(value);
if (stringEntry == null) { if (stringEntry == null) {
// we use "unsafe" hashedBytes, and only copy over if we "miss" on the map, and need to put it there
value = value.deepCopy();
stringEntry = new InternalTermsStatsStringFacet.StringEntry(value, 1, 0, 0, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY); stringEntry = new InternalTermsStatsStringFacet.StringEntry(value, 1, 0, 0, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY);
entries.put(value, stringEntry); entries.put(value, stringEntry);
} else { } else {