LUCENE-7089, LUCENE-7075: add points to flexible queryparser to replace legacy numerics support

This commit is contained in:
Robert Muir 2016-03-09 21:05:26 -05:00
parent f24810bdf1
commit 89cc676f2b
22 changed files with 1148 additions and 121 deletions

View File

@ -52,14 +52,14 @@
* <li>FuzzyQueryNode - fuzzy node</li>
* <li>TermRangeQueryNode - used for parametric field:[low_value TO high_value]</li>
* <li>ProximityQueryNode - used for proximity search</li>
* <li>NumericRangeQueryNode - used for numeric range search</li>
* <li>LegacyNumericRangeQueryNode - used for numeric range search</li>
* <li>TokenizedPhraseQueryNode - used by tokenizers/lemmatizers/analyzers for phrases/autophrases</li>
* </ul>
* <p>
* Leaf Nodes:
* <ul>
* <li>FieldQueryNode - field/value node</li>
* <li>NumericQueryNode - used for numeric search</li>
* <li>LegacyNumericQueryNode - used for numeric search</li>
* <li>PathQueryNode - {@link org.apache.lucene.queryparser.flexible.core.nodes.QueryNode} object used with path-like queries</li>
* <li>OpaqueQueryNode - Used as for part of the query that can be parsed by other parsers. schema/value</li>
* <li>PrefixWildcardQueryNode - non-phrase wildcard query</li>

View File

