Fix FuzzyQuery to properly handle Object, number, dates or String.

This makes FuzzyQueryBuilder and Parser take an Object as a value using the
same logic as termQuery, so that numbers, dates or Strings would be properly
handled.

Relates #11865
Closes #12020
This commit is contained in:
Alex Ksikes 2015-07-02 19:43:48 -05:00
parent 786d034d75
commit a6c0007325
12 changed files with 92 additions and 46 deletions

View File

@ -25,14 +25,7 @@ import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.Term; import org.apache.lucene.index.Term;
import org.apache.lucene.index.Terms; import org.apache.lucene.index.Terms;
import org.apache.lucene.queries.TermsQuery; import org.apache.lucene.queries.TermsQuery;
import org.apache.lucene.search.ConstantScoreQuery; import org.apache.lucene.search.*;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.MultiTermQuery;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.RegexpQuery;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TermRangeQuery;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.elasticsearch.action.fieldstats.FieldStats; import org.elasticsearch.action.fieldstats.FieldStats;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
@ -463,8 +456,8 @@ public abstract class MappedFieldType extends FieldType {
includeLower, includeUpper); includeLower, includeUpper);
} }
public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) {
return new FuzzyQuery(createTerm(value), fuzziness.asDistance(value), prefixLength, maxExpansions, transpositions); return new FuzzyQuery(createTerm(value), fuzziness.asDistance(BytesRefs.toString(value)), prefixLength, maxExpansions, transpositions);
} }
public Query prefixQuery(Object value, @Nullable MultiTermQuery.RewriteMethod method, @Nullable QueryParseContext context) { public Query prefixQuery(Object value, @Nullable MultiTermQuery.RewriteMethod method, @Nullable QueryParseContext context) {

View File

@ -171,8 +171,8 @@ public class ByteFieldMapper extends NumberFieldMapper {
} }
@Override @Override
public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) {
byte iValue = Byte.parseByte(value); byte iValue = parseValue(value);
byte iSim = fuzziness.asByte(); byte iSim = fuzziness.asByte();
return NumericRangeQuery.newIntRange(names().indexName(), numericPrecisionStep(), return NumericRangeQuery.newIntRange(names().indexName(), numericPrecisionStep(),
iValue - iSim, iValue - iSim,

View File

@ -395,8 +395,8 @@ public class DateFieldMapper extends NumberFieldMapper {
} }
@Override @Override
public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) {
long iValue = dateMathParser().parse(value, now()); long iValue = parseValue(value);
long iSim; long iSim;
try { try {
iSim = fuzziness.asTimeValue().millis(); iSim = fuzziness.asTimeValue().millis();

View File

@ -20,7 +20,6 @@
package org.elasticsearch.index.mapper.core; package org.elasticsearch.index.mapper.core;
import com.carrotsearch.hppc.DoubleArrayList; import com.carrotsearch.hppc.DoubleArrayList;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
@ -178,8 +177,8 @@ public class DoubleFieldMapper extends NumberFieldMapper {
} }
@Override @Override
public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) {
double iValue = Double.parseDouble(value); double iValue = parseDoubleValue(value);
double iSim = fuzziness.asDouble(); double iSim = fuzziness.asDouble();
return NumericRangeQuery.newDoubleRange(names().indexName(), numericPrecisionStep(), return NumericRangeQuery.newDoubleRange(names().indexName(), numericPrecisionStep(),
iValue - iSim, iValue - iSim,

View File

@ -20,7 +20,6 @@
package org.elasticsearch.index.mapper.core; package org.elasticsearch.index.mapper.core;
import com.carrotsearch.hppc.FloatArrayList; import com.carrotsearch.hppc.FloatArrayList;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
@ -179,8 +178,8 @@ public class FloatFieldMapper extends NumberFieldMapper {
} }
@Override @Override
public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) {
float iValue = Float.parseFloat(value); float iValue = parseValue(value);
final float iSim = fuzziness.asFloat(); final float iSim = fuzziness.asFloat();
return NumericRangeQuery.newFloatRange(names().indexName(), numericPrecisionStep(), return NumericRangeQuery.newFloatRange(names().indexName(), numericPrecisionStep(),
iValue - iSim, iValue - iSim,

View File

@ -180,8 +180,8 @@ public class IntegerFieldMapper extends NumberFieldMapper {
} }
@Override @Override
public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) {
int iValue = Integer.parseInt(value); int iValue = parseValue(value);
int iSim = fuzziness.asInt(); int iSim = fuzziness.asInt();
return NumericRangeQuery.newIntRange(names().indexName(), numericPrecisionStep(), return NumericRangeQuery.newIntRange(names().indexName(), numericPrecisionStep(),
iValue - iSim, iValue - iSim,

View File

@ -178,8 +178,8 @@ public class LongFieldMapper extends NumberFieldMapper {
} }
@Override @Override
public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) {
long iValue = Long.parseLong(value); long iValue = parseLongValue(value);
final long iSim = fuzziness.asLong(); final long iSim = fuzziness.asLong();
return NumericRangeQuery.newLongRange(names().indexName(), numericPrecisionStep(), return NumericRangeQuery.newLongRange(names().indexName(), numericPrecisionStep(),
iValue - iSim, iValue - iSim,

View File

@ -20,7 +20,6 @@
package org.elasticsearch.index.mapper.core; package org.elasticsearch.index.mapper.core;
import com.carrotsearch.hppc.LongArrayList; import com.carrotsearch.hppc.LongArrayList;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.NumericTokenStream; import org.apache.lucene.analysis.NumericTokenStream;
import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.TokenStream;
@ -42,13 +41,7 @@ import org.elasticsearch.common.util.ByteUtils;
import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.common.util.CollectionUtils;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.analysis.NamedAnalyzer; import org.elasticsearch.index.analysis.NamedAnalyzer;
import org.elasticsearch.index.mapper.FieldMapper; import org.elasticsearch.index.mapper.*;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperParsingException;
import org.elasticsearch.index.mapper.MergeMappingException;
import org.elasticsearch.index.mapper.MergeResult;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.internal.AllFieldMapper; import org.elasticsearch.index.mapper.internal.AllFieldMapper;
import java.io.IOException; import java.io.IOException;
@ -158,7 +151,7 @@ public abstract class NumberFieldMapper extends FieldMapper implements AllFieldM
} }
@Override @Override
public abstract Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions); public abstract Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions);
@Override @Override
public boolean useTermQueryWithQueryString() { public boolean useTermQueryWithQueryString() {

View File

@ -176,8 +176,8 @@ public class ShortFieldMapper extends NumberFieldMapper {
} }
@Override @Override
public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) {
short iValue = Short.parseShort(value); short iValue = parseValue(value);
short iSim = fuzziness.asShort(); short iSim = fuzziness.asShort();
return NumericRangeQuery.newIntRange(names().indexName(), numericPrecisionStep(), return NumericRangeQuery.newIntRange(names().indexName(), numericPrecisionStep(),
iValue - iSim, iValue - iSim,

View File

@ -20,7 +20,6 @@
package org.elasticsearch.index.mapper.ip; package org.elasticsearch.index.mapper.ip;
import com.google.common.net.InetAddresses; import com.google.common.net.InetAddresses;
import org.apache.lucene.analysis.NumericTokenStream; import org.apache.lucene.analysis.NumericTokenStream;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexOptions; import org.apache.lucene.index.IndexOptions;
@ -218,8 +217,8 @@ public class IpFieldMapper extends NumberFieldMapper {
} }
@Override @Override
public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) {
long iValue = ipToLong(value); long iValue = parseValue(value);
long iSim; long iSim;
try { try {
iSim = ipToLong(fuzziness.asString()); iSim = ipToLong(fuzziness.asString());

View File

@ -49,16 +49,77 @@ public class FuzzyQueryBuilder extends MultiTermQueryBuilder implements Boostabl
private String queryName; private String queryName;
/** /**
* Constructs a new term query. * Constructs a new fuzzy query.
* *
* @param name The name of the field * @param name The name of the field
* @param value The value of the term * @param value The value of the text
*/ */
public FuzzyQueryBuilder(String name, Object value) { public FuzzyQueryBuilder(String name, Object value) {
this.name = name; this.name = name;
this.value = value; this.value = value;
} }
/**
* Constructs a new fuzzy query.
*
* @param name The name of the field
* @param value The value of the text
*/
public FuzzyQueryBuilder(String name, String value) {
this(name, (Object) value);
}
/**
* Constructs a new fuzzy query.
*
* @param name The name of the field
* @param value The value of the text
*/
public FuzzyQueryBuilder(String name, int value) {
this(name, (Object) value);
}
/**
* Constructs a new fuzzy query.
*
* @param name The name of the field
* @param value The value of the text
*/
public FuzzyQueryBuilder(String name, long value) {
this(name, (Object) value);
}
/**
* Constructs a new fuzzy query.
*
* @param name The name of the field
* @param value The value of the text
*/
public FuzzyQueryBuilder(String name, float value) {
this(name, (Object) value);
}
/**
* Constructs a new fuzzy query.
*
* @param name The name of the field
* @param value The value of the text
*/
public FuzzyQueryBuilder(String name, double value) {
this(name, (Object) value);
}
// NO COMMIT: not sure we should also allow boolean?
/**
* Constructs a new fuzzy query.
*
* @param name The name of the field
* @param value The value of the text
*/
public FuzzyQueryBuilder(String name, boolean value) {
this(name, (Object) value);
}
/** /**
* Sets the boost for this query. Documents matching this query will (in addition to the normal * Sets the boost for this query. Documents matching this query will (in addition to the normal
* weightings) have their score multiplied by the boost provided. * weightings) have their score multiplied by the boost provided.

View File

@ -25,6 +25,7 @@ import org.apache.lucene.search.MultiTermQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.lucene.BytesRefs;
import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.MappedFieldType;
@ -61,7 +62,7 @@ public class FuzzyQueryParser implements QueryParser {
} }
String fieldName = parser.currentName(); String fieldName = parser.currentName();
String value = null; Object value = null;
float boost = 1.0f; float boost = 1.0f;
Fuzziness fuzziness = DEFAULT_FUZZINESS; Fuzziness fuzziness = DEFAULT_FUZZINESS;
int prefixLength = FuzzyQuery.defaultPrefixLength; int prefixLength = FuzzyQuery.defaultPrefixLength;
@ -80,9 +81,9 @@ public class FuzzyQueryParser implements QueryParser {
currentFieldName = parser.currentName(); currentFieldName = parser.currentName();
} else { } else {
if ("term".equals(currentFieldName)) { if ("term".equals(currentFieldName)) {
value = parser.text(); value = parser.objectBytes();
} else if ("value".equals(currentFieldName)) { } else if ("value".equals(currentFieldName)) {
value = parser.text(); value = parser.objectBytes();
} else if ("boost".equals(currentFieldName)) { } else if ("boost".equals(currentFieldName)) {
boost = parser.floatValue(); boost = parser.floatValue();
} else if (parseContext.parseFieldMatcher().match(currentFieldName, FUZZINESS)) { } else if (parseContext.parseFieldMatcher().match(currentFieldName, FUZZINESS)) {
@ -104,7 +105,7 @@ public class FuzzyQueryParser implements QueryParser {
} }
parser.nextToken(); parser.nextToken();
} else { } else {
value = parser.text(); value = parser.objectBytes();
// move to the next token // move to the next token
parser.nextToken(); parser.nextToken();
} }
@ -112,14 +113,15 @@ public class FuzzyQueryParser implements QueryParser {
if (value == null) { if (value == null) {
throw new QueryParsingException(parseContext, "No value specified for fuzzy query"); throw new QueryParsingException(parseContext, "No value specified for fuzzy query");
} }
Query query = null; Query query = null;
MappedFieldType fieldType = parseContext.fieldMapper(fieldName); MappedFieldType fieldType = parseContext.fieldMapper(fieldName);
if (fieldType != null) { if (fieldType != null) {
query = fieldType.fuzzyQuery(value, fuzziness, prefixLength, maxExpansions, transpositions); query = fieldType.fuzzyQuery(value, fuzziness, prefixLength, maxExpansions, transpositions);
} }
if (query == null) { if (query == null) {
query = new FuzzyQuery(new Term(fieldName, value), fuzziness.asDistance(value), prefixLength, maxExpansions, transpositions); int maxEdits = fuzziness.asDistance(BytesRefs.toString(value));
query = new FuzzyQuery(new Term(fieldName, BytesRefs.toBytesRef(value)), maxEdits, prefixLength, maxExpansions, transpositions);
} }
if (query instanceof MultiTermQuery) { if (query instanceof MultiTermQuery) {
QueryParsers.setRewriteMethod((MultiTermQuery) query, rewriteMethod); QueryParsers.setRewriteMethod((MultiTermQuery) query, rewriteMethod);