summaryrefslogtreecommitdiff
path: root/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/NouveauQueryParser.java
diff options
context:
space:
mode:
Diffstat (limited to 'nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/NouveauQueryParser.java')
-rw-r--r--nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/NouveauQueryParser.java181
1 files changed, 181 insertions, 0 deletions
diff --git a/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/NouveauQueryParser.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/NouveauQueryParser.java
new file mode 100644
index 000000000..6aad65cd4
--- /dev/null
+++ b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/NouveauQueryParser.java
@@ -0,0 +1,181 @@
+//
+// Licensed 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.couchdb.nouveau.lucene9;
+
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.List;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.queryparser.flexible.core.QueryNodeException;
+import org.apache.lucene.queryparser.flexible.core.QueryParserHelper;
+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.NoChildOptimizationQueryNodeProcessor;
+import org.apache.lucene.queryparser.flexible.core.processors.QueryNodeProcessorImpl;
+import org.apache.lucene.queryparser.flexible.core.processors.QueryNodeProcessorPipeline;
+import org.apache.lucene.queryparser.flexible.core.processors.RemoveDeletedQueryNodesProcessor;
+import org.apache.lucene.queryparser.flexible.standard.builders.StandardQueryTreeBuilder;
+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.nodes.PointQueryNode;
+import org.apache.lucene.queryparser.flexible.standard.nodes.PointRangeQueryNode;
+import org.apache.lucene.queryparser.flexible.standard.nodes.TermRangeQueryNode;
+import org.apache.lucene.queryparser.flexible.standard.parser.StandardSyntaxParser;
+import org.apache.lucene.queryparser.flexible.standard.processors.AllowLeadingWildcardProcessor;
+import org.apache.lucene.queryparser.flexible.standard.processors.AnalyzerQueryNodeProcessor;
+import org.apache.lucene.queryparser.flexible.standard.processors.BooleanQuery2ModifierNodeProcessor;
+import org.apache.lucene.queryparser.flexible.standard.processors.BooleanSingleChildOptimizationQueryNodeProcessor;
+import org.apache.lucene.queryparser.flexible.standard.processors.BoostQueryNodeProcessor;
+import org.apache.lucene.queryparser.flexible.standard.processors.DefaultPhraseSlopQueryNodeProcessor;
+import org.apache.lucene.queryparser.flexible.standard.processors.FuzzyQueryNodeProcessor;
+import org.apache.lucene.queryparser.flexible.standard.processors.IntervalQueryNodeProcessor;
+import org.apache.lucene.queryparser.flexible.standard.processors.MatchAllDocsQueryNodeProcessor;
+import org.apache.lucene.queryparser.flexible.standard.processors.MultiFieldQueryNodeProcessor;
+import org.apache.lucene.queryparser.flexible.standard.processors.MultiTermRewriteMethodProcessor;
+import org.apache.lucene.queryparser.flexible.standard.processors.OpenRangeQueryNodeProcessor;
+import org.apache.lucene.queryparser.flexible.standard.processors.PhraseSlopQueryNodeProcessor;
+import org.apache.lucene.queryparser.flexible.standard.processors.RegexpQueryNodeProcessor;
+import org.apache.lucene.queryparser.flexible.standard.processors.RemoveEmptyNonLeafQueryNodeProcessor;
+import org.apache.lucene.queryparser.flexible.standard.processors.TermRangeQueryNodeProcessor;
+import org.apache.lucene.queryparser.flexible.standard.processors.WildcardQueryNodeProcessor;
+import org.apache.lucene.search.Query;
+
+public final class NouveauQueryParser extends QueryParserHelper {
+
+ public NouveauQueryParser(final Analyzer analyzer) {
+ super(
+ new StandardQueryConfigHandler(),
+ new StandardSyntaxParser(),
+ new NouveauQueryNodeProcessorPipeline(),
+ new StandardQueryTreeBuilder());
+ getQueryConfigHandler().set(ConfigurationKeys.ENABLE_POSITION_INCREMENTS, true);
+ getQueryConfigHandler().set(ConfigurationKeys.ANALYZER, analyzer);
+ }
+
+ @Override
+ public Query parse(String query, String defaultField) throws QueryNodeException {
+ return (Query) super.parse(query, defaultField);
+ }
+
+ /**
+ * Same pipeline as StandardQueryParser but we substitute
+ * PointQueryNodeProcessor and PointRangeQueryNodeProcessor for
+ * NouveauPointProcessor below.
+ */
+ public static class NouveauQueryNodeProcessorPipeline extends QueryNodeProcessorPipeline {
+
+ public NouveauQueryNodeProcessorPipeline() {
+ super(null);
+ add(new WildcardQueryNodeProcessor());
+ add(new MultiFieldQueryNodeProcessor());
+ add(new FuzzyQueryNodeProcessor());
+ add(new RegexpQueryNodeProcessor());
+ add(new MatchAllDocsQueryNodeProcessor());
+ add(new OpenRangeQueryNodeProcessor());
+ add(new NouveauPointProcessor());
+ add(new TermRangeQueryNodeProcessor());
+ add(new AllowLeadingWildcardProcessor());
+ add(new AnalyzerQueryNodeProcessor());
+ add(new PhraseSlopQueryNodeProcessor());
+ add(new BooleanQuery2ModifierNodeProcessor());
+ add(new NoChildOptimizationQueryNodeProcessor());
+ add(new RemoveDeletedQueryNodesProcessor());
+ add(new RemoveEmptyNonLeafQueryNodeProcessor());
+ add(new BooleanSingleChildOptimizationQueryNodeProcessor());
+ add(new DefaultPhraseSlopQueryNodeProcessor());
+ add(new BoostQueryNodeProcessor());
+ add(new MultiTermRewriteMethodProcessor());
+ add(new IntervalQueryNodeProcessor());
+ }
+ }
+
+ /**
+ * If it looks like a number, treat it as a number.
+ */
+ public static class NouveauPointProcessor extends QueryNodeProcessorImpl {
+
+ @Override
+ protected QueryNode postProcessNode(final QueryNode node) throws QueryNodeException {
+ final var numberFormat = NumberFormat.getInstance();
+ final var pointsConfig = new PointsConfig(numberFormat, Double.class);
+
+ if (node instanceof FieldQueryNode && !(node.getParent() instanceof RangeQueryNode)) {
+ final var fieldNode = (FieldQueryNode) node;
+ String text = fieldNode.getTextAsString();
+ if (text.length() == 0) {
+ return node;
+ }
+ final Number number;
+ try {
+ number = numberFormat.parse(text).doubleValue();
+ } catch (final ParseException e) {
+ return node;
+ }
+ final var lowerNode = new PointQueryNode(fieldNode.getField(), number, numberFormat);
+ final var upperNode = new PointQueryNode(fieldNode.getField(), number, numberFormat);
+ return new PointRangeQueryNode(lowerNode, upperNode, true, true, pointsConfig);
+ }
+
+ if (node instanceof TermRangeQueryNode) {
+ final var termRangeNode = (TermRangeQueryNode) node;
+ final var lower = termRangeNode.getLowerBound();
+ final var upper = termRangeNode.getUpperBound();
+ final var lowerText = lower.getTextAsString();
+ final var upperText = upper.getTextAsString();
+ Number lowerNumber = null, upperNumber = null;
+
+ if (lowerText.length() > 0 && !lowerText.equals("-Infinity")) {
+ try {
+ lowerNumber = numberFormat.parse(lowerText).doubleValue();
+ } catch (final ParseException e) {
+ return node;
+ }
+ }
+
+ if (upperText.length() > 0 && !upperText.equals("Infinity")) {
+ try {
+ upperNumber = numberFormat.parse(upperText).doubleValue();
+ } catch (final ParseException e) {
+ return node;
+ }
+ }
+
+ final var lowerNode = new PointQueryNode(termRangeNode.getField(), lowerNumber, numberFormat);
+ final var upperNode = new PointQueryNode(termRangeNode.getField(), upperNumber, numberFormat);
+ final var lowerInclusive = termRangeNode.isLowerInclusive();
+ final var upperInclusive = termRangeNode.isUpperInclusive();
+
+ return new PointRangeQueryNode(
+ lowerNode, upperNode, lowerInclusive, upperInclusive, pointsConfig);
+ }
+
+ return node;
+ }
+
+ @Override
+ protected QueryNode preProcessNode(final QueryNode node) throws QueryNodeException {
+ return node;
+ }
+
+ @Override
+ protected List<QueryNode> setChildrenOrder(final List<QueryNode> children) throws QueryNodeException {
+ return children;
+ }
+
+ }
+
+} \ No newline at end of file