Query DSL: Fuzzy query support for numeric / date types, closes #907.

This commit is contained in:
kimchy 2011-05-05 16:36:06 +03:00
parent dffb11bdbf
commit 0f78100b97
20 changed files with 344 additions and 42 deletions

View File

@ -23,6 +23,7 @@ import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.MultiTermQuery;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.collect.ImmutableMap;
@ -155,19 +156,18 @@ public class MapperQueryParser extends QueryParser {
}
@Override protected Query getFuzzyQuery(String field, String termStr, float minSimilarity) throws ParseException {
String indexedNameField = field;
currentMapper = null;
if (parseContext.mapperService() != null) {
MapperService.SmartNameFieldMappers fieldMappers = parseContext.mapperService().smartName(field);
if (fieldMappers != null) {
currentMapper = fieldMappers.fieldMappers().mapper();
if (currentMapper != null) {
indexedNameField = currentMapper.names().indexName();
Query fuzzyQuery = currentMapper.fuzzyQuery(termStr, minSimilarity, fuzzyPrefixLength, FuzzyQuery.defaultMaxExpansions);
return wrapSmartNameQuery(fuzzyQuery, fieldMappers, parseContext);
}
return wrapSmartNameQuery(super.getFuzzyQuery(indexedNameField, termStr, minSimilarity), fieldMappers, parseContext);
}
}
return super.getFuzzyQuery(indexedNameField, termStr, minSimilarity);
return super.getFuzzyQuery(field, termStr, minSimilarity);
}
@Override protected Query getPrefixQuery(String field, String termStr) throws ParseException {

View File

@ -151,6 +151,10 @@ public interface FieldMapper<T> {
*/
Query fieldQuery(String value, QueryParseContext context);
Query fuzzyQuery(String value, String minSim, int prefixLength, int maxExpansions);
Query fuzzyQuery(String value, double minSim, int prefixLength, int maxExpansions);
/**
* A term query to use when parsing a query string. Can return <tt>null</tt>.
*/

View File

@ -321,6 +321,14 @@ public abstract class AbstractFieldMapper<T> implements FieldMapper<T>, XContent
return new TermQuery(new Term(names.indexName(), indexedValue(value)));
}
@Override public Query fuzzyQuery(String value, String minSim, int prefixLength, int maxExpansions) {
return new FuzzyQuery(new Term(names.indexName(), value), Float.parseFloat(minSim), prefixLength, maxExpansions);
}
@Override public Query fuzzyQuery(String value, double minSim, int prefixLength, int maxExpansions) {
return new FuzzyQuery(new Term(names.indexName(), value), (float) minSim, prefixLength, maxExpansions);
}
@Override public Filter fieldFilter(String value) {
return new TermFilter(new Term(names.indexName(), indexedValue(value)));
}

View File

@ -89,7 +89,7 @@ public class BoostFieldMapper extends NumberFieldMapper<Float> implements org.el
protected BoostFieldMapper(String name, String indexName, int precisionStep, Field.Index index, Field.Store store,
float boost, boolean omitNorms, boolean omitTermFreqAndPositions,
Float nullValue) {
super(new Names(name, indexName, indexName, name), precisionStep, index, store, boost, omitNorms, omitTermFreqAndPositions,
super(new Names(name, indexName, indexName, name), precisionStep, null, index, store, boost, omitNorms, omitTermFreqAndPositions,
new NamedAnalyzer("_float/" + precisionStep, new NumericFloatAnalyzer(precisionStep)),
new NamedAnalyzer("_float/max", new NumericFloatAnalyzer(Integer.MAX_VALUE)));
this.nullValue = nullValue;
@ -115,6 +115,24 @@ public class BoostFieldMapper extends NumberFieldMapper<Float> implements org.el
return NumericUtils.floatToPrefixCoded(Float.parseFloat(value));
}
@Override public Query fuzzyQuery(String value, String minSim, int prefixLength, int maxExpansions) {
float iValue = Float.parseFloat(value);
float iSim = Float.parseFloat(minSim);
return NumericRangeQuery.newFloatRange(names.indexName(), precisionStep,
iValue - iSim,
iValue + iSim,
true, true);
}
@Override public Query fuzzyQuery(String value, double minSim, int prefixLength, int maxExpansions) {
float iValue = Float.parseFloat(value);
float iSim = (float) (minSim * dFuzzyFactor);
return NumericRangeQuery.newFloatRange(names.indexName(), precisionStep,
iValue - iSim,
iValue + iSim,
true, true);
}
@Override public Query rangeQuery(String lowerTerm, String upperTerm, boolean includeLower, boolean includeUpper) {
return NumericRangeQuery.newFloatRange(names.indexName(), precisionStep,
lowerTerm == null ? null : Float.parseFloat(lowerTerm),

View File

@ -72,7 +72,7 @@ public class ByteFieldMapper extends NumberFieldMapper<Byte> {
@Override public ByteFieldMapper build(BuilderContext context) {
ByteFieldMapper fieldMapper = new ByteFieldMapper(buildNames(context),
precisionStep, index, store, boost, omitNorms, omitTermFreqAndPositions, nullValue);
precisionStep, fuzzyFactor, index, store, boost, omitNorms, omitTermFreqAndPositions, nullValue);
fieldMapper.includeInAll(includeInAll);
return fieldMapper;
}
@ -97,10 +97,10 @@ public class ByteFieldMapper extends NumberFieldMapper<Byte> {
private String nullValueAsString;
protected ByteFieldMapper(Names names, int precisionStep, Field.Index index, Field.Store store,
protected ByteFieldMapper(Names names, int precisionStep, String fuzzyFactor, Field.Index index, Field.Store store,
float boost, boolean omitNorms, boolean omitTermFreqAndPositions,
Byte nullValue) {
super(names, precisionStep, index, store, boost, omitNorms, omitTermFreqAndPositions,
super(names, precisionStep, fuzzyFactor, index, store, boost, omitNorms, omitTermFreqAndPositions,
new NamedAnalyzer("_byte/" + precisionStep, new NumericIntegerAnalyzer(precisionStep)),
new NamedAnalyzer("_byte/max", new NumericIntegerAnalyzer(Integer.MAX_VALUE)));
this.nullValue = nullValue;
@ -127,6 +127,30 @@ public class ByteFieldMapper extends NumberFieldMapper<Byte> {
return NumericUtils.intToPrefixCoded(Byte.parseByte(value));
}
@Override public Query fuzzyQuery(String value, String minSim, int prefixLength, int maxExpansions) {
byte iValue = Byte.parseByte(value);
byte iSim;
try {
iSim = Byte.parseByte(minSim);
} catch (NumberFormatException e) {
iSim = (byte) Float.parseFloat(minSim);
}
return NumericRangeQuery.newIntRange(names.indexName(), precisionStep,
iValue - iSim,
iValue + iSim,
true, true);
}
@Override public Query fuzzyQuery(String value, double minSim, int prefixLength, int maxExpansions) {
byte iValue = Byte.parseByte(value);
byte iSim = (byte) (minSim * dFuzzyFactor);
return NumericRangeQuery.newIntRange(names.indexName(), precisionStep,
iValue - iSim,
iValue + iSim,
true, true);
}
@Override public Query rangeQuery(String lowerTerm, String upperTerm, boolean includeLower, boolean includeUpper) {
return NumericRangeQuery.newIntRange(names.indexName(), precisionStep,
lowerTerm == null ? null : Integer.parseInt(lowerTerm),
@ -221,6 +245,9 @@ public class ByteFieldMapper extends NumberFieldMapper<Byte> {
if (precisionStep != Defaults.PRECISION_STEP) {
builder.field("precision_step", precisionStep);
}
if (fuzzyFactor != Defaults.FUZZY_FACTOR) {
builder.field("fuzzy_factor", fuzzyFactor);
}
if (nullValue != null) {
builder.field("null_value", nullValue);
}

View File

@ -30,6 +30,7 @@ import org.elasticsearch.common.Numbers;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.joda.Joda;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.analysis.NamedAnalyzer;
@ -82,7 +83,7 @@ public class DateFieldMapper extends NumberFieldMapper<Long> {
@Override public DateFieldMapper build(BuilderContext context) {
DateFieldMapper fieldMapper = new DateFieldMapper(buildNames(context), dateTimeFormatter,
precisionStep, index, store, boost, omitNorms, omitTermFreqAndPositions, nullValue);
precisionStep, fuzzyFactor, index, store, boost, omitNorms, omitTermFreqAndPositions, nullValue);
fieldMapper.includeInAll(includeInAll);
return fieldMapper;
}
@ -109,17 +110,28 @@ public class DateFieldMapper extends NumberFieldMapper<Long> {
private String nullValue;
protected DateFieldMapper(Names names, FormatDateTimeFormatter dateTimeFormatter, int precisionStep,
protected DateFieldMapper(Names names, FormatDateTimeFormatter dateTimeFormatter, int precisionStep, String fuzzyFactor,
Field.Index index, Field.Store store,
float boost, boolean omitNorms, boolean omitTermFreqAndPositions,
String nullValue) {
super(names, precisionStep, index, store, boost, omitNorms, omitTermFreqAndPositions,
super(names, precisionStep, fuzzyFactor, index, store, boost, omitNorms, omitTermFreqAndPositions,
new NamedAnalyzer("_date/" + precisionStep, new NumericDateAnalyzer(precisionStep, dateTimeFormatter.parser())),
new NamedAnalyzer("_date/max", new NumericDateAnalyzer(Integer.MAX_VALUE, dateTimeFormatter.parser())));
this.dateTimeFormatter = dateTimeFormatter;
this.nullValue = nullValue;
}
@Override protected double parseFuzzyFactor(String fuzzyFactor) {
if (fuzzyFactor == null) {
return 1.0d;
}
try {
return TimeValue.parseTimeValue(fuzzyFactor, null).millis();
} catch (Exception e) {
return Double.parseDouble(fuzzyFactor);
}
}
@Override protected int maxPrecisionStep() {
return 64;
}
@ -155,6 +167,30 @@ public class DateFieldMapper extends NumberFieldMapper<Long> {
return NumericUtils.longToPrefixCoded(dateTimeFormatter.parser().parseMillis(value));
}
@Override public Query fuzzyQuery(String value, String minSim, int prefixLength, int maxExpansions) {
long iValue = parseStringValue(value);
long iSim;
try {
iSim = TimeValue.parseTimeValue(minSim, null).millis();
} catch (Exception e) {
// not a time format
iSim = (long) Double.parseDouble(minSim);
}
return NumericRangeQuery.newLongRange(names.indexName(), precisionStep,
iValue - iSim,
iValue + iSim,
true, true);
}
@Override public Query fuzzyQuery(String value, double minSim, int prefixLength, int maxExpansions) {
long iValue = parseStringValue(value);
long iSim = (long) (minSim * dFuzzyFactor);
return NumericRangeQuery.newLongRange(names.indexName(), precisionStep,
iValue - iSim,
iValue + iSim,
true, true);
}
@Override public Query rangeQuery(String lowerTerm, String upperTerm, boolean includeLower, boolean includeUpper) {
return NumericRangeQuery.newLongRange(names.indexName(), precisionStep,
lowerTerm == null ? null : parseStringValue(lowerTerm),
@ -253,6 +289,9 @@ public class DateFieldMapper extends NumberFieldMapper<Long> {
if (precisionStep != Defaults.PRECISION_STEP) {
builder.field("precision_step", precisionStep);
}
if (fuzzyFactor != Defaults.FUZZY_FACTOR) {
builder.field("fuzzy_factor", fuzzyFactor);
}
builder.field("format", dateTimeFormatter.format());
if (nullValue != null) {
builder.field("null_value", nullValue);

View File

@ -72,7 +72,7 @@ public class DoubleFieldMapper extends NumberFieldMapper<Double> {
@Override public DoubleFieldMapper build(BuilderContext context) {
DoubleFieldMapper fieldMapper = new DoubleFieldMapper(buildNames(context),
precisionStep, index, store, boost, omitNorms, omitTermFreqAndPositions, nullValue);
precisionStep, fuzzyFactor, index, store, boost, omitNorms, omitTermFreqAndPositions, nullValue);
fieldMapper.includeInAll(includeInAll);
return fieldMapper;
}
@ -98,11 +98,11 @@ public class DoubleFieldMapper extends NumberFieldMapper<Double> {
private String nullValueAsString;
protected DoubleFieldMapper(Names names, int precisionStep,
protected DoubleFieldMapper(Names names, int precisionStep, String fuzzyFactor,
Field.Index index, Field.Store store,
float boost, boolean omitNorms, boolean omitTermFreqAndPositions,
Double nullValue) {
super(names, precisionStep, index, store, boost, omitNorms, omitTermFreqAndPositions,
super(names, precisionStep, fuzzyFactor, index, store, boost, omitNorms, omitTermFreqAndPositions,
new NamedAnalyzer("_double/" + precisionStep, new NumericDoubleAnalyzer(precisionStep)),
new NamedAnalyzer("_double/max", new NumericDoubleAnalyzer(Integer.MAX_VALUE)));
this.nullValue = nullValue;
@ -129,6 +129,24 @@ public class DoubleFieldMapper extends NumberFieldMapper<Double> {
return NumericUtils.doubleToPrefixCoded(Double.parseDouble(value));
}
@Override public Query fuzzyQuery(String value, String minSim, int prefixLength, int maxExpansions) {
double iValue = Double.parseDouble(value);
double iSim = Double.parseDouble(minSim);
return NumericRangeQuery.newDoubleRange(names.indexName(), precisionStep,
iValue - iSim,
iValue + iSim,
true, true);
}
@Override public Query fuzzyQuery(String value, double minSim, int prefixLength, int maxExpansions) {
double iValue = Double.parseDouble(value);
double iSim = minSim * dFuzzyFactor;
return NumericRangeQuery.newDoubleRange(names.indexName(), precisionStep,
iValue - iSim,
iValue + iSim,
true, true);
}
@Override public Query rangeQuery(String lowerTerm, String upperTerm, boolean includeLower, boolean includeUpper) {
return NumericRangeQuery.newDoubleRange(names.indexName(), precisionStep,
lowerTerm == null ? null : Double.parseDouble(lowerTerm),
@ -224,6 +242,9 @@ public class DoubleFieldMapper extends NumberFieldMapper<Double> {
if (precisionStep != Defaults.PRECISION_STEP) {
builder.field("precision_step", precisionStep);
}
if (fuzzyFactor != Defaults.FUZZY_FACTOR) {
builder.field("fuzzy_factor", fuzzyFactor);
}
if (nullValue != null) {
builder.field("null_value", nullValue);
}

View File

@ -73,7 +73,7 @@ public class FloatFieldMapper extends NumberFieldMapper<Float> {
@Override public FloatFieldMapper build(BuilderContext context) {
FloatFieldMapper fieldMapper = new FloatFieldMapper(buildNames(context),
precisionStep, index, store, boost, omitNorms, omitTermFreqAndPositions, nullValue);
precisionStep, fuzzyFactor, index, store, boost, omitNorms, omitTermFreqAndPositions, nullValue);
fieldMapper.includeInAll(includeInAll);
return fieldMapper;
}
@ -98,10 +98,10 @@ public class FloatFieldMapper extends NumberFieldMapper<Float> {
private String nullValueAsString;
protected FloatFieldMapper(Names names, int precisionStep, Field.Index index, Field.Store store,
protected FloatFieldMapper(Names names, int precisionStep, String fuzzyFactor, Field.Index index, Field.Store store,
float boost, boolean omitNorms, boolean omitTermFreqAndPositions,
Float nullValue) {
super(names, precisionStep, index, store, boost, omitNorms, omitTermFreqAndPositions,
super(names, precisionStep, fuzzyFactor, index, store, boost, omitNorms, omitTermFreqAndPositions,
new NamedAnalyzer("_float/" + precisionStep, new NumericFloatAnalyzer(precisionStep)),
new NamedAnalyzer("_float/max", new NumericFloatAnalyzer(Integer.MAX_VALUE)));
this.nullValue = nullValue;
@ -128,6 +128,24 @@ public class FloatFieldMapper extends NumberFieldMapper<Float> {
return NumericUtils.floatToPrefixCoded(Float.parseFloat(value));
}
@Override public Query fuzzyQuery(String value, String minSim, int prefixLength, int maxExpansions) {
float iValue = Float.parseFloat(value);
float iSim = Float.parseFloat(minSim);
return NumericRangeQuery.newFloatRange(names.indexName(), precisionStep,
iValue - iSim,
iValue + iSim,
true, true);
}
@Override public Query fuzzyQuery(String value, double minSim, int prefixLength, int maxExpansions) {
float iValue = Float.parseFloat(value);
float iSim = (float) (minSim * dFuzzyFactor);
return NumericRangeQuery.newFloatRange(names.indexName(), precisionStep,
iValue - iSim,
iValue + iSim,
true, true);
}
@Override public Query rangeQuery(String lowerTerm, String upperTerm, boolean includeLower, boolean includeUpper) {
return NumericRangeQuery.newFloatRange(names.indexName(), precisionStep,
lowerTerm == null ? null : Float.parseFloat(lowerTerm),
@ -224,6 +242,9 @@ public class FloatFieldMapper extends NumberFieldMapper<Float> {
if (precisionStep != Defaults.PRECISION_STEP) {
builder.field("precision_step", precisionStep);
}
if (fuzzyFactor != Defaults.FUZZY_FACTOR) {
builder.field("fuzzy_factor", fuzzyFactor);
}
if (nullValue != null) {
builder.field("null_value", nullValue);
}

View File

@ -73,7 +73,7 @@ public class IntegerFieldMapper extends NumberFieldMapper<Integer> {
@Override public IntegerFieldMapper build(BuilderContext context) {
IntegerFieldMapper fieldMapper = new IntegerFieldMapper(buildNames(context),
precisionStep, index, store, boost, omitNorms, omitTermFreqAndPositions, nullValue);
precisionStep, fuzzyFactor, index, store, boost, omitNorms, omitTermFreqAndPositions, nullValue);
fieldMapper.includeInAll(includeInAll);
return fieldMapper;
}
@ -98,10 +98,10 @@ public class IntegerFieldMapper extends NumberFieldMapper<Integer> {
private String nullValueAsString;
protected IntegerFieldMapper(Names names, int precisionStep, Field.Index index, Field.Store store,
protected IntegerFieldMapper(Names names, int precisionStep, String fuzzyFactor, Field.Index index, Field.Store store,
float boost, boolean omitNorms, boolean omitTermFreqAndPositions,
Integer nullValue) {
super(names, precisionStep, index, store, boost, omitNorms, omitTermFreqAndPositions,
super(names, precisionStep, fuzzyFactor, index, store, boost, omitNorms, omitTermFreqAndPositions,
new NamedAnalyzer("_int/" + precisionStep, new NumericIntegerAnalyzer(precisionStep)),
new NamedAnalyzer("_int/max", new NumericIntegerAnalyzer(Integer.MAX_VALUE)));
this.nullValue = nullValue;
@ -128,6 +128,29 @@ public class IntegerFieldMapper extends NumberFieldMapper<Integer> {
return NumericUtils.intToPrefixCoded(Integer.parseInt(value));
}
@Override public Query fuzzyQuery(String value, String minSim, int prefixLength, int maxExpansions) {
int iValue = Integer.parseInt(value);
int iSim;
try {
iSim = Integer.parseInt(minSim);
} catch (NumberFormatException e) {
iSim = (int) Float.parseFloat(minSim);
}
return NumericRangeQuery.newIntRange(names.indexName(), precisionStep,
iValue - iSim,
iValue + iSim,
true, true);
}
@Override public Query fuzzyQuery(String value, double minSim, int prefixLength, int maxExpansions) {
int iValue = Integer.parseInt(value);
int iSim = (int) (minSim * dFuzzyFactor);
return NumericRangeQuery.newIntRange(names.indexName(), precisionStep,
iValue - iSim,
iValue + iSim,
true, true);
}
@Override public Query rangeQuery(String lowerTerm, String upperTerm, boolean includeLower, boolean includeUpper) {
return NumericRangeQuery.newIntRange(names.indexName(), precisionStep,
lowerTerm == null ? null : Integer.parseInt(lowerTerm),
@ -223,6 +246,9 @@ public class IntegerFieldMapper extends NumberFieldMapper<Integer> {
if (precisionStep != Defaults.PRECISION_STEP) {
builder.field("precision_step", precisionStep);
}
if (fuzzyFactor != Defaults.FUZZY_FACTOR) {
builder.field("fuzzy_factor", fuzzyFactor);
}
if (nullValue != null) {
builder.field("null_value", nullValue);
}

View File

@ -73,7 +73,7 @@ public class LongFieldMapper extends NumberFieldMapper<Long> {
@Override public LongFieldMapper build(BuilderContext context) {
LongFieldMapper fieldMapper = new LongFieldMapper(buildNames(context),
precisionStep, index, store, boost, omitNorms, omitTermFreqAndPositions, nullValue);
precisionStep, fuzzyFactor, index, store, boost, omitNorms, omitTermFreqAndPositions, nullValue);
fieldMapper.includeInAll(includeInAll);
return fieldMapper;
}
@ -98,10 +98,10 @@ public class LongFieldMapper extends NumberFieldMapper<Long> {
private String nullValueAsString;
protected LongFieldMapper(Names names, int precisionStep, Field.Index index, Field.Store store,
protected LongFieldMapper(Names names, int precisionStep, String fuzzyFactor, Field.Index index, Field.Store store,
float boost, boolean omitNorms, boolean omitTermFreqAndPositions,
Long nullValue) {
super(names, precisionStep, index, store, boost, omitNorms, omitTermFreqAndPositions,
super(names, precisionStep, fuzzyFactor, index, store, boost, omitNorms, omitTermFreqAndPositions,
new NamedAnalyzer("_long/" + precisionStep, new NumericLongAnalyzer(precisionStep)),
new NamedAnalyzer("_long/max", new NumericLongAnalyzer(Integer.MAX_VALUE)));
this.nullValue = nullValue;
@ -128,6 +128,29 @@ public class LongFieldMapper extends NumberFieldMapper<Long> {
return NumericUtils.longToPrefixCoded(Long.parseLong(value));
}
@Override public Query fuzzyQuery(String value, String minSim, int prefixLength, int maxExpansions) {
long iValue = Long.parseLong(value);
long iSim;
try {
iSim = Long.parseLong(minSim);
} catch (NumberFormatException e) {
iSim = (long) Double.parseDouble(minSim);
}
return NumericRangeQuery.newLongRange(names.indexName(), precisionStep,
iValue - iSim,
iValue + iSim,
true, true);
}
@Override public Query fuzzyQuery(String value, double minSim, int prefixLength, int maxExpansions) {
long iValue = Long.parseLong(value);
long iSim = (long) (minSim * dFuzzyFactor);
return NumericRangeQuery.newLongRange(names.indexName(), precisionStep,
iValue - iSim,
iValue + iSim,
true, true);
}
@Override public Query rangeQuery(String lowerTerm, String upperTerm, boolean includeLower, boolean includeUpper) {
return NumericRangeQuery.newLongRange(names.indexName(), precisionStep,
lowerTerm == null ? null : Long.parseLong(lowerTerm),
@ -222,6 +245,9 @@ public class LongFieldMapper extends NumberFieldMapper<Long> {
if (precisionStep != Defaults.PRECISION_STEP) {
builder.field("precision_step", precisionStep);
}
if (fuzzyFactor != Defaults.FUZZY_FACTOR) {
builder.field("fuzzy_factor", fuzzyFactor);
}
if (nullValue != null) {
builder.field("null_value", nullValue);
}

View File

@ -26,6 +26,7 @@ import org.apache.lucene.document.Fieldable;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.NumericUtils;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.index.analysis.NamedAnalyzer;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.FieldDataType;
@ -44,12 +45,15 @@ public abstract class NumberFieldMapper<T extends Number> extends AbstractFieldM
public static final Field.Index INDEX = Field.Index.NOT_ANALYZED;
public static final boolean OMIT_NORMS = true;
public static final boolean OMIT_TERM_FREQ_AND_POSITIONS = true;
public static final String FUZZY_FACTOR = null;
}
public abstract static class Builder<T extends Builder, Y extends NumberFieldMapper> extends AbstractFieldMapper.Builder<T, Y> {
protected int precisionStep = Defaults.PRECISION_STEP;
protected String fuzzyFactor = Defaults.FUZZY_FACTOR;
public Builder(String name) {
super(name);
this.index = Defaults.INDEX;
@ -77,10 +81,19 @@ public abstract class NumberFieldMapper<T extends Number> extends AbstractFieldM
this.precisionStep = precisionStep;
return builder;
}
public T fuzzyFactor(String fuzzyFactor) {
this.fuzzyFactor = fuzzyFactor;
return builder;
}
}
protected int precisionStep;
protected String fuzzyFactor;
protected double dFuzzyFactor;
protected Boolean includeInAll;
private ThreadLocal<NumericTokenStream> tokenStream = new ThreadLocal<NumericTokenStream>() {
@ -89,7 +102,7 @@ public abstract class NumberFieldMapper<T extends Number> extends AbstractFieldM
}
};
protected NumberFieldMapper(Names names, int precisionStep,
protected NumberFieldMapper(Names names, int precisionStep, @Nullable String fuzzyFactor,
Field.Index index, Field.Store store,
float boost, boolean omitNorms, boolean omitTermFreqAndPositions,
NamedAnalyzer indexAnalyzer, NamedAnalyzer searchAnalyzer) {
@ -99,6 +112,15 @@ public abstract class NumberFieldMapper<T extends Number> extends AbstractFieldM
} else {
this.precisionStep = precisionStep;
}
this.fuzzyFactor = fuzzyFactor;
this.dFuzzyFactor = parseFuzzyFactor(fuzzyFactor);
}
protected double parseFuzzyFactor(String fuzzyFactor) {
if (fuzzyFactor == null) {
return 1.0d;
}
return Double.parseDouble(fuzzyFactor);
}
@Override public void includeInAll(Boolean includeInAll) {
@ -134,6 +156,10 @@ public abstract class NumberFieldMapper<T extends Number> extends AbstractFieldM
return rangeQuery(value, value, true, true);
}
@Override public abstract Query fuzzyQuery(String value, String minSim, int prefixLength, int maxExpansions);
@Override public abstract Query fuzzyQuery(String value, double minSim, int prefixLength, int maxExpansions);
/**
* Numeric field level filter are basically range queries with same value and included. That's the recommended
* way to execute it.

View File

@ -73,7 +73,7 @@ public class ShortFieldMapper extends NumberFieldMapper<Short> {
@Override public ShortFieldMapper build(BuilderContext context) {
ShortFieldMapper fieldMapper = new ShortFieldMapper(buildNames(context),
precisionStep, index, store, boost, omitNorms, omitTermFreqAndPositions, nullValue);
precisionStep, fuzzyFactor, index, store, boost, omitNorms, omitTermFreqAndPositions, nullValue);
fieldMapper.includeInAll(includeInAll);
return fieldMapper;
}
@ -98,10 +98,10 @@ public class ShortFieldMapper extends NumberFieldMapper<Short> {
private String nullValueAsString;
protected ShortFieldMapper(Names names, int precisionStep, Field.Index index, Field.Store store,
protected ShortFieldMapper(Names names, int precisionStep, String fuzzyFactor, Field.Index index, Field.Store store,
float boost, boolean omitNorms, boolean omitTermFreqAndPositions,
Short nullValue) {
super(names, precisionStep, index, store, boost, omitNorms, omitTermFreqAndPositions,
super(names, precisionStep, fuzzyFactor, index, store, boost, omitNorms, omitTermFreqAndPositions,
new NamedAnalyzer("_short/" + precisionStep, new NumericIntegerAnalyzer(precisionStep)),
new NamedAnalyzer("_short/max", new NumericIntegerAnalyzer(Integer.MAX_VALUE)));
this.nullValue = nullValue;
@ -128,6 +128,29 @@ public class ShortFieldMapper extends NumberFieldMapper<Short> {
return NumericUtils.intToPrefixCoded(Short.parseShort(value));
}
@Override public Query fuzzyQuery(String value, String minSim, int prefixLength, int maxExpansions) {
short iValue = Short.parseShort(value);
short iSim;
try {
iSim = Short.parseShort(minSim);
} catch (NumberFormatException e) {
iSim = (short) Float.parseFloat(minSim);
}
return NumericRangeQuery.newIntRange(names.indexName(), precisionStep,
iValue - iSim,
iValue + iSim,
true, true);
}
@Override public Query fuzzyQuery(String value, double minSim, int prefixLength, int maxExpansions) {
short iValue = Short.parseShort(value);
short iSim = (short) (minSim * dFuzzyFactor);
return NumericRangeQuery.newIntRange(names.indexName(), precisionStep,
iValue - iSim,
iValue + iSim,
true, true);
}
@Override public Query rangeQuery(String lowerTerm, String upperTerm, boolean includeLower, boolean includeUpper) {
return NumericRangeQuery.newIntRange(names.indexName(), precisionStep,
lowerTerm == null ? null : Integer.parseInt(lowerTerm),
@ -222,6 +245,9 @@ public class ShortFieldMapper extends NumberFieldMapper<Short> {
if (precisionStep != Defaults.PRECISION_STEP) {
builder.field("precision_step", precisionStep);
}
if (fuzzyFactor != Defaults.FUZZY_FACTOR) {
builder.field("fuzzy_factor", fuzzyFactor);
}
if (nullValue != null) {
builder.field("null_value", nullValue);
}

View File

@ -68,7 +68,7 @@ public class SizeFieldMapper extends IntegerFieldMapper {
}
public SizeFieldMapper(boolean enabled, Field.Store store) {
super(new Names(Defaults.NAME), Defaults.PRECISION_STEP, Defaults.INDEX, store, Defaults.BOOST, Defaults.OMIT_NORMS, Defaults.OMIT_TERM_FREQ_AND_POSITIONS, Defaults.NULL_VALUE);
super(new Names(Defaults.NAME), Defaults.PRECISION_STEP, Defaults.FUZZY_FACTOR, Defaults.INDEX, store, Defaults.BOOST, Defaults.OMIT_NORMS, Defaults.OMIT_TERM_FREQ_AND_POSITIONS, Defaults.NULL_VALUE);
this.enabled = enabled;
}

View File

@ -42,6 +42,8 @@ public class XContentTypeParsers {
Object propNode = entry.getValue();
if (propName.equals("precision_step")) {
builder.precisionStep(nodeIntegerValue(propNode));
} else if (propName.equals("fuzzy_factor")) {
builder.fuzzyFactor(propNode.toString());
}
}
}

View File

@ -22,10 +22,8 @@ package org.elasticsearch.index.mapper.xcontent.ip;
import org.apache.lucene.analysis.NumericTokenStream;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.NumericRangeFilter;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.*;
import org.apache.lucene.util.NumericUtils;
import org.elasticsearch.ElasticSearchIllegalArgumentException;
import org.elasticsearch.common.Numbers;
@ -130,7 +128,7 @@ public class IpFieldMapper extends NumberFieldMapper<Long> {
Field.Index index, Field.Store store,
float boost, boolean omitNorms, boolean omitTermFreqAndPositions,
String nullValue) {
super(names, precisionStep, index, store, boost, omitNorms, omitTermFreqAndPositions,
super(names, precisionStep, null, index, store, boost, omitNorms, omitTermFreqAndPositions,
new NamedAnalyzer("_ip/" + precisionStep, new NumericIpAnalyzer(precisionStep)),
new NamedAnalyzer("_ip/max", new NumericIpAnalyzer(Integer.MAX_VALUE)));
this.nullValue = nullValue;
@ -171,6 +169,19 @@ public class IpFieldMapper extends NumberFieldMapper<Long> {
return NumericUtils.longToPrefixCoded(ipToLong(value));
}
@Override public Query fuzzyQuery(String value, String minSim, int prefixLength, int maxExpansions) {
long iValue = ipToLong(value);
long iSim = ipToLong(minSim);
return NumericRangeQuery.newLongRange(names.indexName(), precisionStep,
iValue - iSim,
iValue + iSim,
true, true);
}
@Override public Query fuzzyQuery(String value, double minSim, int prefixLength, int maxExpansions) {
return new FuzzyQuery(new Term(names.indexName(), value), (float) minSim, prefixLength, maxExpansions);
}
@Override public Query rangeQuery(String lowerTerm, String upperTerm, boolean includeLower, boolean includeUpper) {
return NumericRangeQuery.newLongRange(names.indexName(), precisionStep,
lowerTerm == null ? null : ipToLong(lowerTerm),

View File

@ -32,11 +32,11 @@ public class FuzzyQueryBuilder extends BaseQueryBuilder {
private final String name;
private final String value;
private final Object value;
private float boost = -1;
private Float minSimilarity;
private String minSimilarity;
private Integer prefixLength;
@ -46,7 +46,7 @@ public class FuzzyQueryBuilder extends BaseQueryBuilder {
* @param name The name of the field
* @param value The value of the term
*/
public FuzzyQueryBuilder(String name, String value) {
public FuzzyQueryBuilder(String name, Object value) {
this.name = name;
this.value = value;
}
@ -61,6 +61,11 @@ public class FuzzyQueryBuilder extends BaseQueryBuilder {
}
public FuzzyQueryBuilder minSimilarity(float defaultMinSimilarity) {
this.minSimilarity = Float.toString(defaultMinSimilarity);
return this;
}
public FuzzyQueryBuilder minSimilarity(String defaultMinSimilarity) {
this.minSimilarity = defaultMinSimilarity;
return this;
}

View File

@ -59,7 +59,7 @@ public class FuzzyQueryParser extends AbstractIndexComponent implements XContent
String value = null;
float boost = 1.0f;
float minSimilarity = FuzzyQuery.defaultMinSimilarity;
String minSimilarity = "0.5";
int prefixLength = FuzzyQuery.defaultPrefixLength;
int maxExpansions = FuzzyQuery.defaultMaxExpansions;
token = parser.nextToken();
@ -76,7 +76,7 @@ public class FuzzyQueryParser extends AbstractIndexComponent implements XContent
} else if ("boost".equals(currentFieldName)) {
boost = parser.floatValue();
} else if ("min_similarity".equals(currentFieldName) || "minSimilarity".equals(currentFieldName)) {
minSimilarity = parser.floatValue();
minSimilarity = parser.text();
} else if ("prefix_length".equals(currentFieldName) || "prefixLength".equals(currentFieldName)) {
prefixLength = parser.intValue();
} else if ("max_expansions".equals(currentFieldName) || "maxExpansions".equals(currentFieldName)) {
@ -95,11 +95,18 @@ public class FuzzyQueryParser extends AbstractIndexComponent implements XContent
throw new QueryParsingException(index, "No value specified for fuzzy query");
}
Query query = null;
MapperService.SmartNameFieldMappers smartNameFieldMappers = parseContext.smartFieldMappers(fieldName);
if (smartNameFieldMappers != null) {
if (smartNameFieldMappers.hasMapper()) {
query = smartNameFieldMappers.mapper().fuzzyQuery(value, minSimilarity, prefixLength, maxExpansions);
}
}
if (query == null) {
query = new FuzzyQuery(new Term(fieldName, value), Float.parseFloat(minSimilarity), prefixLength, maxExpansions);
}
query.setBoost(boost);
FuzzyQuery fuzzyQuery = new FuzzyQuery(new Term(fieldName, value), minSimilarity, prefixLength, maxExpansions);
fuzzyQuery.setBoost(boost);
return wrapSmartNameQuery(fuzzyQuery, smartNameFieldMappers, parseContext);
return wrapSmartNameQuery(query, smartNameFieldMappers, parseContext);
}
}

View File

@ -331,6 +331,16 @@ public class SimpleIndexQueryParserTests {
assertThat(fuzzyQuery.getBoost(), equalTo(2.0f));
}
@Test public void testFuzzyQueryWithFields2() throws IOException {
IndexQueryParser queryParser = queryParser();
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/xcontent/fuzzy-with-fields2.json");
Query parsedQuery = queryParser.parse(query).query();
assertThat(parsedQuery, instanceOf(NumericRangeQuery.class));
NumericRangeQuery fuzzyQuery = (NumericRangeQuery) parsedQuery;
assertThat(fuzzyQuery.getMin().longValue(), equalTo(7l));
assertThat(fuzzyQuery.getMax().longValue(), equalTo(17l));
}
@Test public void testFieldQueryBuilder1() throws IOException {
IndexQueryParser queryParser = queryParser();
Query parsedQuery = queryParser.parse(fieldQuery("age", 34).buildAsBytes()).query();
@ -763,6 +773,16 @@ public class SimpleIndexQueryParserTests {
assertThat(parsedQuery, instanceOf(BoostingQuery.class));
}
@Test public void testQueryStringFuzzyNumeric() throws IOException {
IndexQueryParser queryParser = queryParser();
String query = copyToStringFromClasspath("/org/elasticsearch/index/query/xcontent/query2.json");
Query parsedQuery = queryParser.parse(query).query();
assertThat(parsedQuery, instanceOf(NumericRangeQuery.class));
NumericRangeQuery fuzzyQuery = (NumericRangeQuery) parsedQuery;
assertThat(fuzzyQuery.getMin().longValue(), equalTo(12l));
assertThat(fuzzyQuery.getMax().longValue(), equalTo(12l));
}
@Test public void testBoolQueryBuilder() throws IOException {
IndexQueryParser queryParser = queryParser();
Query parsedQuery = queryParser.parse(boolQuery().must(termQuery("content", "test1")).must(termQuery("content", "test4")).mustNot(termQuery("content", "test2")).should(termQuery("content", "test3"))).query();

View File

@ -0,0 +1,9 @@
{
"fuzzy" : {
"age" : {
"value" : 12,
"min_similarity" : 5,
"boost" : 2.0
}
}
}

View File

@ -0,0 +1,6 @@
{
query_string : {
default_field : "age",
query: "12~0.2"
}
}