diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index eedba58ca73..97eea1c638c 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -84,6 +84,9 @@ New Features
* SOLR-5287: You can edit files in the conf directory from the admin UI
(Erick Erickson, Stefan Matheis)
+* SOLR-5447: Add a QParserPlugin for Lucene's SimpleQueryParser.
+ (Jack Conradson via shalin)
+
Bug Fixes
----------------------
diff --git a/solr/core/src/java/org/apache/solr/search/QParserPlugin.java b/solr/core/src/java/org/apache/solr/search/QParserPlugin.java
index 4cbe8b38dfc..a0f572d2a86 100644
--- a/solr/core/src/java/org/apache/solr/search/QParserPlugin.java
+++ b/solr/core/src/java/org/apache/solr/search/QParserPlugin.java
@@ -52,7 +52,8 @@ public abstract class QParserPlugin implements NamedListInitializedPlugin, SolrI
MaxScoreQParserPlugin.NAME, MaxScoreQParserPlugin.class,
BlockJoinParentQParserPlugin.NAME, BlockJoinParentQParserPlugin.class,
BlockJoinChildQParserPlugin.NAME, BlockJoinChildQParserPlugin.class,
- CollapsingQParserPlugin.NAME, CollapsingQParserPlugin.class
+ CollapsingQParserPlugin.NAME, CollapsingQParserPlugin.class,
+ SimpleQParserPlugin.NAME, SimpleQParserPlugin.class
};
/** return a {@link QParser} */
diff --git a/solr/core/src/java/org/apache/solr/search/SimpleQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/SimpleQParserPlugin.java
new file mode 100644
index 00000000000..5e5c6e837ad
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/search/SimpleQParserPlugin.java
@@ -0,0 +1,173 @@
+package org.apache.solr.search;
+
+/*
+ * 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.
+ */
+
+import org.apache.lucene.queryparser.simple.SimpleQueryParser;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.Query;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.SimpleParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.parser.QueryParser;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.util.SolrPluginUtils;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Create a query from the input value that will be parsed by Lucene's SimpleQueryParser.
+ * See {@link org.apache.lucene.queryparser.simple.SimpleQueryParser} for details on the exact syntax allowed
+ * to be used for queries.
+ *
+ * The following options may be applied for parsing the query.
+ *
+ * -
+ * q.operations - Used to enable specific operations for parsing. The operations that can be enabled are
+ * and, not, or, prefix, phrase, precedence, escape, and whitespace. By default all operations
+ * are enabled. All operations can be disabled by passing in an empty string to this parameter.
+ *
+ * -
+ * q.op - Used to specify the operator to be used if whitespace is a delimiter. Either 'AND' or 'OR'
+ * can be specified for this parameter. Any other string will cause an exception to be thrown.
+ * If this parameter is not specified 'OR' will be used by default.
+ *
+ * -
+ * qf - The list of query fields and boosts to use when building the simple query. The format is the following:
+ *
fieldA^1.0 fieldB^2.2
. A field can also be specified without a boost by simply listing the
+ * field as fieldA fieldB
. Any field without a boost will default to use a boost of 1.0.
+ *
+ * -
+ * df - An override for the default field specified in the schema or a default field if one is not specified
+ * in the schema. If qf is not specified the default field will be used as the field to run the query
+ * against.
+ *
+ *
+ */
+public class SimpleQParserPlugin extends QParserPlugin {
+ /** The name that can be used to specify this plugin should be used to parse the query. */
+ public static String NAME = "simple";
+
+ /** Enables {@code AND} operator (+) */
+ private static final String AND_OPERATOR = "AND";
+ /** Enables {@code NOT} operator (-) */
+ private static final String NOT_OPERATOR = "NOT";
+ /** Enables {@code OR} operator (|) */
+ private static final String OR_OPERATOR = "OR";
+ /** Enables {@code PREFIX} operator (*) */
+ private static final String PREFIX_OPERATOR = "PREFIX";
+ /** Enables {@code PHRASE} operator (") */
+ private static final String PHRASE_OPERATOR = "PHRASE";
+ /** Enables {@code PRECEDENCE} operators: {@code (} and {@code )} */
+ private static final String PRECEDENCE_OPERATORS = "PRECEDENCE";
+ /** Enables {@code ESCAPE} operator (\) */
+ private static final String ESCAPE_OPERATOR = "ESCAPE";
+ /** Enables {@code WHITESPACE} operators: ' ' '\n' '\r' '\t' */
+ private static final String WHITESPACE_OPERATOR = "WHITESPACE";
+
+ /** Map of string operators to their int counterparts in SimpleQueryParser. */
+ private static final Map OPERATORS = new HashMap();
+
+ /* Setup the map of possible operators. */
+ static {
+ OPERATORS.put(AND_OPERATOR, SimpleQueryParser.AND_OPERATOR);
+ OPERATORS.put(NOT_OPERATOR, SimpleQueryParser.NOT_OPERATOR);
+ OPERATORS.put(OR_OPERATOR, SimpleQueryParser.OR_OPERATOR);
+ OPERATORS.put(PREFIX_OPERATOR, SimpleQueryParser.PREFIX_OPERATOR);
+ OPERATORS.put(PHRASE_OPERATOR, SimpleQueryParser.PHRASE_OPERATOR);
+ OPERATORS.put(PRECEDENCE_OPERATORS, SimpleQueryParser.PRECEDENCE_OPERATORS);
+ OPERATORS.put(ESCAPE_OPERATOR, SimpleQueryParser.ESCAPE_OPERATOR);
+ OPERATORS.put(WHITESPACE_OPERATOR, SimpleQueryParser.WHITESPACE_OPERATOR);
+ }
+
+ /** No initialization is necessary so this method is empty. */
+ @Override
+ public void init(NamedList args) {
+ }
+
+ /** Returns a QParser that will create a query by using Lucene's SimpleQueryParser. */
+ @Override
+ public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
+ // Some of the parameters may come in through localParams, so combine them with params.
+ SolrParams defaultParams = SolrParams.wrapDefaults(localParams, params);
+
+ // This will be used to specify what fields and boosts will be used by SimpleQueryParser.
+ Map queryFields = SolrPluginUtils.parseFieldBoosts(defaultParams.get(SimpleParams.QF));
+
+ if (queryFields.isEmpty()) {
+ // It qf is not specified setup up the queryFields map to use the defaultField.
+ String defaultField = QueryParsing.getDefaultField(req.getSchema(), defaultParams.get(CommonParams.DF));
+
+ if (defaultField == null) {
+ // A query cannot be run without having a field or set of fields to run against.
+ throw new IllegalStateException("Neither " + SimpleParams.QF + ", " + CommonParams.DF
+ + ", nor the default search field are present.");
+ }
+
+ queryFields.put(defaultField, 1.0F);
+ }
+ else {
+ for (Map.Entry queryField : queryFields.entrySet()) {
+ if (queryField.getValue() == null) {
+ // Some fields may be specified without a boost, so default the boost to 1.0 since a null value
+ // will not be accepted by SimpleQueryParser.
+ queryField.setValue(1.0F);
+ }
+ }
+ }
+
+ // Setup the operations that are enabled for the query.
+ int enabledOps = 0;
+ String opParam = defaultParams.get(SimpleParams.QO);
+
+ if (opParam == null) {
+ // All operations will be enabled.
+ enabledOps = -1;
+ } else {
+ // Parse the specified enabled operations to be used by the query.
+ String[] operations = opParam.split(",");
+
+ for (String operation : operations) {
+ Integer enabledOp = OPERATORS.get(operation.trim().toUpperCase(Locale.getDefault()));
+
+ if (enabledOp != null) {
+ enabledOps |= enabledOp;
+ }
+ }
+ }
+
+ // Create a SimpleQueryParser using the analyzer from the schema.
+ final SimpleQueryParser parser = new SimpleQueryParser(req.getSchema().getAnalyzer(), queryFields, enabledOps);
+
+ // Set the default operator to be either 'AND' or 'OR' for the query.
+ QueryParser.Operator defaultOp = QueryParsing.getQueryParserDefaultOperator(req.getSchema(), defaultParams.get(QueryParsing.OP));
+
+ if (defaultOp == QueryParser.Operator.AND) {
+ parser.setDefaultOperator(BooleanClause.Occur.MUST);
+ }
+
+ // Return a QParser that wraps a SimpleQueryParser.
+ return new QParser(qstr, localParams, params, req) {
+ public Query parse() throws SyntaxError {
+ return parser.parse(qstr);
+ }
+ };
+ }
+}
diff --git a/solr/core/src/test-files/solr/collection1/conf/schema-simpleqpplugin.xml b/solr/core/src/test-files/solr/collection1/conf/schema-simpleqpplugin.xml
new file mode 100644
index 00000000000..e6724421c91
--- /dev/null
+++ b/solr/core/src/test-files/solr/collection1/conf/schema-simpleqpplugin.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text0
+ id
+
diff --git a/solr/core/src/test/org/apache/solr/search/TestSimpleQParserPlugin.java b/solr/core/src/test/org/apache/solr/search/TestSimpleQParserPlugin.java
new file mode 100644
index 00000000000..0e2a0a502e3
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/search/TestSimpleQParserPlugin.java
@@ -0,0 +1,208 @@
+package org.apache.solr.search;
+
+/*
+ * 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.
+ */
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/** Simple tests for SimpleQParserPlugin. */
+public class TestSimpleQParserPlugin extends SolrTestCaseJ4 {
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ initCore("solrconfig-basic.xml","schema-simpleqpplugin.xml");
+ index();
+ }
+
+ public static void index() throws Exception {
+ assertU(adoc("id", "42", "text0", "t0 t0 t0", "text1", "t0 t1 t2", "text-keyword0", "kw0 kw0 kw0"));
+ assertU(adoc("id", "43", "text0", "t0 t1 t2", "text1", "t3 t4 t5", "text-keyword0", "kw0 kw1 kw2"));
+ assertU(adoc("id", "44", "text0", "t0 t1 t1", "text1", "t6 t7 t8", "text-keyword0", "kw3 kw4 kw5"));
+ assertU(adoc("id", "45", "text0", "t0 t0 t1", "text1", "t9 t10 t11", "text-keyword0", "kw6 kw7 kw8"));
+ assertU(adoc("id", "46", "text0", "t1 t1 t1", "text1", "t12 t13 t14", "text-keyword0", "kw9 kw10 kw11"));
+ assertU(adoc("id", "47", "text0", "and", "text1", "+", "text-keyword0", "+"));
+ assertU(adoc("id", "48", "text0", "not", "text1", "-", "text-keyword0", "-"));
+ assertU(adoc("id", "49", "text0", "or", "text1", "|", "text-keyword0", "|"));
+ assertU(adoc("id", "50", "text0", "prefix", "text1", "t*", "text-keyword0", "kw*"));
+ assertU(adoc("id", "51", "text0", "phrase", "text1", "\"", "text-keyword0", "\""));
+ assertU(adoc("id", "52", "text0", "open", "text1", "(", "text-keyword0", "("));
+ assertU(adoc("id", "53", "text0", "close", "text1", ")", "text-keyword0", ")"));
+ assertU(adoc("id", "54", "text0", "escape", "text1", "\\", "text-keyword0", "\\"));
+ assertU(adoc("id", "55", "text0", "whitespace", "text1", "whitespace", "text-keyword0", " "));
+ assertU(adoc("id", "55", "text0", "whitespace", "text1", "whitespace", "text-keyword0", "\n"));
+ assertU(commit());
+ }
+
+ @Test
+ public void testQueryFields() throws Exception {
+ assertJQ(req("defType", "simple", "qf", "text0^2 text1 text-keyword0", "q", "t3"), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "qf", "text0^3 text1^4 text-keyword0^0.55", "q", "t0"), "/response/numFound==4");
+ assertJQ(req("defType", "simple", "qf", "text-keyword0^9.2", "q", "\"kw9 kw10 kw11\""), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "qf", "text-keyword0", "q", "kw9 kw10 kw11"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text1 text-keyword0", "q", "kw9"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0", "q", "t2"), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "qf", "text0^1.1 text1^0.9", "q", "t2 t9 t12"), "/response/numFound==4");
+ }
+
+ @Test
+ public void testDefaultField() throws Exception {
+ assertJQ(req("defType", "simple", "q", "t2 t9 t12"), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "q", "t3"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "df", "text1", "q", "t2 t9 t12"), "/response/numFound==3");
+ assertJQ(req("defType", "simple", "df", "text1", "q", "t3"), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "df", "text-keyword0", "q", "\"kw9 kw10 kw11\""), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "df", "text-keyword0", "q", "kw9 kw10 kw11"), "/response/numFound==0");
+ }
+
+ @Test
+ public void testQueryFieldPriority() throws Exception {
+ assertJQ(req("defType", "simple", "qf", "text0^2 text1 text-keyword0", "df", "text0", "q", "t3"), "/response/numFound==1");
+ }
+
+ @Test
+ public void testOnlyAndOperatorEnabledDisabled() throws Exception {
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "+",
+ "q.operators", "NOT, OR, PHRASE, PREFIX, PRECEDENCE, ESCAPE, WHITESPACE"), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "-",
+ "q.operators", "NOT, OR, PHRASE, PREFIX, PRECEDENCE, ESCAPE, WHITESPACE"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "+",
+ "q.operators", "AND"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "-",
+ "q.operators", "AND"), "/response/numFound==1");
+ }
+
+ @Test
+ public void testOnlyNotOperatorEnabledDisabled() throws Exception {
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "-",
+ "q.operators", "AND, OR, PHRASE, PREFIX, PRECEDENCE, ESCAPE, WHITESPACE"), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "|",
+ "q.operators", "AND, OR, PHRASE, PREFIX, PRECEDENCE, ESCAPE, WHITESPACE"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "-",
+ "q.operators", "NOT"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "|",
+ "q.operators", "NOT"), "/response/numFound==1");
+ }
+
+ @Test
+ public void testOnlyOrOperatorEnabledDisabled() throws Exception {
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "|",
+ "q.operators", "AND, NOT, PHRASE, PREFIX, PRECEDENCE, ESCAPE, WHITESPACE"), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "\"",
+ "q.operators", "AND, NOT, PHRASE, PREFIX, PRECEDENCE, ESCAPE, WHITESPACE"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "|",
+ "q.operators", "OR"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "\"",
+ "q.operators", "OR"), "/response/numFound==1");
+ }
+
+ @Test
+ public void testOnlyPhraseOperatorEnabledDisabled() throws Exception {
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "\"",
+ "q.operators", "AND, NOT, OR, PREFIX, PRECEDENCE, ESCAPE, WHITESPACE"), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "|",
+ "q.operators", "AND, NOT, OR, PREFIX, PRECEDENCE, ESCAPE, WHITESPACE"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "\"",
+ "q.operators", "PHRASE"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "|",
+ "q.operators", "PHRASE"), "/response/numFound==1");
+ }
+
+ @Test
+ public void testOnlyPrefixOperatorEnabledDisabled() throws Exception {
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "t*",
+ "q.operators", "AND, NOT, OR, PHRASE, PRECEDENCE, ESCAPE, WHITESPACE"), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "(",
+ "q.operators", "AND, NOT, OR, PHRASE, PRECEDENCE, ESCAPE, WHITESPACE"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "t*",
+ "q.operators", "PREFIX"), "/response/numFound==6");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "(",
+ "q.operators", "PREFIX"), "/response/numFound==1");
+ }
+
+ @Test
+ public void testOnlyPrecedenceOperatorEnabledDisabled() throws Exception {
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "(",
+ "q.operators", "AND, NOT, OR, PHRASE, PREFIX, ESCAPE, WHITESPACE"), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "\\",
+ "q.operators", "AND, NOT, OR, PHRASE, PREFIX, ESCAPE, WHITESPACE"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "(",
+ "q.operators", "PRECEDENCE"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "\\",
+ "q.operators", "PRECEDENCE"), "/response/numFound==1");
+
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", ")",
+ "q.operators", "AND, NOT, OR, PHRASE, PREFIX, ESCAPE, WHITESPACE"), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "\\",
+ "q.operators", "AND, NOT, OR, PHRASE, PREFIX, ESCAPE, WHITESPACE"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", ")",
+ "q.operators", "PRECEDENCE"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "\\",
+ "q.operators", "PRECEDENCE"), "/response/numFound==1");
+ }
+
+ @Test
+ public void testOnlyEscapeOperatorEnabledDisabled() throws Exception {
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "\\",
+ "q.operators", "AND, NOT, OR, PHRASE, PREFIX, PRECEDENCE, WHITESPACE"), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "\n",
+ "q.operators", "AND, NOT, OR, PHRASE, PREFIX, PRECEDENCE, WHITESPACE"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "\\",
+ "q.operators", "ESCAPE"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "\n",
+ "q.operators", "ESCAPE"), "/response/numFound==1");
+ }
+
+ @Test
+ public void testOnlyWhitespaceOperatorEnabledDisabled() throws Exception {
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "\n",
+ "q.operators", "AND, NOT, OR, PHRASE, PREFIX, PRECEDENCE, ESCAPE"), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "\\",
+ "q.operators", "AND, NOT, OR, PHRASE, PREFIX, PRECEDENCE, ESCAPE"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "\n",
+ "q.operators", "WHITESPACE"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "\\",
+ "q.operators", "WHITESPACE"), "/response/numFound==1");
+ }
+
+ @Test
+ public void testArbitraryOperatorsEnabledDisabled() throws Exception {
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "kw0+kw1+kw2| \\ ",
+ "q.operators", "AND, NOT, OR, PHRASE"), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "qf", "text0 text1 text-keyword0", "q", "t1 + t2 \\",
+ "q.operators", "AND, WHITESPACE"), "/response/numFound==3");
+ assertJQ(req("defType", "simple", "qf", "text0 text-keyword0", "q", "t0 + (-t1 -t2) |",
+ "q.operators", "AND, NOT, PRECEDENCE, WHITESPACE"), "/response/numFound==4");
+ }
+
+ @Test
+ public void testNoOperators() throws Exception {
+ assertJQ(req("defType", "simple", "qf", "text1 text-keyword0", "q", "kw0 kw1 kw2",
+ "q.operators", ""), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "qf", "text1", "q", "t1 t2 t3",
+ "q.operators", ""), "/response/numFound==2");
+ }
+
+ @Test
+ public void testDefaultOperator() throws Exception {
+ assertJQ(req("defType", "simple", "qf", "text1 text-keyword0", "q", "t2 t3",
+ "q.op", "AND"), "/response/numFound==0");
+ assertJQ(req("defType", "simple", "qf", "text0 text-keyword0", "q", "t0 t2",
+ "q.op", "AND"), "/response/numFound==1");
+ assertJQ(req("defType", "simple", "qf", "text1", "q", "t2 t3"), "/response/numFound==2");
+ }
+}
diff --git a/solr/solrj/src/java/org/apache/solr/common/params/SimpleParams.java b/solr/solrj/src/java/org/apache/solr/common/params/SimpleParams.java
new file mode 100644
index 00000000000..1fd89030f30
--- /dev/null
+++ b/solr/solrj/src/java/org/apache/solr/common/params/SimpleParams.java
@@ -0,0 +1,29 @@
+package org.apache.solr.common.params;
+
+/*
+ * 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.
+ */
+
+/**
+ * Parameters used by the SimpleQParser.
+ */
+public interface SimpleParams {
+ /** Query fields and boosts. */
+ public static String QF = "qf";
+
+ /** Override the currently enabled/disabled query operators. */
+ public static String QO = "q.operators";
+}