From a6c00073256cff58ccf83ec6699166bedd34a6f7 Mon Sep 17 00:00:00 2001 From: Alex Ksikes Date: Thu, 2 Jul 2015 19:43:48 -0500 Subject: [PATCH] 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 --- .../index/mapper/MappedFieldType.java | 13 +--- .../index/mapper/core/ByteFieldMapper.java | 4 +- .../index/mapper/core/DateFieldMapper.java | 4 +- .../index/mapper/core/DoubleFieldMapper.java | 5 +- .../index/mapper/core/FloatFieldMapper.java | 5 +- .../index/mapper/core/IntegerFieldMapper.java | 4 +- .../index/mapper/core/LongFieldMapper.java | 4 +- .../index/mapper/core/NumberFieldMapper.java | 11 +--- .../index/mapper/core/ShortFieldMapper.java | 4 +- .../index/mapper/ip/IpFieldMapper.java | 5 +- .../index/query/FuzzyQueryBuilder.java | 65 ++++++++++++++++++- .../index/query/FuzzyQueryParser.java | 14 ++-- 12 files changed, 92 insertions(+), 46 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java b/core/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java index 02366a3f79e..152bdca7575 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java @@ -25,14 +25,7 @@ import org.apache.lucene.index.IndexOptions; import org.apache.lucene.index.Term; import org.apache.lucene.index.Terms; import org.apache.lucene.queries.TermsQuery; -import org.apache.lucene.search.ConstantScoreQuery; -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.search.*; import org.apache.lucene.util.BytesRef; import org.elasticsearch.action.fieldstats.FieldStats; import org.elasticsearch.common.Nullable; @@ -463,8 +456,8 @@ public abstract class MappedFieldType extends FieldType { includeLower, includeUpper); } - public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { - return new FuzzyQuery(createTerm(value), fuzziness.asDistance(value), prefixLength, maxExpansions, transpositions); + public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean 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) { diff --git a/core/src/main/java/org/elasticsearch/index/mapper/core/ByteFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/core/ByteFieldMapper.java index 197bac8843e..92944f7e8fd 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/core/ByteFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/core/ByteFieldMapper.java @@ -171,8 +171,8 @@ public class ByteFieldMapper extends NumberFieldMapper { } @Override - public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { - byte iValue = Byte.parseByte(value); + public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { + byte iValue = parseValue(value); byte iSim = fuzziness.asByte(); return NumericRangeQuery.newIntRange(names().indexName(), numericPrecisionStep(), iValue - iSim, diff --git a/core/src/main/java/org/elasticsearch/index/mapper/core/DateFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/core/DateFieldMapper.java index c02c7f34bc9..eccf9035a56 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/core/DateFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/core/DateFieldMapper.java @@ -395,8 +395,8 @@ public class DateFieldMapper extends NumberFieldMapper { } @Override - public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { - long iValue = dateMathParser().parse(value, now()); + public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { + long iValue = parseValue(value); long iSim; try { iSim = fuzziness.asTimeValue().millis(); diff --git a/core/src/main/java/org/elasticsearch/index/mapper/core/DoubleFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/core/DoubleFieldMapper.java index 49db4c984f3..49ea3c2e25a 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/core/DoubleFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/core/DoubleFieldMapper.java @@ -20,7 +20,6 @@ package org.elasticsearch.index.mapper.core; import com.carrotsearch.hppc.DoubleArrayList; - import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.document.Field; @@ -178,8 +177,8 @@ public class DoubleFieldMapper extends NumberFieldMapper { } @Override - public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { - double iValue = Double.parseDouble(value); + public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { + double iValue = parseDoubleValue(value); double iSim = fuzziness.asDouble(); return NumericRangeQuery.newDoubleRange(names().indexName(), numericPrecisionStep(), iValue - iSim, diff --git a/core/src/main/java/org/elasticsearch/index/mapper/core/FloatFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/core/FloatFieldMapper.java index 50b44582350..8012672c369 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/core/FloatFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/core/FloatFieldMapper.java @@ -20,7 +20,6 @@ package org.elasticsearch.index.mapper.core; import com.carrotsearch.hppc.FloatArrayList; - import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.document.Field; @@ -179,8 +178,8 @@ public class FloatFieldMapper extends NumberFieldMapper { } @Override - public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { - float iValue = Float.parseFloat(value); + public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { + float iValue = parseValue(value); final float iSim = fuzziness.asFloat(); return NumericRangeQuery.newFloatRange(names().indexName(), numericPrecisionStep(), iValue - iSim, diff --git a/core/src/main/java/org/elasticsearch/index/mapper/core/IntegerFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/core/IntegerFieldMapper.java index eb45f482a79..1271de9808b 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/core/IntegerFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/core/IntegerFieldMapper.java @@ -180,8 +180,8 @@ public class IntegerFieldMapper extends NumberFieldMapper { } @Override - public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { - int iValue = Integer.parseInt(value); + public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { + int iValue = parseValue(value); int iSim = fuzziness.asInt(); return NumericRangeQuery.newIntRange(names().indexName(), numericPrecisionStep(), iValue - iSim, diff --git a/core/src/main/java/org/elasticsearch/index/mapper/core/LongFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/core/LongFieldMapper.java index cc02f0fd1f0..9542b508a19 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/core/LongFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/core/LongFieldMapper.java @@ -178,8 +178,8 @@ public class LongFieldMapper extends NumberFieldMapper { } @Override - public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { - long iValue = Long.parseLong(value); + public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { + long iValue = parseLongValue(value); final long iSim = fuzziness.asLong(); return NumericRangeQuery.newLongRange(names().indexName(), numericPrecisionStep(), iValue - iSim, diff --git a/core/src/main/java/org/elasticsearch/index/mapper/core/NumberFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/core/NumberFieldMapper.java index 022ce75c092..78406c2afbc 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/core/NumberFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/core/NumberFieldMapper.java @@ -20,7 +20,6 @@ package org.elasticsearch.index.mapper.core; import com.carrotsearch.hppc.LongArrayList; - import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.NumericTokenStream; 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.xcontent.XContentBuilder; import org.elasticsearch.index.analysis.NamedAnalyzer; -import org.elasticsearch.index.mapper.FieldMapper; -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.*; import org.elasticsearch.index.mapper.internal.AllFieldMapper; import java.io.IOException; @@ -158,7 +151,7 @@ public abstract class NumberFieldMapper extends FieldMapper implements AllFieldM } @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 public boolean useTermQueryWithQueryString() { diff --git a/core/src/main/java/org/elasticsearch/index/mapper/core/ShortFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/core/ShortFieldMapper.java index 649ac2296dd..b40d570e69d 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/core/ShortFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/core/ShortFieldMapper.java @@ -176,8 +176,8 @@ public class ShortFieldMapper extends NumberFieldMapper { } @Override - public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { - short iValue = Short.parseShort(value); + public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { + short iValue = parseValue(value); short iSim = fuzziness.asShort(); return NumericRangeQuery.newIntRange(names().indexName(), numericPrecisionStep(), iValue - iSim, diff --git a/core/src/main/java/org/elasticsearch/index/mapper/ip/IpFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/ip/IpFieldMapper.java index 4cda12fb874..8e4e7c48783 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/ip/IpFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/ip/IpFieldMapper.java @@ -20,7 +20,6 @@ package org.elasticsearch.index.mapper.ip; import com.google.common.net.InetAddresses; - import org.apache.lucene.analysis.NumericTokenStream; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexOptions; @@ -218,8 +217,8 @@ public class IpFieldMapper extends NumberFieldMapper { } @Override - public Query fuzzyQuery(String value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { - long iValue = ipToLong(value); + public Query fuzzyQuery(Object value, Fuzziness fuzziness, int prefixLength, int maxExpansions, boolean transpositions) { + long iValue = parseValue(value); long iSim; try { iSim = ipToLong(fuzziness.asString()); diff --git a/core/src/main/java/org/elasticsearch/index/query/FuzzyQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/FuzzyQueryBuilder.java index ce17e66d361..23557b1a4cf 100644 --- a/core/src/main/java/org/elasticsearch/index/query/FuzzyQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/FuzzyQueryBuilder.java @@ -49,16 +49,77 @@ public class FuzzyQueryBuilder extends MultiTermQueryBuilder implements Boostabl private String queryName; /** - * Constructs a new term query. + * Constructs a new fuzzy query. * * @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) { this.name = name; 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 * weightings) have their score multiplied by the boost provided. diff --git a/core/src/main/java/org/elasticsearch/index/query/FuzzyQueryParser.java b/core/src/main/java/org/elasticsearch/index/query/FuzzyQueryParser.java index 26260f3621f..f2137a54dd1 100644 --- a/core/src/main/java/org/elasticsearch/index/query/FuzzyQueryParser.java +++ b/core/src/main/java/org/elasticsearch/index/query/FuzzyQueryParser.java @@ -25,6 +25,7 @@ import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.Query; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.lucene.BytesRefs; import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.mapper.MappedFieldType; @@ -61,7 +62,7 @@ public class FuzzyQueryParser implements QueryParser { } String fieldName = parser.currentName(); - String value = null; + Object value = null; float boost = 1.0f; Fuzziness fuzziness = DEFAULT_FUZZINESS; int prefixLength = FuzzyQuery.defaultPrefixLength; @@ -80,9 +81,9 @@ public class FuzzyQueryParser implements QueryParser { currentFieldName = parser.currentName(); } else { if ("term".equals(currentFieldName)) { - value = parser.text(); + value = parser.objectBytes(); } else if ("value".equals(currentFieldName)) { - value = parser.text(); + value = parser.objectBytes(); } else if ("boost".equals(currentFieldName)) { boost = parser.floatValue(); } else if (parseContext.parseFieldMatcher().match(currentFieldName, FUZZINESS)) { @@ -104,7 +105,7 @@ public class FuzzyQueryParser implements QueryParser { } parser.nextToken(); } else { - value = parser.text(); + value = parser.objectBytes(); // move to the next token parser.nextToken(); } @@ -112,14 +113,15 @@ public class FuzzyQueryParser implements QueryParser { if (value == null) { throw new QueryParsingException(parseContext, "No value specified for fuzzy query"); } - + Query query = null; MappedFieldType fieldType = parseContext.fieldMapper(fieldName); if (fieldType != null) { query = fieldType.fuzzyQuery(value, fuzziness, prefixLength, maxExpansions, transpositions); } 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) { QueryParsers.setRewriteMethod((MultiTermQuery) query, rewriteMethod);