@ -29,7 +29,8 @@ import org.apache.lucene.queryparser.flexible.core.QueryParserHelper;
import org.apache.lucene.queryparser.flexible.core.config.QueryConfigHandler;
import org.apache.lucene.queryparser.flexible.standard.builders.StandardQueryTreeBuilder;
import org.apache.lucene.queryparser.flexible.standard.config.FuzzyConfig;
import org.apache.lucene.queryparser.flexible.standard.config.NumericConfig;
import org.apache.lucene.queryparser.flexible.standard.config.LegacyNumericConfig;
import org.apache.lucene.queryparser.flexible.standard.config.PointsConfig;
import org.apache.lucene.queryparser.flexible.standard.config.StandardQueryConfigHandler;
import org.apache.lucene.queryparser.flexible.standard.config.StandardQueryConfigHandler.ConfigurationKeys;
import org.apache.lucene.queryparser.flexible.standard.config.StandardQueryConfigHandler.Operator;
@ -322,12 +323,30 @@ public class StandardQueryParser extends QueryParserHelper implements CommonQuer
}
public void setNumericConfigMap(Map<String,NumericConfig> numericConfigMap) {
getQueryConfigHandler().set(ConfigurationKeys.NUMERIC_CONFIG_MAP, numericConfigMap);
/**
* Sets field configuration for legacy numeric fields
* @deprecated Index with points instead and use {@link #setPointsConfigMap(Map)}
*/
@Deprecated
public void setLegacyNumericConfigMap(Map<String,LegacyNumericConfig> legacyNumericConfigMap) {
getQueryConfigHandler().set(ConfigurationKeys.LEGACY_NUMERIC_CONFIG_MAP, legacyNumericConfigMap);
}
public Map<String,NumericConfig> getNumericConfigMap() {
return getQueryConfigHandler().get(ConfigurationKeys.NUMERIC_CONFIG_MAP);
/**
* Gets field configuration for legacy numeric fields
* @deprecated Index with points instead and use {@link #getPointsConfigMap()}
*/
@Deprecated
public Map<String,LegacyNumericConfig> getLegacyNumericConfigMap() {
return getQueryConfigHandler().get(ConfigurationKeys.LEGACY_NUMERIC_CONFIG_MAP);
}
public void setPointsConfigMap(Map<String,PointsConfig> pointsConfigMap) {
getQueryConfigHandler().set(ConfigurationKeys.POINTS_CONFIG_MAP, pointsConfigMap);
}
public Map<String,PointsConfig> getPointsConfigMap() {
return getQueryConfigHandler().get(ConfigurationKeys.POINTS_CONFIG_MAP);
}
/**

View File

@ -22,38 +22,40 @@ import org.apache.lucene.queryparser.flexible.core.messages.QueryParserMessages;
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
import org.apache.lucene.queryparser.flexible.core.util.StringUtils;
import org.apache.lucene.queryparser.flexible.messages.MessageImpl;
import org.apache.lucene.queryparser.flexible.standard.config.NumericConfig;
import org.apache.lucene.queryparser.flexible.standard.nodes.NumericQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.NumericRangeQueryNode;
import org.apache.lucene.queryparser.flexible.standard.config.LegacyNumericConfig;
import org.apache.lucene.queryparser.flexible.standard.nodes.LegacyNumericQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.LegacyNumericRangeQueryNode;
import org.apache.lucene.search.LegacyNumericRangeQuery;
/**
* Builds {@link org.apache.lucene.search.LegacyNumericRangeQuery}s out of {@link NumericRangeQueryNode}s.
* Builds {@link org.apache.lucene.search.LegacyNumericRangeQuery}s out of {@link LegacyNumericRangeQueryNode}s.
*
* @see org.apache.lucene.search.LegacyNumericRangeQuery
* @see NumericRangeQueryNode
* @see LegacyNumericRangeQueryNode
* @deprecated Index with points and use {@link PointRangeQueryNodeBuilder} instead.
*/
public class NumericRangeQueryNodeBuilder implements StandardQueryBuilder {
@Deprecated
public class LegacyNumericRangeQueryNodeBuilder implements StandardQueryBuilder {
/**
* Constructs a {@link NumericRangeQueryNodeBuilder} object.
* Constructs a {@link LegacyNumericRangeQueryNodeBuilder} object.
*/
public NumericRangeQueryNodeBuilder() {
public LegacyNumericRangeQueryNodeBuilder() {
// empty constructor
}
@Override
public LegacyNumericRangeQuery<? extends Number> build(QueryNode queryNode)
throws QueryNodeException {
NumericRangeQueryNode numericRangeNode = (NumericRangeQueryNode) queryNode;
LegacyNumericRangeQueryNode numericRangeNode = (LegacyNumericRangeQueryNode) queryNode;
NumericQueryNode lowerNumericNode = numericRangeNode.getLowerBound();
NumericQueryNode upperNumericNode = numericRangeNode.getUpperBound();
LegacyNumericQueryNode lowerNumericNode = numericRangeNode.getLowerBound();
LegacyNumericQueryNode upperNumericNode = numericRangeNode.getUpperBound();
Number lowerNumber = lowerNumericNode.getValue();
Number upperNumber = upperNumericNode.getValue();
NumericConfig numericConfig = numericRangeNode.getNumericConfig();
LegacyNumericConfig numericConfig = numericRangeNode.getNumericConfig();
FieldType.LegacyNumericType numberType = numericConfig.getType();
String field = StringUtils.toString(numericRangeNode.getField());
boolean minInclusive = numericRangeNode.isLowerInclusive();

View File

@ -0,0 +1,137 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.queryparser.flexible.standard.builders;
import org.apache.lucene.document.DoublePoint;
import org.apache.lucene.document.FloatPoint;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.index.PointValues;
import org.apache.lucene.queryparser.flexible.core.QueryNodeException;
import org.apache.lucene.queryparser.flexible.core.messages.QueryParserMessages;
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
import org.apache.lucene.queryparser.flexible.core.util.StringUtils;
import org.apache.lucene.queryparser.flexible.messages.MessageImpl;
import org.apache.lucene.queryparser.flexible.standard.config.PointsConfig;
import org.apache.lucene.queryparser.flexible.standard.nodes.PointQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.PointRangeQueryNode;
import org.apache.lucene.search.Query;
/**
* Builds {@link PointValues} range queries out of {@link PointRangeQueryNode}s.
*
* @see PointRangeQueryNode
*/
public class PointRangeQueryNodeBuilder implements StandardQueryBuilder {
/**
* Constructs a {@link PointRangeQueryNodeBuilder} object.
*/
public PointRangeQueryNodeBuilder() {
// empty constructor
}
@Override
public Query build(QueryNode queryNode) throws QueryNodeException {
PointRangeQueryNode numericRangeNode = (PointRangeQueryNode) queryNode;
PointQueryNode lowerNumericNode = numericRangeNode.getLowerBound();
PointQueryNode upperNumericNode = numericRangeNode.getUpperBound();
Number lowerNumber = lowerNumericNode.getValue();
Number upperNumber = upperNumericNode.getValue();
PointsConfig pointsConfig = numericRangeNode.getPointsConfig();
Class<? extends Number> numberType = pointsConfig.getType();
String field = StringUtils.toString(numericRangeNode.getField());
boolean minInclusive = numericRangeNode.isLowerInclusive();
boolean maxInclusive = numericRangeNode.isUpperInclusive();
// TODO: push down cleaning up of crazy nulls and inclusive/exclusive elsewhere
if (Integer.class.equals(numberType)) {
Integer lower = (Integer) lowerNumber;
if (lower == null) {
lower = Integer.MIN_VALUE;
}
if (minInclusive == false) {
lower = lower + 1;
}
Integer upper = (Integer) upperNumber;
if (upper == null) {
upper = Integer.MAX_VALUE;
}
if (maxInclusive == false) {
upper = upper - 1;
}
return IntPoint.newRangeQuery(field, lower, upper);
} else if (Long.class.equals(numberType)) {
Long lower = (Long) lowerNumber;
if (lower == null) {
lower = Long.MIN_VALUE;
}
if (minInclusive == false) {
lower = lower + 1;
}
Long upper = (Long) upperNumber;
if (upper == null) {
upper = Long.MAX_VALUE;
}
if (maxInclusive == false) {
upper = upper - 1;
}
return LongPoint.newRangeQuery(field, lower, upper);
} else if (Float.class.equals(numberType)) {
Float lower = (Float) lowerNumber;
if (lower == null) {
lower = Float.NEGATIVE_INFINITY;
}
if (minInclusive == false) {
lower = Math.nextUp(lower);
}
Float upper = (Float) upperNumber;
if (upper == null) {
upper = Float.POSITIVE_INFINITY;
}
if (maxInclusive == false) {
upper = Math.nextDown(upper);
}
return FloatPoint.newRangeQuery(field, lower, upper);
} else if (Double.class.equals(numberType)) {
Double lower = (Double) lowerNumber;
if (lower == null) {
lower = Double.NEGATIVE_INFINITY;
}
if (minInclusive == false) {
lower = Math.nextUp(lower);
}
Double upper = (Double) upperNumber;
if (upper == null) {
upper = Double.POSITIVE_INFINITY;
}
if (maxInclusive == false) {
upper = Math.nextDown(upper);
}
return DoublePoint.newRangeQuery(field, lower, upper);
} else {
throw new QueryNodeException(new MessageImpl(QueryParserMessages.UNSUPPORTED_NUMERIC_DATA_TYPE, numberType));
}
}
}

View File

@ -30,8 +30,10 @@ import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.SlopQueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.TokenizedPhraseQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.MultiPhraseQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.NumericQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.NumericRangeQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.PointQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.PointRangeQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.LegacyNumericQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.LegacyNumericRangeQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.PrefixWildcardQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.TermRangeQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.RegexpQueryNode;
@ -57,8 +59,10 @@ public class StandardQueryTreeBuilder extends QueryTreeBuilder implements
setBuilder(FieldQueryNode.class, new FieldQueryNodeBuilder());
setBuilder(BooleanQueryNode.class, new BooleanQueryNodeBuilder());
setBuilder(FuzzyQueryNode.class, new FuzzyQueryNodeBuilder());
setBuilder(NumericQueryNode.class, new DummyQueryNodeBuilder());
setBuilder(NumericRangeQueryNode.class, new NumericRangeQueryNodeBuilder());
setBuilder(LegacyNumericQueryNode.class, new DummyQueryNodeBuilder());
setBuilder(LegacyNumericRangeQueryNode.class, new LegacyNumericRangeQueryNodeBuilder());
setBuilder(PointQueryNode.class, new DummyQueryNodeBuilder());
setBuilder(PointRangeQueryNode.class, new PointRangeQueryNodeBuilder());
setBuilder(BoostQueryNode.class, new BoostQueryNodeBuilder());
setBuilder(ModifierQueryNode.class, new ModifierQueryNodeBuilder());
setBuilder(WildcardQueryNode.class, new WildcardQueryNodeBuilder());

View File

@ -28,8 +28,10 @@ import org.apache.lucene.document.FieldType.LegacyNumericType;
*
* @see org.apache.lucene.search.LegacyNumericRangeQuery
* @see NumberFormat
* @deprecated Index with Points instead and use {@link PointsConfig}
*/
public class NumericConfig {
@Deprecated
public class LegacyNumericConfig {
private int precisionStep;
@ -38,7 +40,7 @@ public class NumericConfig {
private FieldType.LegacyNumericType type;
/**
* Constructs a {@link NumericConfig} object.
* Constructs a {@link LegacyNumericConfig} object.
*
* @param precisionStep
* the precision used to index the numeric values
@ -48,11 +50,11 @@ public class NumericConfig {
* @param type
* the numeric type used to index the numeric values
*
* @see NumericConfig#setPrecisionStep(int)
* @see NumericConfig#setNumberFormat(NumberFormat)
* @see LegacyNumericConfig#setPrecisionStep(int)
* @see LegacyNumericConfig#setNumberFormat(NumberFormat)
* @see #setType(org.apache.lucene.document.FieldType.LegacyNumericType)
*/
public NumericConfig(int precisionStep, NumberFormat format,
public LegacyNumericConfig(int precisionStep, NumberFormat format,
LegacyNumericType type) {
setPrecisionStep(precisionStep);
setNumberFormat(format);
@ -141,8 +143,8 @@ public class NumericConfig {
if (obj == this) return true;
if (obj instanceof NumericConfig) {
NumericConfig other = (NumericConfig) obj;
if (obj instanceof LegacyNumericConfig) {
LegacyNumericConfig other = (LegacyNumericConfig) obj;
if (this.precisionStep == other.precisionStep
&& this.type == other.type

View File

@ -25,25 +25,27 @@ import org.apache.lucene.queryparser.flexible.standard.config.StandardQueryConfi
/**
* This listener is used to listen to {@link FieldConfig} requests in
* {@link QueryConfigHandler} and add {@link ConfigurationKeys#NUMERIC_CONFIG}
* based on the {@link ConfigurationKeys#NUMERIC_CONFIG_MAP} set in the
* {@link QueryConfigHandler} and add {@link ConfigurationKeys#LEGACY_NUMERIC_CONFIG}
* based on the {@link ConfigurationKeys#LEGACY_NUMERIC_CONFIG_MAP} set in the
* {@link QueryConfigHandler}.
*
* @see NumericConfig
* @see LegacyNumericConfig
* @see QueryConfigHandler
* @see ConfigurationKeys#NUMERIC_CONFIG
* @see ConfigurationKeys#NUMERIC_CONFIG_MAP
* @see ConfigurationKeys#LEGACY_NUMERIC_CONFIG
* @see ConfigurationKeys#LEGACY_NUMERIC_CONFIG_MAP
* @deprecated Index with Points instead and use {@link PointsConfigListener}
*/
public class NumericFieldConfigListener implements FieldConfigListener {
@Deprecated
public class LegacyNumericFieldConfigListener implements FieldConfigListener {
final private QueryConfigHandler config;
/**
* Construcs a {@link NumericFieldConfigListener} object using the given {@link QueryConfigHandler}.
* Constructs a {@link LegacyNumericFieldConfigListener} object using the given {@link QueryConfigHandler}.
*
* @param config the {@link QueryConfigHandler} it will listen too
*/
public NumericFieldConfigListener(QueryConfigHandler config) {
public LegacyNumericFieldConfigListener(QueryConfigHandler config) {
if (config == null) {
throw new IllegalArgumentException("config cannot be null!");
@ -55,15 +57,15 @@ public class NumericFieldConfigListener implements FieldConfigListener {
@Override
public void buildFieldConfig(FieldConfig fieldConfig) {
Map<String,NumericConfig> numericConfigMap = config
.get(ConfigurationKeys.NUMERIC_CONFIG_MAP);
Map<String,LegacyNumericConfig> numericConfigMap = config
.get(ConfigurationKeys.LEGACY_NUMERIC_CONFIG_MAP);
if (numericConfigMap != null) {
NumericConfig numericConfig = numericConfigMap
LegacyNumericConfig numericConfig = numericConfigMap
.get(fieldConfig.getField());
if (numericConfig != null) {
fieldConfig.set(ConfigurationKeys.NUMERIC_CONFIG, numericConfig);
fieldConfig.set(ConfigurationKeys.LEGACY_NUMERIC_CONFIG, numericConfig);
}
}

View File

@ -0,0 +1,124 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.queryparser.flexible.standard.config;
import java.text.NumberFormat;
import org.apache.lucene.index.PointValues;
/**
* This class holds the configuration used to parse numeric queries and create
* {@link PointValues} queries.
*
* @see PointValues
* @see NumberFormat
*/
public class PointsConfig {
private NumberFormat format;
private Class<? extends Number> type;
/**
* Constructs a {@link PointsConfig} object.
*
* @param format
* the {@link NumberFormat} used to parse a {@link String} to
* {@link Number}
* @param type
* the numeric type used to index the numeric values
*
* @see PointsConfig#setNumberFormat(NumberFormat)
*/
public PointsConfig(NumberFormat format, Class<? extends Number> type) {
setNumberFormat(format);
setType(type);
}
/**
* Returns the {@link NumberFormat} used to parse a {@link String} to
* {@link Number}
*
* @return the {@link NumberFormat} used to parse a {@link String} to
* {@link Number}
*/
public NumberFormat getNumberFormat() {
return format;
}
/**
* Returns the numeric type used to index the numeric values
*
* @return the numeric type used to index the numeric values
*/
public Class<? extends Number> getType() {
return type;
}
/**
* Sets the numeric type used to index the numeric values
*
* @param type the numeric type used to index the numeric values
*/
public void setType(Class<? extends Number> type) {
if (type == null) {
throw new IllegalArgumentException("type cannot be null!");
}
if (Integer.class.equals(type) == false &&
Long.class.equals(type) == false &&
Float.class.equals(type) == false &&
Double.class.equals(type) == false) {
throw new IllegalArgumentException("unsupported numeric type: " + type);
}
this.type = type;
}
/**
* Sets the {@link NumberFormat} used to parse a {@link String} to
* {@link Number}
*
* @param format
* the {@link NumberFormat} used to parse a {@link String} to
* {@link Number}, cannot be <code>null</code>
*/
public void setNumberFormat(NumberFormat format) {
if (format == null) {
throw new IllegalArgumentException("format cannot be null!");
}
this.format = format;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + format.hashCode();
result = prime * result + type.hashCode();
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
PointsConfig other = (PointsConfig) obj;
if (!format.equals(other.format)) return false;
if (!type.equals(other.type)) return false;
return true;
}
}

View File

@ -0,0 +1,65 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.queryparser.flexible.standard.config;
import java.util.Map;
import org.apache.lucene.queryparser.flexible.core.config.FieldConfig;
import org.apache.lucene.queryparser.flexible.core.config.FieldConfigListener;
import org.apache.lucene.queryparser.flexible.core.config.QueryConfigHandler;
import org.apache.lucene.queryparser.flexible.standard.config.StandardQueryConfigHandler.ConfigurationKeys;
/**
* This listener is used to listen to {@link FieldConfig} requests in
* {@link QueryConfigHandler} and add {@link ConfigurationKeys#POINTS_CONFIG}
* based on the {@link ConfigurationKeys#POINTS_CONFIG_MAP} set in the
* {@link QueryConfigHandler}.
*
* @see PointsConfig
* @see QueryConfigHandler
* @see ConfigurationKeys#POINTS_CONFIG
* @see ConfigurationKeys#POINTS_CONFIG_MAP
*/
public class PointsConfigListener implements FieldConfigListener {
final private QueryConfigHandler config;
/**
* Constructs a {@link PointsConfigListener} object using the given {@link QueryConfigHandler}.
*
* @param config the {@link QueryConfigHandler} it will listen too
*/
public PointsConfigListener(QueryConfigHandler config) {
if (config == null) {
throw new IllegalArgumentException("config cannot be null!");
}
this.config = config;
}
@Override
public void buildFieldConfig(FieldConfig fieldConfig) {
Map<String,PointsConfig> pointsConfigMap = config.get(ConfigurationKeys.POINTS_CONFIG_MAP);
if (pointsConfigMap != null) {
PointsConfig pointsConfig = pointsConfigMap.get(fieldConfig.getField());
if (pointsConfig != null) {
fieldConfig.set(ConfigurationKeys.POINTS_CONFIG, pointsConfig);
}
}
}
}

View File

@ -167,21 +167,41 @@ public class StandardQueryConfigHandler extends QueryConfigHandler {
final public static ConfigurationKey<Float> BOOST = ConfigurationKey.newInstance();
/**
* Key used to set a field to its {@link NumericConfig}.
* Key used to set a field to its {@link LegacyNumericConfig}.
*
* @see StandardQueryParser#setNumericConfigMap(Map)
* @see StandardQueryParser#getNumericConfigMap()
* @see StandardQueryParser#setLegacyNumericConfigMap(Map)
* @see StandardQueryParser#getLegacyNumericConfigMap()
* @deprecated Index with Points instead and use {@link #POINTS_CONFIG}
*/
final public static ConfigurationKey<NumericConfig> NUMERIC_CONFIG = ConfigurationKey.newInstance();
@Deprecated
final public static ConfigurationKey<LegacyNumericConfig> LEGACY_NUMERIC_CONFIG = ConfigurationKey.newInstance();
/**
* Key used to set the {@link NumericConfig} in {@link FieldConfig} for numeric fields.
* Key used to set the {@link LegacyNumericConfig} in {@link FieldConfig} for numeric fields.
*
* @see StandardQueryParser#setNumericConfigMap(Map)
* @see StandardQueryParser#getNumericConfigMap()
* @see StandardQueryParser#setLegacyNumericConfigMap(Map)
* @see StandardQueryParser#getLegacyNumericConfigMap()
* @deprecated Index with Points instead and use {@link #POINTS_CONFIG_MAP}
*/
final public static ConfigurationKey<Map<String,NumericConfig>> NUMERIC_CONFIG_MAP = ConfigurationKey.newInstance();
@Deprecated
final public static ConfigurationKey<Map<String,LegacyNumericConfig>> LEGACY_NUMERIC_CONFIG_MAP = ConfigurationKey.newInstance();
/**
* Key used to set a field to its {@link PointsConfig}.
*
* @see StandardQueryParser#setLegacyNumericConfigMap(Map)
* @see StandardQueryParser#getLegacyNumericConfigMap()
*/
final public static ConfigurationKey<PointsConfig> POINTS_CONFIG = ConfigurationKey.newInstance();
/**
* Key used to set the {@link PointsConfig} in {@link FieldConfig} for point fields.
*
* @see StandardQueryParser#setLegacyNumericConfigMap(Map)
* @see StandardQueryParser#getLegacyNumericConfigMap()
*/
final public static ConfigurationKey<Map<String,PointsConfig>> POINTS_CONFIG_MAP = ConfigurationKey.newInstance();
}
/**
@ -195,7 +215,8 @@ public class StandardQueryConfigHandler extends QueryConfigHandler {
// Add listener that will build the FieldConfig.
addFieldConfigListener(new FieldBoostMapFCListener(this));
addFieldConfigListener(new FieldDateResolutionFCListener(this));
addFieldConfigListener(new NumericFieldConfigListener(this));
addFieldConfigListener(new LegacyNumericFieldConfigListener(this));
addFieldConfigListener(new PointsConfigListener(this));
// Default Values
set(ConfigurationKeys.ALLOW_LEADING_WILDCARD, false); // default in 2.9

View File

@ -0,0 +1,153 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.queryparser.flexible.standard.nodes;
import java.text.NumberFormat;
import java.util.Locale;
import org.apache.lucene.queryparser.flexible.core.nodes.FieldQueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.FieldValuePairQueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNodeImpl;
import org.apache.lucene.queryparser.flexible.core.parser.EscapeQuerySyntax;
import org.apache.lucene.queryparser.flexible.core.parser.EscapeQuerySyntax.Type;
import org.apache.lucene.queryparser.flexible.standard.config.LegacyNumericConfig;
/**
* This query node represents a field query that holds a numeric value. It is
* similar to {@link FieldQueryNode}, however the {@link #getValue()} returns a
* {@link Number}.
*
* @see LegacyNumericConfig
* @deprecated Index with Points instead and use {@link PointQueryNode} instead.
*/
@Deprecated
public class LegacyNumericQueryNode extends QueryNodeImpl implements
FieldValuePairQueryNode<Number> {
private NumberFormat numberFormat;
private CharSequence field;
private Number value;
/**
* Creates a {@link LegacyNumericQueryNode} object using the given field,
* {@link Number} value and {@link NumberFormat} used to convert the value to
* {@link String}.
*
* @param field the field associated with this query node
* @param value the value hold by this node
* @param numberFormat the {@link NumberFormat} used to convert the value to {@link String}
*/
public LegacyNumericQueryNode(CharSequence field, Number value,
NumberFormat numberFormat) {
super();
setNumberFormat(numberFormat);
setField(field);
setValue(value);
}
/**
* Returns the field associated with this node.
*
* @return the field associated with this node
*/
@Override
public CharSequence getField() {
return this.field;
}
/**
* Sets the field associated with this node.
*
* @param fieldName the field associated with this node
*/
@Override
public void setField(CharSequence fieldName) {
this.field = fieldName;
}
/**
* This method is used to get the value converted to {@link String} and
* escaped using the given {@link EscapeQuerySyntax}.
*
* @param escaper the {@link EscapeQuerySyntax} used to escape the value {@link String}
*
* @return the value converte to {@link String} and escaped
*/
protected CharSequence getTermEscaped(EscapeQuerySyntax escaper) {
return escaper.escape(numberFormat.format(this.value),
Locale.ROOT, Type.NORMAL);
}
@Override
public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) {
if (isDefaultField(this.field)) {
return getTermEscaped(escapeSyntaxParser);
} else {
return this.field + ":" + getTermEscaped(escapeSyntaxParser);
}
}
/**
* Sets the {@link NumberFormat} used to convert the value to {@link String}.
*
* @param format the {@link NumberFormat} used to convert the value to {@link String}
*/
public void setNumberFormat(NumberFormat format) {
this.numberFormat = format;
}
/**
* Returns the {@link NumberFormat} used to convert the value to {@link String}.
*
* @return the {@link NumberFormat} used to convert the value to {@link String}
*/
public NumberFormat getNumberFormat() {
return this.numberFormat;
}
/**
* Returns the numeric value as {@link Number}.
*
* @return the numeric value
*/
@Override
public Number getValue() {
return value;
}
/**
* Sets the numeric value.
*
* @param value the numeric value
*/
@Override
public void setValue(Number value) {
this.value = value;
}
@Override
public String toString() {
return "<numeric field='" + this.field + "' number='"
+ numberFormat.format(value) + "'/>";
}
}

View File

@ -21,34 +21,36 @@ import org.apache.lucene.document.FieldType.LegacyNumericType;
import org.apache.lucene.queryparser.flexible.core.QueryNodeException;
import org.apache.lucene.queryparser.flexible.core.messages.QueryParserMessages;
import org.apache.lucene.queryparser.flexible.messages.MessageImpl;
import org.apache.lucene.queryparser.flexible.standard.config.NumericConfig;
import org.apache.lucene.queryparser.flexible.standard.config.LegacyNumericConfig;
/**
* This query node represents a range query composed by {@link NumericQueryNode}
* This query node represents a range query composed by {@link LegacyNumericQueryNode}
* bounds, which means the bound values are {@link Number}s.
*
* @see NumericQueryNode
* @see LegacyNumericQueryNode
* @see AbstractRangeQueryNode
* @deprecated Index with Points instead and use {@link PointRangeQueryNode} instead.
*/
public class NumericRangeQueryNode extends
AbstractRangeQueryNode<NumericQueryNode> {
@Deprecated
public class LegacyNumericRangeQueryNode extends
AbstractRangeQueryNode<LegacyNumericQueryNode> {
public NumericConfig numericConfig;
public LegacyNumericConfig numericConfig;
/**
* Constructs a {@link NumericRangeQueryNode} object using the given
* {@link NumericQueryNode} as its bounds and {@link NumericConfig}.
* Constructs a {@link LegacyNumericRangeQueryNode} object using the given
* {@link LegacyNumericQueryNode} as its bounds and {@link LegacyNumericConfig}.
*
* @param lower the lower bound
* @param upper the upper bound
* @param lowerInclusive <code>true</code> if the lower bound is inclusive, otherwise, <code>false</code>
* @param upperInclusive <code>true</code> if the upper bound is inclusive, otherwise, <code>false</code>
* @param numericConfig the {@link NumericConfig} that represents associated with the upper and lower bounds
* @param numericConfig the {@link LegacyNumericConfig} that represents associated with the upper and lower bounds
*
* @see #setBounds(NumericQueryNode, NumericQueryNode, boolean, boolean, NumericConfig)
* @see #setBounds(LegacyNumericQueryNode, LegacyNumericQueryNode, boolean, boolean, LegacyNumericConfig)
*/
public NumericRangeQueryNode(NumericQueryNode lower, NumericQueryNode upper,
boolean lowerInclusive, boolean upperInclusive, NumericConfig numericConfig) throws QueryNodeException {
public LegacyNumericRangeQueryNode(LegacyNumericQueryNode lower, LegacyNumericQueryNode upper,
boolean lowerInclusive, boolean upperInclusive, LegacyNumericConfig numericConfig) throws QueryNodeException {
setBounds(lower, upper, lowerInclusive, upperInclusive, numericConfig);
}
@ -73,17 +75,17 @@ public class NumericRangeQueryNode extends
/**
* Sets the upper and lower bounds of this range query node and the
* {@link NumericConfig} associated with these bounds.
* {@link LegacyNumericConfig} associated with these bounds.
*
* @param lower the lower bound
* @param upper the upper bound
* @param lowerInclusive <code>true</code> if the lower bound is inclusive, otherwise, <code>false</code>
* @param upperInclusive <code>true</code> if the upper bound is inclusive, otherwise, <code>false</code>
* @param numericConfig the {@link NumericConfig} that represents associated with the upper and lower bounds
* @param numericConfig the {@link LegacyNumericConfig} that represents associated with the upper and lower bounds
*
*/
public void setBounds(NumericQueryNode lower, NumericQueryNode upper,
boolean lowerInclusive, boolean upperInclusive, NumericConfig numericConfig) throws QueryNodeException {
public void setBounds(LegacyNumericQueryNode lower, LegacyNumericQueryNode upper,
boolean lowerInclusive, boolean upperInclusive, LegacyNumericConfig numericConfig) throws QueryNodeException {
if (numericConfig == null) {
throw new IllegalArgumentException("numericConfig cannot be null!");
@ -123,11 +125,11 @@ public class NumericRangeQueryNode extends
}
/**
* Returns the {@link NumericConfig} associated with the lower and upper bounds.
* Returns the {@link LegacyNumericConfig} associated with the lower and upper bounds.
*
* @return the {@link NumericConfig} associated with the lower and upper bounds
* @return the {@link LegacyNumericConfig} associated with the lower and upper bounds
*/
public NumericConfig getNumericConfig() {
public LegacyNumericConfig getNumericConfig() {
return this.numericConfig;
}

View File

@ -24,16 +24,16 @@ import org.apache.lucene.queryparser.flexible.core.nodes.FieldValuePairQueryNode
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNodeImpl;
import org.apache.lucene.queryparser.flexible.core.parser.EscapeQuerySyntax;
import org.apache.lucene.queryparser.flexible.core.parser.EscapeQuerySyntax.Type;
import org.apache.lucene.queryparser.flexible.standard.config.NumericConfig;
import org.apache.lucene.queryparser.flexible.standard.config.PointsConfig;
/**
* This query node represents a field query that holds a numeric value. It is
* This query node represents a field query that holds a point value. It is
* similar to {@link FieldQueryNode}, however the {@link #getValue()} returns a
* {@link Number}.
*
* @see NumericConfig
* @see PointsConfig
*/
public class NumericQueryNode extends QueryNodeImpl implements
public class PointQueryNode extends QueryNodeImpl implements
FieldValuePairQueryNode<Number> {
private NumberFormat numberFormat;
@ -43,7 +43,7 @@ public class NumericQueryNode extends QueryNodeImpl implements
private Number value;
/**
* Creates a {@link NumericQueryNode} object using the given field,
* Creates a {@link PointQueryNode} object using the given field,
* {@link Number} value and {@link NumberFormat} used to convert the value to
* {@link String}.
*
@ -51,7 +51,7 @@ public class NumericQueryNode extends QueryNodeImpl implements
* @param value the value hold by this node
* @param numberFormat the {@link NumberFormat} used to convert the value to {@link String}
*/
public NumericQueryNode(CharSequence field, Number value,
public PointQueryNode(CharSequence field, Number value,
NumberFormat numberFormat) {
super();

View File

@ -0,0 +1,124 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.queryparser.flexible.standard.nodes;
import org.apache.lucene.queryparser.flexible.core.QueryNodeException;
import org.apache.lucene.queryparser.flexible.standard.config.PointsConfig;
/**
* This query node represents a range query composed by {@link PointQueryNode}
* bounds, which means the bound values are {@link Number}s.
*
* @see PointQueryNode
* @see AbstractRangeQueryNode
*/
public class PointRangeQueryNode extends AbstractRangeQueryNode<PointQueryNode> {
public PointsConfig numericConfig;
/**
* Constructs a {@link PointRangeQueryNode} object using the given
* {@link PointQueryNode} as its bounds and {@link PointsConfig}.
*
* @param lower the lower bound
* @param upper the upper bound
* @param lowerInclusive <code>true</code> if the lower bound is inclusive, otherwise, <code>false</code>
* @param upperInclusive <code>true</code> if the upper bound is inclusive, otherwise, <code>false</code>
* @param numericConfig the {@link PointsConfig} that represents associated with the upper and lower bounds
*
* @see #setBounds(PointQueryNode, PointQueryNode, boolean, boolean, PointsConfig)
*/
public PointRangeQueryNode(PointQueryNode lower, PointQueryNode upper,
boolean lowerInclusive, boolean upperInclusive, PointsConfig numericConfig) throws QueryNodeException {
setBounds(lower, upper, lowerInclusive, upperInclusive, numericConfig);
}
/**
* Sets the upper and lower bounds of this range query node and the
* {@link PointsConfig} associated with these bounds.
*
* @param lower the lower bound
* @param upper the upper bound
* @param lowerInclusive <code>true</code> if the lower bound is inclusive, otherwise, <code>false</code>
* @param upperInclusive <code>true</code> if the upper bound is inclusive, otherwise, <code>false</code>
* @param pointsConfig the {@link PointsConfig} that represents associated with the upper and lower bounds
*
*/
public void setBounds(PointQueryNode lower, PointQueryNode upper,
boolean lowerInclusive, boolean upperInclusive, PointsConfig pointsConfig) throws QueryNodeException {
if (pointsConfig == null) {
throw new IllegalArgumentException("pointsConfig cannot be null!");
}
Class<? extends Number> lowerNumberType, upperNumberType;
if (lower != null && lower.getValue() != null) {
lowerNumberType = lower.getValue().getClass();
} else {
lowerNumberType = null;
}
if (upper != null && upper.getValue() != null) {
upperNumberType = upper.getValue().getClass();
} else {
upperNumberType = null;
}
if (lowerNumberType != null
&& !lowerNumberType.equals(pointsConfig.getType())) {
throw new IllegalArgumentException(
"lower value's type should be the same as numericConfig type: "
+ lowerNumberType + " != " + pointsConfig.getType());
}
if (upperNumberType != null
&& !upperNumberType.equals(pointsConfig.getType())) {
throw new IllegalArgumentException(
"upper value's type should be the same as numericConfig type: "
+ upperNumberType + " != " + pointsConfig.getType());
}
super.setBounds(lower, upper, lowerInclusive, upperInclusive);
this.numericConfig = pointsConfig;
}
/**
* Returns the {@link PointsConfig} associated with the lower and upper bounds.
*
* @return the {@link PointsConfig} associated with the lower and upper bounds
*/
public PointsConfig getPointsConfig() {
return this.numericConfig;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("<pointRange lowerInclusive='");
sb.append(isLowerInclusive());
sb.append("' upperInclusive='");
sb.append(isUpperInclusive());
sb.append("' type='");
sb.append(numericConfig.getType().getSimpleName());
sb.append("'>\n");
sb.append(getLowerBound()).append('\n');
sb.append(getUpperBound()).append('\n');
sb.append("</pointRange>");
return sb.toString();
}
}

View File

@ -30,19 +30,19 @@ import org.apache.lucene.queryparser.flexible.core.nodes.FieldQueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.RangeQueryNode;
import org.apache.lucene.queryparser.flexible.core.processors.QueryNodeProcessorImpl;
import org.apache.lucene.queryparser.flexible.standard.config.NumericConfig;
import org.apache.lucene.queryparser.flexible.standard.config.LegacyNumericConfig;
import org.apache.lucene.queryparser.flexible.standard.config.StandardQueryConfigHandler.ConfigurationKeys;
import org.apache.lucene.queryparser.flexible.standard.nodes.NumericQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.NumericRangeQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.LegacyNumericQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.LegacyNumericRangeQueryNode;
/**
* This processor is used to convert {@link FieldQueryNode}s to
* {@link NumericRangeQueryNode}s. It looks for
* {@link ConfigurationKeys#NUMERIC_CONFIG} set in the {@link FieldConfig} of
* {@link LegacyNumericRangeQueryNode}s. It looks for
* {@link ConfigurationKeys#LEGACY_NUMERIC_CONFIG} set in the {@link FieldConfig} of
* every {@link FieldQueryNode} found. If
* {@link ConfigurationKeys#NUMERIC_CONFIG} is found, it considers that
* {@link ConfigurationKeys#LEGACY_NUMERIC_CONFIG} is found, it considers that
* {@link FieldQueryNode} to be a numeric query and convert it to
* {@link NumericRangeQueryNode} with upper and lower inclusive and lower and
* {@link LegacyNumericRangeQueryNode} with upper and lower inclusive and lower and
* upper equals to the value represented by the {@link FieldQueryNode} converted
* to {@link Number}. It means that <b>field:1</b> is converted to <b>field:[1
* TO 1]</b>. <br>
@ -50,17 +50,19 @@ import org.apache.lucene.queryparser.flexible.standard.nodes.NumericRangeQueryNo
* Note that {@link FieldQueryNode}s children of a
* {@link RangeQueryNode} are ignored.
*
* @see ConfigurationKeys#NUMERIC_CONFIG
* @see ConfigurationKeys#LEGACY_NUMERIC_CONFIG
* @see FieldQueryNode
* @see NumericConfig
* @see NumericQueryNode
* @see LegacyNumericConfig
* @see LegacyNumericQueryNode
* @deprecated Index with points and use {@link PointQueryNodeProcessor} instead.
*/
public class NumericQueryNodeProcessor extends QueryNodeProcessorImpl {
@Deprecated
public class LegacyNumericQueryNodeProcessor extends QueryNodeProcessorImpl {
/**
* Constructs a {@link NumericQueryNodeProcessor} object.
* Constructs a {@link LegacyNumericQueryNodeProcessor} object.
*/
public NumericQueryNodeProcessor() {
public LegacyNumericQueryNodeProcessor() {
// empty constructor
}
@ -78,8 +80,8 @@ public class NumericQueryNodeProcessor extends QueryNodeProcessorImpl {
.getFieldAsString());
if (fieldConfig != null) {
NumericConfig numericConfig = fieldConfig
.get(ConfigurationKeys.NUMERIC_CONFIG);
LegacyNumericConfig numericConfig = fieldConfig
.get(ConfigurationKeys.LEGACY_NUMERIC_CONFIG);
if (numericConfig != null) {
@ -118,12 +120,12 @@ public class NumericQueryNodeProcessor extends QueryNodeProcessorImpl {
QueryParserMessages.NUMERIC_CANNOT_BE_EMPTY, fieldNode.getFieldAsString()));
}
NumericQueryNode lowerNode = new NumericQueryNode(fieldNode
LegacyNumericQueryNode lowerNode = new LegacyNumericQueryNode(fieldNode
.getField(), number, numberFormat);
NumericQueryNode upperNode = new NumericQueryNode(fieldNode
LegacyNumericQueryNode upperNode = new LegacyNumericQueryNode(fieldNode
.getField(), number, numberFormat);
return new NumericRangeQueryNode(lowerNode, upperNode, true, true,
return new LegacyNumericRangeQueryNode(lowerNode, upperNode, true, true,
numericConfig);
}

View File

@ -30,32 +30,34 @@ import org.apache.lucene.queryparser.flexible.core.nodes.FieldQueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
import org.apache.lucene.queryparser.flexible.core.processors.QueryNodeProcessorImpl;
import org.apache.lucene.queryparser.flexible.core.util.StringUtils;
import org.apache.lucene.queryparser.flexible.standard.config.NumericConfig;
import org.apache.lucene.queryparser.flexible.standard.config.LegacyNumericConfig;
import org.apache.lucene.queryparser.flexible.standard.config.StandardQueryConfigHandler.ConfigurationKeys;
import org.apache.lucene.queryparser.flexible.standard.nodes.NumericQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.NumericRangeQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.LegacyNumericQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.LegacyNumericRangeQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.TermRangeQueryNode;
/**
* This processor is used to convert {@link TermRangeQueryNode}s to
* {@link NumericRangeQueryNode}s. It looks for
* {@link ConfigurationKeys#NUMERIC_CONFIG} set in the {@link FieldConfig} of
* {@link LegacyNumericRangeQueryNode}s. It looks for
* {@link ConfigurationKeys#LEGACY_NUMERIC_CONFIG} set in the {@link FieldConfig} of
* every {@link TermRangeQueryNode} found. If
* {@link ConfigurationKeys#NUMERIC_CONFIG} is found, it considers that
* {@link ConfigurationKeys#LEGACY_NUMERIC_CONFIG} is found, it considers that
* {@link TermRangeQueryNode} to be a numeric range query and convert it to
* {@link NumericRangeQueryNode}.
* {@link LegacyNumericRangeQueryNode}.
*
* @see ConfigurationKeys#NUMERIC_CONFIG
* @see ConfigurationKeys#LEGACY_NUMERIC_CONFIG
* @see TermRangeQueryNode
* @see NumericConfig
* @see NumericRangeQueryNode
* @see LegacyNumericConfig
* @see LegacyNumericRangeQueryNode
* @deprecated Index with points and use {@link PointRangeQueryNodeProcessor} instead.
*/
public class NumericRangeQueryNodeProcessor extends QueryNodeProcessorImpl {
@Deprecated
public class LegacyNumericRangeQueryNodeProcessor extends QueryNodeProcessorImpl {
/**
* Constructs an empty {@link NumericRangeQueryNode} object.
* Constructs an empty {@link LegacyNumericRangeQueryNode} object.
*/
public NumericRangeQueryNodeProcessor() {
public LegacyNumericRangeQueryNodeProcessor() {
// empty constructor
}
@ -72,8 +74,8 @@ public class NumericRangeQueryNodeProcessor extends QueryNodeProcessorImpl {
if (fieldConfig != null) {
NumericConfig numericConfig = fieldConfig
.get(ConfigurationKeys.NUMERIC_CONFIG);
LegacyNumericConfig numericConfig = fieldConfig
.get(ConfigurationKeys.LEGACY_NUMERIC_CONFIG);
if (numericConfig != null) {
@ -131,15 +133,15 @@ public class NumericRangeQueryNodeProcessor extends QueryNodeProcessorImpl {
if (lowerNumber != null) lowerNumber = lowerNumber.floatValue();
}
NumericQueryNode lowerNode = new NumericQueryNode(
LegacyNumericQueryNode lowerNode = new LegacyNumericQueryNode(
termRangeNode.getField(), lowerNumber, numberFormat);
NumericQueryNode upperNode = new NumericQueryNode(
LegacyNumericQueryNode upperNode = new LegacyNumericQueryNode(
termRangeNode.getField(), upperNumber, numberFormat);
boolean lowerInclusive = termRangeNode.isLowerInclusive();
boolean upperInclusive = termRangeNode.isUpperInclusive();
return new NumericRangeQueryNode(lowerNode, upperNode,
return new LegacyNumericRangeQueryNode(lowerNode, upperNode,
lowerInclusive, upperInclusive, numericConfig);
}

View File

@ -0,0 +1,136 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.queryparser.flexible.standard.processors;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.List;
import org.apache.lucene.queryparser.flexible.messages.MessageImpl;
import org.apache.lucene.queryparser.flexible.core.QueryNodeException;
import org.apache.lucene.queryparser.flexible.core.QueryNodeParseException;
import org.apache.lucene.queryparser.flexible.core.config.FieldConfig;
import org.apache.lucene.queryparser.flexible.core.config.QueryConfigHandler;
import org.apache.lucene.queryparser.flexible.core.messages.QueryParserMessages;
import org.apache.lucene.queryparser.flexible.core.nodes.FieldQueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.RangeQueryNode;
import org.apache.lucene.queryparser.flexible.core.processors.QueryNodeProcessorImpl;
import org.apache.lucene.queryparser.flexible.standard.config.PointsConfig;
import org.apache.lucene.queryparser.flexible.standard.config.StandardQueryConfigHandler.ConfigurationKeys;
import org.apache.lucene.queryparser.flexible.standard.nodes.PointQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.PointRangeQueryNode;
/**
* This processor is used to convert {@link FieldQueryNode}s to
* {@link PointRangeQueryNode}s. It looks for
* {@link ConfigurationKeys#POINTS_CONFIG} set in the {@link FieldConfig} of
* every {@link FieldQueryNode} found. If
* {@link ConfigurationKeys#POINTS_CONFIG} is found, it considers that
* {@link FieldQueryNode} to be a numeric query and convert it to
* {@link PointRangeQueryNode} with upper and lower inclusive and lower and
* upper equals to the value represented by the {@link FieldQueryNode} converted
* to {@link Number}. It means that <b>field:1</b> is converted to <b>field:[1
* TO 1]</b>. <br>
* <br>
* Note that {@link FieldQueryNode}s children of a
* {@link RangeQueryNode} are ignored.
*
* @see ConfigurationKeys#POINTS_CONFIG
* @see FieldQueryNode
* @see PointsConfig
* @see PointQueryNode
*/
public class PointQueryNodeProcessor extends QueryNodeProcessorImpl {
/**
* Constructs a {@link PointQueryNodeProcessor} object.
*/
public PointQueryNodeProcessor() {
// empty constructor
}
@Override
protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException {
if (node instanceof FieldQueryNode
&& !(node.getParent() instanceof RangeQueryNode)) {
QueryConfigHandler config = getQueryConfigHandler();
if (config != null) {
FieldQueryNode fieldNode = (FieldQueryNode) node;
FieldConfig fieldConfig = config.getFieldConfig(fieldNode
.getFieldAsString());
if (fieldConfig != null) {
PointsConfig numericConfig = fieldConfig.get(ConfigurationKeys.POINTS_CONFIG);
if (numericConfig != null) {
NumberFormat numberFormat = numericConfig.getNumberFormat();
String text = fieldNode.getTextAsString();
Number number = null;
if (text.length() > 0) {
try {
number = numberFormat.parse(text);
} catch (ParseException e) {
throw new QueryNodeParseException(new MessageImpl(
QueryParserMessages.COULD_NOT_PARSE_NUMBER, fieldNode
.getTextAsString(), numberFormat.getClass()
.getCanonicalName()), e);
}
if (Integer.class.equals(numericConfig.getType())) {
number = number.intValue();
} else if (Long.class.equals(numericConfig.getType())) {
number = number.longValue();
} else if (Double.class.equals(numericConfig.getType())) {
number = number.doubleValue();
} else if (Float.class.equals(numericConfig.getType())) {
number = number.floatValue();
}
} else {
throw new QueryNodeParseException(new MessageImpl(
QueryParserMessages.NUMERIC_CANNOT_BE_EMPTY, fieldNode.getFieldAsString()));
}
PointQueryNode lowerNode = new PointQueryNode(fieldNode.getField(), number, numberFormat);
PointQueryNode upperNode = new PointQueryNode(fieldNode.getField(), number, numberFormat);
return new PointRangeQueryNode(lowerNode, upperNode, true, true, numericConfig);
}
}
}
}
return node;
}
@Override
protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException {
return node;
}
@Override
protected List<QueryNode> setChildrenOrder(List<QueryNode> children) throws QueryNodeException {
return children;
}
}

View File

@ -0,0 +1,148 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.queryparser.flexible.standard.processors;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.List;
import org.apache.lucene.queryparser.flexible.messages.MessageImpl;
import org.apache.lucene.queryparser.flexible.core.QueryNodeException;
import org.apache.lucene.queryparser.flexible.core.QueryNodeParseException;
import org.apache.lucene.queryparser.flexible.core.config.FieldConfig;
import org.apache.lucene.queryparser.flexible.core.config.QueryConfigHandler;
import org.apache.lucene.queryparser.flexible.core.messages.QueryParserMessages;
import org.apache.lucene.queryparser.flexible.core.nodes.FieldQueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
import org.apache.lucene.queryparser.flexible.core.processors.QueryNodeProcessorImpl;
import org.apache.lucene.queryparser.flexible.core.util.StringUtils;
import org.apache.lucene.queryparser.flexible.standard.config.PointsConfig;
import org.apache.lucene.queryparser.flexible.standard.config.StandardQueryConfigHandler.ConfigurationKeys;
import org.apache.lucene.queryparser.flexible.standard.nodes.PointQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.PointRangeQueryNode;
import org.apache.lucene.queryparser.flexible.standard.nodes.TermRangeQueryNode;
/**
* This processor is used to convert {@link TermRangeQueryNode}s to
* {@link PointRangeQueryNode}s. It looks for
* {@link ConfigurationKeys#POINTS_CONFIG} set in the {@link FieldConfig} of
* every {@link TermRangeQueryNode} found. If
* {@link ConfigurationKeys#POINTS_CONFIG} is found, it considers that
* {@link TermRangeQueryNode} to be a numeric range query and convert it to
* {@link PointRangeQueryNode}.
*
* @see ConfigurationKeys#POINTS_CONFIG
* @see TermRangeQueryNode
* @see PointsConfig
* @see PointRangeQueryNode
*/
public class PointRangeQueryNodeProcessor extends QueryNodeProcessorImpl {
/**
* Constructs an empty {@link PointRangeQueryNodeProcessor} object.
*/
public PointRangeQueryNodeProcessor() {
// empty constructor
}
@Override
protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException {
if (node instanceof TermRangeQueryNode) {
QueryConfigHandler config = getQueryConfigHandler();
if (config != null) {
TermRangeQueryNode termRangeNode = (TermRangeQueryNode) node;
FieldConfig fieldConfig = config.getFieldConfig(StringUtils.toString(termRangeNode.getField()));
if (fieldConfig != null) {
PointsConfig numericConfig = fieldConfig.get(ConfigurationKeys.POINTS_CONFIG);
if (numericConfig != null) {
FieldQueryNode lower = termRangeNode.getLowerBound();
FieldQueryNode upper = termRangeNode.getUpperBound();
String lowerText = lower.getTextAsString();
String upperText = upper.getTextAsString();
NumberFormat numberFormat = numericConfig.getNumberFormat();
Number lowerNumber = null, upperNumber = null;
if (lowerText.length() > 0) {
try {
lowerNumber = numberFormat.parse(lowerText);
} catch (ParseException e) {
throw new QueryNodeParseException(new MessageImpl(
QueryParserMessages.COULD_NOT_PARSE_NUMBER, lower
.getTextAsString(), numberFormat.getClass()
.getCanonicalName()), e);
}
}
if (upperText.length() > 0) {
try {
upperNumber = numberFormat.parse(upperText);
} catch (ParseException e) {
throw new QueryNodeParseException(new MessageImpl(
QueryParserMessages.COULD_NOT_PARSE_NUMBER, upper
.getTextAsString(), numberFormat.getClass()
.getCanonicalName()), e);
}
}
if (Integer.class.equals(numericConfig.getType())) {
if (upperNumber != null) upperNumber = upperNumber.intValue();
if (lowerNumber != null) lowerNumber = lowerNumber.intValue();
} else if (Long.class.equals(numericConfig.getType())) {
if (upperNumber != null) upperNumber = upperNumber.longValue();
if (lowerNumber != null) lowerNumber = lowerNumber.longValue();
} else if (Double.class.equals(numericConfig.getType())) {
if (upperNumber != null) upperNumber = upperNumber.doubleValue();
if (lowerNumber != null) lowerNumber = lowerNumber.doubleValue();
} else if (Float.class.equals(numericConfig.getType())) {
if (upperNumber != null) upperNumber = upperNumber.floatValue();
if (lowerNumber != null) lowerNumber = lowerNumber.floatValue();
}
PointQueryNode lowerNode = new PointQueryNode(termRangeNode.getField(), lowerNumber, numberFormat);
PointQueryNode upperNode = new PointQueryNode(termRangeNode.getField(), upperNumber, numberFormat);
boolean lowerInclusive = termRangeNode.isLowerInclusive();
boolean upperInclusive = termRangeNode.isUpperInclusive();
return new PointRangeQueryNode(lowerNode, upperNode, lowerInclusive, upperInclusive, numericConfig);
}
}
}
}
return node;
}
@Override
protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException {
return node;
}
@Override
protected List<QueryNode> setChildrenOrder(List<QueryNode> children) throws QueryNodeException {
return children;
}
}

View File

@ -55,8 +55,10 @@ public class StandardQueryNodeProcessorPipeline extends
add(new FuzzyQueryNodeProcessor());
add(new MatchAllDocsQueryNodeProcessor());
add(new OpenRangeQueryNodeProcessor());
add(new NumericQueryNodeProcessor());
add(new NumericRangeQueryNodeProcessor());
add(new LegacyNumericQueryNodeProcessor());
add(new LegacyNumericRangeQueryNodeProcessor());
add(new PointQueryNodeProcessor());
add(new PointRangeQueryNodeProcessor());
add(new LowercaseExpandedTermsQueryNodeProcessor());
add(new TermRangeQueryNodeProcessor());
add(new AllowLeadingWildcardProcessor());

View File

@ -44,7 +44,7 @@ import org.apache.lucene.index.RandomIndexWriter;
import org.apache.lucene.queryparser.flexible.core.QueryNodeException;
import org.apache.lucene.queryparser.flexible.core.parser.EscapeQuerySyntax;
import org.apache.lucene.queryparser.flexible.standard.config.NumberDateFormat;
import org.apache.lucene.queryparser.flexible.standard.config.NumericConfig;
import org.apache.lucene.queryparser.flexible.standard.config.LegacyNumericConfig;
import org.apache.lucene.queryparser.flexible.standard.parser.EscapeQuerySyntaxImpl;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
@ -56,7 +56,7 @@ import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class TestNumericQueryParser extends LuceneTestCase {
public class TestLegacyNumericQueryParser extends LuceneTestCase {
private static enum NumberType {
NEGATIVE, ZERO, POSITIVE;
@ -193,12 +193,12 @@ public class TestNumericQueryParser extends LuceneTestCase {
.setMergePolicy(newLogMergePolicy()));
Document doc = new Document();
HashMap<String,NumericConfig> numericConfigMap = new HashMap<>();
HashMap<String,LegacyNumericConfig> numericConfigMap = new HashMap<>();
HashMap<String,Field> numericFieldMap = new HashMap<>();
qp.setNumericConfigMap(numericConfigMap);
qp.setLegacyNumericConfigMap(numericConfigMap);
for (LegacyNumericType type : LegacyNumericType.values()) {
numericConfigMap.put(type.name(), new NumericConfig(PRECISION_STEP,
numericConfigMap.put(type.name(), new LegacyNumericConfig(PRECISION_STEP,
NUMBER_FORMAT, type));
FieldType ft = new FieldType(LegacyIntField.TYPE_NOT_STORED);
@ -229,7 +229,7 @@ public class TestNumericQueryParser extends LuceneTestCase {
doc.add(field);
}
numericConfigMap.put(DATE_FIELD_NAME, new NumericConfig(PRECISION_STEP,
numericConfigMap.put(DATE_FIELD_NAME, new LegacyNumericConfig(PRECISION_STEP,
DATE_FORMAT, LegacyNumericType.LONG));
FieldType ft = new FieldType(LegacyLongField.TYPE_NOT_STORED);
ft.setStored(true);

View File

@ -0,0 +1,82 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.queryparser.flexible.standard;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.apache.lucene.document.DoublePoint;
import org.apache.lucene.document.FloatPoint;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.queryparser.flexible.standard.config.PointsConfig;
import org.apache.lucene.util.LuceneTestCase;
/** Simple test for point field integration into the flexible QP */
public class TestPointQueryParser extends LuceneTestCase {
public void testIntegers() throws Exception {
StandardQueryParser parser = new StandardQueryParser();
Map<String,PointsConfig> pointsConfig = new HashMap<>();
pointsConfig.put("intField", new PointsConfig(NumberFormat.getIntegerInstance(Locale.ROOT), Integer.class));
parser.setPointsConfigMap(pointsConfig);
assertEquals(IntPoint.newRangeQuery("intField", 1, 3),
parser.parse("intField:[1 TO 3]", "body"));
assertEquals(IntPoint.newRangeQuery("intField", 1, 1),
parser.parse("intField:1", "body"));
}
public void testLongs() throws Exception {
StandardQueryParser parser = new StandardQueryParser();
Map<String,PointsConfig> pointsConfig = new HashMap<>();
pointsConfig.put("longField", new PointsConfig(NumberFormat.getIntegerInstance(Locale.ROOT), Long.class));
parser.setPointsConfigMap(pointsConfig);
assertEquals(LongPoint.newRangeQuery("longField", 1, 3),
parser.parse("longField:[1 TO 3]", "body"));
assertEquals(LongPoint.newRangeQuery("longField", 1, 1),
parser.parse("longField:1", "body"));
}
public void testFloats() throws Exception {
StandardQueryParser parser = new StandardQueryParser();
Map<String,PointsConfig> pointsConfig = new HashMap<>();
pointsConfig.put("floatField", new PointsConfig(NumberFormat.getNumberInstance(Locale.ROOT), Float.class));
parser.setPointsConfigMap(pointsConfig);
assertEquals(FloatPoint.newRangeQuery("floatField", 1.5F, 3.6F),
parser.parse("floatField:[1.5 TO 3.6]", "body"));
assertEquals(FloatPoint.newRangeQuery("floatField", 1.5F, 1.5F),
parser.parse("floatField:1.5", "body"));
}
public void testDoubles() throws Exception {
StandardQueryParser parser = new StandardQueryParser();
Map<String,PointsConfig> pointsConfig = new HashMap<>();
pointsConfig.put("doubleField", new PointsConfig(NumberFormat.getNumberInstance(Locale.ROOT), Double.class));
parser.setPointsConfigMap(pointsConfig);
assertEquals(DoublePoint.newRangeQuery("doubleField", 1.5D, 3.6D),
parser.parse("doubleField:[1.5 TO 3.6]", "body"));
assertEquals(DoublePoint.newRangeQuery("floatField", 1.5D, 1.5D),
parser.parse("doubleField:1.5", "body"));
}
}

View File

@ -548,7 +548,7 @@ org.apache.lucene.queryparser.flexible.spans.TestSpanQueryParser=711,339,113,55,
org.apache.lucene.queryparser.flexible.spans.TestSpanQueryParserSimpleSample=51,644,92,32,129,60,21
org.apache.lucene.queryparser.flexible.standard.TestMultiAnalyzerQPHelper=44,84,87,34,260,35,229
org.apache.lucene.queryparser.flexible.standard.TestMultiFieldQPHelper=1152,1779,1888,384,179,1665,445
org.apache.lucene.queryparser.flexible.standard.TestNumericQueryParser=344,496,451,1373,733,1420,367
org.apache.lucene.queryparser.flexible.standard.TestLegacyNumericQueryParser=344,496,451,1373,733,1420,367
org.apache.lucene.queryparser.flexible.standard.TestQPHelper=287,676,989,2137,860,586,612
org.apache.lucene.queryparser.flexible.standard.TestStandardQP=1643,430,2182,2193,600,1506,741
org.apache.lucene.queryparser.surround.query.SrndQueryTest=1062,92,92,212,65,95,113