You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ho...@apache.org on 2014/01/22 17:50:07 UTC
svn commit: r1560412 - in /lucene/dev/trunk/solr: ./
core/src/java/org/apache/solr/parser/ core/src/java/org/apache/solr/schema/
core/src/java/org/apache/solr/search/
core/src/test-files/solr/collection1/conf/
core/src/test/org/apache/solr/schema/ core...
Author: hossman
Date: Wed Jan 22 16:50:07 2014
New Revision: 1560412
URL: http://svn.apache.org/r1560412
Log:
SOLR-5594: Allow FieldTypes to specify custom PrefixQuery behavior
Added:
lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema-customfield.xml (with props)
lucene/dev/trunk/solr/core/src/test/org/apache/solr/schema/MyCrazyCustomField.java (with props)
lucene/dev/trunk/solr/core/src/test/org/apache/solr/schema/TrieIntPrefixActsAsRangeQueryFieldType.java (with props)
lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestOverriddenPrefixQueryForCustomFieldType.java (with props)
Modified:
lucene/dev/trunk/solr/CHANGES.txt
lucene/dev/trunk/solr/core/src/java/org/apache/solr/parser/SolrQueryParserBase.java
lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/BinaryField.java
lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/FieldType.java
lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/PrefixQParserPlugin.java
lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/SimpleQParserPlugin.java
Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1560412&r1=1560411&r2=1560412&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Wed Jan 22 16:50:07 2014
@@ -151,6 +151,9 @@ New Features
* SOLR-5476: Overseer Role for nodes (Noble Paul)
+* SOLR-5594: Allow FieldTypes to specify custom PrefixQuery behavior
+ (Anshum Gupta via hossman)
+
Bug Fixes
----------------------
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/parser/SolrQueryParserBase.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/parser/SolrQueryParserBase.java?rev=1560412&r1=1560411&r2=1560412&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/parser/SolrQueryParserBase.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/parser/SolrQueryParserBase.java Wed Jan 22 16:50:07 2014
@@ -28,7 +28,6 @@ import org.apache.lucene.search.MatchAll
import org.apache.lucene.search.MultiPhraseQuery;
import org.apache.lucene.search.MultiTermQuery;
import org.apache.lucene.search.PhraseQuery;
-import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.RegexpQuery;
import org.apache.lucene.search.WildcardQuery;
@@ -419,10 +418,8 @@ public abstract class SolrQueryParserBas
* @return new PrefixQuery instance
*/
protected Query newPrefixQuery(Term prefix){
- PrefixQuery query = new PrefixQuery(prefix);
SchemaField sf = schema.getField(prefix.field());
- query.setRewriteMethod(sf.getType().getRewriteMethod(parser, sf));
- return query;
+ return sf.getType().getPrefixQuery(parser, sf, prefix.text());
}
/**
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/BinaryField.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/BinaryField.java?rev=1560412&r1=1560411&r2=1560412&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/BinaryField.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/BinaryField.java Wed Jan 22 16:50:07 2014
@@ -21,8 +21,6 @@ import java.io.IOException;
import java.nio.ByteBuffer;
import org.apache.lucene.document.Field;
-import org.apache.lucene.index.GeneralField;
-import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.StorableField;
import org.apache.lucene.search.SortField;
import org.apache.lucene.util.BytesRef;
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/FieldType.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/FieldType.java?rev=1560412&r1=1560411&r2=1560412&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/FieldType.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/FieldType.java Wed Jan 22 16:50:07 2014
@@ -35,6 +35,7 @@ import org.apache.lucene.search.DocTermO
import org.apache.lucene.search.FieldCacheRangeFilter;
import org.apache.lucene.search.FieldCacheRewriteMethod;
import org.apache.lucene.search.MultiTermQuery;
+import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TermQuery;
@@ -427,6 +428,25 @@ public abstract class FieldType extends
return getClass().getName();
}
+
+ /**
+ * Returns a Query instance for doing prefix searches on this field type.
+ * Also, other QueryParser implementations may have different semantics.
+ * <p/>
+ * Sub-classes should override this method to provide their own range query implementation.
+ *
+ * @param parser the {@link org.apache.solr.search.QParser} calling the method
+ * @param sf the schema field
+ * @param termStr the term string for prefix query
+ * @return a Query instance to perform prefix search
+ *
+ */
+ public Query getPrefixQuery(QParser parser, SchemaField sf, String termStr) {
+ PrefixQuery query = new PrefixQuery(new Term(sf.getName(), termStr));
+ query.setRewriteMethod(sf.getType().getRewriteMethod(parser, sf));
+ return query;
+ }
+
/**
* Default analyzer for types that only produce 1 verbatim token...
* A maximum size of chars to be read must be specified
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/PrefixQParserPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/PrefixQParserPlugin.java?rev=1560412&r1=1560411&r2=1560412&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/PrefixQParserPlugin.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/PrefixQParserPlugin.java Wed Jan 22 16:50:07 2014
@@ -22,6 +22,8 @@ import org.apache.lucene.search.Query;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.schema.SchemaField;
+
/**
* Create a prefix query from the input value. Currently no analysis or
* value transformation is done to create this prefix query (subject to change).
@@ -41,7 +43,8 @@ public class PrefixQParserPlugin extends
return new QParser(qstr, localParams, params, req) {
@Override
public Query parse() {
- return new PrefixQuery(new Term(localParams.get(QueryParsing.F), localParams.get(QueryParsing.V)));
+ SchemaField sf = req.getSchema().getField(localParams.get(QueryParsing.F));
+ return sf.getType().getPrefixQuery(this, sf, localParams.get(QueryParsing.V));
}
};
}
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/SimpleQParserPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/SimpleQParserPlugin.java?rev=1560412&r1=1560411&r2=1560412&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/SimpleQParserPlugin.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/SimpleQParserPlugin.java Wed Jan 22 16:50:07 2014
@@ -32,6 +32,7 @@ import org.apache.solr.parser.QueryParse
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.IndexSchema;
+import org.apache.solr.schema.SchemaField;
import org.apache.solr.schema.TextField;
import org.apache.solr.util.SolrPluginUtils;
@@ -112,97 +113,122 @@ public class SimpleQParserPlugin extends
/** 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);
+ return new SimpleQParser(qstr, localParams, params, req);
+ }
- // This will be used to specify what fields and boosts will be used by SimpleQueryParser.
- Map<String, Float> queryFields = SolrPluginUtils.parseFieldBoosts(defaultParams.get(SimpleParams.QF));
+ private static class SimpleQParser extends QParser {
+ private SimpleQueryParser parser;
- 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.");
- }
+ public SimpleQParser (String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
- queryFields.put(defaultField, 1.0F);
- }
- else {
- for (Map.Entry<String, Float> 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);
+ super(qstr, localParams, params, 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<String, Float> 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<String, Float> 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(",");
+ // 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.ROOT));
+ for (String operation : operations) {
+ Integer enabledOp = OPERATORS.get(operation.trim().toUpperCase(Locale.ROOT));
- if (enabledOp != null) {
- enabledOps |= enabledOp;
+ if (enabledOp != null) {
+ enabledOps |= enabledOp;
+ }
}
}
- }
- // Create a SimpleQueryParser using the analyzer from the schema.
- final IndexSchema schema = req.getSchema();
- final SimpleQueryParser parser = new SimpleQueryParser(req.getSchema().getAnalyzer(), queryFields, enabledOps) {
- // Override newPrefixQuery to provide a multi term analyzer for prefix queries run against TextFields.
- @Override
- protected Query newPrefixQuery(String text) {
- BooleanQuery bq = new BooleanQuery(true);
-
- for (Map.Entry<String, Float> entry : weights.entrySet()) {
- String field = entry.getKey();
- FieldType type = schema.getFieldType(field);
- Query prefix;
-
- if (type instanceof TextField) {
- // If the field type is a TextField then use the multi term analyzer.
- Analyzer analyzer = ((TextField)type).getMultiTermAnalyzer();
- String term = TextField.analyzeMultiTerm(field, text, analyzer).utf8ToString();
- prefix = new PrefixQuery(new Term(field, term));
- } else {
- // If the type is *not* a TextField don't do any analysis.
- prefix = new PrefixQuery(new Term(entry.getKey(), text));
- }
+ // Create a SimpleQueryParser using the analyzer from the schema.
+ final IndexSchema schema = req.getSchema();
+ parser = new SolrSimpleQueryParser(req.getSchema().getAnalyzer(), queryFields, enabledOps, this, schema);
- prefix.setBoost(entry.getValue());
- bq.add(prefix, BooleanClause.Occur.SHOULD);
- }
+ // Set the default operator to be either 'AND' or 'OR' for the query.
+ QueryParser.Operator defaultOp = QueryParsing.getQueryParserDefaultOperator(req.getSchema(), defaultParams.get(QueryParsing.OP));
- return simplify(bq);
+ if (defaultOp == QueryParser.Operator.AND) {
+ parser.setDefaultOperator(BooleanClause.Occur.MUST);
}
- };
+ }
+
+ @Override
+ public Query parse() throws SyntaxError {
+ return parser.parse(qstr);
+ }
- // 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);
+ private static class SolrSimpleQueryParser extends SimpleQueryParser {
+ QParser qParser;
+ IndexSchema schema;
+
+ public SolrSimpleQueryParser(Analyzer analyzer, Map<String, Float> weights, int flags,
+ QParser qParser, IndexSchema schema) {
+ super(analyzer, weights, flags);
+ this.qParser = qParser;
+ this.schema = schema;
}
- // Return a QParser that wraps a SimpleQueryParser.
- return new QParser(qstr, localParams, params, req) {
- public Query parse() throws SyntaxError {
- return parser.parse(qstr);
+ @Override
+ protected Query newPrefixQuery(String text) {
+ BooleanQuery bq = new BooleanQuery(true);
+
+ for (Map.Entry<String, Float> entry : weights.entrySet()) {
+ String field = entry.getKey();
+ FieldType type = schema.getFieldType(field);
+ Query prefix;
+
+ if (type instanceof TextField) {
+ // If the field type is a TextField then use the multi term analyzer.
+ Analyzer analyzer = ((TextField)type).getMultiTermAnalyzer();
+ String term = TextField.analyzeMultiTerm(field, text, analyzer).utf8ToString();
+ SchemaField sf = schema.getField(field);
+ prefix = sf.getType().getPrefixQuery(qParser, sf, term);
+ } else {
+ // If the type is *not* a TextField don't do any analysis.
+ SchemaField sf = schema.getField(field);
+ prefix = type.getPrefixQuery(qParser, sf, text);
+ }
+
+ prefix.setBoost(entry.getValue());
+ bq.add(prefix, BooleanClause.Occur.SHOULD);
}
- };
+
+ return simplify(bq);
+ }
+
+
}
}
+
Added: lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema-customfield.xml
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema-customfield.xml?rev=1560412&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema-customfield.xml (added)
+++ lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema-customfield.xml Wed Jan 22 16:50:07 2014
@@ -0,0 +1,69 @@
+<?xml version="1.0" ?>
+<!--
+ 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.
+-->
+
+<!-- The Solr schema file. This file should be named "schema.xml" and
+ should be located where the classloader for the Solr webapp can find it.
+
+ This schema is used for testing, and as such has everything and the
+ kitchen sink thrown in. See example/solr/conf/schema.xml for a
+ more concise example.
+
+ -->
+
+<schema name="test" version="1.2">
+ <types>
+
+ <!-- field type definitions... note that the "name" attribute is
+ just a label to be used by field definitions. The "class"
+ attribute and any other attributes determine the real type and
+ behavior of the fieldtype.
+ -->
+
+ <!-- numeric field types that store and index the text
+ value verbatim (and hence don't sort correctly or support range queries.)
+ These are provided more for backward compatability, allowing one
+ to create a schema that matches an existing lucene index.
+ -->
+ <fieldType name="integer" class="solr.IntField"/>
+ <fieldType name="long" class="solr.LongField"/>
+ <fieldtype name="float" class="solr.FloatField"/>
+ <fieldType name="double" class="solr.DoubleField"/>
+ <fieldType name="customfield" class="org.apache.solr.schema.MyCrazyCustomField" multiValued="true" positionIncrementGap="100">
+ <analyzer>
+ <tokenizer class="solr.StandardTokenizerFactory"/>
+ </analyzer>
+ </fieldType>
+
+ <fieldType name="customtrieintfield" class="org.apache.solr.schema.TrieIntPrefixActsAsRangeQueryFieldType"/>
+
+ </types>
+
+ <fields>
+ <field name="id" type="integer" indexed="true" stored="true" multiValued="false" required="true"/>
+ <field name="intfield" type="integer" indexed="true" stored="true"/>
+ <field name="swap_foo_bar_in_prefix_query" type="customfield" indexed="true" stored="true" multiValued="true"/>
+ <field name="int_prefix_as_range" type="customtrieintfield" indexed="true" stored="true"/>
+
+ <field name="_version_" type="long" indexed="true" stored="true" multiValued="false" />
+
+ </fields>
+
+ <uniqueKey>id</uniqueKey>
+
+
+</schema>
Added: lucene/dev/trunk/solr/core/src/test/org/apache/solr/schema/MyCrazyCustomField.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/schema/MyCrazyCustomField.java?rev=1560412&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/schema/MyCrazyCustomField.java (added)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/schema/MyCrazyCustomField.java Wed Jan 22 16:50:07 2014
@@ -0,0 +1,61 @@
+package org.apache.solr.schema;
+
+/*
+ * 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.index.StorableField;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.PrefixQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.SortField;
+import org.apache.solr.response.TextResponseWriter;
+import org.apache.solr.search.QParser;
+
+import java.io.IOException;
+
+/**
+ * Custom field that overrides the PrefixQuery behaviour to map queries such that:
+ * (foo* becomes bar*) and (bar* becomes foo*).
+ * This is used for testing overridded prefix query for custom fields in TestOverriddenPrefixQueryForCustomFieldType
+ */
+public class MyCrazyCustomField extends TextField {
+
+
+ @Override
+ public void write(TextResponseWriter writer, String name, StorableField f) throws IOException {
+ writer.writeStr(name, f.stringValue(), true);
+ }
+
+ @Override
+ public SortField getSortField(final SchemaField field, final boolean reverse) {
+ field.checkSortability();
+ return getStringSort(field, reverse);
+ }
+
+ @Override
+ public Query getPrefixQuery(QParser parser, SchemaField sf, String termStr) {
+ if(termStr.equals("foo")) {
+ termStr = "bar";
+ } else if (termStr.equals("bar")) {
+ termStr = "foo";
+ }
+
+ PrefixQuery query = new PrefixQuery(new Term(sf.getName(), termStr));
+ query.setRewriteMethod(sf.getType().getRewriteMethod(parser, sf));
+ return query;
+ }
+}
Added: lucene/dev/trunk/solr/core/src/test/org/apache/solr/schema/TrieIntPrefixActsAsRangeQueryFieldType.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/schema/TrieIntPrefixActsAsRangeQueryFieldType.java?rev=1560412&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/schema/TrieIntPrefixActsAsRangeQueryFieldType.java (added)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/schema/TrieIntPrefixActsAsRangeQueryFieldType.java Wed Jan 22 16:50:07 2014
@@ -0,0 +1,33 @@
+package org.apache.solr.schema;
+
+/*
+ * 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.search.Query;
+import org.apache.solr.search.QParser;
+
+/**
+ * Custom field type that overrides the prefix query behavior to map "X*" to [X TO Integer.MAX_VALUE].
+ * * This is used for testing overridded prefix query for custom fields in TestOverriddenPrefixQueryForCustomFieldType
+ */
+public class TrieIntPrefixActsAsRangeQueryFieldType extends TrieIntField {
+
+ public Query getPrefixQuery(QParser parser, SchemaField sf, String termStr) {
+ return getRangeQuery(parser, sf, termStr, new String(Integer.MAX_VALUE + ""), true, false);
+ }
+
+}
Added: lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestOverriddenPrefixQueryForCustomFieldType.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestOverriddenPrefixQueryForCustomFieldType.java?rev=1560412&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestOverriddenPrefixQueryForCustomFieldType.java (added)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestOverriddenPrefixQueryForCustomFieldType.java Wed Jan 22 16:50:07 2014
@@ -0,0 +1,152 @@
+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.search.*;
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.request.SolrRequestInfo;
+import org.apache.solr.response.SolrQueryResponse;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.Random;
+
+public class TestOverriddenPrefixQueryForCustomFieldType extends SolrTestCaseJ4 {
+
+ private static int[] counts= new int[2];
+ private static int otherCounts;
+ String[] otherTerms = {"this", "that", "those", "randomness"};
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ initCore("solrconfig-basic.xml", "schema-customfield.xml");
+ }
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ // if you override setUp or tearDown, you better call
+ // the super classes version
+ super.setUp();
+ clearIndex();
+ assertU(commit());
+ }
+
+ public void createIndex(int nDocs) {
+ Random r = random();
+
+ for (int i=0; i<nDocs; i++) {
+ SolrInputDocument doc = new SolrInputDocument();
+ doc.addField("id", ""+i);
+ int t = r.nextInt(1000);
+ if(t%3 == 0) {
+ doc.addField("swap_foo_bar_in_prefix_query", "foo" + i);
+ counts[0]++;
+ } else if(t%3 == 1) {
+ doc.addField("swap_foo_bar_in_prefix_query", "foo" + i);
+ doc.addField("swap_foo_bar_in_prefix_query", "spam" + i);
+ otherCounts++;
+ counts[0]++;
+ } else {
+ doc.addField("swap_foo_bar_in_prefix_query", "bar" + i);
+ counts[1]++;
+ }
+ //Randomly add noise
+
+ doc.addField("int_prefix_as_range", i);
+ doc.addField("intfield", i);
+
+ assertU(adoc(doc));
+ }
+ assertU(commit());
+ }
+
+ @Test
+ public void testPrefixQueries() throws Exception {
+ createIndex(100);
+ assertQ(req("fl", "id", "q", "*:*"), "//*[@numFound='100']");
+
+ // Test that prefix query actually transforms foo <-> bar.
+ assertQ(req("q", "swap_foo_bar_in_prefix_query:foo*"), "//*[@numFound='" + counts[1] + "']");
+
+ assertQ(req("q", "swap_foo_bar_in_prefix_query:bar*"), "//*[@numFound='" + counts[0] + "']");
+ assertQ(req("q", "swap_foo_bar_in_prefix_query:spam*"), "//*[@numFound='" + otherCounts + "']");
+
+ assertQ(req("q", "intfield:2*"), "//*[@numFound='11']"); //2 and the 10 in twenties
+
+ //Custom field should query for the range [2,MAX_INT)
+ assertQ(req("q", "int_prefix_as_range:2*"),"//*[@numFound='98']");
+
+ }
+
+ @Test
+ public void testQuery() throws Exception {
+ SolrQueryRequest req = req("myField","swap_foo_bar_in_prefix_query");
+
+ try {
+ assertQueryEquals(req,
+ "{!simple qf=$myField}foo*",
+ "{!simple qf=$myField}foo*",
+ "{!prefix f=swap_foo_bar_in_prefix_query}foo",
+ "{!lucene df=$myField v=foo*}",
+ "{!lucene}swap_foo_bar_in_prefix_query:foo*");
+
+ req.close();
+ req = req("myField", "int_prefix_as_range");
+ assertQueryEquals(req,
+ "{!lucene}int_prefix_as_range:[42 TO 2147483647}",
+ "{!lucene}int_prefix_as_range:42*",
+ "{!prefix f=int_prefix_as_range}42",
+ "{!simple qf=int_prefix_as_range}42*",
+ "{!simple df=int_prefix_as_range}42*");
+
+ } finally {
+ req.close();
+ }
+ }
+
+ /**
+ * @see org.apache.lucene.search.QueryUtils#check
+ * @see org.apache.lucene.search.QueryUtils#checkEqual
+ */
+ protected void assertQueryEquals(final SolrQueryRequest req,
+ final String... inputs) throws Exception {
+
+ final Query[] queries = new Query[inputs.length];
+
+ try {
+ SolrQueryResponse rsp = new SolrQueryResponse();
+ SolrRequestInfo.setRequestInfo(new SolrRequestInfo(req, rsp));
+ for (int i = 0; i < inputs.length; i++) {
+ queries[i] = (QParser.getParser(inputs[i], null, req).getQuery());
+ }
+ } finally {
+ SolrRequestInfo.clearRequestInfo();
+ }
+
+ for (int i = 0; i < queries.length; i++) {
+ org.apache.lucene.search.QueryUtils.check(queries[i]);
+ for (int j = i; j < queries.length; j++) {
+ org.apache.lucene.search.QueryUtils.checkEqual(queries[i], queries[j]);
+ }
+ }
+ }
+}