Query DSL: Fuzzy query support for numeric / date types, closes #907.
This commit is contained in:
parent
dffb11bdbf
commit
0f78100b97
|
@ -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 {
|
||||
|
|
|
@ -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>.
|
||||
*/
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"fuzzy" : {
|
||||
"age" : {
|
||||
"value" : 12,
|
||||
"min_similarity" : 5,
|
||||
"boost" : 2.0
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
query_string : {
|
||||
default_field : "age",
|
||||
query: "12~0.2"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue