| Index: src/java/org/apache/lucene/queryParser/QueryParser.jj |
| =================================================================== |
| --- src/java/org/apache/lucene/queryParser/QueryParser.jj (revision 797318) |
| +++ src/java/org/apache/lucene/queryParser/QueryParser.jj (working copy) |
| @@ -119,7 +119,10 @@ |
| * use a different method for date conversion. |
| * </p> |
| * |
| - * <p>Note that QueryParser is <em>not</em> thread-safe.</p> |
| + * <p>Note that QueryParser is <em>not</em> thread-safe.</p> |
| + * |
| + * @deprecated use new the flexible query parser instead |
| + * |
| */ |
| public class QueryParser { |
| |
| Index: src/java/org/apache/lucene/queryParser/ParseException.java |
| =================================================================== |
| --- src/java/org/apache/lucene/queryParser/ParseException.java (revision 797318) |
| +++ src/java/org/apache/lucene/queryParser/ParseException.java (working copy) |
| @@ -10,6 +10,9 @@ |
| * |
| * You can modify this class to customize your error reporting |
| * mechanisms so long as you retain the public fields. |
| + * |
| + * @deprecated use new the flexible query parser instead: {@link org.apache.lucene.queryParser.original.parser.ParseException} |
| + * |
| */ |
| public class ParseException extends Exception { |
| |
| Index: src/java/org/apache/lucene/queryParser/QueryParserConstants.java |
| =================================================================== |
| --- src/java/org/apache/lucene/queryParser/QueryParserConstants.java (revision 797318) |
| +++ src/java/org/apache/lucene/queryParser/QueryParserConstants.java (working copy) |
| @@ -5,6 +5,9 @@ |
| /** |
| * Token literal values and constants. |
| * Generated by org.javacc.parser.OtherFilesGen#start() |
| + * |
| + * @deprecated use new the flexible query parser instead: {@link org.apache.lucene.queryParser.original.parser.QueryParserConstants} |
| + * |
| */ |
| public interface QueryParserConstants { |
| |
| Index: src/java/org/apache/lucene/queryParser/ComplexPhraseQueryParser.java |
| =================================================================== |
| --- src/java/org/apache/lucene/queryParser/ComplexPhraseQueryParser.java (revision 797318) |
| +++ src/java/org/apache/lucene/queryParser/ComplexPhraseQueryParser.java (working copy) |
| @@ -53,8 +53,8 @@ |
| * currently simply feeds all phrase content through an analyzer to select |
| * phrase terms - any "special" syntax such as * ~ * etc are not given special |
| * status |
| - * |
| - * |
| + * |
| + * @deprecated use new the flexible query parser instead |
| */ |
| public class ComplexPhraseQueryParser extends QueryParser { |
| private ArrayList/*<ComplexPhraseQuery>*/complexPhrases = null; |
| Index: src/java/org/apache/lucene/queryParser/TokenMgrError.java |
| =================================================================== |
| --- src/java/org/apache/lucene/queryParser/TokenMgrError.java (revision 797318) |
| +++ src/java/org/apache/lucene/queryParser/TokenMgrError.java (working copy) |
| @@ -2,7 +2,11 @@ |
| /* JavaCCOptions: */ |
| package org.apache.lucene.queryParser; |
| |
| -/** Token Manager Error. */ |
| +/** Token Manager Error. |
| + * |
| + * @deprecated use new the flexible query parser instead: {@link org.apache.lucene.queryParser.original.parser.TokenMgrError} |
| + * |
| + */ |
| public class TokenMgrError extends Error |
| { |
| |
| Index: src/java/org/apache/lucene/queryParser/Token.java |
| =================================================================== |
| --- src/java/org/apache/lucene/queryParser/Token.java (revision 797318) |
| +++ src/java/org/apache/lucene/queryParser/Token.java (working copy) |
| @@ -4,6 +4,9 @@ |
| |
| /** |
| * Describes the input token stream. |
| + * |
| + * @deprecated use new the flexible query parser instead: {@link org.apache.lucene.queryParser.original.parser.Token} |
| + * |
| */ |
| |
| public class Token { |
| Index: src/java/org/apache/lucene/queryParser/CharStream.java |
| =================================================================== |
| --- src/java/org/apache/lucene/queryParser/CharStream.java (revision 797318) |
| +++ src/java/org/apache/lucene/queryParser/CharStream.java (working copy) |
| @@ -15,6 +15,8 @@ |
| * column number and the String that constitutes a token and are not used |
| * by the lexer. Hence their implementation won't affect the generated lexer's |
| * operation. |
| + * |
| + * @deprecated this class will be removed in Lucene 3.0, when the {@link QueryParser} is removed |
| */ |
| |
| public interface CharStream { |
| Index: src/java/org/apache/lucene/queryParser/QueryParserTokenManager.java |
| =================================================================== |
| --- src/java/org/apache/lucene/queryParser/QueryParserTokenManager.java (revision 797318) |
| +++ src/java/org/apache/lucene/queryParser/QueryParserTokenManager.java (working copy) |
| @@ -33,7 +33,11 @@ |
| import org.apache.lucene.search.WildcardQuery; |
| import org.apache.lucene.util.Parameter; |
| |
| -/** Token Manager. */ |
| +/** Token Manager. |
| + * |
| + * @deprecated use new the flexible query parser instead |
| + * |
| + */ |
| public class QueryParserTokenManager implements QueryParserConstants |
| { |
| |
| Index: src/java/org/apache/lucene/queryParser/package.html |
| =================================================================== |
| --- src/java/org/apache/lucene/queryParser/package.html (revision 797318) |
| +++ src/java/org/apache/lucene/queryParser/package.html (working copy) |
| @@ -20,6 +20,8 @@ |
| <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| </head> |
| <body> |
| +NOTE: Please look into lucene contrib/queryparser for the new flexible queryparser api. |
| + |
| A simple query parser implemented with JavaCC. |
| <p>Note that JavaCC defines lots of public classes, methods and fields |
| that do not need to be public. These clutter the documentation. |
| Index: src/java/org/apache/lucene/queryParser/FastCharStream.java |
| =================================================================== |
| --- src/java/org/apache/lucene/queryParser/FastCharStream.java (revision 797318) |
| +++ src/java/org/apache/lucene/queryParser/FastCharStream.java (working copy) |
| @@ -16,6 +16,7 @@ |
| * 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 java.io.*; |
| @@ -23,7 +24,11 @@ |
| /** An efficient implementation of JavaCC's CharStream interface. <p>Note that |
| * this does not do line-number counting, but instead keeps track of the |
| * character position of the token in the input, as required by Lucene's {@link |
| - * org.apache.lucene.analysis.Token} API. */ |
| + * org.apache.lucene.analysis.Token} API. |
| + * |
| + * @deprecated this class will be removed in Lucene 3.0, when the {@link QueryParser} is removed |
| + * |
| + * */ |
| public final class FastCharStream implements CharStream { |
| char[] buffer = null; |
| |
| Index: src/java/org/apache/lucene/queryParser/MultiFieldQueryParser.java |
| =================================================================== |
| --- src/java/org/apache/lucene/queryParser/MultiFieldQueryParser.java (revision 797318) |
| +++ src/java/org/apache/lucene/queryParser/MultiFieldQueryParser.java (working copy) |
| @@ -20,7 +20,6 @@ |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| -import java.util.Vector; |
| |
| import org.apache.lucene.analysis.Analyzer; |
| import org.apache.lucene.search.BooleanClause; |
| @@ -31,7 +30,13 @@ |
| |
| /** |
| * A QueryParser which constructs queries to search multiple fields. |
| - * |
| + * |
| + * @deprecated This class will be removed in Lucene 3.0, {@link LuceneQueryParserHelper} should be used instead, |
| + * which is currently in queryparser contrib. The static methods can be found in {@link QueryParserUtil} class. |
| + * |
| + * @see LuceneQueryParserHelper |
| + * @see LuceneQueryConfigHandler#setMultiFields(CharSequence[]) |
| + * @see LuceneQueryConfigHandler#setFieldsBoost(Map) |
| * |
| * @version $Revision$ |
| */ |
| Index: src/java/org/apache/lucene/queryParser/QueryParser.java |
| =================================================================== |
| --- src/java/org/apache/lucene/queryParser/QueryParser.java (revision 797318) |
| +++ src/java/org/apache/lucene/queryParser/QueryParser.java (working copy) |
| @@ -96,6 +96,9 @@ |
| * </p> |
| * |
| * <p>Note that QueryParser is <em>not</em> thread-safe.</p> |
| + * |
| + * @deprecated This class will be removed in Lucene 3.0, {@link LuceneQueryParserHelper} should be used instead, |
| + * which is currently in queryparser contrib. The method {@link #escape(String)} was moved to {@link QueryParserUtil} class. |
| */ |
| public class QueryParser implements QueryParserConstants { |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/config/package.html |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/config/package.html (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/config/package.html (revision 0) |
| @@ -0,0 +1,48 @@ |
| +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> |
| +<!-- |
| + 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. |
| +--> |
| +<html> |
| +<head> |
| + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| +</head> |
| +<body> |
| + |
| +<h2>Query Configuration Interfaces</h2> |
| +<p> |
| +The package <tt>org.apache.lucene.queryParser.config</tt> contains query configuration handler |
| +abstract class that all config handlers should extend. |
| +</p> |
| +<p> |
| +See {@link org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler} for a reference |
| +implementation. |
| +</p> |
| +<p> |
| +{@link org.apache.lucene.queryParser.config.FieldConfig} and {@link org.apache.lucene.queryParser.config.Queryconfig} |
| + should use {@link org.apache.lucene.util.Attribute} to store all attributes |
| +required by the config implementation. See <tt>org.apache.lucene.queryParser.original.config.*Attribute</tt> |
| +for reference implementation. |
| +</p> |
| +<p> |
| +The {@link org.apache.lucene.queryParser.config.QueryConfigHandler}, {@link org.apache.lucene.queryParser.config.FieldConfig}, |
| + and {@link org.apache.lucene.util.Attribute}s are used in the processors to access config |
| +information in a flexible and independent way. |
| +See {@link org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor} for a |
| +reference implementation. |
| +</p> |
| +</body> |
| +</html |
| + |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/config/package.html |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/config/QueryConfigHandler.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/config/QueryConfigHandler.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/config/QueryConfigHandler.java (revision 0) |
| @@ -0,0 +1,55 @@ |
| +package org.apache.lucene.queryParser.config; |
| + |
| +/** |
| + * 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.processors.QueryNodeProcessor; |
| +import org.apache.lucene.util.Attribute; |
| +import org.apache.lucene.util.AttributeSource; |
| + |
| +/** |
| + * {@link QueryConfigHandler} should be implemented by classes that intends to |
| + * provide configuration to {@link QueryNodeProcessor} objects. |
| + * |
| + * This class extends {@link AttributeSource}, so {@link Attribute}s can be |
| + * attached to it. |
| + * |
| + * The class that implements this class should also provides {@link FieldConfig} |
| + * objects for each collection field. |
| + * |
| + * @see Attribute |
| + * @see FieldConfig |
| + * @see FieldConfigListener |
| + */ |
| +public abstract class QueryConfigHandler extends AttributeSource { |
| + |
| + /** |
| + * The class that implements this method should return an implementation of |
| + * {@link FieldConfig} for a specific field name. If the implemented |
| + * {@link QueryConfigHandler} does not know a specific field name, it may |
| + * return <code>null</code>, indicating there is no configuration for that |
| + * field. |
| + * |
| + * @param fieldName |
| + * the field name |
| + * @return a {@link FieldConfig} object containing the field name |
| + * configuration or <code>null</code>, if the implemented |
| + * {@link QueryConfigHandler} has no configuration for that field |
| + */ |
| + public abstract FieldConfig getFieldConfig(CharSequence fieldName); |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/config/QueryConfigHandler.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/config/FieldConfig.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/config/FieldConfig.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/config/FieldConfig.java (revision 0) |
| @@ -0,0 +1,60 @@ |
| +package org.apache.lucene.queryParser.config; |
| + |
| +/** |
| + * 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.util.AttributeSource; |
| + |
| +/** |
| + * This class represents a field configuration. Every configuration should be |
| + * set using the methods inherited from {@link AttributeSource}. |
| + * |
| + * @see QueryConfigHandler |
| + * @see org.apache.lucene.util.Attribute |
| + */ |
| +public class FieldConfig extends AttributeSource { |
| + |
| + private CharSequence fieldName; |
| + |
| + /** |
| + * Constructs a {@link FieldConfig} |
| + * |
| + * @param fieldName |
| + * the field name, it cannot be null |
| + * @throws IllegalArgumentException |
| + * if the field name is null |
| + */ |
| + public FieldConfig(CharSequence fieldName) { |
| + |
| + if (fieldName == null) { |
| + throw new IllegalArgumentException("field name should not be null!"); |
| + } |
| + |
| + this.fieldName = fieldName; |
| + |
| + } |
| + |
| + /** |
| + * Returns the field name this configuration represents. |
| + * |
| + * @return the field name |
| + */ |
| + public CharSequence getFieldName() { |
| + return this.fieldName; |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/config/FieldConfig.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/config/FieldConfigListener.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/config/FieldConfigListener.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/config/FieldConfigListener.java (revision 0) |
| @@ -0,0 +1,21 @@ |
| +package org.apache.lucene.queryParser.config; |
| + |
| +/** |
| + * This interface should be implemented by classes that wants to listen for |
| + * field configuration requests. The implementation receives a |
| + * {@link FieldConfig} object and may add/change its attributes. |
| + * |
| + * @see FieldConfig |
| + * @see QueryConfigHandler |
| + */ |
| +public interface FieldConfigListener { |
| + |
| + /** |
| + * This method is called ever time a field configuration is requested. |
| + * |
| + * @param fieldConfig |
| + * the field configuration requested, should never be null |
| + */ |
| + void getQueryConfig(FieldConfig fieldConfig); |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/config/FieldConfigListener.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/config/DefaultQueryConfigHandler.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/config/DefaultQueryConfigHandler.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/config/DefaultQueryConfigHandler.java (revision 0) |
| @@ -0,0 +1,42 @@ |
| +package org.apache.lucene.queryParser.config; |
| + |
| +import java.util.LinkedList; |
| + |
| +/** |
| + * This class can be used to hold any query configuration and no field |
| + * configuration. For field configuration, it creates a empty |
| + * {@link FieldConfig} object and delegate it to field config listeners, they |
| + * are responsible for setting up all the field configuration. |
| + * |
| + * @see FieldConfigListener |
| + * @see FieldConfig |
| + * @see QueryConfigHandler |
| + */ |
| +public class DefaultQueryConfigHandler extends QueryConfigHandler { |
| + |
| + private LinkedList<FieldConfigListener> listeners = new LinkedList<FieldConfigListener>();; |
| + |
| + @Override |
| + public FieldConfig getFieldConfig(CharSequence fieldName) { |
| + FieldConfig fieldConfig = new FieldConfig(fieldName); |
| + |
| + for (FieldConfigListener listener : this.listeners) { |
| + listener.getQueryConfig(fieldConfig); |
| + } |
| + |
| + return fieldConfig; |
| + |
| + } |
| + |
| + /** |
| + * Adds a listener. The added listeners are called in the order they are |
| + * added. |
| + * |
| + * @param listener |
| + * the listener to be added |
| + */ |
| + public void addFieldConfigListener(FieldConfigListener listener) { |
| + this.listeners.add(listener); |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/config/DefaultQueryConfigHandler.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/package.html |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/package.html (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/package.html (revision 0) |
| @@ -0,0 +1,129 @@ |
| +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> |
| +<!-- |
| + 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. |
| +--> |
| +<html> |
| +<head> |
| + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| +</head> |
| +<body> |
| + |
| +<h2>Flexible Query Parser</h2> |
| +<p> |
| +Features: |
| + <ol> |
| + <li>Full support for lucene 2.4.2 syntax</li> |
| + <li>Full support for boolean logic (not enabled)</li> |
| + <li>QueryNode Trees - support for several syntaxes, |
| + that are convert into similar syntax QueryNode trees.</li> |
| + <li>QueryNode Processors - Optimize, validate, rewrite the |
| + QueryNode trees</li> |
| + <li>Processors Pipelines - Select your favorite Processor |
| + and build a processor pipeline, to implement the features you need</li> |
| + <li>Config Interfaces - Allow the consumer of the Query Parser to implement |
| + a diff Config Handler Objects to suite their needs.</li> |
| + <li>Original Lucene Builders - convert queries into several lucene |
| + representations. supported conversion is using a 2.4 compatible logic</li> |
| + </ol> |
| +</p> |
| + |
| +<tt> |
| +<p> |
| +This new query parser was designed to have very generic |
| +architecture, so that this query parser can be easily used for different |
| +products with varying query syntaxes. This code is much more |
| +flexible and extensible than the current Lucene query parser. |
| +</p> |
| +<p> |
| +The new query parser goal is to separate syntax and semantics of a query. E.g. 'a AND |
| +b', '+a +b', 'AND(a,b)' could be different syntaxes for the same query. |
| +It distinguishes the semantics of the different query components, e.g. |
| +whether and how to tokenize/lemmatize/normalize the different terms or |
| +which Query objects to create for the terms. It allows to |
| +write a parser with a new syntax, while reusing the underlying |
| +semantics, as quickly as possible. |
| +</p> |
| +<p> |
| +The query parser has three layers and its core is what we call the |
| +QueryNode tree. It is a tree that initially represents the syntax of the |
| +original query, e.g. for 'a AND b': |
| +</p> |
| +<p> |
| + AND<br/> |
| + / \<br/> |
| +A B<br/> |
| +</p> |
| +<p> |
| +The three layers are:<br/> |
| +1. QueryParser<br/> |
| +2. QueryNodeProcessor<br/> |
| +3. QueryBuilder<br/> |
| +</p> |
| +<p> |
| +1. The upper layer is the text parsing layer which simply transforms the |
| +query text string into a {@link org.apache.lucene.queryParser.nodes.QueryNode} tree. Every text parser |
| +must implement the interface {@link org.apache.lucene.queryParser.parser.Parser}, Lucene default implementations |
| +implements it using JavaCC. |
| +</p> |
| +2. The query node processors do most of the work. It is in fact a |
| +configurable chain of processors. Each processors can walk the tree and |
| +modify nodes or even the tree's structure. That makes it possible to |
| +e.g. do query optimization before the query is executed or to tokenize |
| +terms. |
| +</p> |
| +<p> |
| +3. The third layer is a configurable map of builders, which map {@link QueryNode} types to its specific |
| +builder that will transform the QueryNode into Lucene Query object. |
| +</p> |
| +<p> |
| +Furthermore, the query parser uses flexible configuration objects, which |
| +are based on AttributeSource/Attribute. It also uses message classes that |
| +allow to attach resource bundles. This makes it possible to translate |
| +messages, which is an important feature of a query parser. |
| +</p> |
| +<p> |
| +This design allows to develop different query syntaxes very quickly. |
| +</p> |
| +<p> |
| +A Lucene-compatible syntax is implemented using this new query parser |
| +API and is located under org.apache.lucene.queryParser.original. |
| +<p> |
| +To make it simpler to use the new query parser, specially for people that does not |
| +want to extend it, the class {@link org.apache.lucene.queryParser.original.LuceneQueryParserHelper} |
| +may be helpful. It uses the default Lucene query processors, text parser and builders, so |
| +you don't need to worry about dealing with those. |
| + |
| +{@link org.apache.lucene.queryParser.original.LuceneQueryParserHelper} usage: |
| +<ul> |
| +LuceneQueryParserHelper qpHelper = new LuceneQueryParserHelper(); |
| + |
| +<br/><br/> |
| +LuceneQueryConfigHandler config = qpHelper.getQueryConfigHandler(); |
| +<br/><br/> |
| +config.setAllowLeadingWildcard(true); |
| +<br/><br/> |
| +config.setAnalyzer(new WhitespaceAnalyzer()); |
| +<br/><br/> |
| +Query query = qpHelper.parse("apache AND lucene", "defaultField"); |
| +</ul> |
| +To make it easy for people who are using current Lucene's query parser to switch to |
| +the new one, there is a QueryParserWrapper under org.apache.lucene.queryParser.original |
| +that keeps the old query parser interface, but uses the new query parser features. |
| +</p> |
| +</p> |
| +</tt> |
| +</body> |
| +</html> |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/package.html |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/QueryNodeError.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/QueryNodeError.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/QueryNodeError.java (revision 0) |
| @@ -0,0 +1,75 @@ |
| +package org.apache.lucene.queryParser; |
| + |
| +/** |
| + * 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.messages.Message; |
| +import org.apache.lucene.messages.NLSException; |
| + |
| +/** |
| + * Error class with NLS support |
| + * |
| + * @see org.apache.lucene.messages.NLS |
| + * @see org.apache.lucene.messages.Message |
| + */ |
| +public class QueryNodeError extends Error implements NLSException { |
| + |
| + private static final long serialVersionUID = 1804855832182710327L; |
| + private Message message; |
| + |
| + /** |
| + * @param message |
| + * - NLS Message Object |
| + */ |
| + public QueryNodeError(Message message) { |
| + super(message.getKey()); |
| + |
| + this.message = message; |
| + |
| + } |
| + |
| + /** |
| + * @param throwable |
| + * - @see java.lang.Error |
| + */ |
| + public QueryNodeError(Throwable throwable) { |
| + super(throwable); |
| + } |
| + |
| + /** |
| + * @param message |
| + * - NLS Message Object |
| + * @param throwable |
| + * - @see java.lang.Error |
| + */ |
| + public QueryNodeError(Message message, Throwable throwable) { |
| + super(message.getKey(), throwable); |
| + |
| + this.message = message; |
| + |
| + } |
| + |
| + /* |
| + * (non-Javadoc) |
| + * |
| + * @see org.apache.lucene.messages.NLSException#getMessageObject() |
| + */ |
| + public Message getMessageObject() { |
| + return this.message; |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/QueryNodeError.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/QueryParserHelper.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/QueryParserHelper.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/QueryParserHelper.java (revision 0) |
| @@ -0,0 +1,261 @@ |
| +package org.apache.lucene.queryParser; |
| + |
| +/** |
| + * 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.builders.QueryBuilder; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.parser.Parser; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessor; |
| + |
| +/** |
| + * <p> |
| + * This class is a helper for the query parser framework, it does all the three |
| + * query parser phrases at once: text parsing, query processing and query |
| + * building. |
| + * </p> |
| + * <p> |
| + * It contains methods that allows the user to change the implementation used on |
| + * the three phases. |
| + * </p> |
| + * |
| + * @see QueryNodeProcessor |
| + * @see Parser |
| + * @see QueryBuilder |
| + * @see QueryConfigHandler |
| + */ |
| +public class QueryParserHelper<C extends QueryConfigHandler, T extends Parser, P extends QueryNodeProcessor, B extends QueryBuilder> { |
| + |
| + private P processor; |
| + |
| + private T textParser; |
| + |
| + private B queryBuilder; |
| + |
| + private C config; |
| + |
| + /** |
| + * Creates a query parser helper object using the specified configuration, |
| + * text parser, processor and builder. |
| + * |
| + * @param queryConfigHandler |
| + * the query configuration handler that will be initially set to this |
| + * helper |
| + * @param textParser |
| + * the text parser that will be initially set to this helper |
| + * @param processor |
| + * the query processor that will be initially set to this helper |
| + * @param builder |
| + * the query builder that will be initially set to this helper |
| + * |
| + * @see QueryNodeProcessor |
| + * @see Parser |
| + * @see QueryBuilder |
| + * @see QueryConfigHandler |
| + */ |
| + public QueryParserHelper(C queryConfigHandler, T textParser, P processor, |
| + B builder) { |
| + this.textParser = textParser; |
| + this.config = queryConfigHandler; |
| + this.processor = processor; |
| + this.queryBuilder = builder; |
| + |
| + if (processor != null) { |
| + processor.setQueryConfigHandler(queryConfigHandler); |
| + } |
| + |
| + } |
| + |
| + /** |
| + * Returns the processor object used to process the query node tree, it |
| + * returns <code>null</code> if no processor is used. |
| + * |
| + * @return the actual processor used to process the query node tree, |
| + * <code>null</code> if no processor is used |
| + * |
| + * @see QueryNodeProcessor |
| + * @see #setQueryNodeProcessor(QueryNodeProcessor) |
| + */ |
| + public P getQueryNodeProcessor() { |
| + return processor; |
| + } |
| + |
| + /** |
| + * Sets the processor that will be used to process the query node tree. If |
| + * there is any {@link QueryConfigHandler} returned by |
| + * {@link #getQueryConfigHandler()}, it will be set on the processor. The |
| + * argument can be <code>null</code>, which means that no processor will be |
| + * used to process the query node tree. |
| + * |
| + * @param processor |
| + * the processor that will be used to process the query node tree, |
| + * this argument can be <code>null</code> |
| + * |
| + * @see #getQueryNodeProcessor() |
| + * @see QueryNodeProcessor |
| + */ |
| + public void setQueryNodeProcessor(P processor) { |
| + this.processor = processor; |
| + this.processor.setQueryConfigHandler(getQueryConfigHandler()); |
| + |
| + } |
| + |
| + /** |
| + * Sets the text parser that will be used to parse the query string, it cannot |
| + * be <code>null</code>. |
| + * |
| + * @param textParser |
| + * the text parser that will be used to parse the query string |
| + * |
| + * @see #getTextParser() |
| + * @see Parser |
| + */ |
| + public void setTextParser(T textParser) { |
| + |
| + if (textParser == null) { |
| + throw new IllegalArgumentException("textParser should not be null!"); |
| + } |
| + |
| + this.textParser = textParser; |
| + |
| + } |
| + |
| + /** |
| + * The query builder that will be used to build an object from the query node |
| + * tree. It cannot be <code>null</code>. |
| + * |
| + * @param queryBuilder |
| + * the query builder used to build something from the query node tree |
| + * |
| + * @see #getQueryBuilder() |
| + * @see QueryBuilder |
| + */ |
| + public void setQueryBuilder(B queryBuilder) { |
| + |
| + if (queryBuilder == null) { |
| + throw new IllegalArgumentException("queryBuilder should not be null!"); |
| + } |
| + |
| + this.queryBuilder = queryBuilder; |
| + |
| + } |
| + |
| + /** |
| + * Returns the query configuration handler, which is used during the query |
| + * node tree processing. It can be <code>null</code>. |
| + * |
| + * @return the query configuration handler used on the query processing, |
| + * <code>null</code> if not query configuration handler is defined |
| + * |
| + * @see QueryConfigHandler |
| + * @see #setQueryConfigHandler(QueryConfigHandler) |
| + */ |
| + public C getQueryConfigHandler() { |
| + return config; |
| + } |
| + |
| + /** |
| + * Returns the query builder used to build a object from the query node tree. |
| + * The object produced by this builder is returned by |
| + * {@link #parse(String, String)}. |
| + * |
| + * @return the query builder |
| + * |
| + * @see #setQueryBuilder(QueryBuilder) |
| + * @see QueryBuilder |
| + */ |
| + public B getQueryBuilder() { |
| + return this.queryBuilder; |
| + } |
| + |
| + /** |
| + * Returns the text parser used to build a query node tree from a query |
| + * string. The default text parser instance returned by this method is a |
| + * {@link Parser}. |
| + * |
| + * @return the text parse used to build query node trees. |
| + * |
| + * @see Parser |
| + * @see #setTextParser(Parser) |
| + */ |
| + public T getTextParser() { |
| + return this.textParser; |
| + } |
| + |
| + /** |
| + * Sets the query configuration handler that will be used during query |
| + * processing. It can be <code>null</code>. It's also set to the processor |
| + * returned by {@link #getQueryNodeProcessor()}. |
| + * |
| + * @param config |
| + * the query configuration handler used during query processing, it |
| + * can be <code>null</code> |
| + * |
| + * @see #getQueryConfigHandler() |
| + * @see QueryConfigHandler |
| + */ |
| + public void setQueryConfigHandler(C config) { |
| + this.config = config; |
| + QueryNodeProcessor processor = getQueryNodeProcessor(); |
| + |
| + if (processor != null) { |
| + processor.setQueryConfigHandler(config); |
| + } |
| + |
| + } |
| + |
| + /** |
| + * Parses a query string to an object, usually some query object. <br/> |
| + * <br/> |
| + * In this method the three phases are executed: <br/> |
| + * <br/> |
| + * 1st - the query string is parsed using the |
| + * text parser returned by {@link #getTextParser()}, the result is a query |
| + * node tree <br/> |
| + * <br/> |
| + * 2nd - the query node tree is processed by the |
| + * processor returned by {@link #getQueryNodeProcessor()} <br/> |
| + * <br/> |
| + * 3th - a object is built from the query node |
| + * tree using the builder returned by {@link #getQueryBuilder()} |
| + * |
| + * @param query |
| + * the query string |
| + * @param defaultField |
| + * the default field used by the text parser |
| + * |
| + * @return the object built from the query |
| + * |
| + * @throws QueryNodeException |
| + * if something wrong happens along the three phases |
| + */ |
| + public Object parse(String query, String defaultField) |
| + throws QueryNodeException { |
| + QueryNode queryTree = getTextParser().parse(query, defaultField); |
| + |
| + QueryNodeProcessor processor = getQueryNodeProcessor(); |
| + |
| + if (processor != null) { |
| + queryTree = processor.process(queryTree); |
| + } |
| + |
| + return getQueryBuilder().build(queryTree); |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/QueryParserHelper.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/messages/QueryParserMessages.properties |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/messages/QueryParserMessages.properties (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/messages/QueryParserMessages.properties (revision 0) |
| @@ -0,0 +1,45 @@ |
| +# This resource bundle contains Flexible Query Parser messages. |
| + |
| +#<CREATEDBY>Apache Lucene Community</CREATEDBY> |
| +# <REPLACEMENT arg="{0}" value="detailed_message"/> |
| +INVALID_SYNTAX = Syntax Error: {0} |
| + |
| +#<CREATEDBY>Apache Lucene Community</CREATEDBY> |
| +# <REPLACEMENT arg="{0}" value="invalid_query"/> |
| +# <REPLACEMENT arg="{1}" value="detailed_message"/> |
| +INVALID_SYNTAX_CANNOT_PARSE = Syntax Error, cannot parse {0}: {1} |
| + |
| +#<CREATEDBY>Apache Lucene Community</CREATEDBY> |
| +INVALID_SYNTAX_FUZZY_LIMITS = The similarity value for a fuzzy search must be between 0.0 and 1.0. |
| + |
| +#<CREATEDBY>Apache Lucene Community</CREATEDBY> |
| +INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION = Truncated unicode escape sequence. |
| + |
| +#<CREATEDBY>Apache Lucene Community</CREATEDBY> |
| +INVALID_SYNTAX_ESCAPE_CHARACTER = Term can not end with escape character. |
| + |
| +#<CREATEDBY>Apache Lucene Community</CREATEDBY> |
| +INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE = None-hex character in unicode escape sequence: {0} |
| + |
| +#<CREATEDBY>Apache Lucene Community</CREATEDBY> |
| +NODE_ACTION_NOT_SUPPORTED = This node does not support this action. |
| + |
| +#<CREATEDBY>Apache Lucene Community</CREATEDBY> |
| +PARAMETER_VALUE_NOT_SUPPORTED = Parameter {1} with value {0} not supported. |
| + |
| +#<CREATEDBY>Apache Lucene Community</CREATEDBY> |
| +# <REPLACEMENT arg="{0}" value="query"/> |
| +# <REPLACEMENT arg="{1}" value="error/class"/> |
| +LUCENE_QUERY_CONVERSION_ERROR = Cannot convert query to lucene syntax: {0} error: {1} |
| + |
| +#<CREATEDBY>Apache Lucene Community</CREATEDBY> |
| +EMPTY_MESSAGE = |
| + |
| +#<CREATEDBY>Apache Lucene Community</CREATEDBY> |
| +WILDCARD_NOT_SUPPORTED = Wildcard is not supported for query: {0} |
| + |
| +#<CREATEDBY>Apache Lucene Community</CREATEDBY> |
| +TOO_MANY_BOOLEAN_CLAUSES = Too many boolean clauses, the maximum supported is {0}: {1} |
| + |
| +#<CREATEDBY>Apache Lucene Community</CREATEDBY> |
| +LEADING_WILDCARD_NOT_ALLOWED = Leading wildcard is not allowed: {0} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/messages/QueryParserMessages.properties |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/messages/QueryParserMessages.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/messages/QueryParserMessages.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/messages/QueryParserMessages.java (revision 0) |
| @@ -0,0 +1,54 @@ |
| +package org.apache.lucene.queryParser.messages; |
| + |
| +/** |
| + * 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.messages.NLS; |
| + |
| +/** |
| + * Flexible Query Parser message bundle class |
| + */ |
| +public class QueryParserMessages extends NLS { |
| + |
| + private static final String BUNDLE_NAME = QueryParserMessages.class.getName(); |
| + |
| + private QueryParserMessages() { |
| + // Do not instantiate |
| + } |
| + |
| + static { |
| + // register all string ids with NLS class and initialize static string |
| + // values |
| + NLS.initializeMessages(BUNDLE_NAME, QueryParserMessages.class); |
| + } |
| + |
| + // static string must match the strings in the property files. |
| + public static String INVALID_SYNTAX; |
| + public static String INVALID_SYNTAX_CANNOT_PARSE; |
| + public static String INVALID_SYNTAX_FUZZY_LIMITS; |
| + public static String INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION; |
| + public static String INVALID_SYNTAX_ESCAPE_CHARACTER; |
| + public static String INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE; |
| + public static String NODE_ACTION_NOT_SUPPORTED; |
| + public static String PARAMETER_VALUE_NOT_SUPPORTED; |
| + public static String LUCENE_QUERY_CONVERSION_ERROR; |
| + public static String EMPTY_MESSAGE; |
| + public static String WILDCARD_NOT_SUPPORTED; |
| + public static String TOO_MANY_BOOLEAN_CLAUSES; |
| + public static String LEADING_WILDCARD_NOT_ALLOWED; |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/messages/QueryParserMessages.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/messages/package.html |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/messages/package.html (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/messages/package.html (revision 0) |
| @@ -0,0 +1,25 @@ |
| +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> |
| +<!-- |
| + 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. |
| +--> |
| +<html> |
| +<head> |
| + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| +</head> |
| +<body> |
| +Messages for the Flexible Query Parser, they use <tt>org.apache.lucene.messages.NLS</tt> API. |
| +</body> |
| +</html> |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/messages/package.html |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/builders/QueryBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/builders/QueryBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/builders/QueryBuilder.java (revision 0) |
| @@ -0,0 +1,43 @@ |
| +package org.apache.lucene.queryParser.builders; |
| + |
| +/** |
| + * 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.QueryNodeException; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| + |
| +/** |
| + * This interface is used by implementors classes that builds some kind of |
| + * object from a query tree. |
| + * |
| + * @see QueryTreeBuilder |
| + */ |
| +public interface QueryBuilder { |
| + |
| + /** |
| + * Builds some kind of object from a query tree. |
| + * |
| + * @param queryNode |
| + * the query tree root node |
| + * |
| + * @return some object generated from the query tree |
| + * |
| + * @throws QueryNodeException |
| + */ |
| + Object build(QueryNode queryNode) throws QueryNodeException; |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/builders/QueryBuilder.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/builders/package.html |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/builders/package.html (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/builders/package.html (revision 0) |
| @@ -0,0 +1,33 @@ |
| +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> |
| +<!-- |
| + 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. |
| +--> |
| +<html> |
| +<head> |
| + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| +</head> |
| +<body> |
| + |
| +<h2>Query Parser Builders</h2> |
| +<p> |
| +The package <tt>org.apache.lucene.queryParser.builders</tt> contains the interface that |
| +builders must implement, it also contain a utility {@link org.apache.lucene.queryParser.builders.QueryTreeBuilder}, which walks the tree |
| +and call the Builder for each node in the tree. |
| +</p> |
| +<p> |
| +</p> |
| +</body> |
| +</html> |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/builders/package.html |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/builders/QueryTreeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/builders/QueryTreeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/builders/QueryTreeBuilder.java (revision 0) |
| @@ -0,0 +1,222 @@ |
| +package org.apache.lucene.queryParser.builders; |
| + |
| +/** |
| + * 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 java.util.HashMap; |
| +import java.util.List; |
| + |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.nodes.FieldableNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.parser.EscapeQuerySyntaxImpl; |
| + |
| +/** |
| + * This class should be used when there is a builder for each type of node. |
| + * |
| + * The type of node may be defined in 2 different ways: - by the field name, |
| + * when the node implements the {@link FieldableNode} interface - by its class, |
| + * it keeps checking the class and all the interfaces and classes this class |
| + * implements/extends until it finds a builder for that class/interface |
| + * |
| + * This class always check if there is a builder for the field name before it |
| + * checks for the node class. So, field name builders have precedence over class |
| + * builders. |
| + * |
| + * When a builder is found for a node, it's called and the node is passed to the |
| + * builder. If the returned built object is not <code>null</code>, it's tagged |
| + * on the node using the tag {@link QueryTreeBuilder#QUERY_TREE_BUILDER_TAGID}. |
| + * |
| + * The children are usually built before the parent node. However, if a builder |
| + * associated to a node is an instance of {@link QueryTreeBuilder}, the node is |
| + * delegated to this builder and it's responsible to build the node and its |
| + * children. |
| + * |
| + * @see QueryBuilder |
| + */ |
| +public class QueryTreeBuilder implements QueryBuilder { |
| + |
| + /** |
| + * This tag is used to tag the nodes in a query tree with the built objects |
| + * produced from their own associated builder. |
| + */ |
| + public static final String QUERY_TREE_BUILDER_TAGID = QueryTreeBuilder.class |
| + .getName(); |
| + |
| + private HashMap<Class<? extends QueryNode>, QueryBuilder> queryNodeBuilders; |
| + |
| + private HashMap<CharSequence, QueryBuilder> fieldNameBuilders; |
| + |
| + /** |
| + * {@link QueryTreeBuilder} constructor. |
| + */ |
| + public QueryTreeBuilder() { |
| + // empty constructor |
| + } |
| + |
| + /** |
| + * Associates a field name with a builder. |
| + * |
| + * @param fieldName |
| + * the field name |
| + * @param builder |
| + * the builder to be associated |
| + */ |
| + public void setBuilder(CharSequence fieldName, QueryBuilder builder) { |
| + |
| + if (this.fieldNameBuilders == null) { |
| + this.fieldNameBuilders = new HashMap<CharSequence, QueryBuilder>(); |
| + } |
| + |
| + this.fieldNameBuilders.put(fieldName, builder); |
| + |
| + } |
| + |
| + /** |
| + * Associates a class with a builder |
| + * |
| + * @param queryNodeClass |
| + * the class |
| + * @param builder |
| + * the builder to be associated |
| + */ |
| + public void setBuilder(Class<? extends QueryNode> queryNodeClass, |
| + QueryBuilder builder) { |
| + |
| + if (this.queryNodeBuilders == null) { |
| + this.queryNodeBuilders = new HashMap<Class<? extends QueryNode>, QueryBuilder>(); |
| + } |
| + |
| + this.queryNodeBuilders.put(queryNodeClass, builder); |
| + |
| + } |
| + |
| + private void process(QueryNode node) throws QueryNodeException { |
| + |
| + if (node != null) { |
| + QueryBuilder builder = getBuilder(node); |
| + |
| + if (!(builder instanceof QueryTreeBuilder)) { |
| + List<QueryNode> children = node.getChildren(); |
| + |
| + if (children != null) { |
| + |
| + for (QueryNode child : children) { |
| + process(child); |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + processNode(node, builder); |
| + |
| + } |
| + |
| + } |
| + |
| + private QueryBuilder getBuilder(QueryNode node) { |
| + QueryBuilder builder = null; |
| + |
| + if (this.fieldNameBuilders != null && node instanceof FieldableNode) { |
| + |
| + builder = this.fieldNameBuilders.get(((FieldableNode) node).getField()); |
| + |
| + } |
| + |
| + if (builder == null && this.queryNodeBuilders != null) { |
| + |
| + Class<?> clazz = node.getClass(); |
| + |
| + do { |
| + builder = getQueryBuilder(clazz); |
| + |
| + if (builder == null) { |
| + Class<?>[] classes = node.getClass().getInterfaces(); |
| + |
| + for (Class<?> actualClass : classes) { |
| + builder = getQueryBuilder(actualClass); |
| + |
| + if (builder != null) { |
| + break; |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + } while (builder == null && (clazz = clazz.getSuperclass()) != null); |
| + |
| + } |
| + |
| + return builder; |
| + |
| + } |
| + |
| + private void processNode(QueryNode node, QueryBuilder builder) |
| + throws QueryNodeException { |
| + |
| + if (builder == null) { |
| + |
| + throw new QueryNodeException(new MessageImpl( |
| + QueryParserMessages.LUCENE_QUERY_CONVERSION_ERROR, node |
| + .toQueryString(new EscapeQuerySyntaxImpl()), node.getClass() |
| + .getName())); |
| + |
| + } |
| + |
| + Object obj = builder.build(node); |
| + |
| + if (obj != null) { |
| + node.setTag(QUERY_TREE_BUILDER_TAGID, obj); |
| + } |
| + |
| + } |
| + |
| + private QueryBuilder getQueryBuilder(Class<?> clazz) { |
| + |
| + if (QueryNode.class.isAssignableFrom(clazz)) { |
| + return this.queryNodeBuilders.get(clazz); |
| + } |
| + |
| + return null; |
| + |
| + } |
| + |
| + /** |
| + * Builds some kind of object from a query tree. Each node in the query tree |
| + * is built using an specific builder associated to it. |
| + * |
| + * @param queryNode |
| + * the query tree root node |
| + * |
| + * @return the built object |
| + * |
| + * @throws QueryNodeException |
| + * if some node builder throws a {@link QueryNodeException} or if |
| + * there is a node which had no builder associated to it |
| + */ |
| + public Object build(QueryNode queryNode) throws QueryNodeException { |
| + process(queryNode); |
| + |
| + return queryNode.getTag(QUERY_TREE_BUILDER_TAGID); |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/builders/QueryTreeBuilder.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/QueryNodeParseException.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/QueryNodeParseException.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/QueryNodeParseException.java (revision 0) |
| @@ -0,0 +1,121 @@ |
| +package org.apache.lucene.queryParser; |
| + |
| +/** |
| + * 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.messages.Message; |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.parser.Parser; |
| + |
| +/** |
| + * This should be thrown when an exception happens during the query parsing from |
| + * string to the query node tree. |
| + * |
| + * @see QueryNodeException |
| + * @see Parser |
| + * @see QueryNode |
| + */ |
| +public class QueryNodeParseException extends QueryNodeException { |
| + |
| + private static final long serialVersionUID = 8197535103538766773L; |
| + |
| + private CharSequence query; |
| + |
| + private int beginColumn = -1; |
| + |
| + private int beginLine = -1; |
| + |
| + private String errorToken = ""; |
| + |
| + public QueryNodeParseException(Message message) { |
| + super(message); |
| + } |
| + |
| + public QueryNodeParseException(Throwable throwable) { |
| + super(throwable); |
| + } |
| + |
| + public QueryNodeParseException(Message message, Throwable throwable) { |
| + super(message, throwable); |
| + } |
| + |
| + public void setQuery(CharSequence query) { |
| + this.query = query; |
| + this.message = new MessageImpl( |
| + QueryParserMessages.INVALID_SYNTAX_CANNOT_PARSE, query, ""); |
| + } |
| + |
| + public CharSequence getQuery() { |
| + return this.query; |
| + } |
| + |
| + /** |
| + * @param errorToken |
| + * the errorToken in the query |
| + */ |
| + protected void setErrorToken(String errorToken) { |
| + this.errorToken = errorToken; |
| + } |
| + |
| + public String getErrorToken() { |
| + return this.errorToken; |
| + } |
| + |
| + public void setNonLocalizedMessage(Message message) { |
| + this.message = message; |
| + } |
| + |
| + /** |
| + * For EndOfLine and EndOfFile ("<EOF>") parsing problems the last char in the |
| + * string is returned For the case where the parser is not able to figure out |
| + * the line and column number -1 will be returned |
| + * |
| + * @return line where the problem was found |
| + */ |
| + public int getBeginLine() { |
| + return this.beginLine; |
| + } |
| + |
| + /** |
| + * For EndOfLine and EndOfFile ("<EOF>") parsing problems the last char in the |
| + * string is returned For the case where the parser is not able to figure out |
| + * the line and column number -1 will be returned |
| + * |
| + * @return column of the first char where the problem was found |
| + */ |
| + public int getBeginColumn() { |
| + return this.beginColumn; |
| + } |
| + |
| + /** |
| + * @param beginLine |
| + * the beginLine to set |
| + */ |
| + protected void setBeginLine(int beginLine) { |
| + this.beginLine = beginLine; |
| + } |
| + |
| + /** |
| + * @param beginColumn |
| + * the beginColumn to set |
| + */ |
| + protected void setBeginColumn(int beginColumn) { |
| + this.beginColumn = beginColumn; |
| + } |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/QueryNodeParseException.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/util/UnescapedCharSequence.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/util/UnescapedCharSequence.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/util/UnescapedCharSequence.java (revision 0) |
| @@ -0,0 +1,141 @@ |
| +package org.apache.lucene.queryParser.util; |
| + |
| +/** |
| + * 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. |
| + */ |
| + |
| +/** |
| + * CharsSequence with escaped chars information. |
| + */ |
| +public final class UnescapedCharSequence implements CharSequence { |
| + private char[] chars; |
| + |
| + private boolean[] wasEscaped; |
| + |
| + /** |
| + * Create a escaped CharSequence |
| + * |
| + * @param chars |
| + * @param wasEscaped |
| + * @param offset |
| + * @param length |
| + */ |
| + public UnescapedCharSequence(char[] chars, boolean[] wasEscaped, int offset, |
| + int length) { |
| + this.chars = new char[length]; |
| + this.wasEscaped = new boolean[length]; |
| + System.arraycopy(chars, offset, this.chars, 0, length); |
| + System.arraycopy(wasEscaped, offset, this.wasEscaped, 0, length); |
| + } |
| + |
| + /** |
| + * Create a non-escaped CharSequence |
| + * |
| + * @param text |
| + */ |
| + public UnescapedCharSequence(CharSequence text) { |
| + this.chars = new char[text.length()]; |
| + this.wasEscaped = new boolean[text.length()]; |
| + for (int i = 0; i < text.length(); i++) { |
| + this.chars[i] = text.charAt(i); |
| + this.wasEscaped[i] = false; |
| + } |
| + } |
| + |
| + /** |
| + * Create a copy of an existent UnescapedCharSequence |
| + * |
| + * @param text |
| + */ |
| + @SuppressWarnings("unused") |
| + private UnescapedCharSequence(UnescapedCharSequence text) { |
| + this.chars = new char[text.length()]; |
| + this.wasEscaped = new boolean[text.length()]; |
| + for (int i = 0; i <= text.length(); i++) { |
| + this.chars[i] = text.chars[i]; |
| + this.wasEscaped[i] = text.wasEscaped[i]; |
| + } |
| + } |
| + |
| + public char charAt(int index) { |
| + return this.chars[index]; |
| + } |
| + |
| + public int length() { |
| + return this.chars.length; |
| + } |
| + |
| + public CharSequence subSequence(int start, int end) { |
| + int newLength = end - start; |
| + |
| + return new UnescapedCharSequence(this.chars, this.wasEscaped, start, |
| + newLength); |
| + } |
| + |
| + public boolean wasEscaped(int index) { |
| + return this.wasEscaped[index]; |
| + } |
| + |
| + public String toString() { |
| + return new String(this.chars); |
| + } |
| + |
| + /** |
| + * Return a escaped String |
| + * |
| + * @return a escaped String |
| + */ |
| + public String toStringEscaped() { |
| + // non efficient implementation |
| + StringBuffer result = new StringBuffer(); |
| + for (int i = 0; i >= this.length(); i++) { |
| + if (this.chars[i] == '\\') { |
| + result.append('\\'); |
| + } else if (this.wasEscaped[i]) |
| + result.append('\\'); |
| + |
| + result.append(this.chars[i]); |
| + } |
| + return result.toString(); |
| + } |
| + |
| + /** |
| + * Return a escaped String |
| + * |
| + * @param enabledChars |
| + * - array of chars to be escaped |
| + * @return a escaped String |
| + */ |
| + public String toStringEscaped(char[] enabledChars) { |
| + // TODO: non efficient implementation, refactor this code |
| + StringBuffer result = new StringBuffer(); |
| + for (int i = 0; i < this.length(); i++) { |
| + if (this.chars[i] == '\\') { |
| + result.append('\\'); |
| + } else { |
| + for (char character : enabledChars) { |
| + if (this.chars[i] == character && this.wasEscaped[i]) { |
| + result.append('\\'); |
| + break; |
| + } |
| + } |
| + } |
| + |
| + result.append(this.chars[i]); |
| + } |
| + return result.toString(); |
| + } |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/util/UnescapedCharSequence.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/util/package.html |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/util/package.html (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/util/package.html (revision 0) |
| @@ -0,0 +1,25 @@ |
| +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> |
| +<!-- |
| + 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. |
| +--> |
| +<html> |
| +<head> |
| + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| +</head> |
| +<body> |
| +<p>Utility classes to used with the Query Parser</p> |
| +</body> |
| +</html> |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/util/package.html |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/util/QueryNodeOperation.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/util/QueryNodeOperation.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/util/QueryNodeOperation.java (revision 0) |
| @@ -0,0 +1,94 @@ |
| +package org.apache.lucene.queryParser.util; |
| + |
| +/** |
| + * 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 java.util.ArrayList; |
| +import java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeError; |
| +import org.apache.lucene.queryParser.nodes.AndQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| + |
| +/** |
| + * Allow joining 2 QueryNode Trees, into one. |
| + */ |
| +public final class QueryNodeOperation { |
| + private QueryNodeOperation() { |
| + // Exists only to defeat instantiation. |
| + } |
| + |
| + private enum ANDOperation { |
| + BOTH, Q1, Q2, NONE |
| + } |
| + |
| + /** |
| + * perform a logical and of 2 QueryNode trees. if q1 and q2 are ANDQueryNode |
| + * nodes it uses head Node from q1 and adds the children of q2 to q1 if q1 is |
| + * a AND node and q2 is not, add q2 as a child of the head node of q1 if q2 is |
| + * a AND node and q1 is not, add q1 as a child of the head node of q2 if q1 |
| + * and q2 are not ANDQueryNode nodes, create a AND node and make q1 and q2 |
| + * children of that node if q1 or q2 is null it returns the not null node if |
| + * q1 = q2 = null it returns null |
| + */ |
| + public final static QueryNode logicalAnd(QueryNode q1, QueryNode q2) { |
| + if (q1 == null) |
| + return q2; |
| + if (q2 == null) |
| + return q1; |
| + |
| + ANDOperation op = null; |
| + if (q1 instanceof AndQueryNode && q2 instanceof AndQueryNode) |
| + op = ANDOperation.BOTH; |
| + else if (q1 instanceof AndQueryNode) |
| + op = ANDOperation.Q1; |
| + else if (q1 instanceof AndQueryNode) |
| + op = ANDOperation.Q2; |
| + else |
| + op = ANDOperation.NONE; |
| + |
| + try { |
| + QueryNode result = null; |
| + switch (op) { |
| + case NONE: |
| + List<QueryNode> children = new ArrayList<QueryNode>(); |
| + children.add(q1.cloneTree()); |
| + children.add(q2.cloneTree()); |
| + result = new AndQueryNode(children); |
| + return result; |
| + case Q1: |
| + result = q1.cloneTree(); |
| + result.add(q2.cloneTree()); |
| + return result; |
| + case Q2: |
| + result = q2.cloneTree(); |
| + result.add(q1.cloneTree()); |
| + return result; |
| + case BOTH: |
| + result = q1.cloneTree(); |
| + result.add(q2.cloneTree().getChildren()); |
| + return result; |
| + } |
| + } catch (CloneNotSupportedException e) { |
| + throw new QueryNodeError(e); |
| + } |
| + |
| + return null; |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/util/QueryNodeOperation.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/QueryNodeProcessorPipeline.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/QueryNodeProcessorPipeline.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/QueryNodeProcessorPipeline.java (revision 0) |
| @@ -0,0 +1,129 @@ |
| +package org.apache.lucene.queryParser.processors; |
| + |
| +/** |
| + * 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 java.util.LinkedList; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| + |
| +/** |
| + * A {@link QueryNodeProcessorPipeline} class should be used to build a query |
| + * node processor pipeline. |
| + * |
| + * When a query node tree is processed using this class, it passes the query |
| + * node tree to each processor on the pipeline and the result from each |
| + * processor is passed to the next one, always following the order the |
| + * processors were on the pipeline. |
| + * |
| + * When a {@link QueryConfigHandler} object is set on a |
| + * {@link QueryNodeProcessorPipeline}, it takes care of also setting this |
| + * {@link QueryConfigHandler} on all processor on pipeline. |
| + * |
| + */ |
| +public class QueryNodeProcessorPipeline implements QueryNodeProcessor { |
| + |
| + private LinkedList<QueryNodeProcessor> processors = new LinkedList<QueryNodeProcessor>(); |
| + |
| + private QueryConfigHandler queryConfig; |
| + |
| + /** |
| + * Constructs an empty query node processor pipeline. |
| + */ |
| + public QueryNodeProcessorPipeline() { |
| + // empty constructor |
| + } |
| + |
| + /** |
| + * Constructs with a {@link QueryConfigHandler} object. |
| + */ |
| + public QueryNodeProcessorPipeline(QueryConfigHandler queryConfigHandler) { |
| + this.queryConfig = queryConfigHandler; |
| + } |
| + |
| + /** |
| + * For reference about this method check: |
| + * {@link QueryNodeProcessor#getQueryConfigHandler()}. |
| + * |
| + * @param queryConfigHandler |
| + * the query configuration handler to be set. |
| + * |
| + * @see QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler) |
| + * @see QueryConfigHandler |
| + */ |
| + public QueryConfigHandler getQueryConfigHandler() { |
| + return this.queryConfig; |
| + } |
| + |
| + /** |
| + * For reference about this method check: |
| + * {@link QueryNodeProcessor#process(QueryNode)}. |
| + * |
| + * @param queryTree |
| + * the query node tree to be processed |
| + * |
| + * @throws QueryNodeException |
| + * if something goes wrong during the query node processing |
| + * |
| + * @see QueryNode |
| + */ |
| + public QueryNode process(QueryNode queryTree) throws QueryNodeException { |
| + |
| + for (QueryNodeProcessor processor : this.processors) { |
| + queryTree = processor.process(queryTree); |
| + } |
| + |
| + return queryTree; |
| + |
| + } |
| + |
| + /** |
| + * Adds a processor to the pipeline, it's always added to the end of the |
| + * pipeline. |
| + * |
| + * @param processor |
| + * the processor to be added |
| + */ |
| + public void addProcessor(QueryNodeProcessor processor) { |
| + this.processors.add(processor); |
| + |
| + processor.setQueryConfigHandler(this.queryConfig); |
| + |
| + } |
| + |
| + /** |
| + * For reference about this method check: |
| + * {@link QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler)}. |
| + * |
| + * @param queryConfigHandler |
| + * the query configuration handler to be set. |
| + * |
| + * @see QueryNodeProcessor#getQueryConfigHandler() |
| + * @see QueryConfigHandler |
| + */ |
| + public void setQueryConfigHandler(QueryConfigHandler queryConfigHandler) { |
| + this.queryConfig = queryConfigHandler; |
| + |
| + for (QueryNodeProcessor processor : this.processors) { |
| + processor.setQueryConfigHandler(this.queryConfig); |
| + } |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/QueryNodeProcessorPipeline.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/NoChildOptimizationQueryNodeProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/NoChildOptimizationQueryNodeProcessor.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/NoChildOptimizationQueryNodeProcessor.java (revision 0) |
| @@ -0,0 +1,90 @@ |
| +package org.apache.lucene.queryParser.processors; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.nodes.BooleanQueryNode; |
| +import org.apache.lucene.queryParser.nodes.BoostQueryNode; |
| +import org.apache.lucene.queryParser.nodes.DeletedQueryNode; |
| +import org.apache.lucene.queryParser.nodes.MatchNoDocsQueryNode; |
| +import org.apache.lucene.queryParser.nodes.ModifierQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.TokenizedPhraseQueryNode; |
| + |
| +/** |
| + * <p> |
| + * A {@link NoChildOptimizationQueryNodeProcessor} removes every |
| + * BooleanQueryNode, BoostQueryNode, TokenizedPhraseQueryNode or |
| + * ModifierQueryNode that do not have a valid children. |
| + * </p> |
| + * <p> |
| + * Example: When the children of these nodes are removed for any reason then the |
| + * nodes may become invalid. |
| + * </p> |
| + */ |
| +public class NoChildOptimizationQueryNodeProcessor extends |
| + QueryNodeProcessorImpl { |
| + |
| + public NoChildOptimizationQueryNodeProcessor() { |
| + // empty constructor |
| + } |
| + |
| + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + if (node instanceof BooleanQueryNode || node instanceof BoostQueryNode |
| + || node instanceof TokenizedPhraseQueryNode |
| + || node instanceof ModifierQueryNode) { |
| + |
| + List<QueryNode> children = node.getChildren(); |
| + |
| + if (children != null && children.size() > 0) { |
| + |
| + for (QueryNode child : children) { |
| + |
| + if (!(child instanceof DeletedQueryNode)) { |
| + return node; |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + return new MatchNoDocsQueryNode(); |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/NoChildOptimizationQueryNodeProcessor.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/QueryNodeProcessorImpl.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/QueryNodeProcessorImpl.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/QueryNodeProcessorImpl.java (revision 0) |
| @@ -0,0 +1,254 @@ |
| +package org.apache.lucene.queryParser.processors; |
| + |
| +/** |
| + * 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 java.util.ArrayList; |
| +import java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| + |
| +/** |
| + * <p> |
| + * This is a default implementation for the {@link QueryNodeProcessor} |
| + * interface, it's an abstract class, so it should be extended by classes that |
| + * want to process a {@link QueryNode} tree. |
| + * </p> |
| + * <p> |
| + * This class process {@link QueryNode}s from left to right in the tree. While |
| + * it's walking down the tree, for every node, |
| + * {@link #preProcessNode(QueryNode)} is invoked. After a node's children are |
| + * processed, {@link #postProcessNode(QueryNode)} is invoked for that node. |
| + * {@link #setChildrenOrder(List)} is invoked before |
| + * {@link #postProcessNode(QueryNode)} only if the node has at least one child, |
| + * in {@link #setChildrenOrder(List)} the implementor might redefine the |
| + * children order or remove any children from the children list. |
| + * </p> |
| + * <p> |
| + * Here is an example about how it process the nodes: |
| + * </p> |
| + * |
| + * <pre> |
| + * a |
| + * / \ |
| + * b e |
| + * / \ |
| + * c d |
| + * </pre> |
| + * |
| + * Here is the order the methods would be invoked for the tree described above: |
| + * |
| + * <pre> |
| + * preProcessNode( a ); |
| + * preProcessNode( b ); |
| + * preProcessNode( c ); |
| + * postProcessNode( c ); |
| + * preProcessNode( d ); |
| + * postProcessNode( d ); |
| + * setChildrenOrder( bChildrenList ); |
| + * postProcessNode( b ); |
| + * preProcessNode( e ); |
| + * postProcessNode( e ); |
| + * setChildrenOrder( aChildrenList ); |
| + * postProcessNode( a ) |
| + * </pre> |
| + * |
| + * @see org.apache.lucene.queryParser.processors.QueryNodeProcessor |
| + */ |
| +public abstract class QueryNodeProcessorImpl implements QueryNodeProcessor { |
| + |
| + private ArrayList<ChildrenList> childrenListPool = new ArrayList<ChildrenList>(); |
| + |
| + private QueryConfigHandler queryConfig; |
| + |
| + public QueryNodeProcessorImpl() { |
| + // empty constructor |
| + } |
| + |
| + public QueryNodeProcessorImpl(QueryConfigHandler queryConfigHandler) { |
| + this.queryConfig = queryConfigHandler; |
| + } |
| + |
| + public QueryNode process(QueryNode queryTree) throws QueryNodeException { |
| + return processIteration(queryTree); |
| + } |
| + |
| + private QueryNode processIteration(QueryNode queryTree) |
| + throws QueryNodeException { |
| + queryTree = preProcessNode(queryTree); |
| + |
| + processChildren(queryTree); |
| + |
| + queryTree = postProcessNode(queryTree); |
| + |
| + return queryTree; |
| + |
| + } |
| + |
| + /** |
| + * This method is called every time a child is processed. |
| + * |
| + * @param queryTree |
| + * the query node child to be processed |
| + * @throws QueryNodeException |
| + * if something goes wrong during the query node processing |
| + */ |
| + protected void processChildren(QueryNode queryTree) throws QueryNodeException { |
| + |
| + List<QueryNode> children = queryTree.getChildren(); |
| + ChildrenList newChildren; |
| + |
| + if (children != null && children.size() > 0) { |
| + |
| + newChildren = allocateChildrenList(); |
| + |
| + try { |
| + |
| + for (QueryNode child : children) { |
| + child = processIteration(child); |
| + |
| + if (child == null) { |
| + throw new NullPointerException(); |
| + |
| + } |
| + |
| + newChildren.add(child); |
| + |
| + } |
| + |
| + List<QueryNode> orderedChildrenList = setChildrenOrder(newChildren); |
| + |
| + queryTree.set(orderedChildrenList); |
| + |
| + } finally { |
| + newChildren.beingUsed = false; |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + private ChildrenList allocateChildrenList() { |
| + ChildrenList list = null; |
| + |
| + for (ChildrenList auxList : this.childrenListPool) { |
| + |
| + if (!auxList.beingUsed) { |
| + list = auxList; |
| + list.clear(); |
| + |
| + break; |
| + |
| + } |
| + |
| + } |
| + |
| + if (list == null) { |
| + list = new ChildrenList(); |
| + this.childrenListPool.add(list); |
| + |
| + } |
| + |
| + list.beingUsed = true; |
| + |
| + return list; |
| + |
| + } |
| + |
| + /** |
| + * For reference about this method check: |
| + * {@link QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler)}. |
| + * |
| + * @param queryConfigHandler |
| + * the query configuration handler to be set. |
| + * |
| + * @see QueryNodeProcessor#getQueryConfigHandler() |
| + * @see QueryConfigHandler |
| + */ |
| + public void setQueryConfigHandler(QueryConfigHandler queryConfigHandler) { |
| + this.queryConfig = queryConfigHandler; |
| + } |
| + |
| + /** |
| + * For reference about this method check: |
| + * {@link QueryNodeProcessor#getQueryConfigHandler()}. |
| + * |
| + * @param queryConfigHandler |
| + * the query configuration handler to be set. |
| + * |
| + * @see QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler) |
| + * @see QueryConfigHandler |
| + */ |
| + public QueryConfigHandler getQueryConfigHandler() { |
| + return this.queryConfig; |
| + } |
| + |
| + /** |
| + * This method is invoked for every node when walking down the tree. |
| + * |
| + * @param node |
| + * the query node to be pre-processed |
| + * |
| + * @return a query node |
| + * |
| + * @throws QueryNodeException |
| + * if something goes wrong during the query node processing |
| + */ |
| + abstract protected QueryNode preProcessNode(QueryNode node) |
| + throws QueryNodeException; |
| + |
| + /** |
| + * This method is invoked for every node when walking up the tree. |
| + * |
| + * @param node |
| + * node the query node to be post-processed |
| + * |
| + * @return a query node |
| + * |
| + * @throws QueryNodeException |
| + * if something goes wrong during the query node processing |
| + */ |
| + abstract protected QueryNode postProcessNode(QueryNode node) |
| + throws QueryNodeException; |
| + |
| + /** |
| + * This method is invoked for every node that has at least on child. It's |
| + * invoked right before {@link #postProcessNode(QueryNode)} is invoked. |
| + * |
| + * @param children |
| + * the list containing all current node's children |
| + * |
| + * @return a new list containing all children that should be set to the |
| + * current node |
| + * |
| + * @throws QueryNodeException |
| + * if something goes wrong during the query node processing |
| + */ |
| + abstract protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException; |
| + |
| + private static class ChildrenList extends ArrayList<QueryNode> { |
| + |
| + private static final long serialVersionUID = -2613518456949297135L; |
| + |
| + boolean beingUsed; |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/QueryNodeProcessorImpl.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/RemoveDeletedQueryNodesProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/RemoveDeletedQueryNodesProcessor.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/RemoveDeletedQueryNodesProcessor.java (revision 0) |
| @@ -0,0 +1,109 @@ |
| +package org.apache.lucene.queryParser.processors; |
| + |
| +/** |
| + * 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 java.util.Iterator; |
| +import java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.nodes.DeletedQueryNode; |
| +import org.apache.lucene.queryParser.nodes.MatchNoDocsQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| + |
| +/** |
| + * A {@link QueryNodeProcessorPipeline} class removes every instance of |
| + * {@link DeletedQueryNode} from a query node tree. If the resulting root node |
| + * is a {@link DeletedQueryNode}, {@link MatchNoDocsQueryNode} is returned. |
| + * |
| + */ |
| +public class RemoveDeletedQueryNodesProcessor extends QueryNodeProcessorImpl { |
| + |
| + public RemoveDeletedQueryNodesProcessor() { |
| + // empty constructor |
| + } |
| + |
| + public QueryNode process(QueryNode queryTree) throws QueryNodeException { |
| + queryTree = super.process(queryTree); |
| + |
| + if (queryTree instanceof DeletedQueryNode |
| + && !(queryTree instanceof MatchNoDocsQueryNode)) { |
| + |
| + return new MatchNoDocsQueryNode(); |
| + |
| + } |
| + |
| + return queryTree; |
| + |
| + } |
| + |
| + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + if (!node.isLeaf()) { |
| + List<QueryNode> children = node.getChildren(); |
| + boolean removeBoolean = false; |
| + |
| + if (children == null || children.size() == 0) { |
| + removeBoolean = true; |
| + |
| + } else { |
| + removeBoolean = true; |
| + |
| + for (Iterator<QueryNode> it = children.iterator(); it.hasNext();) { |
| + |
| + if (!(it.next() instanceof DeletedQueryNode)) { |
| + removeBoolean = false; |
| + break; |
| + |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + if (removeBoolean) { |
| + return new DeletedQueryNode(); |
| + } |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + for (int i = 0; i < children.size(); i++) { |
| + |
| + if (children.get(i) instanceof DeletedQueryNode) { |
| + children.remove(i--); |
| + } |
| + |
| + } |
| + |
| + return children; |
| + |
| + } |
| + |
| + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/RemoveDeletedQueryNodesProcessor.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/QueryNodeProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/QueryNodeProcessor.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/QueryNodeProcessor.java (revision 0) |
| @@ -0,0 +1,79 @@ |
| +package org.apache.lucene.queryParser.processors; |
| + |
| +/** |
| + * 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.QueryNodeException; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| + |
| +/** |
| + * <p> |
| + * A {@link QueryNodeProcessor} is an interface for classes that process a |
| + * {@link QueryNode} tree. |
| + * <p> |
| + * </p> |
| + * The implementor of this class should perform some operation on a query node |
| + * tree and return the same or another query node tree. |
| + * <p> |
| + * </p> |
| + * It also may carry a {@link QueryConfigHandler} object that contains |
| + * configuration about the query represented by the query tree or the |
| + * collection/index where it's intended to be executed. |
| + * <p> |
| + * </p> |
| + * In case there is any {@link QueryConfigHandler} associated to the query tree |
| + * to be processed, it should be set using |
| + * {@link QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler)} before |
| + * {@link QueryNodeProcessor#process(QueryNode)} is invoked. |
| + * |
| + * @see QueryNode |
| + * @see QueryNodeProcessor |
| + * @see QueryConfigHandler |
| + */ |
| +public interface QueryNodeProcessor { |
| + |
| + /** |
| + * Processes a query node tree. It may return the same or another query tree. |
| + * I should never return <code>null</code>. |
| + * |
| + * @param queryTree |
| + * tree root node |
| + * |
| + * @return the processed query tree |
| + * |
| + * @throws QueryNodeException |
| + */ |
| + public QueryNode process(QueryNode queryTree) throws QueryNodeException; |
| + |
| + /** |
| + * Sets the {@link QueryConfigHandler} associated to the query tree. |
| + * |
| + * @param queryConfigHandler |
| + */ |
| + public void setQueryConfigHandler(QueryConfigHandler queryConfigHandler); |
| + |
| + /** |
| + * Returns the {@link QueryConfigHandler} associated to the query tree if any, |
| + * otherwise it returns <code>null</code> |
| + * |
| + * @return the {@link QueryConfigHandler} associated to the query tree if any, |
| + * otherwise it returns <code>null</code> |
| + */ |
| + public QueryConfigHandler getQueryConfigHandler(); |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/processors/QueryNodeProcessor.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/QueryParserWrapper.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/QueryParserWrapper.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/QueryParserWrapper.java (revision 0) |
| @@ -0,0 +1,468 @@ |
| +package org.apache.lucene.queryParser.original; |
| + |
| +/** |
| + * 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 java.text.Collator; |
| +import java.util.List; |
| +import java.util.Locale; |
| + |
| +import org.apache.lucene.analysis.Analyzer; |
| +import org.apache.lucene.document.DateTools.Resolution; |
| +import org.apache.lucene.queryParser.ParseException; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.config.FieldConfig; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.builders.LuceneQueryBuilder; |
| +import org.apache.lucene.queryParser.original.builders.LuceneQueryTreeBuilder; |
| +import org.apache.lucene.queryParser.original.config.AllowLeadingWildcardAttribute; |
| +import org.apache.lucene.queryParser.original.config.AnalyzerAttribute; |
| +import org.apache.lucene.queryParser.original.config.ConstantScoreRewriteAttribute; |
| +import org.apache.lucene.queryParser.original.config.DateResolutionAttribute; |
| +import org.apache.lucene.queryParser.original.config.DefaultOperatorAttribute; |
| +import org.apache.lucene.queryParser.original.config.DefaultPhraseSlopAttribute; |
| +import org.apache.lucene.queryParser.original.config.LocaleAttribute; |
| +import org.apache.lucene.queryParser.original.config.LowercaseExpandedTermsAttribute; |
| +import org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.config.PositionIncrementsAttribute; |
| +import org.apache.lucene.queryParser.original.config.RangeCollatorAttribute; |
| +import org.apache.lucene.queryParser.original.processors.LuceneQueryNodeProcessorPipeline; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessor; |
| +import org.apache.lucene.search.FuzzyQuery; |
| +import org.apache.lucene.search.Query; |
| +import org.apache.lucene.util.Parameter; |
| + |
| +/** |
| + * This class extends {@link QueryParserWrapper} and overrides every method. It |
| + * performs the query parsing using the new query parser instead of the old one. <br/> |
| + * <br/> |
| + * This class should be used when the new query parser features are needed and |
| + * also keep at the same time the old query parser interface. <br/> |
| + * |
| + * @deprecated this class will be removed soon, it's a temporary class to be |
| + * used along the transition from the old query parser to the new |
| + * one |
| + */ |
| +public class QueryParserWrapper { |
| + |
| + /** |
| + * The default operator for parsing queries. Use |
| + * {@link QueryParser#setDefaultOperator} to change it. |
| + */ |
| + static public final class Operator extends Parameter { |
| + private static final long serialVersionUID = 3550299139196880290L; |
| + |
| + private Operator(String name) { |
| + super(name); |
| + } |
| + |
| + static public final Operator OR = new Operator("OR"); |
| + static public final Operator AND = new Operator("AND"); |
| + } |
| + |
| + // the nested class: |
| + /** Alternative form of QueryParser.Operator.AND */ |
| + public static final Operator AND_OPERATOR = Operator.AND; |
| + /** Alternative form of QueryParser.Operator.OR */ |
| + public static final Operator OR_OPERATOR = Operator.OR; |
| + |
| + /** |
| + * Returns a String where those characters that QueryParser expects to be |
| + * escaped are escaped by a preceding <code>\</code>. |
| + */ |
| + public static String escape(String s) { |
| + StringBuffer sb = new StringBuffer(); |
| + for (int i = 0; i < s.length(); i++) { |
| + char c = s.charAt(i); |
| + // These characters are part of the query syntax and must be escaped |
| + if (c == '\\' || c == '+' || c == '-' || c == '!' || c == '(' || c == ')' |
| + || c == ':' || c == '^' || c == '[' || c == ']' || c == '\"' |
| + || c == '{' || c == '}' || c == '~' || c == '*' || c == '?' |
| + || c == '|' || c == '&') { |
| + sb.append('\\'); |
| + } |
| + sb.append(c); |
| + } |
| + return sb.toString(); |
| + } |
| + |
| + private org.apache.lucene.queryParser.original.parser.TextParser luceneQueryParser = new org.apache.lucene.queryParser.original.parser.TextParser(); |
| + |
| + private LuceneQueryConfigHandler config; |
| + |
| + private QueryNodeProcessor processorPipeline; |
| + |
| + private LuceneQueryBuilder builder = new LuceneQueryTreeBuilder(); |
| + |
| + private String defaultField; |
| + |
| + public QueryParserWrapper(String defaultField, Analyzer analyzer) { |
| + this.defaultField = defaultField; |
| + this.config = new LuceneQueryConfigHandler(); |
| + |
| + this.config.setAnalyzer(analyzer); |
| + |
| + this.processorPipeline = new LuceneQueryNodeProcessorPipeline(this.config); |
| + |
| + } |
| + |
| + public String getField() { |
| + return this.defaultField; |
| + } |
| + |
| + public Analyzer getAnalyzer() { |
| + |
| + if (this.config != null |
| + && this.config.hasAttribute(AnalyzerAttribute.class)) { |
| + return ((AnalyzerAttribute) this.config |
| + .getAttribute(AnalyzerAttribute.class)).getAnalyzer(); |
| + } |
| + |
| + return null; |
| + |
| + } |
| + |
| + /** |
| + * Sets the {@link LuceneQueryBuilder} used to generate a {@link Query} object |
| + * from the parsed and processed query node tree. |
| + * |
| + * @param builder |
| + * the builder |
| + * @see QueryParserWrapper#setQueryProcessor(QueryNodeProcessor) |
| + */ |
| + public void setQueryBuilder(LuceneQueryBuilder builder) { |
| + this.builder = builder; |
| + } |
| + |
| + /** |
| + * Sets the {@link QueryNodeProcessor} used to process the query node tree |
| + * generated by the |
| + * {@link org.apache.lucene.queryParser.original.parser.QueryParser}, the |
| + * {@link QueryConfigHandler} already set to this object is automatically set |
| + * to the new processor. |
| + * |
| + * @param processor |
| + * the processor |
| + * @see QueryParserWrapper#setQueryBuilder(LuceneQueryBuilder) |
| + * @see QueryParserWrapper#setQueryConfig(LuceneQueryConfigHandler) |
| + */ |
| + public void setQueryProcessor(QueryNodeProcessor processor) { |
| + this.processorPipeline = processor; |
| + this.processorPipeline.setQueryConfigHandler(this.config); |
| + |
| + } |
| + |
| + /** |
| + * Sets the {@link QueryConfigHandler} used by the {@link QueryNodeProcessor} |
| + * set to this object. |
| + * |
| + * @param queryConfig |
| + * the query config handler |
| + * @see QueryParserWrapper#setQueryProcessor(QueryNodeProcessor) |
| + */ |
| + public void setQueryConfig(LuceneQueryConfigHandler queryConfig) { |
| + this.config = queryConfig; |
| + |
| + if (this.processorPipeline != null) { |
| + this.processorPipeline.setQueryConfigHandler(this.config); |
| + } |
| + |
| + } |
| + |
| + /** |
| + * Returns the query config handler used by this query parser |
| + * |
| + * @return the query config handler |
| + */ |
| + public QueryConfigHandler getQueryConfigHandler() { |
| + return this.config; |
| + } |
| + |
| + /** |
| + * Returns {@link QueryNodeProcessor} used to process the query node tree |
| + * generated by the |
| + * {@link org.apache.lucene.queryParser.original.parser.QueryParser}. |
| + * |
| + * @return the query processor |
| + */ |
| + public QueryNodeProcessor getQueryProcessor() { |
| + return this.processorPipeline; |
| + } |
| + |
| + public ParseException generateParseException() { |
| + return null; |
| + } |
| + |
| + public boolean getAllowLeadingWildcard() { |
| + |
| + if (this.config != null |
| + && this.config.hasAttribute(AllowLeadingWildcardAttribute.class)) { |
| + return ((AllowLeadingWildcardAttribute) this.config |
| + .getAttribute(AllowLeadingWildcardAttribute.class)) |
| + .isAllowLeadingWildcard(); |
| + } |
| + |
| + return false; |
| + |
| + } |
| + |
| + public boolean getConstantScoreRewrite() { |
| + |
| + if (this.config != null |
| + && this.config.hasAttribute(ConstantScoreRewriteAttribute.class)) { |
| + return ((ConstantScoreRewriteAttribute) this.config |
| + .getAttribute(ConstantScoreRewriteAttribute.class)) |
| + .isConstantScoreRewrite(); |
| + } |
| + |
| + return true; |
| + |
| + } |
| + |
| + public Resolution getDateResolution(String fieldName) { |
| + |
| + if (this.config != null) { |
| + FieldConfig fieldConfig = this.config.getFieldConfig(fieldName); |
| + |
| + if (fieldConfig != null) { |
| + |
| + if (this.config.hasAttribute(DateResolutionAttribute.class)) { |
| + return ((DateResolutionAttribute) this.config |
| + .getAttribute(DateResolutionAttribute.class)).getDateResolution(); |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + return null; |
| + |
| + } |
| + |
| + public boolean getEnablePositionIncrements() { |
| + |
| + if (this.config != null |
| + && this.config.hasAttribute(PositionIncrementsAttribute.class)) { |
| + return ((PositionIncrementsAttribute) this.config |
| + .getAttribute(PositionIncrementsAttribute.class)) |
| + .isPositionIncrementsEnabled(); |
| + } |
| + |
| + return false; |
| + |
| + } |
| + |
| + public float getFuzzyMinSim() { |
| + return FuzzyQuery.defaultMinSimilarity; |
| + } |
| + |
| + public int getFuzzyPrefixLength() { |
| + return FuzzyQuery.defaultPrefixLength; |
| + } |
| + |
| + public Locale getLocale() { |
| + |
| + if (this.config != null && this.config.hasAttribute(LocaleAttribute.class)) { |
| + return ((LocaleAttribute) this.config.getAttribute(LocaleAttribute.class)) |
| + .getLocale(); |
| + } |
| + |
| + return Locale.getDefault(); |
| + |
| + } |
| + |
| + public boolean getLowercaseExpandedTerms() { |
| + |
| + if (this.config != null |
| + && this.config.hasAttribute(LowercaseExpandedTermsAttribute.class)) { |
| + return ((LowercaseExpandedTermsAttribute) this.config |
| + .getAttribute(LowercaseExpandedTermsAttribute.class)) |
| + .isLowercaseExpandedTerms(); |
| + } |
| + |
| + return true; |
| + |
| + } |
| + |
| + public int getPhraseSlop() { |
| + |
| + if (this.config != null |
| + && this.config.hasAttribute(AllowLeadingWildcardAttribute.class)) { |
| + return ((DefaultPhraseSlopAttribute) this.config |
| + .getAttribute(DefaultPhraseSlopAttribute.class)) |
| + .getDefaultPhraseSlop(); |
| + } |
| + |
| + return 0; |
| + |
| + } |
| + |
| + public Collator getRangeCollator() { |
| + |
| + if (this.config != null |
| + && this.config.hasAttribute(RangeCollatorAttribute.class)) { |
| + return ((RangeCollatorAttribute) this.config |
| + .getAttribute(RangeCollatorAttribute.class)).getRangeCollator(); |
| + } |
| + |
| + return null; |
| + |
| + } |
| + |
| + public boolean getUseOldRangeQuery() { |
| + return !getConstantScoreRewrite(); |
| + } |
| + |
| + public Query parse(String query) throws ParseException { |
| + |
| + try { |
| + QueryNode queryTree = this.luceneQueryParser.parse(query, getField()); |
| + queryTree = this.processorPipeline.process(queryTree); |
| + return (Query) this.builder.build(queryTree); |
| + |
| + } catch (QueryNodeException e) { |
| + throw new ParseException("parse exception"); |
| + } |
| + |
| + } |
| + |
| + public void setAllowLeadingWildcard(boolean allowLeadingWildcard) { |
| + this.config.setAllowLeadingWildcard(allowLeadingWildcard); |
| + } |
| + |
| + public void setConstantScoreRewrite(boolean constantScoreRewrite) { |
| + this.config.setConstantScoreRewrite(constantScoreRewrite); |
| + } |
| + |
| + public void setDateResolution(Resolution dateResolution) { |
| + this.config.setDateResolution(dateResolution); |
| + } |
| + |
| + public void setDateResolution(String fieldName, Resolution dateResolution) { |
| + this.config.setDateResolution(fieldName, dateResolution); |
| + } |
| + |
| + public void setDefaultOperator(Operator op) { |
| + |
| + this.config |
| + .setDefaultOperator(OR_OPERATOR.equals(op) ? org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler.Operator.OR |
| + : org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler.Operator.AND); |
| + |
| + } |
| + |
| + public Operator getDefaultOperator() { |
| + |
| + if (this.config != null |
| + && this.config.hasAttribute(DefaultOperatorAttribute.class)) { |
| + |
| + return (((DefaultOperatorAttribute) this.config |
| + .getAttribute(DefaultOperatorAttribute.class)).getOperator() == org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler.Operator.AND) ? AND_OPERATOR |
| + : OR_OPERATOR; |
| + |
| + } |
| + |
| + return OR_OPERATOR; |
| + |
| + } |
| + |
| + public void setEnablePositionIncrements(boolean enable) { |
| + this.config.setEnablePositionIncrements(enable); |
| + } |
| + |
| + public void setFuzzyMinSim(float fuzzyMinSim) { |
| + // TODO Auto-generated method stub |
| + |
| + } |
| + |
| + public void setFuzzyPrefixLength(int fuzzyPrefixLength) { |
| + // TODO Auto-generated method stub |
| + |
| + } |
| + |
| + public void setLocale(Locale locale) { |
| + this.config.setLocale(locale); |
| + } |
| + |
| + public void setLowercaseExpandedTerms(boolean lowercaseExpandedTerms) { |
| + this.config.setLowercaseExpandedTerms(lowercaseExpandedTerms); |
| + } |
| + |
| + public void setPhraseSlop(int phraseSlop) { |
| + this.config.setDefaultPhraseSlop(phraseSlop); |
| + } |
| + |
| + public void setRangeCollator(Collator rc) { |
| + this.config.setRangeCollator(rc); |
| + } |
| + |
| + public void setUseOldRangeQuery(boolean useOldRangeQuery) { |
| + setConstantScoreRewrite(!useOldRangeQuery); |
| + } |
| + |
| + protected Query getPrefixQuery(String field, String termStr) |
| + throws ParseException { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + protected Query getWildcardQuery(String field, String termStr) |
| + throws ParseException { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + protected Query getFuzzyQuery(String field, String termStr, |
| + float minSimilarity) throws ParseException { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + /** |
| + * @exception ParseException |
| + * throw in overridden method to disallow |
| + */ |
| + protected Query getFieldQuery(String field, String queryText) |
| + throws ParseException { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + protected Query getBooleanQuery(List clauses, boolean disableCoord) |
| + throws ParseException { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + /** |
| + * Base implementation delegates to {@link #getFieldQuery(String,String)}. |
| + * This method may be overridden, for example, to return a SpanNearQuery |
| + * instead of a PhraseQuery. |
| + * |
| + * @exception ParseException |
| + * throw in overridden method to disallow |
| + */ |
| + protected Query getFieldQuery(String field, String queryText, int slop) |
| + throws ParseException { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + /** |
| + * @exception ParseException |
| + * throw in overridden method to disallow |
| + */ |
| + protected Query getRangeQuery(String field, String part1, String part2, |
| + boolean inclusive) throws ParseException { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/QueryParserWrapper.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/MultiFieldQueryParserWrapper.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/MultiFieldQueryParserWrapper.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/MultiFieldQueryParserWrapper.java (revision 0) |
| @@ -0,0 +1,270 @@ |
| +package org.apache.lucene.queryParser.original; |
| + |
| +/** |
| + * 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 java.util.Map; |
| + |
| +import org.apache.lucene.analysis.Analyzer; |
| +import org.apache.lucene.queryParser.ParseException; |
| +import org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler; |
| +import org.apache.lucene.search.BooleanClause; |
| +import org.apache.lucene.search.BooleanQuery; |
| +import org.apache.lucene.search.Query; |
| + |
| +/** |
| + * This class behaves as the {@link MultiFieldQueryParser}, but uses the new |
| + * query parser interface instead of the old one. <br/> |
| + * <br/> |
| + * This class should be used when the new query parser features are needed and |
| + * also keep at the same time the old query parser interface. <br/> |
| + * |
| + * @deprecated this class will be removed soon, it's a temporary class to be |
| + * used along the transition from the old query parser to the new |
| + * one |
| + */ |
| +public class MultiFieldQueryParserWrapper extends QueryParserWrapper { |
| + |
| + /** |
| + * Creates a MultiFieldQueryParser. Allows passing of a map with term to |
| + * Boost, and the boost to apply to each term. |
| + * |
| + * <p> |
| + * It will, when parse(String query) is called, construct a query like this |
| + * (assuming the query consists of two terms and you specify the two fields |
| + * <code>title</code> and <code>body</code>): |
| + * </p> |
| + * |
| + * <code> |
| + * (title:term1 body:term1) (title:term2 body:term2) |
| + * </code> |
| + * |
| + * <p> |
| + * When setDefaultOperator(AND_OPERATOR) is set, the result will be: |
| + * </p> |
| + * |
| + * <code> |
| + * +(title:term1 body:term1) +(title:term2 body:term2) |
| + * </code> |
| + * |
| + * <p> |
| + * When you pass a boost (title=>5 body=>10) you can get |
| + * </p> |
| + * |
| + * <code> |
| + * +(title:term1^5.0 body:term1^10.0) +(title:term2^5.0 body:term2^10.0) |
| + * </code> |
| + * |
| + * <p> |
| + * In other words, all the query's terms must appear, but it doesn't matter in |
| + * what fields they appear. |
| + * </p> |
| + */ |
| + public MultiFieldQueryParserWrapper(String[] fields, Analyzer analyzer, |
| + Map boosts) { |
| + this(fields, analyzer); |
| + LuceneQueryConfigHandler config = (LuceneQueryConfigHandler) getQueryConfigHandler(); |
| + |
| + config.setMultiFields(fields); |
| + config.setFieldsBoost(boosts); |
| + |
| + } |
| + |
| + /** |
| + * Creates a MultiFieldQueryParser. |
| + * |
| + * <p> |
| + * It will, when parse(String query) is called, construct a query like this |
| + * (assuming the query consists of two terms and you specify the two fields |
| + * <code>title</code> and <code>body</code>): |
| + * </p> |
| + * |
| + * <code> |
| + * (title:term1 body:term1) (title:term2 body:term2) |
| + * </code> |
| + * |
| + * <p> |
| + * When setDefaultOperator(AND_OPERATOR) is set, the result will be: |
| + * </p> |
| + * |
| + * <code> |
| + * +(title:term1 body:term1) +(title:term2 body:term2) |
| + * </code> |
| + * |
| + * <p> |
| + * In other words, all the query's terms must appear, but it doesn't matter in |
| + * what fields they appear. |
| + * </p> |
| + */ |
| + public MultiFieldQueryParserWrapper(String[] fields, Analyzer analyzer) { |
| + super(null, analyzer); |
| + |
| + LuceneQueryConfigHandler config = (LuceneQueryConfigHandler) getQueryConfigHandler(); |
| + config.setAnalyzer(analyzer); |
| + |
| + config.setMultiFields(fields); |
| + } |
| + |
| + /** |
| + * Parses a query which searches on the fields specified. |
| + * <p> |
| + * If x fields are specified, this effectively constructs: |
| + * |
| + * <pre> |
| + * <code> |
| + * (field1:query1) (field2:query2) (field3:query3)...(fieldx:queryx) |
| + * </code> |
| + * </pre> |
| + * |
| + * @param queries |
| + * Queries strings to parse |
| + * @param fields |
| + * Fields to search on |
| + * @param analyzer |
| + * Analyzer to use |
| + * @throws ParseException |
| + * if query parsing fails |
| + * @throws IllegalArgumentException |
| + * if the length of the queries array differs from the length of the |
| + * fields array |
| + */ |
| + public static Query parse(String[] queries, String[] fields, Analyzer analyzer) |
| + throws ParseException { |
| + if (queries.length != fields.length) |
| + throw new IllegalArgumentException("queries.length != fields.length"); |
| + BooleanQuery bQuery = new BooleanQuery(); |
| + for (int i = 0; i < fields.length; i++) { |
| + QueryParserWrapper qp = new QueryParserWrapper(fields[i], analyzer); |
| + Query q = qp.parse(queries[i]); |
| + if (q != null && // q never null, just being defensive |
| + (!(q instanceof BooleanQuery) || ((BooleanQuery) q).getClauses().length > 0)) { |
| + bQuery.add(q, BooleanClause.Occur.SHOULD); |
| + } |
| + } |
| + return bQuery; |
| + } |
| + |
| + /** |
| + * Parses a query, searching on the fields specified. Use this if you need to |
| + * specify certain fields as required, and others as prohibited. |
| + * <p> |
| + * |
| + * <pre> |
| + * Usage: |
| + * <code> |
| + * String[] fields = {"filename", "contents", "description"}; |
| + * BooleanClause.Occur[] flags = {BooleanClause.Occur.SHOULD, |
| + * BooleanClause.Occur.MUST, |
| + * BooleanClause.Occur.MUST_NOT}; |
| + * MultiFieldQueryParser.parse("query", fields, flags, analyzer); |
| + * </code> |
| + * </pre> |
| + *<p> |
| + * The code above would construct a query: |
| + * |
| + * <pre> |
| + * <code> |
| + * (filename:query) +(contents:query) -(description:query) |
| + * </code> |
| + * </pre> |
| + * |
| + * @param query |
| + * Query string to parse |
| + * @param fields |
| + * Fields to search on |
| + * @param flags |
| + * Flags describing the fields |
| + * @param analyzer |
| + * Analyzer to use |
| + * @throws ParseException |
| + * if query parsing fails |
| + * @throws IllegalArgumentException |
| + * if the length of the fields array differs from the length of the |
| + * flags array |
| + */ |
| + public static Query parse(String query, String[] fields, |
| + BooleanClause.Occur[] flags, Analyzer analyzer) throws ParseException { |
| + if (fields.length != flags.length) |
| + throw new IllegalArgumentException("fields.length != flags.length"); |
| + BooleanQuery bQuery = new BooleanQuery(); |
| + for (int i = 0; i < fields.length; i++) { |
| + QueryParserWrapper qp = new QueryParserWrapper(fields[i], analyzer); |
| + Query q = qp.parse(query); |
| + if (q != null && // q never null, just being defensive |
| + (!(q instanceof BooleanQuery) || ((BooleanQuery) q).getClauses().length > 0)) { |
| + bQuery.add(q, flags[i]); |
| + } |
| + } |
| + return bQuery; |
| + } |
| + |
| + /** |
| + * Parses a query, searching on the fields specified. Use this if you need to |
| + * specify certain fields as required, and others as prohibited. |
| + * <p> |
| + * |
| + * <pre> |
| + * Usage: |
| + * <code> |
| + * String[] query = {"query1", "query2", "query3"}; |
| + * String[] fields = {"filename", "contents", "description"}; |
| + * BooleanClause.Occur[] flags = {BooleanClause.Occur.SHOULD, |
| + * BooleanClause.Occur.MUST, |
| + * BooleanClause.Occur.MUST_NOT}; |
| + * MultiFieldQueryParser.parse(query, fields, flags, analyzer); |
| + * </code> |
| + * </pre> |
| + *<p> |
| + * The code above would construct a query: |
| + * |
| + * <pre> |
| + * <code> |
| + * (filename:query1) +(contents:query2) -(description:query3) |
| + * </code> |
| + * </pre> |
| + * |
| + * @param queries |
| + * Queries string to parse |
| + * @param fields |
| + * Fields to search on |
| + * @param flags |
| + * Flags describing the fields |
| + * @param analyzer |
| + * Analyzer to use |
| + * @throws ParseException |
| + * if query parsing fails |
| + * @throws IllegalArgumentException |
| + * if the length of the queries, fields, and flags array differ |
| + */ |
| + public static Query parse(String[] queries, String[] fields, |
| + BooleanClause.Occur[] flags, Analyzer analyzer) throws ParseException { |
| + if (!(queries.length == fields.length && queries.length == flags.length)) |
| + throw new IllegalArgumentException( |
| + "queries, fields, and flags array have have different length"); |
| + BooleanQuery bQuery = new BooleanQuery(); |
| + for (int i = 0; i < fields.length; i++) { |
| + QueryParserWrapper qp = new QueryParserWrapper(fields[i], analyzer); |
| + Query q = qp.parse(queries[i]); |
| + if (q != null && // q never null, just being defensive |
| + (!(q instanceof BooleanQuery) || ((BooleanQuery) q).getClauses().length > 0)) { |
| + bQuery.add(q, flags[i]); |
| + } |
| + } |
| + return bQuery; |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/MultiFieldQueryParserWrapper.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/package.html |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/package.html (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/package.html (revision 0) |
| @@ -0,0 +1,48 @@ |
| +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> |
| +<!-- |
| + 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. |
| +--> |
| +<html> |
| +<head> |
| + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| +</head> |
| +<body> |
| + |
| +<h2>Lucene Flexible Query Parser</h2> |
| +<p> |
| +The old Lucene query parser used to have only one class that performed |
| +all the parsing operations. In the new query parser structure, the |
| +parsing was divided in 3 steps: parsing (syntax), processing (semantic) |
| +and building. |
| +</p> |
| +<p> |
| +The classes contained in the package org.apache.lucene.queryParser.original |
| +are used to reproduce the same behaviour as the old query parser. |
| +</p> |
| + |
| +<p> |
| +Check <tt>org.apache.lucene.queryParser.original.LuceneQueryParserHelper</tt> to quick start using the Lucene query parser. |
| +</p> |
| + |
| +<p> |
| +There are 2 wrapper classes that extends QueryParser and MultiFieldQueryParser. |
| +The classes implement internally the new query parser structure. These 2 |
| +classes are deprecated and should only be used when there is a need to use the |
| +old query parser interface. |
| +</p> |
| + |
| +</body> |
| +</html> |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/package.html |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/QueryParserUtil.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/QueryParserUtil.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/QueryParserUtil.java (revision 0) |
| @@ -0,0 +1,189 @@ |
| +package org.apache.lucene.queryParser.original; |
| + |
| +import org.apache.lucene.analysis.Analyzer; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.search.BooleanClause; |
| +import org.apache.lucene.search.BooleanQuery; |
| +import org.apache.lucene.search.Query; |
| + |
| +/** |
| + * This class defines utility methods to (help) parse query strings into |
| + * {@link Query} objects. |
| + */ |
| +final public class QueryParserUtil { |
| + |
| + /** |
| + * Parses a query which searches on the fields specified. |
| + * <p> |
| + * If x fields are specified, this effectively constructs: |
| + * |
| + * <pre> |
| + * <code> |
| + * (field1:query1) (field2:query2) (field3:query3)...(fieldx:queryx) |
| + * </code> |
| + * </pre> |
| + * |
| + * @param queries |
| + * Queries strings to parse |
| + * @param fields |
| + * Fields to search on |
| + * @param analyzer |
| + * Analyzer to use |
| + * @throws IllegalArgumentException |
| + * if the length of the queries array differs from the length of the |
| + * fields array |
| + */ |
| + public static Query parse(String[] queries, String[] fields, Analyzer analyzer) |
| + throws QueryNodeException { |
| + if (queries.length != fields.length) |
| + throw new IllegalArgumentException("queries.length != fields.length"); |
| + BooleanQuery bQuery = new BooleanQuery(); |
| + |
| + LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + qp.getQueryConfigHandler().setAnalyzer(analyzer); |
| + |
| + for (int i = 0; i < fields.length; i++) { |
| + Query q = qp.parse(queries[i], fields[i]); |
| + |
| + if (q != null && // q never null, just being defensive |
| + (!(q instanceof BooleanQuery) || ((BooleanQuery) q).getClauses().length > 0)) { |
| + bQuery.add(q, BooleanClause.Occur.SHOULD); |
| + } |
| + } |
| + return bQuery; |
| + } |
| + |
| + /** |
| + * Parses a query, searching on the fields specified. Use this if you need to |
| + * specify certain fields as required, and others as prohibited. |
| + * <p> |
| + * |
| + * <pre> |
| + * Usage: |
| + * <code> |
| + * String[] fields = {"filename", "contents", "description"}; |
| + * BooleanClause.Occur[] flags = {BooleanClause.Occur.SHOULD, |
| + * BooleanClause.Occur.MUST, |
| + * BooleanClause.Occur.MUST_NOT}; |
| + * MultiFieldQueryParser.parse("query", fields, flags, analyzer); |
| + * </code> |
| + * </pre> |
| + *<p> |
| + * The code above would construct a query: |
| + * |
| + * <pre> |
| + * <code> |
| + * (filename:query) +(contents:query) -(description:query) |
| + * </code> |
| + * </pre> |
| + * |
| + * @param query |
| + * Query string to parse |
| + * @param fields |
| + * Fields to search on |
| + * @param flags |
| + * Flags describing the fields |
| + * @param analyzer |
| + * Analyzer to use |
| + * @throws IllegalArgumentException |
| + * if the length of the fields array differs from the length of the |
| + * flags array |
| + */ |
| + public static Query parse(String query, String[] fields, |
| + BooleanClause.Occur[] flags, Analyzer analyzer) throws QueryNodeException { |
| + if (fields.length != flags.length) |
| + throw new IllegalArgumentException("fields.length != flags.length"); |
| + BooleanQuery bQuery = new BooleanQuery(); |
| + |
| + LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + qp.getQueryConfigHandler().setAnalyzer(analyzer); |
| + |
| + for (int i = 0; i < fields.length; i++) { |
| + Query q = qp.parse(query, fields[i]); |
| + |
| + if (q != null && // q never null, just being defensive |
| + (!(q instanceof BooleanQuery) || ((BooleanQuery) q).getClauses().length > 0)) { |
| + bQuery.add(q, flags[i]); |
| + } |
| + } |
| + return bQuery; |
| + } |
| + |
| + /** |
| + * Parses a query, searching on the fields specified. Use this if you need to |
| + * specify certain fields as required, and others as prohibited. |
| + * <p> |
| + * |
| + * <pre> |
| + * Usage: |
| + * <code> |
| + * String[] query = {"query1", "query2", "query3"}; |
| + * String[] fields = {"filename", "contents", "description"}; |
| + * BooleanClause.Occur[] flags = {BooleanClause.Occur.SHOULD, |
| + * BooleanClause.Occur.MUST, |
| + * BooleanClause.Occur.MUST_NOT}; |
| + * MultiFieldQueryParser.parse(query, fields, flags, analyzer); |
| + * </code> |
| + * </pre> |
| + *<p> |
| + * The code above would construct a query: |
| + * |
| + * <pre> |
| + * <code> |
| + * (filename:query1) +(contents:query2) -(description:query3) |
| + * </code> |
| + * </pre> |
| + * |
| + * @param queries |
| + * Queries string to parse |
| + * @param fields |
| + * Fields to search on |
| + * @param flags |
| + * Flags describing the fields |
| + * @param analyzer |
| + * Analyzer to use |
| + * @throws IllegalArgumentException |
| + * if the length of the queries, fields, and flags array differ |
| + */ |
| + public static Query parse(String[] queries, String[] fields, |
| + BooleanClause.Occur[] flags, Analyzer analyzer) throws QueryNodeException { |
| + if (!(queries.length == fields.length && queries.length == flags.length)) |
| + throw new IllegalArgumentException( |
| + "queries, fields, and flags array have have different length"); |
| + BooleanQuery bQuery = new BooleanQuery(); |
| + |
| + LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + qp.getQueryConfigHandler().setAnalyzer(analyzer); |
| + |
| + for (int i = 0; i < fields.length; i++) { |
| + Query q = qp.parse(queries[i], fields[i]); |
| + |
| + if (q != null && // q never null, just being defensive |
| + (!(q instanceof BooleanQuery) || ((BooleanQuery) q).getClauses().length > 0)) { |
| + bQuery.add(q, flags[i]); |
| + } |
| + } |
| + return bQuery; |
| + } |
| + |
| + /** |
| + * Returns a String where those characters that TextParser expects to be |
| + * escaped are escaped by a preceding <code>\</code>. |
| + */ |
| + public static String escape(String s) { |
| + StringBuffer sb = new StringBuffer(); |
| + for (int i = 0; i < s.length(); i++) { |
| + char c = s.charAt(i); |
| + // These characters are part of the query syntax and must be escaped |
| + if (c == '\\' || c == '+' || c == '-' || c == '!' || c == '(' || c == ')' |
| + || c == ':' || c == '^' || c == '[' || c == ']' || c == '\"' |
| + || c == '{' || c == '}' || c == '~' || c == '*' || c == '?' |
| + || c == '|' || c == '&') { |
| + sb.append('\\'); |
| + } |
| + sb.append(c); |
| + } |
| + return sb.toString(); |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/QueryParserUtil.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/BoostQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/BoostQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/BoostQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,54 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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.QueryNodeException; |
| +import org.apache.lucene.queryParser.builders.QueryTreeBuilder; |
| +import org.apache.lucene.queryParser.nodes.BoostQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.search.Query; |
| + |
| +/** |
| + * This builder basically reads the {@link Query} object set on the |
| + * {@link BoostQueryNode} child using |
| + * {@link QueryTreeBuilder#QUERY_TREE_BUILDER_TAGID} and applies the boost value |
| + * defined in the {@link BoostQueryNode}. |
| + */ |
| +public class BoostQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public BoostQueryNodeBuilder() { |
| + // empty constructor |
| + } |
| + |
| + public Query build(QueryNode queryNode) throws QueryNodeException { |
| + BoostQueryNode boostNode = (BoostQueryNode) queryNode; |
| + QueryNode child = boostNode.getChild(); |
| + |
| + if (child == null) { |
| + return null; |
| + } |
| + |
| + Query query = (Query) child |
| + .getTag(QueryTreeBuilder.QUERY_TREE_BUILDER_TAGID); |
| + query.setBoost(boostNode.getValue()); |
| + |
| + return query; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/BooleanQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/BooleanQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/BooleanQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,110 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.builders.QueryTreeBuilder; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.nodes.BooleanQueryNode; |
| +import org.apache.lucene.queryParser.nodes.ModifierQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.parser.EscapeQuerySyntaxImpl; |
| +import org.apache.lucene.search.BooleanClause; |
| +import org.apache.lucene.search.BooleanQuery; |
| +import org.apache.lucene.search.Query; |
| +import org.apache.lucene.search.BooleanQuery.TooManyClauses; |
| + |
| +/** |
| + * Builds a {@link BooleanQuery} object from a {@link BooleanQueryNode} object. |
| + * Every children in the {@link BooleanQueryNode} object must be already tagged |
| + * using {@link QueryTreeBuilder#QUERY_TREE_BUILDER_TAGID} with a {@link Query} |
| + * object. <br/> |
| + * <br/> |
| + * It takes in consideration if the children is a {@link ModifierQueryNode} to |
| + * define the {@link BooleanClause}. |
| + */ |
| +public class BooleanQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public BooleanQueryNodeBuilder() { |
| + // empty constructor |
| + } |
| + |
| + public BooleanQuery build(QueryNode queryNode) throws QueryNodeException { |
| + BooleanQueryNode booleanNode = (BooleanQueryNode) queryNode; |
| + |
| + BooleanQuery bQuery = new BooleanQuery(); |
| + List<QueryNode> children = booleanNode.getChildren(); |
| + |
| + if (children != null) { |
| + |
| + for (QueryNode child : children) { |
| + Object obj = child.getTag(QueryTreeBuilder.QUERY_TREE_BUILDER_TAGID); |
| + |
| + if (obj != null) { |
| + Query query = (Query) obj; |
| + |
| + try { |
| + bQuery.add(query, getModifierValue(child)); |
| + |
| + } catch (TooManyClauses ex) { |
| + |
| + throw new QueryNodeException(new MessageImpl( |
| + QueryParserMessages.TOO_MANY_BOOLEAN_CLAUSES, BooleanQuery |
| + .getMaxClauseCount(), queryNode |
| + .toQueryString(new EscapeQuerySyntaxImpl())), ex); |
| + |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + return bQuery; |
| + |
| + } |
| + |
| + private static BooleanClause.Occur getModifierValue(QueryNode node) |
| + throws QueryNodeException { |
| + |
| + if (node instanceof ModifierQueryNode) { |
| + ModifierQueryNode mNode = ((ModifierQueryNode) node); |
| + switch (mNode.getModifier()) { |
| + |
| + case MOD_REQ: |
| + return BooleanClause.Occur.MUST; |
| + |
| + case MOD_NOT: |
| + return BooleanClause.Occur.MUST_NOT; |
| + |
| + case MOD_NONE: |
| + return BooleanClause.Occur.SHOULD; |
| + |
| + } |
| + |
| + } |
| + |
| + return BooleanClause.Occur.SHOULD; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/ModifierQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/ModifierQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/ModifierQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,45 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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.QueryNodeException; |
| +import org.apache.lucene.queryParser.builders.QueryTreeBuilder; |
| +import org.apache.lucene.queryParser.nodes.ModifierQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.search.Query; |
| + |
| +/** |
| + * Builds no object, it only returns the {@link Query} object set on the |
| + * {@link ModifierQueryNode} object using a |
| + * {@link QueryTreeBuilder#QUERY_TREE_BUILDER_TAGID} tag. |
| + */ |
| +public class ModifierQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public ModifierQueryNodeBuilder() { |
| + // empty constructor |
| + } |
| + |
| + public Query build(QueryNode queryNode) throws QueryNodeException { |
| + ModifierQueryNode modifierNode = (ModifierQueryNode) queryNode; |
| + |
| + return (Query) (modifierNode).getChild().getTag( |
| + QueryTreeBuilder.QUERY_TREE_BUILDER_TAGID); |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/LuceneQueryTreeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/LuceneQueryTreeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/LuceneQueryTreeBuilder.java (revision 0) |
| @@ -0,0 +1,78 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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.QueryNodeException; |
| +import org.apache.lucene.queryParser.builders.QueryTreeBuilder; |
| +import org.apache.lucene.queryParser.nodes.BooleanQueryNode; |
| +import org.apache.lucene.queryParser.nodes.BoostQueryNode; |
| +import org.apache.lucene.queryParser.nodes.FieldQueryNode; |
| +import org.apache.lucene.queryParser.nodes.FuzzyQueryNode; |
| +import org.apache.lucene.queryParser.nodes.GroupQueryNode; |
| +import org.apache.lucene.queryParser.nodes.MatchAllDocsQueryNode; |
| +import org.apache.lucene.queryParser.nodes.MatchNoDocsQueryNode; |
| +import org.apache.lucene.queryParser.nodes.ModifierQueryNode; |
| +import org.apache.lucene.queryParser.nodes.PrefixWildcardQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.SlopQueryNode; |
| +import org.apache.lucene.queryParser.nodes.TokenizedPhraseQueryNode; |
| +import org.apache.lucene.queryParser.nodes.WildcardQueryNode; |
| +import org.apache.lucene.queryParser.original.nodes.LuceneBooleanQueryNode; |
| +import org.apache.lucene.queryParser.original.nodes.MultiPhraseQueryNode; |
| +import org.apache.lucene.queryParser.original.nodes.RangeQueryNode; |
| +import org.apache.lucene.queryParser.original.processors.LuceneQueryNodeProcessorPipeline; |
| +import org.apache.lucene.search.Query; |
| + |
| +/** |
| + * This query tree builder only defines the necessary map to build a |
| + * {@link Query} tree object. It should be used to generate a {@link Query} tree |
| + * object from a query node tree processed by a |
| + * {@link LuceneQueryNodeProcessorPipeline}. <br/> |
| + * |
| + * @see QueryTreeBuilder |
| + * @see LuceneQueryNodeProcessorPipeline |
| + */ |
| +public class LuceneQueryTreeBuilder extends QueryTreeBuilder implements |
| + LuceneQueryBuilder { |
| + |
| + public LuceneQueryTreeBuilder() { |
| + setBuilder(GroupQueryNode.class, new GroupQueryNodeBuilder()); |
| + setBuilder(FieldQueryNode.class, new FieldQueryNodeBuilder()); |
| + setBuilder(BooleanQueryNode.class, new BooleanQueryNodeBuilder()); |
| + setBuilder(FuzzyQueryNode.class, new FuzzyQueryNodeBuilder()); |
| + setBuilder(BoostQueryNode.class, new BoostQueryNodeBuilder()); |
| + setBuilder(ModifierQueryNode.class, new ModifierQueryNodeBuilder()); |
| + setBuilder(WildcardQueryNode.class, new WildcardQueryNodeBuilder()); |
| + setBuilder(TokenizedPhraseQueryNode.class, new PhraseQueryNodeBuilder()); |
| + setBuilder(MatchNoDocsQueryNode.class, new MatchNoDocsQueryNodeBuilder()); |
| + setBuilder(PrefixWildcardQueryNode.class, |
| + new PrefixWildcardQueryNodeBuilder()); |
| + setBuilder(RangeQueryNode.class, new RangeQueryNodeBuilder()); |
| + setBuilder(SlopQueryNode.class, new SlopQueryNodeBuilder()); |
| + setBuilder(LuceneBooleanQueryNode.class, |
| + new LuceneBooleanQueryNodeBuilder()); |
| + setBuilder(MultiPhraseQueryNode.class, new MultiPhraseQueryNodeBuilder()); |
| + setBuilder(MatchAllDocsQueryNode.class, new MatchAllDocsQueryNodeBuilder()); |
| + |
| + } |
| + |
| + public Query build(QueryNode queryNode) throws QueryNodeException { |
| + return (Query) super.build(queryNode); |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MultiPhraseQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MultiPhraseQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MultiPhraseQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,84 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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 java.util.LinkedList; |
| +import java.util.List; |
| +import java.util.TreeMap; |
| + |
| +import org.apache.lucene.index.Term; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.builders.QueryTreeBuilder; |
| +import org.apache.lucene.queryParser.nodes.FieldQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.nodes.MultiPhraseQueryNode; |
| +import org.apache.lucene.search.MultiPhraseQuery; |
| +import org.apache.lucene.search.TermQuery; |
| + |
| +/** |
| + * Builds a {@link MultiPhraseQuery} object from a {@link MultiPhraseQueryNode} |
| + * object. |
| + */ |
| +public class MultiPhraseQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public MultiPhraseQueryNodeBuilder() { |
| + // empty constructor |
| + } |
| + |
| + public MultiPhraseQuery build(QueryNode queryNode) throws QueryNodeException { |
| + MultiPhraseQueryNode phraseNode = (MultiPhraseQueryNode) queryNode; |
| + |
| + MultiPhraseQuery phraseQuery = new MultiPhraseQuery(); |
| + |
| + List<QueryNode> children = phraseNode.getChildren(); |
| + |
| + if (children != null) { |
| + TreeMap<Integer, List<Term>> positionTermMap = new TreeMap<Integer, List<Term>>(); |
| + |
| + for (QueryNode child : children) { |
| + FieldQueryNode termNode = (FieldQueryNode) child; |
| + TermQuery termQuery = (TermQuery) termNode |
| + .getTag(QueryTreeBuilder.QUERY_TREE_BUILDER_TAGID); |
| + List<Term> termList = positionTermMap.get(termNode |
| + .getPositionIncrement()); |
| + |
| + if (termList == null) { |
| + termList = new LinkedList<Term>(); |
| + positionTermMap.put(termNode.getPositionIncrement(), termList); |
| + |
| + } |
| + |
| + termList.add(termQuery.getTerm()); |
| + |
| + } |
| + |
| + for (int positionIncrement : positionTermMap.keySet()) { |
| + List<Term> termList = positionTermMap.get(positionIncrement); |
| + |
| + phraseQuery.add(termList.toArray(new Term[termList.size()]), |
| + positionIncrement); |
| + |
| + } |
| + |
| + } |
| + |
| + return phraseQuery; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/WildcardQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/WildcardQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/WildcardQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,44 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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.Term; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.WildcardQueryNode; |
| +import org.apache.lucene.search.WildcardQuery; |
| + |
| +/** |
| + * Builds a {@link WildcardQuery} object from a {@link WildcardQueryNode} |
| + * object. |
| + */ |
| +public class WildcardQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public WildcardQueryNodeBuilder() { |
| + // empty constructor |
| + } |
| + |
| + public WildcardQuery build(QueryNode queryNode) throws QueryNodeException { |
| + WildcardQueryNode wildcardNode = (WildcardQueryNode) queryNode; |
| + |
| + return new WildcardQuery(new Term(wildcardNode.getFieldAsString(), |
| + wildcardNode.getTextAsString())); |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/SlopQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/SlopQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/SlopQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,57 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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.QueryNodeException; |
| +import org.apache.lucene.queryParser.builders.QueryTreeBuilder; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.SlopQueryNode; |
| +import org.apache.lucene.search.MultiPhraseQuery; |
| +import org.apache.lucene.search.PhraseQuery; |
| +import org.apache.lucene.search.Query; |
| + |
| +/** |
| + * This builder basically reads the {@link Query} object set on the |
| + * {@link SlopQueryNode} child using |
| + * {@link QueryTreeBuilder#QUERY_TREE_BUILDER_TAGID} and applies the slop value |
| + * defined in the {@link SlopQueryNode}. |
| + */ |
| +public class SlopQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public SlopQueryNodeBuilder() { |
| + // empty constructor |
| + } |
| + |
| + public Query build(QueryNode queryNode) throws QueryNodeException { |
| + SlopQueryNode phraseSlopNode = (SlopQueryNode) queryNode; |
| + |
| + Query query = (Query) phraseSlopNode.getChild().getTag( |
| + QueryTreeBuilder.QUERY_TREE_BUILDER_TAGID); |
| + |
| + if (query instanceof PhraseQuery) { |
| + ((PhraseQuery) query).setSlop(phraseSlopNode.getValue()); |
| + |
| + } else { |
| + ((MultiPhraseQuery) query).setSlop(phraseSlopNode.getValue()); |
| + } |
| + |
| + return query; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/GroupQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/GroupQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/GroupQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,45 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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.QueryNodeException; |
| +import org.apache.lucene.queryParser.builders.QueryTreeBuilder; |
| +import org.apache.lucene.queryParser.nodes.GroupQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.search.Query; |
| + |
| +/** |
| + * Builds no object, it only returns the {@link Query} object set on the |
| + * {@link GroupQueryNode} object using a |
| + * {@link QueryTreeBuilder#QUERY_TREE_BUILDER_TAGID} tag. |
| + */ |
| +public class GroupQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public GroupQueryNodeBuilder() { |
| + // empty constructor |
| + } |
| + |
| + public Query build(QueryNode queryNode) throws QueryNodeException { |
| + GroupQueryNode groupNode = (GroupQueryNode) queryNode; |
| + |
| + return (Query) (groupNode).getChild().getTag( |
| + QueryTreeBuilder.QUERY_TREE_BUILDER_TAGID); |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/package.html |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/package.html (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/package.html (revision 0) |
| @@ -0,0 +1,35 @@ |
| +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> |
| +<!-- |
| + 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. |
| +--> |
| +<html> |
| +<head> |
| + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| +</head> |
| +<body> |
| + |
| +<h2>Original Lucene Query Node Builders</h2> |
| +<p> |
| +The package org.apache.lucene.queryParser.original.builders contains all the builders needed |
| +to build a Lucene Query object from a query node tree. These builders expect the query node tree was |
| +already processed by the {@link org.apache.lucene.queryParser.original.processors.LuceneQueryNodeProcessorPipeline}. |
| +</p> |
| +<p> |
| +{@link org.apache.lucene.queryParser.original.builders.LuceneQueryTreeBuilder} is a builder that already contains a defined map that maps each QueryNode object |
| +with its respective builder. |
| +</p> |
| +</body> |
| +</html> |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/LuceneQueryBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/LuceneQueryBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/LuceneQueryBuilder.java (revision 0) |
| @@ -0,0 +1,37 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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.QueryNodeException; |
| +import org.apache.lucene.queryParser.builders.QueryBuilder; |
| +import org.apache.lucene.queryParser.builders.QueryTreeBuilder; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.search.Query; |
| + |
| +/** |
| + * This interface should be implemented by every class that wants to build |
| + * {@link Query} objects from {@link QueryNode} objects. <br/> |
| + * |
| + * @see QueryBuilder |
| + * @see QueryTreeBuilder |
| + */ |
| +public interface LuceneQueryBuilder extends QueryBuilder { |
| + |
| + public Query build(QueryNode queryNode) throws QueryNodeException; |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/FuzzyQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/FuzzyQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/FuzzyQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,44 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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.Term; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.nodes.FuzzyQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.search.FuzzyQuery; |
| + |
| +/** |
| + * Builds a {@link FuzzyQuery} object from a {@link FuzzyQueryNode} object. |
| + */ |
| +public class FuzzyQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public FuzzyQueryNodeBuilder() { |
| + // empty constructor |
| + } |
| + |
| + public FuzzyQuery build(QueryNode queryNode) throws QueryNodeException { |
| + FuzzyQueryNode fuzzyNode = (FuzzyQueryNode) queryNode; |
| + |
| + return new FuzzyQuery(new Term(fuzzyNode.getFieldAsString(), fuzzyNode |
| + .getTextAsString()), fuzzyNode.getSimilarity(), fuzzyNode |
| + .getPrefixLength()); |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/PhraseQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/PhraseQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/PhraseQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,64 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.builders.QueryTreeBuilder; |
| +import org.apache.lucene.queryParser.nodes.FieldQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.TokenizedPhraseQueryNode; |
| +import org.apache.lucene.search.PhraseQuery; |
| +import org.apache.lucene.search.TermQuery; |
| + |
| +/** |
| + * Builds a {@link PhraseQuery} object from a {@link TokenizedPhraseQueryNode} |
| + * object. |
| + */ |
| +public class PhraseQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public PhraseQueryNodeBuilder() { |
| + // empty constructor |
| + } |
| + |
| + public PhraseQuery build(QueryNode queryNode) throws QueryNodeException { |
| + TokenizedPhraseQueryNode phraseNode = (TokenizedPhraseQueryNode) queryNode; |
| + |
| + PhraseQuery phraseQuery = new PhraseQuery(); |
| + |
| + List<QueryNode> children = phraseNode.getChildren(); |
| + |
| + if (children != null) { |
| + |
| + for (QueryNode child : children) { |
| + TermQuery termQuery = (TermQuery) child |
| + .getTag(QueryTreeBuilder.QUERY_TREE_BUILDER_TAGID); |
| + FieldQueryNode termNode = (FieldQueryNode) child; |
| + |
| + phraseQuery.add(termQuery.getTerm(), termNode.getPositionIncrement()); |
| + |
| + } |
| + |
| + } |
| + |
| + return phraseQuery; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MatchNoDocsQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MatchNoDocsQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MatchNoDocsQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,52 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.nodes.MatchNoDocsQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.parser.EscapeQuerySyntaxImpl; |
| +import org.apache.lucene.search.BooleanQuery; |
| + |
| +/** |
| + * Builds an empty {@link BooleanQuery} object from a |
| + * {@link MatchNoDocsQueryNode} object. |
| + */ |
| +public class MatchNoDocsQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public MatchNoDocsQueryNodeBuilder() { |
| + // empty constructor |
| + } |
| + |
| + public BooleanQuery build(QueryNode queryNode) throws QueryNodeException { |
| + |
| + // validates node |
| + if (!(queryNode instanceof MatchNoDocsQueryNode)) { |
| + throw new QueryNodeException(new MessageImpl( |
| + QueryParserMessages.LUCENE_QUERY_CONVERSION_ERROR, queryNode |
| + .toQueryString(new EscapeQuerySyntaxImpl()), queryNode.getClass() |
| + .getName())); |
| + } |
| + |
| + return new BooleanQuery(); |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/PrefixWildcardQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/PrefixWildcardQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/PrefixWildcardQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,44 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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.Term; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.nodes.PrefixWildcardQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.search.PrefixQuery; |
| + |
| +/** |
| + * Builds a {@link PrefixQuery} object from a {@link PrefixWildcardQueryNode} |
| + * object. |
| + */ |
| +public class PrefixWildcardQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public PrefixWildcardQueryNodeBuilder() { |
| + // empty constructor |
| + } |
| + |
| + public PrefixQuery build(QueryNode queryNode) throws QueryNodeException { |
| + PrefixWildcardQueryNode wildcardNode = (PrefixWildcardQueryNode) queryNode; |
| + |
| + return new PrefixQuery(new Term(wildcardNode.getFieldAsString(), |
| + wildcardNode.getTextAsString())); |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MatchAllDocsQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MatchAllDocsQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MatchAllDocsQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,52 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.nodes.MatchAllDocsQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.parser.EscapeQuerySyntaxImpl; |
| +import org.apache.lucene.search.MatchAllDocsQuery; |
| + |
| +/** |
| + * Builds a {@link MatchAllDocsQuery} object from a |
| + * {@link MatchAllDocsQueryNode} object. |
| + */ |
| +public class MatchAllDocsQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public MatchAllDocsQueryNodeBuilder() { |
| + // empty constructor |
| + } |
| + |
| + public MatchAllDocsQuery build(QueryNode queryNode) throws QueryNodeException { |
| + |
| + // validates node |
| + if (!(queryNode instanceof MatchAllDocsQueryNode)) { |
| + throw new QueryNodeException(new MessageImpl( |
| + QueryParserMessages.LUCENE_QUERY_CONVERSION_ERROR, queryNode |
| + .toQueryString(new EscapeQuerySyntaxImpl()), queryNode.getClass() |
| + .getName())); |
| + } |
| + |
| + return new MatchAllDocsQuery(); |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/FieldQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/FieldQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/FieldQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,43 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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.Term; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.nodes.FieldQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.search.TermQuery; |
| + |
| +/** |
| + * Builds a {@link TermQuery} object from a {@link FieldQueryNode} object. |
| + */ |
| +public class FieldQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public FieldQueryNodeBuilder() { |
| + // empty constructor |
| + } |
| + |
| + public TermQuery build(QueryNode queryNode) throws QueryNodeException { |
| + FieldQueryNode fieldNode = (FieldQueryNode) queryNode; |
| + |
| + return new TermQuery(new Term(fieldNode.getFieldAsString(), fieldNode |
| + .getTextAsString())); |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/RangeQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/RangeQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/RangeQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,63 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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.QueryNodeException; |
| +import org.apache.lucene.queryParser.nodes.ParametricQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.ParametricQueryNode.CompareOperator; |
| +import org.apache.lucene.queryParser.original.nodes.RangeQueryNode; |
| +import org.apache.lucene.search.TermRangeQuery; |
| + |
| +/** |
| + * Builds a {@link TermRangeQuery} object from a {@link RangeQueryNode} object. |
| + */ |
| +public class RangeQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public RangeQueryNodeBuilder() { |
| + // empty constructor |
| + } |
| + |
| + public TermRangeQuery build(QueryNode queryNode) throws QueryNodeException { |
| + RangeQueryNode rangeNode = (RangeQueryNode) queryNode; |
| + ParametricQueryNode upper = rangeNode.getUpperBound(); |
| + ParametricQueryNode lower = rangeNode.getLowerBound(); |
| + |
| + boolean lowerInclusive = false; |
| + boolean upperInclusive = false; |
| + |
| + if (upper.getOperator() == CompareOperator.LE) { |
| + upperInclusive = true; |
| + } |
| + |
| + if (lower.getOperator() == CompareOperator.GE) { |
| + lowerInclusive = true; |
| + } |
| + |
| + String field = rangeNode.getField().toString(); |
| + |
| + TermRangeQuery rangeQuery = new TermRangeQuery(field, lower |
| + .getTextAsString(), upper.getTextAsString(), lowerInclusive, |
| + upperInclusive, rangeNode.getCollator()); |
| + rangeQuery.setConstantScoreRewrite(rangeNode.isConstantScoreRewrite()); |
| + |
| + return rangeQuery; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/LuceneBooleanQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/LuceneBooleanQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/LuceneBooleanQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,109 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.builders.QueryTreeBuilder; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.nodes.ModifierQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.ModifierQueryNode.Modifier; |
| +import org.apache.lucene.queryParser.original.nodes.LuceneBooleanQueryNode; |
| +import org.apache.lucene.queryParser.original.parser.EscapeQuerySyntaxImpl; |
| +import org.apache.lucene.search.BooleanClause; |
| +import org.apache.lucene.search.BooleanQuery; |
| +import org.apache.lucene.search.Query; |
| +import org.apache.lucene.search.Similarity; |
| +import org.apache.lucene.search.BooleanQuery.TooManyClauses; |
| + |
| +/** |
| + * This builder does the same as the {@link BooleanQueryNodeBuilder}, but this |
| + * considers if the built {@link BooleanQuery} should have its coord disabled or |
| + * not. <br/> |
| + * |
| + * @see BooleanQueryNodeBuilder |
| + * @see BooleanQuery |
| + * @see Similarity#coord(int, int) |
| + */ |
| +public class LuceneBooleanQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public LuceneBooleanQueryNodeBuilder() { |
| + // empty constructor |
| + } |
| + |
| + public BooleanQuery build(QueryNode queryNode) throws QueryNodeException { |
| + LuceneBooleanQueryNode booleanNode = (LuceneBooleanQueryNode) queryNode; |
| + |
| + BooleanQuery bQuery = new BooleanQuery(booleanNode.isDisableCoord()); |
| + List<QueryNode> children = booleanNode.getChildren(); |
| + |
| + if (children != null) { |
| + |
| + for (QueryNode child : children) { |
| + Object obj = child.getTag(QueryTreeBuilder.QUERY_TREE_BUILDER_TAGID); |
| + |
| + if (obj != null) { |
| + Query query = (Query) obj; |
| + |
| + try { |
| + bQuery.add(query, getModifierValue(child)); |
| + } catch (TooManyClauses ex) { |
| + |
| + throw new QueryNodeException(new MessageImpl( |
| + QueryParserMessages.TOO_MANY_BOOLEAN_CLAUSES, BooleanQuery |
| + .getMaxClauseCount(), queryNode |
| + .toQueryString(new EscapeQuerySyntaxImpl())), ex); |
| + |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + return bQuery; |
| + |
| + } |
| + |
| + private static BooleanClause.Occur getModifierValue(QueryNode node) |
| + throws QueryNodeException { |
| + |
| + if (node instanceof ModifierQueryNode) { |
| + ModifierQueryNode mNode = ((ModifierQueryNode) node); |
| + Modifier modifier = mNode.getModifier(); |
| + |
| + if (Modifier.MOD_NONE.equals(modifier)) { |
| + return BooleanClause.Occur.SHOULD; |
| + |
| + } else if (Modifier.MOD_NOT.equals(modifier)) { |
| + return BooleanClause.Occur.MUST_NOT; |
| + |
| + } else { |
| + return BooleanClause.Occur.MUST; |
| + } |
| + } |
| + |
| + return BooleanClause.Occur.SHOULD; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/AnyQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/AnyQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/AnyQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,77 @@ |
| +package org.apache.lucene.queryParser.original.builders; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.builders.QueryTreeBuilder; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.nodes.AnyQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.search.BooleanClause; |
| +import org.apache.lucene.search.BooleanQuery; |
| +import org.apache.lucene.search.Query; |
| +import org.apache.lucene.search.BooleanQuery.TooManyClauses; |
| + |
| +public class AnyQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public AnyQueryNodeBuilder() { |
| + // empty constructor |
| + } |
| + |
| + public BooleanQuery build(QueryNode queryNode) throws QueryNodeException { |
| + AnyQueryNode andNode = (AnyQueryNode) queryNode; |
| + |
| + BooleanQuery bQuery = new BooleanQuery(); |
| + List<QueryNode> children = andNode.getChildren(); |
| + |
| + if (children != null) { |
| + |
| + for (QueryNode child : children) { |
| + Object obj = child.getTag(QueryTreeBuilder.QUERY_TREE_BUILDER_TAGID); |
| + |
| + if (obj != null) { |
| + Query query = (Query) obj; |
| + |
| + try { |
| + bQuery.add(query, BooleanClause.Occur.SHOULD); |
| + } catch (TooManyClauses ex) { |
| + |
| + throw new QueryNodeException(new MessageImpl( |
| + /* |
| + * IQQQ.Q0028E_TOO_MANY_BOOLEAN_CLAUSES, |
| + * BooleanQuery.getMaxClauseCount() |
| + */QueryParserMessages.EMPTY_MESSAGE), ex); |
| + |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + bQuery.setMinimumNumberShouldMatch(andNode.getMinimumMatchingElements()); |
| + |
| + return bQuery; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/package.html |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/package.html (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/package.html (revision 0) |
| @@ -0,0 +1,33 @@ |
| +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> |
| +<!-- |
| + 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. |
| +--> |
| +<html> |
| +<head> |
| + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| +</head> |
| +<body> |
| + |
| +<h2>Lucene Query Parser</h2> |
| +<p> |
| +The package org.apache.lucene.queryParser.original.parser contains the query parser. |
| +</p> |
| +<p> |
| +This query parser only performs the syntax validation and create an QueryNode tree |
| +from a query string. |
| +</p> |
| +</body> |
| +</html> |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/TextParser.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/TextParser.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/TextParser.java (revision 0) |
| @@ -0,0 +1,1086 @@ |
| +/* Generated By:JavaCC: Do not edit this line. TextParser.java */ |
| +package org.apache.lucene.queryParser.original.parser; |
| + |
| +/** |
| + * 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 java.io.StringReader; |
| +import java.util.Vector; |
| + |
| +import org.apache.lucene.messages.Message; |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeParseException; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.nodes.AndQueryNode; |
| +import org.apache.lucene.queryParser.nodes.BooleanQueryNode; |
| +import org.apache.lucene.queryParser.nodes.BoostQueryNode; |
| +import org.apache.lucene.queryParser.nodes.FieldQueryNode; |
| +import org.apache.lucene.queryParser.nodes.FuzzyQueryNode; |
| +import org.apache.lucene.queryParser.nodes.GroupQueryNode; |
| +import org.apache.lucene.queryParser.nodes.ModifierQueryNode; |
| +import org.apache.lucene.queryParser.nodes.OrQueryNode; |
| +import org.apache.lucene.queryParser.nodes.ParametricQueryNode; |
| +import org.apache.lucene.queryParser.nodes.ParametricRangeQueryNode; |
| +import org.apache.lucene.queryParser.nodes.PrefixWildcardQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.QuotedFieldQueryNode; |
| +import org.apache.lucene.queryParser.nodes.SlopQueryNode; |
| +import org.apache.lucene.queryParser.nodes.WildcardQueryNode; |
| +import org.apache.lucene.queryParser.parser.Parser; |
| + |
| +@SuppressWarnings("all") |
| +public class TextParser implements Parser, QueryParserConstants { |
| + |
| + private static final int CONJ_NONE = 0; |
| + private static final int CONJ_AND = 2; |
| + private static final int CONJ_OR = 2; |
| + |
| + // query parser constructor |
| + public TextParser() { |
| + this(new StringReader("")); |
| + } |
| + |
| + /** |
| + * Parses a query string, returning a |
| + * {@link org.apache.lucene.queryParser.nodes.QueryNode}. |
| + * |
| + * @param query |
| + * the query string to be parsed. |
| + * @throws ParseException |
| + * if the parsing fails |
| + */ |
| + public QueryNode parse(CharSequence query, CharSequence field) |
| + throws QueryNodeParseException { |
| + ReInit(new StringReader(query.toString())); |
| + try { |
| + // TopLevelQuery is a Query followed by the end-of-input (EOF) |
| + QueryNode querynode = TopLevelQuery(field); |
| + return querynode; |
| + } catch (ParseException tme) { |
| + tme.setQuery(query); |
| + throw tme; |
| + } catch (Error tme) { |
| + Message message = new MessageImpl( |
| + QueryParserMessages.INVALID_SYNTAX_CANNOT_PARSE, query, tme |
| + .getMessage()); |
| + QueryNodeParseException e = new QueryNodeParseException(tme); |
| + e.setQuery(query); |
| + e.setNonLocalizedMessage(message); |
| + throw e; |
| + } |
| + } |
| + |
| + // * Query ::= ( Clause )* |
| + // * Clause ::= ["+", "-"] [<TERM> ":"] ( <TERM> | "(" Query ")" ) |
| + final public int Conjunction() throws ParseException { |
| + int ret = CONJ_NONE; |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case AND: |
| + case OR: |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case AND: |
| + jj_consume_token(AND); |
| + ret = CONJ_AND; |
| + break; |
| + case OR: |
| + jj_consume_token(OR); |
| + ret = CONJ_OR; |
| + break; |
| + default: |
| + jj_la1[0] = jj_gen; |
| + jj_consume_token(-1); |
| + throw new ParseException(); |
| + } |
| + break; |
| + default: |
| + jj_la1[1] = jj_gen; |
| + ; |
| + } |
| + { |
| + if (true) |
| + return ret; |
| + } |
| + throw new Error("Missing return statement in function"); |
| + } |
| + |
| + final public ModifierQueryNode.Modifier Modifiers() throws ParseException { |
| + ModifierQueryNode.Modifier ret = ModifierQueryNode.Modifier.MOD_NONE; |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case NOT: |
| + case PLUS: |
| + case MINUS: |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case PLUS: |
| + jj_consume_token(PLUS); |
| + ret = ModifierQueryNode.Modifier.MOD_REQ; |
| + break; |
| + case MINUS: |
| + jj_consume_token(MINUS); |
| + ret = ModifierQueryNode.Modifier.MOD_NOT; |
| + break; |
| + case NOT: |
| + jj_consume_token(NOT); |
| + ret = ModifierQueryNode.Modifier.MOD_NOT; |
| + break; |
| + default: |
| + jj_la1[2] = jj_gen; |
| + jj_consume_token(-1); |
| + throw new ParseException(); |
| + } |
| + break; |
| + default: |
| + jj_la1[3] = jj_gen; |
| + ; |
| + } |
| + { |
| + if (true) |
| + return ret; |
| + } |
| + throw new Error("Missing return statement in function"); |
| + } |
| + |
| + // This makes sure that there is no garbage after the query string |
| + final public QueryNode TopLevelQuery(CharSequence field) |
| + throws ParseException { |
| + QueryNode q; |
| + q = Query(field); |
| + jj_consume_token(0); |
| + { |
| + if (true) |
| + return q; |
| + } |
| + throw new Error("Missing return statement in function"); |
| + } |
| + |
| + // These changes were made to introduce operator precedence: |
| + // - Clause() now returns a QueryNode. |
| + // - The modifiers are consumed by Clause() and returned as part of the |
| + // QueryNode Object |
| + // - Query does not consume conjunctions (AND, OR) anymore. |
| + // - This is now done by two new non-terminals: ConjClause and DisjClause |
| + // The parse tree looks similar to this: |
| + // Query ::= DisjQuery ( DisjQuery )* |
| + // DisjQuery ::= ConjQuery ( OR ConjQuery )* |
| + // ConjQuery ::= Clause ( AND Clause )* |
| + // Clause ::= [ Modifier ] ... |
| + final public QueryNode Query(CharSequence field) throws ParseException { |
| + Vector clauses = null; |
| + QueryNode c, first = null; |
| + first = DisjQuery(field); |
| + label_1: while (true) { |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case NOT: |
| + case PLUS: |
| + case MINUS: |
| + case LPAREN: |
| + case STAR: |
| + case QUOTED: |
| + case TERM: |
| + case PREFIXTERM: |
| + case WILDTERM: |
| + case RANGEIN_START: |
| + case RANGEEX_START: |
| + case NUMBER: |
| + ; |
| + break; |
| + default: |
| + jj_la1[4] = jj_gen; |
| + break label_1; |
| + } |
| + c = DisjQuery(field); |
| + if (clauses == null) { |
| + clauses = new Vector(); |
| + clauses.addElement(first); |
| + } |
| + clauses.addElement(c); |
| + } |
| + if (clauses != null) { |
| + { |
| + if (true) |
| + return new BooleanQueryNode(clauses); |
| + } |
| + } else { |
| + { |
| + if (true) |
| + return first; |
| + } |
| + } |
| + throw new Error("Missing return statement in function"); |
| + } |
| + |
| + final public QueryNode DisjQuery(CharSequence field) throws ParseException { |
| + QueryNode first, c; |
| + Vector clauses = null; |
| + first = ConjQuery(field); |
| + label_2: while (true) { |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case OR: |
| + ; |
| + break; |
| + default: |
| + jj_la1[5] = jj_gen; |
| + break label_2; |
| + } |
| + jj_consume_token(OR); |
| + c = ConjQuery(field); |
| + if (clauses == null) { |
| + clauses = new Vector(); |
| + clauses.addElement(first); |
| + } |
| + clauses.addElement(c); |
| + } |
| + if (clauses != null) { |
| + { |
| + if (true) |
| + return new OrQueryNode(clauses); |
| + } |
| + } else { |
| + { |
| + if (true) |
| + return first; |
| + } |
| + } |
| + throw new Error("Missing return statement in function"); |
| + } |
| + |
| + final public QueryNode ConjQuery(CharSequence field) throws ParseException { |
| + QueryNode first, c; |
| + Vector clauses = null; |
| + first = ModClause(field); |
| + label_3: while (true) { |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case AND: |
| + ; |
| + break; |
| + default: |
| + jj_la1[6] = jj_gen; |
| + break label_3; |
| + } |
| + jj_consume_token(AND); |
| + c = ModClause(field); |
| + if (clauses == null) { |
| + clauses = new Vector(); |
| + clauses.addElement(first); |
| + } |
| + clauses.addElement(c); |
| + } |
| + if (clauses != null) { |
| + { |
| + if (true) |
| + return new AndQueryNode(clauses); |
| + } |
| + } else { |
| + { |
| + if (true) |
| + return first; |
| + } |
| + } |
| + throw new Error("Missing return statement in function"); |
| + } |
| + |
| + // QueryNode Query(CharSequence field) : |
| + // { |
| + // List clauses = new ArrayList(); |
| + // List modifiers = new ArrayList(); |
| + // QueryNode q, firstQuery=null; |
| + // ModifierQueryNode.Modifier mods; |
| + // int conj; |
| + // } |
| + // { |
| + // mods=Modifiers() q=Clause(field) |
| + // { |
| + // if (mods == ModifierQueryNode.Modifier.MOD_NONE) firstQuery=q; |
| + // |
| + // // do not create modifier nodes with MOD_NONE |
| + // if (mods != ModifierQueryNode.Modifier.MOD_NONE) { |
| + // q = new ModifierQueryNode(q, mods); |
| + // } |
| + // clauses.add(q); |
| + // } |
| + // ( |
| + // conj=Conjunction() mods=Modifiers() q=Clause(field) |
| + // { |
| + // // do not create modifier nodes with MOD_NONE |
| + // if (mods != ModifierQueryNode.Modifier.MOD_NONE) { |
| + // q = new ModifierQueryNode(q, mods); |
| + // } |
| + // clauses.add(q); |
| + // //TODO: figure out what to do with AND and ORs |
| + // } |
| + // )* |
| + // { |
| + // if (clauses.size() == 1 && firstQuery != null) |
| + // return firstQuery; |
| + // else { |
| + // return new BooleanQueryNode(clauses); |
| + // } |
| + // } |
| + // } |
| + final public QueryNode ModClause(CharSequence field) throws ParseException { |
| + QueryNode q; |
| + ModifierQueryNode.Modifier mods; |
| + mods = Modifiers(); |
| + q = Clause(field); |
| + if (mods != ModifierQueryNode.Modifier.MOD_NONE) { |
| + q = new ModifierQueryNode(q, mods); |
| + } |
| + { |
| + if (true) |
| + return q; |
| + } |
| + throw new Error("Missing return statement in function"); |
| + } |
| + |
| + final public QueryNode Clause(CharSequence field) throws ParseException { |
| + QueryNode q; |
| + Token fieldToken = null, boost = null; |
| + boolean group = false; |
| + if (jj_2_1(2)) { |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case TERM: |
| + fieldToken = jj_consume_token(TERM); |
| + jj_consume_token(COLON); |
| + field = EscapeQuerySyntaxImpl.discardEscapeChar(fieldToken.image); |
| + break; |
| + case STAR: |
| + jj_consume_token(STAR); |
| + jj_consume_token(COLON); |
| + field = "*"; |
| + break; |
| + default: |
| + jj_la1[7] = jj_gen; |
| + jj_consume_token(-1); |
| + throw new ParseException(); |
| + } |
| + } else { |
| + ; |
| + } |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case STAR: |
| + case QUOTED: |
| + case TERM: |
| + case PREFIXTERM: |
| + case WILDTERM: |
| + case RANGEIN_START: |
| + case RANGEEX_START: |
| + case NUMBER: |
| + q = Term(field); |
| + break; |
| + case LPAREN: |
| + jj_consume_token(LPAREN); |
| + q = Query(field); |
| + jj_consume_token(RPAREN); |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case CARAT: |
| + jj_consume_token(CARAT); |
| + boost = jj_consume_token(NUMBER); |
| + break; |
| + default: |
| + jj_la1[8] = jj_gen; |
| + ; |
| + } |
| + group = true; |
| + break; |
| + default: |
| + jj_la1[9] = jj_gen; |
| + jj_consume_token(-1); |
| + throw new ParseException(); |
| + } |
| + if (boost != null) { |
| + float f = (float) 1.0; |
| + try { |
| + f = Float.valueOf(boost.image).floatValue(); |
| + // avoid boosting null queries, such as those caused by stop words |
| + if (q != null) { |
| + q = new BoostQueryNode(q, f); |
| + } |
| + } catch (Exception ignored) { |
| + /* |
| + * Should this be handled somehow? (defaults to "no boost", if boost |
| + * number is invalid) |
| + */ |
| + } |
| + } |
| + if (group) { |
| + q = new GroupQueryNode(q); |
| + } |
| + { |
| + if (true) |
| + return q; |
| + } |
| + throw new Error("Missing return statement in function"); |
| + } |
| + |
| + final public QueryNode Term(CharSequence field) throws ParseException { |
| + Token term, boost = null, fuzzySlop = null, goop1, goop2; |
| + boolean prefix = false; |
| + boolean wildcard = false; |
| + boolean fuzzy = false; |
| + QueryNode q = null; |
| + ParametricQueryNode qLower, qUpper; |
| + float defaultMinSimilarity = 0.5f; |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case STAR: |
| + case TERM: |
| + case PREFIXTERM: |
| + case WILDTERM: |
| + case NUMBER: |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case TERM: |
| + term = jj_consume_token(TERM); |
| + q = new FieldQueryNode(field, EscapeQuerySyntaxImpl |
| + .discardEscapeChar(term.image), term.beginColumn, term.endColumn); |
| + break; |
| + case STAR: |
| + term = jj_consume_token(STAR); |
| + wildcard = true; |
| + q = new WildcardQueryNode(field, EscapeQuerySyntaxImpl |
| + .discardEscapeChar(term.image), term.beginColumn, term.endColumn); |
| + break; |
| + case PREFIXTERM: |
| + term = jj_consume_token(PREFIXTERM); |
| + prefix = true; |
| + q = new PrefixWildcardQueryNode(field, EscapeQuerySyntaxImpl |
| + .discardEscapeChar(term.image), term.beginColumn, term.endColumn); |
| + break; |
| + case WILDTERM: |
| + term = jj_consume_token(WILDTERM); |
| + wildcard = true; |
| + q = new WildcardQueryNode(field, EscapeQuerySyntaxImpl |
| + .discardEscapeChar(term.image), term.beginColumn, term.endColumn); |
| + break; |
| + case NUMBER: |
| + term = jj_consume_token(NUMBER); |
| + break; |
| + default: |
| + jj_la1[10] = jj_gen; |
| + jj_consume_token(-1); |
| + throw new ParseException(); |
| + } |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case FUZZY_SLOP: |
| + fuzzySlop = jj_consume_token(FUZZY_SLOP); |
| + fuzzy = true; |
| + break; |
| + default: |
| + jj_la1[11] = jj_gen; |
| + ; |
| + } |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case CARAT: |
| + jj_consume_token(CARAT); |
| + boost = jj_consume_token(NUMBER); |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case FUZZY_SLOP: |
| + fuzzySlop = jj_consume_token(FUZZY_SLOP); |
| + fuzzy = true; |
| + break; |
| + default: |
| + jj_la1[12] = jj_gen; |
| + ; |
| + } |
| + break; |
| + default: |
| + jj_la1[13] = jj_gen; |
| + ; |
| + } |
| + if (!wildcard && !prefix && fuzzy) { |
| + float fms = defaultMinSimilarity; |
| + try { |
| + fms = Float.valueOf(fuzzySlop.image.substring(1)).floatValue(); |
| + } catch (Exception ignored) { |
| + fms = defaultMinSimilarity; |
| + } |
| + if (fms < 0.0f || fms > 1.0f) { |
| + { |
| + if (true) |
| + throw new ParseException(new MessageImpl( |
| + QueryParserMessages.INVALID_SYNTAX_FUZZY_LIMITS)); |
| + } |
| + } |
| + q = new FuzzyQueryNode(field, EscapeQuerySyntaxImpl |
| + .discardEscapeChar(term.image), fms, term.beginColumn, |
| + term.endColumn); |
| + } |
| + break; |
| + case RANGEIN_START: |
| + jj_consume_token(RANGEIN_START); |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case RANGEIN_GOOP: |
| + goop1 = jj_consume_token(RANGEIN_GOOP); |
| + break; |
| + case RANGEIN_QUOTED: |
| + goop1 = jj_consume_token(RANGEIN_QUOTED); |
| + break; |
| + default: |
| + jj_la1[14] = jj_gen; |
| + jj_consume_token(-1); |
| + throw new ParseException(); |
| + } |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case RANGEIN_TO: |
| + jj_consume_token(RANGEIN_TO); |
| + break; |
| + default: |
| + jj_la1[15] = jj_gen; |
| + ; |
| + } |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case RANGEIN_GOOP: |
| + goop2 = jj_consume_token(RANGEIN_GOOP); |
| + break; |
| + case RANGEIN_QUOTED: |
| + goop2 = jj_consume_token(RANGEIN_QUOTED); |
| + break; |
| + default: |
| + jj_la1[16] = jj_gen; |
| + jj_consume_token(-1); |
| + throw new ParseException(); |
| + } |
| + jj_consume_token(RANGEIN_END); |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case CARAT: |
| + jj_consume_token(CARAT); |
| + boost = jj_consume_token(NUMBER); |
| + break; |
| + default: |
| + jj_la1[17] = jj_gen; |
| + ; |
| + } |
| + if (goop1.kind == RANGEIN_QUOTED) { |
| + goop1.image = goop1.image.substring(1, goop1.image.length() - 1); |
| + } |
| + if (goop2.kind == RANGEIN_QUOTED) { |
| + goop2.image = goop2.image.substring(1, goop2.image.length() - 1); |
| + } |
| + |
| + qLower = new ParametricQueryNode(field, |
| + ParametricQueryNode.CompareOperator.GE, EscapeQuerySyntaxImpl |
| + .discardEscapeChar(goop1.image), goop1.beginColumn, |
| + goop1.endColumn); |
| + qUpper = new ParametricQueryNode(field, |
| + ParametricQueryNode.CompareOperator.LE, EscapeQuerySyntaxImpl |
| + .discardEscapeChar(goop2.image), goop2.beginColumn, |
| + goop2.endColumn); |
| + q = new ParametricRangeQueryNode(qLower, qUpper); |
| + break; |
| + case RANGEEX_START: |
| + jj_consume_token(RANGEEX_START); |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case RANGEEX_GOOP: |
| + goop1 = jj_consume_token(RANGEEX_GOOP); |
| + break; |
| + case RANGEEX_QUOTED: |
| + goop1 = jj_consume_token(RANGEEX_QUOTED); |
| + break; |
| + default: |
| + jj_la1[18] = jj_gen; |
| + jj_consume_token(-1); |
| + throw new ParseException(); |
| + } |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case RANGEEX_TO: |
| + jj_consume_token(RANGEEX_TO); |
| + break; |
| + default: |
| + jj_la1[19] = jj_gen; |
| + ; |
| + } |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case RANGEEX_GOOP: |
| + goop2 = jj_consume_token(RANGEEX_GOOP); |
| + break; |
| + case RANGEEX_QUOTED: |
| + goop2 = jj_consume_token(RANGEEX_QUOTED); |
| + break; |
| + default: |
| + jj_la1[20] = jj_gen; |
| + jj_consume_token(-1); |
| + throw new ParseException(); |
| + } |
| + jj_consume_token(RANGEEX_END); |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case CARAT: |
| + jj_consume_token(CARAT); |
| + boost = jj_consume_token(NUMBER); |
| + break; |
| + default: |
| + jj_la1[21] = jj_gen; |
| + ; |
| + } |
| + if (goop1.kind == RANGEEX_QUOTED) { |
| + goop1.image = goop1.image.substring(1, goop1.image.length() - 1); |
| + } |
| + if (goop2.kind == RANGEEX_QUOTED) { |
| + goop2.image = goop2.image.substring(1, goop2.image.length() - 1); |
| + } |
| + qLower = new ParametricQueryNode(field, |
| + ParametricQueryNode.CompareOperator.GT, EscapeQuerySyntaxImpl |
| + .discardEscapeChar(goop1.image), goop1.beginColumn, |
| + goop1.endColumn); |
| + qUpper = new ParametricQueryNode(field, |
| + ParametricQueryNode.CompareOperator.LT, EscapeQuerySyntaxImpl |
| + .discardEscapeChar(goop2.image), goop2.beginColumn, |
| + goop2.endColumn); |
| + q = new ParametricRangeQueryNode(qLower, qUpper); |
| + break; |
| + case QUOTED: |
| + term = jj_consume_token(QUOTED); |
| + q = new QuotedFieldQueryNode(field, EscapeQuerySyntaxImpl |
| + .discardEscapeChar(term.image.substring(1, term.image.length() - 1)), |
| + term.beginColumn + 1, term.endColumn - 1); |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case FUZZY_SLOP: |
| + fuzzySlop = jj_consume_token(FUZZY_SLOP); |
| + break; |
| + default: |
| + jj_la1[22] = jj_gen; |
| + ; |
| + } |
| + switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) { |
| + case CARAT: |
| + jj_consume_token(CARAT); |
| + boost = jj_consume_token(NUMBER); |
| + break; |
| + default: |
| + jj_la1[23] = jj_gen; |
| + ; |
| + } |
| + int phraseSlop = 0; |
| + |
| + if (fuzzySlop != null) { |
| + try { |
| + phraseSlop = Float.valueOf(fuzzySlop.image.substring(1)).intValue(); |
| + q = new SlopQueryNode(q, phraseSlop); |
| + } catch (Exception ignored) { |
| + /* |
| + * Should this be handled somehow? (defaults to "no PhraseSlop", if |
| + * slop number is invalid) |
| + */ |
| + } |
| + } |
| + break; |
| + default: |
| + jj_la1[24] = jj_gen; |
| + jj_consume_token(-1); |
| + throw new ParseException(); |
| + } |
| + if (boost != null) { |
| + float f = (float) 1.0; |
| + try { |
| + f = Float.valueOf(boost.image).floatValue(); |
| + // avoid boosting null queries, such as those caused by stop words |
| + if (q != null) { |
| + q = new BoostQueryNode(q, f); |
| + } |
| + } catch (Exception ignored) { |
| + /* |
| + * Should this be handled somehow? (defaults to "no boost", if boost |
| + * number is invalid) |
| + */ |
| + } |
| + } |
| + { |
| + if (true) |
| + return q; |
| + } |
| + throw new Error("Missing return statement in function"); |
| + } |
| + |
| + private boolean jj_2_1(int xla) { |
| + jj_la = xla; |
| + jj_lastpos = jj_scanpos = token; |
| + try { |
| + return !jj_3_1(); |
| + } catch (LookaheadSuccess ls) { |
| + return true; |
| + } finally { |
| + jj_save(0, xla); |
| + } |
| + } |
| + |
| + private boolean jj_3R_5() { |
| + if (jj_scan_token(STAR)) |
| + return true; |
| + if (jj_scan_token(COLON)) |
| + return true; |
| + return false; |
| + } |
| + |
| + private boolean jj_3R_4() { |
| + if (jj_scan_token(TERM)) |
| + return true; |
| + if (jj_scan_token(COLON)) |
| + return true; |
| + return false; |
| + } |
| + |
| + private boolean jj_3_1() { |
| + Token xsp; |
| + xsp = jj_scanpos; |
| + if (jj_3R_4()) { |
| + jj_scanpos = xsp; |
| + if (jj_3R_5()) |
| + return true; |
| + } |
| + return false; |
| + } |
| + |
| + /** Generated Token Manager. */ |
| + public QueryParserTokenManager token_source; |
| + JavaCharStream jj_input_stream; |
| + /** Current token. */ |
| + public Token token; |
| + /** Next token. */ |
| + public Token jj_nt; |
| + private int jj_ntk; |
| + private Token jj_scanpos, jj_lastpos; |
| + private int jj_la; |
| + private int jj_gen; |
| + final private int[] jj_la1 = new int[25]; |
| + static private int[] jj_la1_0; |
| + static private int[] jj_la1_1; |
| + static { |
| + jj_la1_init_0(); |
| + jj_la1_init_1(); |
| + } |
| + |
| + private static void jj_la1_init_0() { |
| + jj_la1_0 = new int[] { 0x300, 0x300, 0x1c00, 0x1c00, 0x3ed3c00, 0x200, |
| + 0x100, 0x90000, 0x20000, 0x3ed2000, 0x2690000, 0x100000, 0x100000, |
| + 0x20000, 0x30000000, 0x4000000, 0x30000000, 0x20000, 0x0, 0x40000000, |
| + 0x0, 0x20000, 0x100000, 0x20000, 0x3ed0000, }; |
| + } |
| + |
| + private static void jj_la1_init_1() { |
| + jj_la1_1 = new int[] { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
| + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x3, 0x0, 0x0, 0x0, |
| + 0x0, }; |
| + } |
| + |
| + final private JJCalls[] jj_2_rtns = new JJCalls[1]; |
| + private boolean jj_rescan = false; |
| + private int jj_gc = 0; |
| + |
| + /** Constructor with InputStream. */ |
| + public TextParser(java.io.InputStream stream) { |
| + this(stream, null); |
| + } |
| + |
| + /** Constructor with InputStream and supplied encoding */ |
| + public TextParser(java.io.InputStream stream, String encoding) { |
| + try { |
| + jj_input_stream = new JavaCharStream(stream, encoding, 1, 1); |
| + } catch (java.io.UnsupportedEncodingException e) { |
| + throw new RuntimeException(e); |
| + } |
| + token_source = new QueryParserTokenManager(jj_input_stream); |
| + token = new Token(); |
| + jj_ntk = -1; |
| + jj_gen = 0; |
| + for (int i = 0; i < 25; i++) |
| + jj_la1[i] = -1; |
| + for (int i = 0; i < jj_2_rtns.length; i++) |
| + jj_2_rtns[i] = new JJCalls(); |
| + } |
| + |
| + /** Reinitialise. */ |
| + public void ReInit(java.io.InputStream stream) { |
| + ReInit(stream, null); |
| + } |
| + |
| + /** Reinitialise. */ |
| + public void ReInit(java.io.InputStream stream, String encoding) { |
| + try { |
| + jj_input_stream.ReInit(stream, encoding, 1, 1); |
| + } catch (java.io.UnsupportedEncodingException e) { |
| + throw new RuntimeException(e); |
| + } |
| + token_source.ReInit(jj_input_stream); |
| + token = new Token(); |
| + jj_ntk = -1; |
| + jj_gen = 0; |
| + for (int i = 0; i < 25; i++) |
| + jj_la1[i] = -1; |
| + for (int i = 0; i < jj_2_rtns.length; i++) |
| + jj_2_rtns[i] = new JJCalls(); |
| + } |
| + |
| + /** Constructor. */ |
| + public TextParser(java.io.Reader stream) { |
| + jj_input_stream = new JavaCharStream(stream, 1, 1); |
| + token_source = new QueryParserTokenManager(jj_input_stream); |
| + token = new Token(); |
| + jj_ntk = -1; |
| + jj_gen = 0; |
| + for (int i = 0; i < 25; i++) |
| + jj_la1[i] = -1; |
| + for (int i = 0; i < jj_2_rtns.length; i++) |
| + jj_2_rtns[i] = new JJCalls(); |
| + } |
| + |
| + /** Reinitialise. */ |
| + public void ReInit(java.io.Reader stream) { |
| + jj_input_stream.ReInit(stream, 1, 1); |
| + token_source.ReInit(jj_input_stream); |
| + token = new Token(); |
| + jj_ntk = -1; |
| + jj_gen = 0; |
| + for (int i = 0; i < 25; i++) |
| + jj_la1[i] = -1; |
| + for (int i = 0; i < jj_2_rtns.length; i++) |
| + jj_2_rtns[i] = new JJCalls(); |
| + } |
| + |
| + /** Constructor with generated Token Manager. */ |
| + public TextParser(QueryParserTokenManager tm) { |
| + token_source = tm; |
| + token = new Token(); |
| + jj_ntk = -1; |
| + jj_gen = 0; |
| + for (int i = 0; i < 25; i++) |
| + jj_la1[i] = -1; |
| + for (int i = 0; i < jj_2_rtns.length; i++) |
| + jj_2_rtns[i] = new JJCalls(); |
| + } |
| + |
| + /** Reinitialise. */ |
| + public void ReInit(QueryParserTokenManager tm) { |
| + token_source = tm; |
| + token = new Token(); |
| + jj_ntk = -1; |
| + jj_gen = 0; |
| + for (int i = 0; i < 25; i++) |
| + jj_la1[i] = -1; |
| + for (int i = 0; i < jj_2_rtns.length; i++) |
| + jj_2_rtns[i] = new JJCalls(); |
| + } |
| + |
| + private Token jj_consume_token(int kind) throws ParseException { |
| + Token oldToken; |
| + if ((oldToken = token).next != null) |
| + token = token.next; |
| + else |
| + token = token.next = token_source.getNextToken(); |
| + jj_ntk = -1; |
| + if (token.kind == kind) { |
| + jj_gen++; |
| + if (++jj_gc > 100) { |
| + jj_gc = 0; |
| + for (int i = 0; i < jj_2_rtns.length; i++) { |
| + JJCalls c = jj_2_rtns[i]; |
| + while (c != null) { |
| + if (c.gen < jj_gen) |
| + c.first = null; |
| + c = c.next; |
| + } |
| + } |
| + } |
| + return token; |
| + } |
| + token = oldToken; |
| + jj_kind = kind; |
| + throw generateParseException(); |
| + } |
| + |
| + static private final class LookaheadSuccess extends java.lang.Error { |
| + } |
| + |
| + final private LookaheadSuccess jj_ls = new LookaheadSuccess(); |
| + |
| + private boolean jj_scan_token(int kind) { |
| + if (jj_scanpos == jj_lastpos) { |
| + jj_la--; |
| + if (jj_scanpos.next == null) { |
| + jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken(); |
| + } else { |
| + jj_lastpos = jj_scanpos = jj_scanpos.next; |
| + } |
| + } else { |
| + jj_scanpos = jj_scanpos.next; |
| + } |
| + if (jj_rescan) { |
| + int i = 0; |
| + Token tok = token; |
| + while (tok != null && tok != jj_scanpos) { |
| + i++; |
| + tok = tok.next; |
| + } |
| + if (tok != null) |
| + jj_add_error_token(kind, i); |
| + } |
| + if (jj_scanpos.kind != kind) |
| + return true; |
| + if (jj_la == 0 && jj_scanpos == jj_lastpos) |
| + throw jj_ls; |
| + return false; |
| + } |
| + |
| + /** Get the next Token. */ |
| + final public Token getNextToken() { |
| + if (token.next != null) |
| + token = token.next; |
| + else |
| + token = token.next = token_source.getNextToken(); |
| + jj_ntk = -1; |
| + jj_gen++; |
| + return token; |
| + } |
| + |
| + /** Get the specific Token. */ |
| + final public Token getToken(int index) { |
| + Token t = token; |
| + for (int i = 0; i < index; i++) { |
| + if (t.next != null) |
| + t = t.next; |
| + else |
| + t = t.next = token_source.getNextToken(); |
| + } |
| + return t; |
| + } |
| + |
| + private int jj_ntk() { |
| + if ((jj_nt = token.next) == null) |
| + return (jj_ntk = (token.next = token_source.getNextToken()).kind); |
| + else |
| + return (jj_ntk = jj_nt.kind); |
| + } |
| + |
| + private java.util.List<int[]> jj_expentries = new java.util.ArrayList<int[]>(); |
| + private int[] jj_expentry; |
| + private int jj_kind = -1; |
| + private int[] jj_lasttokens = new int[100]; |
| + private int jj_endpos; |
| + |
| + private void jj_add_error_token(int kind, int pos) { |
| + if (pos >= 100) |
| + return; |
| + if (pos == jj_endpos + 1) { |
| + jj_lasttokens[jj_endpos++] = kind; |
| + } else if (jj_endpos != 0) { |
| + jj_expentry = new int[jj_endpos]; |
| + for (int i = 0; i < jj_endpos; i++) { |
| + jj_expentry[i] = jj_lasttokens[i]; |
| + } |
| + jj_entries_loop: for (java.util.Iterator it = jj_expentries.iterator(); it |
| + .hasNext();) { |
| + int[] oldentry = (int[]) (it.next()); |
| + if (oldentry.length == jj_expentry.length) { |
| + for (int i = 0; i < jj_expentry.length; i++) { |
| + if (oldentry[i] != jj_expentry[i]) { |
| + continue jj_entries_loop; |
| + } |
| + } |
| + jj_expentries.add(jj_expentry); |
| + break jj_entries_loop; |
| + } |
| + } |
| + if (pos != 0) |
| + jj_lasttokens[(jj_endpos = pos) - 1] = kind; |
| + } |
| + } |
| + |
| + /** Generate ParseException. */ |
| + public ParseException generateParseException() { |
| + jj_expentries.clear(); |
| + boolean[] la1tokens = new boolean[34]; |
| + if (jj_kind >= 0) { |
| + la1tokens[jj_kind] = true; |
| + jj_kind = -1; |
| + } |
| + for (int i = 0; i < 25; i++) { |
| + if (jj_la1[i] == jj_gen) { |
| + for (int j = 0; j < 32; j++) { |
| + if ((jj_la1_0[i] & (1 << j)) != 0) { |
| + la1tokens[j] = true; |
| + } |
| + if ((jj_la1_1[i] & (1 << j)) != 0) { |
| + la1tokens[32 + j] = true; |
| + } |
| + } |
| + } |
| + } |
| + for (int i = 0; i < 34; i++) { |
| + if (la1tokens[i]) { |
| + jj_expentry = new int[1]; |
| + jj_expentry[0] = i; |
| + jj_expentries.add(jj_expentry); |
| + } |
| + } |
| + jj_endpos = 0; |
| + jj_rescan_token(); |
| + jj_add_error_token(0, 0); |
| + int[][] exptokseq = new int[jj_expentries.size()][]; |
| + for (int i = 0; i < jj_expentries.size(); i++) { |
| + exptokseq[i] = jj_expentries.get(i); |
| + } |
| + return new ParseException(token, exptokseq, tokenImage); |
| + } |
| + |
| + /** Enable tracing. */ |
| + final public void enable_tracing() { |
| + } |
| + |
| + /** Disable tracing. */ |
| + final public void disable_tracing() { |
| + } |
| + |
| + private void jj_rescan_token() { |
| + jj_rescan = true; |
| + for (int i = 0; i < 1; i++) { |
| + try { |
| + JJCalls p = jj_2_rtns[i]; |
| + do { |
| + if (p.gen > jj_gen) { |
| + jj_la = p.arg; |
| + jj_lastpos = jj_scanpos = p.first; |
| + switch (i) { |
| + case 0: |
| + jj_3_1(); |
| + break; |
| + } |
| + } |
| + p = p.next; |
| + } while (p != null); |
| + } catch (LookaheadSuccess ls) { |
| + } |
| + } |
| + jj_rescan = false; |
| + } |
| + |
| + private void jj_save(int index, int xla) { |
| + JJCalls p = jj_2_rtns[index]; |
| + while (p.gen > jj_gen) { |
| + if (p.next == null) { |
| + p = p.next = new JJCalls(); |
| + break; |
| + } |
| + p = p.next; |
| + } |
| + p.gen = jj_gen + xla - jj_la; |
| + p.first = token; |
| + p.arg = xla; |
| + } |
| + |
| + static final class JJCalls { |
| + int gen; |
| + Token first; |
| + int arg; |
| + JJCalls next; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/Token.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/Token.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/Token.java (revision 0) |
| @@ -0,0 +1,143 @@ |
| +/* Generated By:JavaCC: Do not edit this line. Token.java Version 4.1 */ |
| +/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ |
| +package org.apache.lucene.queryParser.original.parser; |
| + |
| +/** |
| + * 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. |
| + */ |
| + |
| +/** |
| + * Describes the input token stream. |
| + */ |
| + |
| +public class Token implements java.io.Serializable { |
| + |
| + /** |
| + * The version identifier for this Serializable class. Increment only if the |
| + * <i>serialized</i> form of the class changes. |
| + */ |
| + private static final long serialVersionUID = 1L; |
| + |
| + /** |
| + * An integer that describes the kind of this token. This numbering system is |
| + * determined by JavaCCParser, and a table of these numbers is stored in the |
| + * file ...Constants.java. |
| + */ |
| + public int kind; |
| + |
| + /** The line number of the first character of this Token. */ |
| + public int beginLine; |
| + /** The column number of the first character of this Token. */ |
| + public int beginColumn; |
| + /** The line number of the last character of this Token. */ |
| + public int endLine; |
| + /** The column number of the last character of this Token. */ |
| + public int endColumn; |
| + |
| + /** |
| + * The string image of the token. |
| + */ |
| + public String image; |
| + |
| + /** |
| + * A reference to the next regular (non-special) token from the input stream. |
| + * If this is the last token from the input stream, or if the token manager |
| + * has not read tokens beyond this one, this field is set to null. This is |
| + * true only if this token is also a regular token. Otherwise, see below for a |
| + * description of the contents of this field. |
| + */ |
| + public Token next; |
| + |
| + /** |
| + * This field is used to access special tokens that occur prior to this token, |
| + * but after the immediately preceding regular (non-special) token. If there |
| + * are no such special tokens, this field is set to null. When there are more |
| + * than one such special token, this field refers to the last of these special |
| + * tokens, which in turn refers to the next previous special token through its |
| + * specialToken field, and so on until the first special token (whose |
| + * specialToken field is null). The next fields of special tokens refer to |
| + * other special tokens that immediately follow it (without an intervening |
| + * regular token). If there is no such token, this field is null. |
| + */ |
| + public Token specialToken; |
| + |
| + /** |
| + * An optional attribute value of the Token. Tokens which are not used as |
| + * syntactic sugar will often contain meaningful values that will be used |
| + * later on by the compiler or interpreter. This attribute value is often |
| + * different from the image. Any subclass of Token that actually wants to |
| + * return a non-null value can override this method as appropriate. |
| + */ |
| + public Object getValue() { |
| + return null; |
| + } |
| + |
| + /** |
| + * No-argument constructor |
| + */ |
| + public Token() { |
| + } |
| + |
| + /** |
| + * Constructs a new token for the specified Image. |
| + */ |
| + public Token(int kind) { |
| + this(kind, null); |
| + } |
| + |
| + /** |
| + * Constructs a new token for the specified Image and Kind. |
| + */ |
| + public Token(int kind, String image) { |
| + this.kind = kind; |
| + this.image = image; |
| + } |
| + |
| + /** |
| + * Returns the image. |
| + */ |
| + public String toString() { |
| + return image; |
| + } |
| + |
| + /** |
| + * Returns a new Token object, by default. However, if you want, you can |
| + * create and return subclass objects based on the value of ofKind. Simply add |
| + * the cases to the switch for all those special cases. For example, if you |
| + * have a subclass of Token called IDToken that you want to create if ofKind |
| + * is ID, simply add something like : |
| + * |
| + * case MyParserConstants.ID : return new IDToken(ofKind, image); |
| + * |
| + * to the following switch statement. Then you can cast matchedToken variable |
| + * to the appropriate type and use sit in your lexical actions. |
| + */ |
| + public static Token newToken(int ofKind, String image) { |
| + switch (ofKind) { |
| + default: |
| + return new Token(ofKind, image); |
| + } |
| + } |
| + |
| + public static Token newToken(int ofKind) { |
| + return newToken(ofKind, null); |
| + } |
| + |
| +} |
| +/* |
| + * JavaCC - OriginalChecksum=c7458f48213af7d4c6a887e945d19ece (do not edit this |
| + * line) |
| + */ |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/QueryParserConstants.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/QueryParserConstants.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/QueryParserConstants.java (revision 0) |
| @@ -0,0 +1,112 @@ |
| +/* Generated By:JavaCC: Do not edit this line. QueryParserConstants.java */ |
| +package org.apache.lucene.queryParser.original.parser; |
| + |
| +/** |
| + * 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. |
| + */ |
| + |
| +/** |
| + * Token literal values and constants. Generated by |
| + * org.javacc.parser.OtherFilesGen#start() |
| + */ |
| +public interface QueryParserConstants { |
| + |
| + /** End of File. */ |
| + int EOF = 0; |
| + /** RegularExpression Id. */ |
| + int _NUM_CHAR = 1; |
| + /** RegularExpression Id. */ |
| + int _ESCAPED_CHAR = 2; |
| + /** RegularExpression Id. */ |
| + int _TERM_START_CHAR = 3; |
| + /** RegularExpression Id. */ |
| + int _TERM_CHAR = 4; |
| + /** RegularExpression Id. */ |
| + int _WHITESPACE = 5; |
| + /** RegularExpression Id. */ |
| + int _QUOTED_CHAR = 6; |
| + /** RegularExpression Id. */ |
| + int AND = 8; |
| + /** RegularExpression Id. */ |
| + int OR = 9; |
| + /** RegularExpression Id. */ |
| + int NOT = 10; |
| + /** RegularExpression Id. */ |
| + int PLUS = 11; |
| + /** RegularExpression Id. */ |
| + int MINUS = 12; |
| + /** RegularExpression Id. */ |
| + int LPAREN = 13; |
| + /** RegularExpression Id. */ |
| + int RPAREN = 14; |
| + /** RegularExpression Id. */ |
| + int COLON = 15; |
| + /** RegularExpression Id. */ |
| + int STAR = 16; |
| + /** RegularExpression Id. */ |
| + int CARAT = 17; |
| + /** RegularExpression Id. */ |
| + int QUOTED = 18; |
| + /** RegularExpression Id. */ |
| + int TERM = 19; |
| + /** RegularExpression Id. */ |
| + int FUZZY_SLOP = 20; |
| + /** RegularExpression Id. */ |
| + int PREFIXTERM = 21; |
| + /** RegularExpression Id. */ |
| + int WILDTERM = 22; |
| + /** RegularExpression Id. */ |
| + int RANGEIN_START = 23; |
| + /** RegularExpression Id. */ |
| + int RANGEEX_START = 24; |
| + /** RegularExpression Id. */ |
| + int NUMBER = 25; |
| + /** RegularExpression Id. */ |
| + int RANGEIN_TO = 26; |
| + /** RegularExpression Id. */ |
| + int RANGEIN_END = 27; |
| + /** RegularExpression Id. */ |
| + int RANGEIN_QUOTED = 28; |
| + /** RegularExpression Id. */ |
| + int RANGEIN_GOOP = 29; |
| + /** RegularExpression Id. */ |
| + int RANGEEX_TO = 30; |
| + /** RegularExpression Id. */ |
| + int RANGEEX_END = 31; |
| + /** RegularExpression Id. */ |
| + int RANGEEX_QUOTED = 32; |
| + /** RegularExpression Id. */ |
| + int RANGEEX_GOOP = 33; |
| + |
| + /** Lexical state. */ |
| + int Boost = 0; |
| + /** Lexical state. */ |
| + int RangeEx = 1; |
| + /** Lexical state. */ |
| + int RangeIn = 2; |
| + /** Lexical state. */ |
| + int DEFAULT = 3; |
| + |
| + /** Literal token values. */ |
| + String[] tokenImage = { "<EOF>", "<_NUM_CHAR>", "<_ESCAPED_CHAR>", |
| + "<_TERM_START_CHAR>", "<_TERM_CHAR>", "<_WHITESPACE>", "<_QUOTED_CHAR>", |
| + "<token of kind 7>", "<AND>", "<OR>", "<NOT>", "\"+\"", "\"-\"", "\"(\"", |
| + "\")\"", "\":\"", "\"*\"", "\"^\"", "<QUOTED>", "<TERM>", "<FUZZY_SLOP>", |
| + "<PREFIXTERM>", "<WILDTERM>", "\"[\"", "\"{\"", "<NUMBER>", "\"TO\"", |
| + "\"]\"", "<RANGEIN_QUOTED>", "<RANGEIN_GOOP>", "\"TO\"", "\"}\"", |
| + "<RANGEEX_QUOTED>", "<RANGEEX_GOOP>", }; |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/QueryParserTokenManager.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/QueryParserTokenManager.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/QueryParserTokenManager.java (revision 0) |
| @@ -0,0 +1,1171 @@ |
| +/* Generated By:JavaCC: Do not edit this line. QueryParserTokenManager.java */ |
| +package org.apache.lucene.queryParser.original.parser; |
| + |
| +/** |
| + * 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. |
| + */ |
| + |
| +/** Token Manager. */ |
| +public class QueryParserTokenManager implements QueryParserConstants { |
| + |
| + /** Debug output. */ |
| + public java.io.PrintStream debugStream = System.out; |
| + |
| + /** Set debug output. */ |
| + public void setDebugStream(java.io.PrintStream ds) { |
| + debugStream = ds; |
| + } |
| + |
| + private final int jjStopStringLiteralDfa_3(int pos, long active0) { |
| + switch (pos) { |
| + default: |
| + return -1; |
| + } |
| + } |
| + |
| + @SuppressWarnings("unused") |
| + private final int jjStartNfa_3(int pos, long active0) { |
| + return jjMoveNfa_3(jjStopStringLiteralDfa_3(pos, active0), pos + 1); |
| + } |
| + |
| + private int jjStopAtPos(int pos, int kind) { |
| + jjmatchedKind = kind; |
| + jjmatchedPos = pos; |
| + return pos + 1; |
| + } |
| + |
| + private int jjMoveStringLiteralDfa0_3() { |
| + switch (curChar) { |
| + case 40: |
| + return jjStopAtPos(0, 13); |
| + case 41: |
| + return jjStopAtPos(0, 14); |
| + case 42: |
| + return jjStartNfaWithStates_3(0, 16, 36); |
| + case 43: |
| + return jjStopAtPos(0, 11); |
| + case 45: |
| + return jjStopAtPos(0, 12); |
| + case 58: |
| + return jjStopAtPos(0, 15); |
| + case 91: |
| + return jjStopAtPos(0, 23); |
| + case 94: |
| + return jjStopAtPos(0, 17); |
| + case 123: |
| + return jjStopAtPos(0, 24); |
| + default: |
| + return jjMoveNfa_3(0, 0); |
| + } |
| + } |
| + |
| + private int jjStartNfaWithStates_3(int pos, int kind, int state) { |
| + jjmatchedKind = kind; |
| + jjmatchedPos = pos; |
| + try { |
| + curChar = input_stream.readChar(); |
| + } catch (java.io.IOException e) { |
| + return pos + 1; |
| + } |
| + return jjMoveNfa_3(state, pos + 1); |
| + } |
| + |
| + static final long[] jjbitVec0 = { 0x1L, 0x0L, 0x0L, 0x0L }; |
| + static final long[] jjbitVec1 = { 0xfffffffffffffffeL, 0xffffffffffffffffL, |
| + 0xffffffffffffffffL, 0xffffffffffffffffL }; |
| + static final long[] jjbitVec3 = { 0x0L, 0x0L, 0xffffffffffffffffL, |
| + 0xffffffffffffffffL }; |
| + static final long[] jjbitVec4 = { 0xfffefffffffffffeL, 0xffffffffffffffffL, |
| + 0xffffffffffffffffL, 0xffffffffffffffffL }; |
| + |
| + private int jjMoveNfa_3(int startState, int curPos) { |
| + int startsAt = 0; |
| + jjnewStateCnt = 36; |
| + int i = 1; |
| + jjstateSet[0] = startState; |
| + int kind = 0x7fffffff; |
| + for (;;) { |
| + if (++jjround == 0x7fffffff) |
| + ReInitRounds(); |
| + if (curChar < 64) { |
| + long l = 1L << curChar; |
| + do { |
| + switch (jjstateSet[--i]) { |
| + case 36: |
| + case 25: |
| + if ((0xfbfffcf8ffffd9ffL & l) == 0L) |
| + break; |
| + if (kind > 22) |
| + kind = 22; |
| + jjCheckNAddTwoStates(25, 26); |
| + break; |
| + case 0: |
| + if ((0xfbffd4f8ffffd9ffL & l) != 0L) { |
| + if (kind > 22) |
| + kind = 22; |
| + jjCheckNAddTwoStates(25, 26); |
| + } else if ((0x100002600L & l) != 0L) { |
| + if (kind > 7) |
| + kind = 7; |
| + } else if (curChar == 34) |
| + jjCheckNAddStates(0, 2); |
| + else if (curChar == 33) { |
| + if (kind > 10) |
| + kind = 10; |
| + } |
| + if ((0x7bffd0f8ffffd9ffL & l) != 0L) { |
| + if (kind > 19) |
| + kind = 19; |
| + jjCheckNAddStates(3, 7); |
| + } else if (curChar == 42) { |
| + if (kind > 21) |
| + kind = 21; |
| + } |
| + if (curChar == 38) |
| + jjstateSet[jjnewStateCnt++] = 4; |
| + break; |
| + case 4: |
| + if (curChar == 38 && kind > 8) |
| + kind = 8; |
| + break; |
| + case 5: |
| + if (curChar == 38) |
| + jjstateSet[jjnewStateCnt++] = 4; |
| + break; |
| + case 13: |
| + if (curChar == 33 && kind > 10) |
| + kind = 10; |
| + break; |
| + case 14: |
| + if (curChar == 34) |
| + jjCheckNAddStates(0, 2); |
| + break; |
| + case 15: |
| + if ((0xfffffffbffffffffL & l) != 0L) |
| + jjCheckNAddStates(0, 2); |
| + break; |
| + case 17: |
| + jjCheckNAddStates(0, 2); |
| + break; |
| + case 18: |
| + if (curChar == 34 && kind > 18) |
| + kind = 18; |
| + break; |
| + case 20: |
| + if ((0x3ff000000000000L & l) == 0L) |
| + break; |
| + if (kind > 20) |
| + kind = 20; |
| + jjAddStates(8, 9); |
| + break; |
| + case 21: |
| + if (curChar == 46) |
| + jjCheckNAdd(22); |
| + break; |
| + case 22: |
| + if ((0x3ff000000000000L & l) == 0L) |
| + break; |
| + if (kind > 20) |
| + kind = 20; |
| + jjCheckNAdd(22); |
| + break; |
| + case 23: |
| + if (curChar == 42 && kind > 21) |
| + kind = 21; |
| + break; |
| + case 24: |
| + if ((0xfbffd4f8ffffd9ffL & l) == 0L) |
| + break; |
| + if (kind > 22) |
| + kind = 22; |
| + jjCheckNAddTwoStates(25, 26); |
| + break; |
| + case 27: |
| + if (kind > 22) |
| + kind = 22; |
| + jjCheckNAddTwoStates(25, 26); |
| + break; |
| + case 28: |
| + if ((0x7bffd0f8ffffd9ffL & l) == 0L) |
| + break; |
| + if (kind > 19) |
| + kind = 19; |
| + jjCheckNAddStates(3, 7); |
| + break; |
| + case 29: |
| + if ((0x7bfff8f8ffffd9ffL & l) == 0L) |
| + break; |
| + if (kind > 19) |
| + kind = 19; |
| + jjCheckNAddTwoStates(29, 30); |
| + break; |
| + case 31: |
| + if (kind > 19) |
| + kind = 19; |
| + jjCheckNAddTwoStates(29, 30); |
| + break; |
| + case 32: |
| + if ((0x7bfff8f8ffffd9ffL & l) != 0L) |
| + jjCheckNAddStates(10, 12); |
| + break; |
| + case 34: |
| + jjCheckNAddStates(10, 12); |
| + break; |
| + default: |
| + break; |
| + } |
| + } while (i != startsAt); |
| + } else if (curChar < 128) { |
| + long l = 1L << (curChar & 077); |
| + do { |
| + switch (jjstateSet[--i]) { |
| + case 36: |
| + if ((0x97ffffff87ffffffL & l) != 0L) { |
| + if (kind > 22) |
| + kind = 22; |
| + jjCheckNAddTwoStates(25, 26); |
| + } else if (curChar == 92) |
| + jjCheckNAddTwoStates(27, 27); |
| + break; |
| + case 0: |
| + if ((0x97ffffff87ffffffL & l) != 0L) { |
| + if (kind > 19) |
| + kind = 19; |
| + jjCheckNAddStates(3, 7); |
| + } else if (curChar == 92) |
| + jjCheckNAddStates(13, 15); |
| + else if (curChar == 126) { |
| + if (kind > 20) |
| + kind = 20; |
| + jjstateSet[jjnewStateCnt++] = 20; |
| + } |
| + if ((0x97ffffff87ffffffL & l) != 0L) { |
| + if (kind > 22) |
| + kind = 22; |
| + jjCheckNAddTwoStates(25, 26); |
| + } |
| + if (curChar == 78) |
| + jjstateSet[jjnewStateCnt++] = 11; |
| + else if (curChar == 124) |
| + jjstateSet[jjnewStateCnt++] = 8; |
| + else if (curChar == 79) |
| + jjstateSet[jjnewStateCnt++] = 6; |
| + else if (curChar == 65) |
| + jjstateSet[jjnewStateCnt++] = 2; |
| + break; |
| + case 1: |
| + if (curChar == 68 && kind > 8) |
| + kind = 8; |
| + break; |
| + case 2: |
| + if (curChar == 78) |
| + jjstateSet[jjnewStateCnt++] = 1; |
| + break; |
| + case 3: |
| + if (curChar == 65) |
| + jjstateSet[jjnewStateCnt++] = 2; |
| + break; |
| + case 6: |
| + if (curChar == 82 && kind > 9) |
| + kind = 9; |
| + break; |
| + case 7: |
| + if (curChar == 79) |
| + jjstateSet[jjnewStateCnt++] = 6; |
| + break; |
| + case 8: |
| + if (curChar == 124 && kind > 9) |
| + kind = 9; |
| + break; |
| + case 9: |
| + if (curChar == 124) |
| + jjstateSet[jjnewStateCnt++] = 8; |
| + break; |
| + case 10: |
| + if (curChar == 84 && kind > 10) |
| + kind = 10; |
| + break; |
| + case 11: |
| + if (curChar == 79) |
| + jjstateSet[jjnewStateCnt++] = 10; |
| + break; |
| + case 12: |
| + if (curChar == 78) |
| + jjstateSet[jjnewStateCnt++] = 11; |
| + break; |
| + case 15: |
| + if ((0xffffffffefffffffL & l) != 0L) |
| + jjCheckNAddStates(0, 2); |
| + break; |
| + case 16: |
| + if (curChar == 92) |
| + jjstateSet[jjnewStateCnt++] = 17; |
| + break; |
| + case 17: |
| + jjCheckNAddStates(0, 2); |
| + break; |
| + case 19: |
| + if (curChar != 126) |
| + break; |
| + if (kind > 20) |
| + kind = 20; |
| + jjstateSet[jjnewStateCnt++] = 20; |
| + break; |
| + case 24: |
| + if ((0x97ffffff87ffffffL & l) == 0L) |
| + break; |
| + if (kind > 22) |
| + kind = 22; |
| + jjCheckNAddTwoStates(25, 26); |
| + break; |
| + case 25: |
| + if ((0x97ffffff87ffffffL & l) == 0L) |
| + break; |
| + if (kind > 22) |
| + kind = 22; |
| + jjCheckNAddTwoStates(25, 26); |
| + break; |
| + case 26: |
| + if (curChar == 92) |
| + jjCheckNAddTwoStates(27, 27); |
| + break; |
| + case 27: |
| + if (kind > 22) |
| + kind = 22; |
| + jjCheckNAddTwoStates(25, 26); |
| + break; |
| + case 28: |
| + if ((0x97ffffff87ffffffL & l) == 0L) |
| + break; |
| + if (kind > 19) |
| + kind = 19; |
| + jjCheckNAddStates(3, 7); |
| + break; |
| + case 29: |
| + if ((0x97ffffff87ffffffL & l) == 0L) |
| + break; |
| + if (kind > 19) |
| + kind = 19; |
| + jjCheckNAddTwoStates(29, 30); |
| + break; |
| + case 30: |
| + if (curChar == 92) |
| + jjCheckNAddTwoStates(31, 31); |
| + break; |
| + case 31: |
| + if (kind > 19) |
| + kind = 19; |
| + jjCheckNAddTwoStates(29, 30); |
| + break; |
| + case 32: |
| + if ((0x97ffffff87ffffffL & l) != 0L) |
| + jjCheckNAddStates(10, 12); |
| + break; |
| + case 33: |
| + if (curChar == 92) |
| + jjCheckNAddTwoStates(34, 34); |
| + break; |
| + case 34: |
| + jjCheckNAddStates(10, 12); |
| + break; |
| + case 35: |
| + if (curChar == 92) |
| + jjCheckNAddStates(13, 15); |
| + break; |
| + default: |
| + break; |
| + } |
| + } while (i != startsAt); |
| + } else { |
| + int hiByte = (int) (curChar >> 8); |
| + int i1 = hiByte >> 6; |
| + long l1 = 1L << (hiByte & 077); |
| + int i2 = (curChar & 0xff) >> 6; |
| + long l2 = 1L << (curChar & 077); |
| + do { |
| + switch (jjstateSet[--i]) { |
| + case 36: |
| + case 25: |
| + if (!jjCanMove_2(hiByte, i1, i2, l1, l2)) |
| + break; |
| + if (kind > 22) |
| + kind = 22; |
| + jjCheckNAddTwoStates(25, 26); |
| + break; |
| + case 0: |
| + if (jjCanMove_0(hiByte, i1, i2, l1, l2)) { |
| + if (kind > 7) |
| + kind = 7; |
| + } |
| + if (jjCanMove_2(hiByte, i1, i2, l1, l2)) { |
| + if (kind > 22) |
| + kind = 22; |
| + jjCheckNAddTwoStates(25, 26); |
| + } |
| + if (jjCanMove_2(hiByte, i1, i2, l1, l2)) { |
| + if (kind > 19) |
| + kind = 19; |
| + jjCheckNAddStates(3, 7); |
| + } |
| + break; |
| + case 15: |
| + case 17: |
| + if (jjCanMove_1(hiByte, i1, i2, l1, l2)) |
| + jjCheckNAddStates(0, 2); |
| + break; |
| + case 24: |
| + if (!jjCanMove_2(hiByte, i1, i2, l1, l2)) |
| + break; |
| + if (kind > 22) |
| + kind = 22; |
| + jjCheckNAddTwoStates(25, 26); |
| + break; |
| + case 27: |
| + if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) |
| + break; |
| + if (kind > 22) |
| + kind = 22; |
| + jjCheckNAddTwoStates(25, 26); |
| + break; |
| + case 28: |
| + if (!jjCanMove_2(hiByte, i1, i2, l1, l2)) |
| + break; |
| + if (kind > 19) |
| + kind = 19; |
| + jjCheckNAddStates(3, 7); |
| + break; |
| + case 29: |
| + if (!jjCanMove_2(hiByte, i1, i2, l1, l2)) |
| + break; |
| + if (kind > 19) |
| + kind = 19; |
| + jjCheckNAddTwoStates(29, 30); |
| + break; |
| + case 31: |
| + if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) |
| + break; |
| + if (kind > 19) |
| + kind = 19; |
| + jjCheckNAddTwoStates(29, 30); |
| + break; |
| + case 32: |
| + if (jjCanMove_2(hiByte, i1, i2, l1, l2)) |
| + jjCheckNAddStates(10, 12); |
| + break; |
| + case 34: |
| + if (jjCanMove_1(hiByte, i1, i2, l1, l2)) |
| + jjCheckNAddStates(10, 12); |
| + break; |
| + default: |
| + break; |
| + } |
| + } while (i != startsAt); |
| + } |
| + if (kind != 0x7fffffff) { |
| + jjmatchedKind = kind; |
| + jjmatchedPos = curPos; |
| + kind = 0x7fffffff; |
| + } |
| + ++curPos; |
| + if ((i = jjnewStateCnt) == (startsAt = 36 - (jjnewStateCnt = startsAt))) |
| + return curPos; |
| + try { |
| + curChar = input_stream.readChar(); |
| + } catch (java.io.IOException e) { |
| + return curPos; |
| + } |
| + } |
| + } |
| + |
| + private final int jjStopStringLiteralDfa_1(int pos, long active0) { |
| + switch (pos) { |
| + case 0: |
| + if ((active0 & 0x40000000L) != 0L) { |
| + jjmatchedKind = 33; |
| + return 6; |
| + } |
| + return -1; |
| + default: |
| + return -1; |
| + } |
| + } |
| + |
| + private final int jjStartNfa_1(int pos, long active0) { |
| + return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1); |
| + } |
| + |
| + private int jjMoveStringLiteralDfa0_1() { |
| + switch (curChar) { |
| + case 84: |
| + return jjMoveStringLiteralDfa1_1(0x40000000L); |
| + case 125: |
| + return jjStopAtPos(0, 31); |
| + default: |
| + return jjMoveNfa_1(0, 0); |
| + } |
| + } |
| + |
| + private int jjMoveStringLiteralDfa1_1(long active0) { |
| + try { |
| + curChar = input_stream.readChar(); |
| + } catch (java.io.IOException e) { |
| + jjStopStringLiteralDfa_1(0, active0); |
| + return 1; |
| + } |
| + switch (curChar) { |
| + case 79: |
| + if ((active0 & 0x40000000L) != 0L) |
| + return jjStartNfaWithStates_1(1, 30, 6); |
| + break; |
| + default: |
| + break; |
| + } |
| + return jjStartNfa_1(0, active0); |
| + } |
| + |
| + private int jjStartNfaWithStates_1(int pos, int kind, int state) { |
| + jjmatchedKind = kind; |
| + jjmatchedPos = pos; |
| + try { |
| + curChar = input_stream.readChar(); |
| + } catch (java.io.IOException e) { |
| + return pos + 1; |
| + } |
| + return jjMoveNfa_1(state, pos + 1); |
| + } |
| + |
| + private int jjMoveNfa_1(int startState, int curPos) { |
| + int startsAt = 0; |
| + jjnewStateCnt = 7; |
| + int i = 1; |
| + jjstateSet[0] = startState; |
| + int kind = 0x7fffffff; |
| + for (;;) { |
| + if (++jjround == 0x7fffffff) |
| + ReInitRounds(); |
| + if (curChar < 64) { |
| + long l = 1L << curChar; |
| + do { |
| + switch (jjstateSet[--i]) { |
| + case 0: |
| + if ((0xfffffffeffffffffL & l) != 0L) { |
| + if (kind > 33) |
| + kind = 33; |
| + jjCheckNAdd(6); |
| + } |
| + if ((0x100002600L & l) != 0L) { |
| + if (kind > 7) |
| + kind = 7; |
| + } else if (curChar == 34) |
| + jjCheckNAddTwoStates(2, 4); |
| + break; |
| + case 1: |
| + if (curChar == 34) |
| + jjCheckNAddTwoStates(2, 4); |
| + break; |
| + case 2: |
| + if ((0xfffffffbffffffffL & l) != 0L) |
| + jjCheckNAddStates(16, 18); |
| + break; |
| + case 3: |
| + if (curChar == 34) |
| + jjCheckNAddStates(16, 18); |
| + break; |
| + case 5: |
| + if (curChar == 34 && kind > 32) |
| + kind = 32; |
| + break; |
| + case 6: |
| + if ((0xfffffffeffffffffL & l) == 0L) |
| + break; |
| + if (kind > 33) |
| + kind = 33; |
| + jjCheckNAdd(6); |
| + break; |
| + default: |
| + break; |
| + } |
| + } while (i != startsAt); |
| + } else if (curChar < 128) { |
| + long l = 1L << (curChar & 077); |
| + do { |
| + switch (jjstateSet[--i]) { |
| + case 0: |
| + case 6: |
| + if ((0xdfffffffffffffffL & l) == 0L) |
| + break; |
| + if (kind > 33) |
| + kind = 33; |
| + jjCheckNAdd(6); |
| + break; |
| + case 2: |
| + jjAddStates(16, 18); |
| + break; |
| + case 4: |
| + if (curChar == 92) |
| + jjstateSet[jjnewStateCnt++] = 3; |
| + break; |
| + default: |
| + break; |
| + } |
| + } while (i != startsAt); |
| + } else { |
| + int hiByte = (int) (curChar >> 8); |
| + int i1 = hiByte >> 6; |
| + long l1 = 1L << (hiByte & 077); |
| + int i2 = (curChar & 0xff) >> 6; |
| + long l2 = 1L << (curChar & 077); |
| + do { |
| + switch (jjstateSet[--i]) { |
| + case 0: |
| + if (jjCanMove_0(hiByte, i1, i2, l1, l2)) { |
| + if (kind > 7) |
| + kind = 7; |
| + } |
| + if (jjCanMove_1(hiByte, i1, i2, l1, l2)) { |
| + if (kind > 33) |
| + kind = 33; |
| + jjCheckNAdd(6); |
| + } |
| + break; |
| + case 2: |
| + if (jjCanMove_1(hiByte, i1, i2, l1, l2)) |
| + jjAddStates(16, 18); |
| + break; |
| + case 6: |
| + if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) |
| + break; |
| + if (kind > 33) |
| + kind = 33; |
| + jjCheckNAdd(6); |
| + break; |
| + default: |
| + break; |
| + } |
| + } while (i != startsAt); |
| + } |
| + if (kind != 0x7fffffff) { |
| + jjmatchedKind = kind; |
| + jjmatchedPos = curPos; |
| + kind = 0x7fffffff; |
| + } |
| + ++curPos; |
| + if ((i = jjnewStateCnt) == (startsAt = 7 - (jjnewStateCnt = startsAt))) |
| + return curPos; |
| + try { |
| + curChar = input_stream.readChar(); |
| + } catch (java.io.IOException e) { |
| + return curPos; |
| + } |
| + } |
| + } |
| + |
| + private int jjMoveStringLiteralDfa0_0() { |
| + return jjMoveNfa_0(0, 0); |
| + } |
| + |
| + @SuppressWarnings("unused") |
| + private int jjMoveNfa_0(int startState, int curPos) { |
| + int startsAt = 0; |
| + jjnewStateCnt = 3; |
| + int i = 1; |
| + jjstateSet[0] = startState; |
| + int kind = 0x7fffffff; |
| + for (;;) { |
| + if (++jjround == 0x7fffffff) |
| + ReInitRounds(); |
| + if (curChar < 64) { |
| + long l = 1L << curChar; |
| + do { |
| + switch (jjstateSet[--i]) { |
| + case 0: |
| + if ((0x3ff000000000000L & l) == 0L) |
| + break; |
| + if (kind > 25) |
| + kind = 25; |
| + jjAddStates(19, 20); |
| + break; |
| + case 1: |
| + if (curChar == 46) |
| + jjCheckNAdd(2); |
| + break; |
| + case 2: |
| + if ((0x3ff000000000000L & l) == 0L) |
| + break; |
| + if (kind > 25) |
| + kind = 25; |
| + jjCheckNAdd(2); |
| + break; |
| + default: |
| + break; |
| + } |
| + } while (i != startsAt); |
| + } else if (curChar < 128) { |
| + long l = 1L << (curChar & 077); |
| + do { |
| + switch (jjstateSet[--i]) { |
| + default: |
| + break; |
| + } |
| + } while (i != startsAt); |
| + } else { |
| + int hiByte = (int) (curChar >> 8); |
| + int i1 = hiByte >> 6; |
| + |
| + long l1 = 1L << (hiByte & 077); |
| + int i2 = (curChar & 0xff) >> 6; |
| + long l2 = 1L << (curChar & 077); |
| + do { |
| + switch (jjstateSet[--i]) { |
| + default: |
| + break; |
| + } |
| + } while (i != startsAt); |
| + } |
| + if (kind != 0x7fffffff) { |
| + jjmatchedKind = kind; |
| + jjmatchedPos = curPos; |
| + kind = 0x7fffffff; |
| + } |
| + ++curPos; |
| + if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) |
| + return curPos; |
| + try { |
| + curChar = input_stream.readChar(); |
| + } catch (java.io.IOException e) { |
| + return curPos; |
| + } |
| + } |
| + } |
| + |
| + private final int jjStopStringLiteralDfa_2(int pos, long active0) { |
| + switch (pos) { |
| + case 0: |
| + if ((active0 & 0x4000000L) != 0L) { |
| + jjmatchedKind = 29; |
| + return 6; |
| + } |
| + return -1; |
| + default: |
| + return -1; |
| + } |
| + } |
| + |
| + private final int jjStartNfa_2(int pos, long active0) { |
| + return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0), pos + 1); |
| + } |
| + |
| + private int jjMoveStringLiteralDfa0_2() { |
| + switch (curChar) { |
| + case 84: |
| + return jjMoveStringLiteralDfa1_2(0x4000000L); |
| + case 93: |
| + return jjStopAtPos(0, 27); |
| + default: |
| + return jjMoveNfa_2(0, 0); |
| + } |
| + } |
| + |
| + private int jjMoveStringLiteralDfa1_2(long active0) { |
| + try { |
| + curChar = input_stream.readChar(); |
| + } catch (java.io.IOException e) { |
| + jjStopStringLiteralDfa_2(0, active0); |
| + return 1; |
| + } |
| + switch (curChar) { |
| + case 79: |
| + if ((active0 & 0x4000000L) != 0L) |
| + return jjStartNfaWithStates_2(1, 26, 6); |
| + break; |
| + default: |
| + break; |
| + } |
| + return jjStartNfa_2(0, active0); |
| + } |
| + |
| + private int jjStartNfaWithStates_2(int pos, int kind, int state) { |
| + jjmatchedKind = kind; |
| + jjmatchedPos = pos; |
| + try { |
| + curChar = input_stream.readChar(); |
| + } catch (java.io.IOException e) { |
| + return pos + 1; |
| + } |
| + return jjMoveNfa_2(state, pos + 1); |
| + } |
| + |
| + private int jjMoveNfa_2(int startState, int curPos) { |
| + int startsAt = 0; |
| + jjnewStateCnt = 7; |
| + int i = 1; |
| + jjstateSet[0] = startState; |
| + int kind = 0x7fffffff; |
| + for (;;) { |
| + if (++jjround == 0x7fffffff) |
| + ReInitRounds(); |
| + if (curChar < 64) { |
| + long l = 1L << curChar; |
| + do { |
| + switch (jjstateSet[--i]) { |
| + case 0: |
| + if ((0xfffffffeffffffffL & l) != 0L) { |
| + if (kind > 29) |
| + kind = 29; |
| + jjCheckNAdd(6); |
| + } |
| + if ((0x100002600L & l) != 0L) { |
| + if (kind > 7) |
| + kind = 7; |
| + } else if (curChar == 34) |
| + jjCheckNAddTwoStates(2, 4); |
| + break; |
| + case 1: |
| + if (curChar == 34) |
| + jjCheckNAddTwoStates(2, 4); |
| + break; |
| + case 2: |
| + if ((0xfffffffbffffffffL & l) != 0L) |
| + jjCheckNAddStates(16, 18); |
| + break; |
| + case 3: |
| + if (curChar == 34) |
| + jjCheckNAddStates(16, 18); |
| + break; |
| + case 5: |
| + if (curChar == 34 && kind > 28) |
| + kind = 28; |
| + break; |
| + case 6: |
| + if ((0xfffffffeffffffffL & l) == 0L) |
| + break; |
| + if (kind > 29) |
| + kind = 29; |
| + jjCheckNAdd(6); |
| + break; |
| + default: |
| + break; |
| + } |
| + } while (i != startsAt); |
| + } else if (curChar < 128) { |
| + long l = 1L << (curChar & 077); |
| + do { |
| + switch (jjstateSet[--i]) { |
| + case 0: |
| + case 6: |
| + if ((0xffffffffdfffffffL & l) == 0L) |
| + break; |
| + if (kind > 29) |
| + kind = 29; |
| + jjCheckNAdd(6); |
| + break; |
| + case 2: |
| + jjAddStates(16, 18); |
| + break; |
| + case 4: |
| + if (curChar == 92) |
| + jjstateSet[jjnewStateCnt++] = 3; |
| + break; |
| + default: |
| + break; |
| + } |
| + } while (i != startsAt); |
| + } else { |
| + int hiByte = (int) (curChar >> 8); |
| + int i1 = hiByte >> 6; |
| + long l1 = 1L << (hiByte & 077); |
| + int i2 = (curChar & 0xff) >> 6; |
| + long l2 = 1L << (curChar & 077); |
| + do { |
| + switch (jjstateSet[--i]) { |
| + case 0: |
| + if (jjCanMove_0(hiByte, i1, i2, l1, l2)) { |
| + if (kind > 7) |
| + kind = 7; |
| + } |
| + if (jjCanMove_1(hiByte, i1, i2, l1, l2)) { |
| + if (kind > 29) |
| + kind = 29; |
| + jjCheckNAdd(6); |
| + } |
| + break; |
| + case 2: |
| + if (jjCanMove_1(hiByte, i1, i2, l1, l2)) |
| + jjAddStates(16, 18); |
| + break; |
| + case 6: |
| + if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) |
| + break; |
| + if (kind > 29) |
| + kind = 29; |
| + jjCheckNAdd(6); |
| + break; |
| + default: |
| + break; |
| + } |
| + } while (i != startsAt); |
| + } |
| + if (kind != 0x7fffffff) { |
| + jjmatchedKind = kind; |
| + jjmatchedPos = curPos; |
| + kind = 0x7fffffff; |
| + } |
| + ++curPos; |
| + if ((i = jjnewStateCnt) == (startsAt = 7 - (jjnewStateCnt = startsAt))) |
| + return curPos; |
| + try { |
| + curChar = input_stream.readChar(); |
| + } catch (java.io.IOException e) { |
| + return curPos; |
| + } |
| + } |
| + } |
| + |
| + static final int[] jjnextStates = { 15, 16, 18, 29, 32, 23, 33, 30, 20, 21, |
| + 32, 23, 33, 31, 34, 27, 2, 4, 5, 0, 1, }; |
| + |
| + private static final boolean jjCanMove_0(int hiByte, int i1, int i2, long l1, |
| + long l2) { |
| + switch (hiByte) { |
| + case 48: |
| + return ((jjbitVec0[i2] & l2) != 0L); |
| + default: |
| + return false; |
| + } |
| + } |
| + |
| + private static final boolean jjCanMove_1(int hiByte, int i1, int i2, long l1, |
| + long l2) { |
| + switch (hiByte) { |
| + case 0: |
| + return ((jjbitVec3[i2] & l2) != 0L); |
| + default: |
| + if ((jjbitVec1[i1] & l1) != 0L) |
| + return true; |
| + return false; |
| + } |
| + } |
| + |
| + private static final boolean jjCanMove_2(int hiByte, int i1, int i2, long l1, |
| + long l2) { |
| + switch (hiByte) { |
| + case 0: |
| + return ((jjbitVec3[i2] & l2) != 0L); |
| + case 48: |
| + return ((jjbitVec1[i2] & l2) != 0L); |
| + default: |
| + if ((jjbitVec4[i1] & l1) != 0L) |
| + return true; |
| + return false; |
| + } |
| + } |
| + |
| + /** Token literal values. */ |
| + public static final String[] jjstrLiteralImages = { "", null, null, null, |
| + null, null, null, null, null, null, null, "\53", "\55", "\50", "\51", |
| + "\72", "\52", "\136", null, null, null, null, null, "\133", "\173", null, |
| + "\124\117", "\135", null, null, "\124\117", "\175", null, null, }; |
| + |
| + /** Lexer state names. */ |
| + public static final String[] lexStateNames = { "Boost", "RangeEx", "RangeIn", |
| + "DEFAULT", }; |
| + |
| + /** Lex State array. */ |
| + public static final int[] jjnewLexState = { -1, -1, -1, -1, -1, -1, -1, -1, |
| + -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, 2, 1, 3, -1, |
| + 3, -1, -1, -1, 3, -1, -1, }; |
| + static final long[] jjtoToken = { 0x3ffffff01L, }; |
| + static final long[] jjtoSkip = { 0x80L, }; |
| + protected JavaCharStream input_stream; |
| + private final int[] jjrounds = new int[36]; |
| + private final int[] jjstateSet = new int[72]; |
| + protected char curChar; |
| + |
| + /** Constructor. */ |
| + public QueryParserTokenManager(JavaCharStream stream) { |
| + if (JavaCharStream.staticFlag) |
| + throw new Error( |
| + "ERROR: Cannot use a static CharStream class with a non-static lexical analyzer."); |
| + input_stream = stream; |
| + } |
| + |
| + /** Constructor. */ |
| + public QueryParserTokenManager(JavaCharStream stream, int lexState) { |
| + this(stream); |
| + SwitchTo(lexState); |
| + } |
| + |
| + /** Reinitialise parser. */ |
| + public void ReInit(JavaCharStream stream) { |
| + jjmatchedPos = jjnewStateCnt = 0; |
| + curLexState = defaultLexState; |
| + input_stream = stream; |
| + ReInitRounds(); |
| + } |
| + |
| + private void ReInitRounds() { |
| + int i; |
| + jjround = 0x80000001; |
| + for (i = 36; i-- > 0;) |
| + jjrounds[i] = 0x80000000; |
| + } |
| + |
| + /** Reinitialise parser. */ |
| + public void ReInit(JavaCharStream stream, int lexState) { |
| + ReInit(stream); |
| + SwitchTo(lexState); |
| + } |
| + |
| + /** Switch to specified lex state. */ |
| + public void SwitchTo(int lexState) { |
| + if (lexState >= 4 || lexState < 0) |
| + throw new TokenMgrError("Error: Ignoring invalid lexical state : " |
| + + lexState + ". State unchanged.", |
| + TokenMgrError.INVALID_LEXICAL_STATE); |
| + else |
| + curLexState = lexState; |
| + } |
| + |
| + protected Token jjFillToken() { |
| + final Token t; |
| + final String curTokenImage; |
| + final int beginLine; |
| + final int endLine; |
| + final int beginColumn; |
| + final int endColumn; |
| + String im = jjstrLiteralImages[jjmatchedKind]; |
| + curTokenImage = (im == null) ? input_stream.GetImage() : im; |
| + beginLine = input_stream.getBeginLine(); |
| + beginColumn = input_stream.getBeginColumn(); |
| + endLine = input_stream.getEndLine(); |
| + endColumn = input_stream.getEndColumn(); |
| + t = Token.newToken(jjmatchedKind, curTokenImage); |
| + |
| + t.beginLine = beginLine; |
| + t.endLine = endLine; |
| + t.beginColumn = beginColumn; |
| + t.endColumn = endColumn; |
| + |
| + return t; |
| + } |
| + |
| + int curLexState = 3; |
| + int defaultLexState = 3; |
| + int jjnewStateCnt; |
| + int jjround; |
| + int jjmatchedPos; |
| + int jjmatchedKind; |
| + |
| + /** Get the next Token. */ |
| + public Token getNextToken() { |
| + Token matchedToken; |
| + int curPos = 0; |
| + |
| + EOFLoop: for (;;) { |
| + try { |
| + curChar = input_stream.BeginToken(); |
| + } catch (java.io.IOException e) { |
| + jjmatchedKind = 0; |
| + matchedToken = jjFillToken(); |
| + return matchedToken; |
| + } |
| + |
| + switch (curLexState) { |
| + case 0: |
| + jjmatchedKind = 0x7fffffff; |
| + jjmatchedPos = 0; |
| + curPos = jjMoveStringLiteralDfa0_0(); |
| + break; |
| + case 1: |
| + jjmatchedKind = 0x7fffffff; |
| + jjmatchedPos = 0; |
| + curPos = jjMoveStringLiteralDfa0_1(); |
| + break; |
| + case 2: |
| + jjmatchedKind = 0x7fffffff; |
| + jjmatchedPos = 0; |
| + curPos = jjMoveStringLiteralDfa0_2(); |
| + break; |
| + case 3: |
| + jjmatchedKind = 0x7fffffff; |
| + jjmatchedPos = 0; |
| + curPos = jjMoveStringLiteralDfa0_3(); |
| + break; |
| + } |
| + if (jjmatchedKind != 0x7fffffff) { |
| + if (jjmatchedPos + 1 < curPos) |
| + input_stream.backup(curPos - jjmatchedPos - 1); |
| + if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) { |
| + matchedToken = jjFillToken(); |
| + if (jjnewLexState[jjmatchedKind] != -1) |
| + curLexState = jjnewLexState[jjmatchedKind]; |
| + return matchedToken; |
| + } else { |
| + if (jjnewLexState[jjmatchedKind] != -1) |
| + curLexState = jjnewLexState[jjmatchedKind]; |
| + continue EOFLoop; |
| + } |
| + } |
| + int error_line = input_stream.getEndLine(); |
| + int error_column = input_stream.getEndColumn(); |
| + String error_after = null; |
| + boolean EOFSeen = false; |
| + try { |
| + input_stream.readChar(); |
| + input_stream.backup(1); |
| + } catch (java.io.IOException e1) { |
| + EOFSeen = true; |
| + error_after = curPos <= 1 ? "" : input_stream.GetImage(); |
| + if (curChar == '\n' || curChar == '\r') { |
| + error_line++; |
| + error_column = 0; |
| + } else |
| + error_column++; |
| + } |
| + if (!EOFSeen) { |
| + input_stream.backup(1); |
| + error_after = curPos <= 1 ? "" : input_stream.GetImage(); |
| + } |
| + throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, |
| + error_after, curChar, TokenMgrError.LEXICAL_ERROR); |
| + } |
| + } |
| + |
| + private void jjCheckNAdd(int state) { |
| + if (jjrounds[state] != jjround) { |
| + jjstateSet[jjnewStateCnt++] = state; |
| + jjrounds[state] = jjround; |
| + } |
| + } |
| + |
| + private void jjAddStates(int start, int end) { |
| + do { |
| + jjstateSet[jjnewStateCnt++] = jjnextStates[start]; |
| + } while (start++ != end); |
| + } |
| + |
| + private void jjCheckNAddTwoStates(int state1, int state2) { |
| + jjCheckNAdd(state1); |
| + jjCheckNAdd(state2); |
| + } |
| + |
| + private void jjCheckNAddStates(int start, int end) { |
| + do { |
| + jjCheckNAdd(jjnextStates[start]); |
| + } while (start++ != end); |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/TextParser.jj |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/TextParser.jj (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/TextParser.jj (revision 0) |
| @@ -0,0 +1,484 @@ |
| +/** |
| + * Original file is based on the TextParser.jj from lucene 2.3 |
| + */ |
| + |
| +options { |
| + STATIC=false; |
| + JAVA_UNICODE_ESCAPE=true; |
| + USER_CHAR_STREAM=false; |
| + IGNORE_CASE=false; |
| + JDK_VERSION="1.5"; |
| +} |
| + |
| +PARSER_BEGIN(TextParser) |
| +package org.apache.lucene.queryParser.original.parser; |
| + |
| +/** |
| + * 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 java.io.StringReader; |
| +import java.util.ArrayList; |
| +import java.util.List; |
| +import java.util.Vector; |
| + |
| +import org.apache.lucene.messages.Message; |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeError; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.QueryNodeParseException; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.nodes.AndQueryNode; |
| +import org.apache.lucene.queryParser.nodes.BooleanQueryNode; |
| +import org.apache.lucene.queryParser.nodes.BoostQueryNode; |
| +import org.apache.lucene.queryParser.nodes.FieldQueryNode; |
| +import org.apache.lucene.queryParser.nodes.FuzzyQueryNode; |
| +import org.apache.lucene.queryParser.nodes.ModifierQueryNode; |
| +import org.apache.lucene.queryParser.nodes.GroupQueryNode; |
| +import org.apache.lucene.queryParser.nodes.OpaqueQueryNode; |
| +import org.apache.lucene.queryParser.nodes.OrQueryNode; |
| +import org.apache.lucene.queryParser.nodes.ParametricQueryNode; |
| +import org.apache.lucene.queryParser.nodes.ParametricRangeQueryNode; |
| +import org.apache.lucene.queryParser.nodes.PrefixWildcardQueryNode; |
| +import org.apache.lucene.queryParser.nodes.SlopQueryNode; |
| +import org.apache.lucene.queryParser.nodes.ProximityQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNodeImpl; |
| +import org.apache.lucene.queryParser.nodes.QuotedFieldQueryNode; |
| +import org.apache.lucene.queryParser.nodes.WildcardQueryNode; |
| +import org.apache.lucene.queryParser.parser.Parser; |
| + |
| +@SuppressWarnings("all") |
| +public class TextParser implements Parser { |
| + |
| + private static final int CONJ_NONE =0; |
| + private static final int CONJ_AND =2; |
| + private static final int CONJ_OR =2; |
| + |
| + |
| + // query parser constructor |
| + public TextParser() { |
| + this(new StringReader("")); |
| + } |
| + /** Parses a query string, returning a {@link org.apache.lucene.queryParser.nodes.QueryNode}. |
| + * @param query the query string to be parsed. |
| + * @throws ParseException if the parsing fails |
| + */ |
| + public QueryNode parse(CharSequence query, CharSequence field) throws QueryNodeParseException { |
| + ReInit(new StringReader(query.toString())); |
| + try { |
| + // TopLevelQuery is a Query followed by the end-of-input (EOF) |
| + QueryNode querynode = TopLevelQuery(field); |
| + return querynode; |
| + } |
| + catch (ParseException tme) { |
| + tme.setQuery(query); |
| + throw tme; |
| + } |
| + catch (Error tme) { |
| + Message message = new MessageImpl(QueryParserMessages.INVALID_SYNTAX_CANNOT_PARSE, query, tme.getMessage()); |
| + QueryNodeParseException e = new QueryNodeParseException(tme); |
| + e.setQuery(query); |
| + e.setNonLocalizedMessage(message); |
| + throw e; |
| + } |
| + } |
| + |
| +} |
| + |
| +PARSER_END(TextParser) |
| + |
| +/* ***************** */ |
| +/* Token Definitions */ |
| +/* ***************** */ |
| + |
| +<*> TOKEN : { |
| + <#_NUM_CHAR: ["0"-"9"] > |
| +// every character that follows a backslash is considered as an escaped character |
| +| <#_ESCAPED_CHAR: "\\" ~[] > |
| +| <#_TERM_START_CHAR: ( ~[ " ", "\t", "\n", "\r", "\u3000", "+", "-", "!", "(", ")", ":", "^", |
| + "[", "]", "\"", "{", "}", "~", "*", "?", "\\" ] |
| + | <_ESCAPED_CHAR> ) > |
| +| <#_TERM_CHAR: ( <_TERM_START_CHAR> | <_ESCAPED_CHAR> | "-" | "+" ) > |
| +| <#_WHITESPACE: ( " " | "\t" | "\n" | "\r" | "\u3000") > |
| +| <#_QUOTED_CHAR: ( ~[ "\"", "\\" ] | <_ESCAPED_CHAR> ) > |
| +} |
| + |
| +<DEFAULT, RangeIn, RangeEx> SKIP : { |
| + < <_WHITESPACE>> |
| +} |
| + |
| +<DEFAULT> TOKEN : { |
| + <AND: ("AND" | "&&") > |
| +| <OR: ("OR" | "||") > |
| +| <NOT: ("NOT" | "!") > |
| +| <PLUS: "+" > |
| +| <MINUS: "-" > |
| +| <LPAREN: "(" > |
| +| <RPAREN: ")" > |
| +| <COLON: ":" > |
| +| <STAR: "*" > |
| +| <CARAT: "^" > : Boost |
| +| <QUOTED: "\"" (<_QUOTED_CHAR>)* "\""> |
| +| <TERM: <_TERM_START_CHAR> (<_TERM_CHAR>)* > |
| +| <FUZZY_SLOP: "~" ( (<_NUM_CHAR>)+ ( "." (<_NUM_CHAR>)+ )? )? > |
| +| <PREFIXTERM: ("*") | ( <_TERM_START_CHAR> (<_TERM_CHAR>)* "*" ) > |
| +| <WILDTERM: (<_TERM_START_CHAR> | [ "*", "?" ]) (<_TERM_CHAR> | ( [ "*", "?" ] ))* > |
| +| <RANGEIN_START: "[" > : RangeIn |
| +| <RANGEEX_START: "{" > : RangeEx |
| +} |
| + |
| +<Boost> TOKEN : { |
| +<NUMBER: (<_NUM_CHAR>)+ ( "." (<_NUM_CHAR>)+ )? > : DEFAULT |
| +} |
| + |
| +<RangeIn> TOKEN : { |
| +<RANGEIN_TO: "TO"> |
| +| <RANGEIN_END: "]"> : DEFAULT |
| +| <RANGEIN_QUOTED: "\"" (~["\""] | "\\\"")+ "\""> |
| +| <RANGEIN_GOOP: (~[ " ", "]" ])+ > |
| +} |
| + |
| +<RangeEx> TOKEN : { |
| +<RANGEEX_TO: "TO"> |
| +| <RANGEEX_END: "}"> : DEFAULT |
| +| <RANGEEX_QUOTED: "\"" (~["\""] | "\\\"")+ "\""> |
| +| <RANGEEX_GOOP: (~[ " ", "}" ])+ > |
| +} |
| + |
| +// * Query ::= ( Clause )* |
| +// * Clause ::= ["+", "-"] [<TERM> ":"] ( <TERM> | "(" Query ")" ) |
| + |
| +int Conjunction() : { |
| + int ret = CONJ_NONE; |
| +} |
| +{ |
| + [ |
| + <AND> { ret = CONJ_AND; } |
| + | <OR> { ret = CONJ_OR; } |
| + ] |
| + { return ret; } |
| +} |
| + |
| +ModifierQueryNode.Modifier Modifiers() : { |
| + ModifierQueryNode.Modifier ret = ModifierQueryNode.Modifier.MOD_NONE; |
| +} |
| +{ |
| + [ |
| + <PLUS> { ret = ModifierQueryNode.Modifier.MOD_REQ; } |
| + | <MINUS> { ret = ModifierQueryNode.Modifier.MOD_NOT; } |
| + | <NOT> { ret = ModifierQueryNode.Modifier.MOD_NOT; } |
| + ] |
| + { return ret; } |
| +} |
| + |
| +// This makes sure that there is no garbage after the query string |
| +QueryNode TopLevelQuery(CharSequence field) : |
| +{ |
| + QueryNode q; |
| +} |
| +{ |
| + q=Query(field) <EOF> |
| + { |
| + return q; |
| + } |
| +} |
| + |
| +// These changes were made to introduce operator precedence: |
| +// - Clause() now returns a QueryNode. |
| +// - The modifiers are consumed by Clause() and returned as part of the QueryNode Object |
| +// - Query does not consume conjunctions (AND, OR) anymore. |
| +// - This is now done by two new non-terminals: ConjClause and DisjClause |
| +// The parse tree looks similar to this: |
| +// Query ::= DisjQuery ( DisjQuery )* |
| +// DisjQuery ::= ConjQuery ( OR ConjQuery )* |
| +// ConjQuery ::= Clause ( AND Clause )* |
| +// Clause ::= [ Modifier ] ... |
| + |
| + |
| +QueryNode Query(CharSequence field) : |
| +{ |
| + Vector clauses = null; |
| + QueryNode c, first=null; |
| +} |
| +{ |
| + first=DisjQuery(field) |
| + ( |
| + c=DisjQuery(field) |
| + { |
| + if (clauses == null) { |
| + clauses = new Vector(); |
| + clauses.addElement(first); |
| + } |
| + clauses.addElement(c); |
| + } |
| + )* |
| + { |
| + if (clauses != null) { |
| + return new BooleanQueryNode(clauses); |
| + } else { |
| + return first; |
| + } |
| + } |
| +} |
| + |
| +QueryNode DisjQuery(CharSequence field) : { |
| + QueryNode first, c; |
| + Vector clauses = null; |
| +} |
| +{ |
| + first = ConjQuery(field) |
| + ( |
| + <OR> c=ConjQuery(field) |
| + { |
| + if (clauses == null) { |
| + clauses = new Vector(); |
| + clauses.addElement(first); |
| + } |
| + clauses.addElement(c); |
| + } |
| + )* |
| + { |
| + if (clauses != null) { |
| + return new OrQueryNode(clauses); |
| + } else { |
| + return first; |
| + } |
| + } |
| +} |
| + |
| +QueryNode ConjQuery(CharSequence field) : { |
| + QueryNode first, c; |
| + Vector clauses = null; |
| +} |
| +{ |
| + first = ModClause(field) |
| + ( |
| + <AND> c=ModClause(field) |
| + { |
| + if (clauses == null) { |
| + clauses = new Vector(); |
| + clauses.addElement(first); |
| + } |
| + clauses.addElement(c); |
| + } |
| + )* |
| + { |
| + if (clauses != null) { |
| + return new AndQueryNode(clauses); |
| + } else { |
| + return first; |
| + } |
| + } |
| +} |
| + |
| +// QueryNode Query(CharSequence field) : |
| +// { |
| +// List clauses = new ArrayList(); |
| +// List modifiers = new ArrayList(); |
| +// QueryNode q, firstQuery=null; |
| +// ModifierQueryNode.Modifier mods; |
| +// int conj; |
| +// } |
| +// { |
| +// mods=Modifiers() q=Clause(field) |
| +// { |
| +// if (mods == ModifierQueryNode.Modifier.MOD_NONE) firstQuery=q; |
| +// |
| +// // do not create modifier nodes with MOD_NONE |
| +// if (mods != ModifierQueryNode.Modifier.MOD_NONE) { |
| +// q = new ModifierQueryNode(q, mods); |
| +// } |
| +// clauses.add(q); |
| +// } |
| +// ( |
| +// conj=Conjunction() mods=Modifiers() q=Clause(field) |
| +// { |
| +// // do not create modifier nodes with MOD_NONE |
| +// if (mods != ModifierQueryNode.Modifier.MOD_NONE) { |
| +// q = new ModifierQueryNode(q, mods); |
| +// } |
| +// clauses.add(q); |
| +// //TODO: figure out what to do with AND and ORs |
| +// } |
| +// )* |
| +// { |
| +// if (clauses.size() == 1 && firstQuery != null) |
| +// return firstQuery; |
| +// else { |
| +// return new BooleanQueryNode(clauses); |
| +// } |
| +// } |
| +// } |
| + |
| +QueryNode ModClause(CharSequence field) : { |
| + QueryNode q; |
| + ModifierQueryNode.Modifier mods; |
| +} |
| +{ |
| + mods=Modifiers() q= Clause(field) { |
| + if (mods != ModifierQueryNode.Modifier.MOD_NONE) { |
| + q = new ModifierQueryNode(q, mods); |
| + } |
| + return q; |
| + } |
| +} |
| + |
| +QueryNode Clause(CharSequence field) : { |
| + QueryNode q; |
| + Token fieldToken=null, boost=null; |
| + boolean group = false; |
| +} |
| +{ |
| + [ |
| + LOOKAHEAD(2) |
| + ( |
| + fieldToken=<TERM> <COLON> {field=EscapeQuerySyntaxImpl.discardEscapeChar(fieldToken.image);} |
| + | <STAR> <COLON> {field="*";} |
| + ) |
| + ] |
| + |
| + ( |
| + q=Term(field) |
| + | <LPAREN> q=Query(field) <RPAREN> (<CARAT> boost=<NUMBER>)? {group=true;} |
| + |
| + ) |
| + { |
| + if (boost != null) { |
| + float f = (float)1.0; |
| + try { |
| + f = Float.valueOf(boost.image).floatValue(); |
| + // avoid boosting null queries, such as those caused by stop words |
| + if (q != null) { |
| + q = new BoostQueryNode(q, f); |
| + } |
| + } catch (Exception ignored) { |
| + /* Should this be handled somehow? (defaults to "no boost", if |
| + * boost number is invalid) |
| + */ |
| + } |
| + } |
| + if (group) { q = new GroupQueryNode(q);} |
| + return q; |
| + } |
| +} |
| + |
| + |
| +QueryNode Term(CharSequence field) : { |
| + Token term, boost=null, fuzzySlop=null, goop1, goop2; |
| + boolean prefix = false; |
| + boolean wildcard = false; |
| + boolean fuzzy = false; |
| + QueryNode q =null; |
| + ParametricQueryNode qLower, qUpper; |
| + float defaultMinSimilarity = 0.5f; |
| +} |
| +{ |
| + ( |
| + ( |
| + term=<TERM> { q = new FieldQueryNode(field, EscapeQuerySyntaxImpl.discardEscapeChar(term.image), term.beginColumn, term.endColumn); } |
| + | term=<STAR> { wildcard=true; q = new WildcardQueryNode(field, EscapeQuerySyntaxImpl.discardEscapeChar(term.image), term.beginColumn, term.endColumn); } |
| + | term=<PREFIXTERM> { prefix=true; q = new PrefixWildcardQueryNode(field, EscapeQuerySyntaxImpl.discardEscapeChar(term.image), term.beginColumn, term.endColumn); } |
| + | term=<WILDTERM> { wildcard=true; q = new WildcardQueryNode(field, EscapeQuerySyntaxImpl.discardEscapeChar(term.image), term.beginColumn, term.endColumn); } |
| + | term=<NUMBER> |
| + ) |
| + [ fuzzySlop=<FUZZY_SLOP> { fuzzy=true; } ] |
| + [ <CARAT> boost=<NUMBER> [ fuzzySlop=<FUZZY_SLOP> { fuzzy=true; } ] ] |
| + { |
| + if (!wildcard && !prefix && fuzzy) { |
| + float fms = defaultMinSimilarity; |
| + try { |
| + fms = Float.valueOf(fuzzySlop.image.substring(1)).floatValue(); |
| + } catch (Exception ignored) { } |
| + if(fms < 0.0f || fms > 1.0f){ |
| + throw new ParseException(new MessageImpl(QueryParserMessages.INVALID_SYNTAX_FUZZY_LIMITS)); |
| + } |
| + q = new FuzzyQueryNode(field, EscapeQuerySyntaxImpl.discardEscapeChar(term.image), fms, term.beginColumn, term.endColumn); |
| + } |
| + } |
| + | ( <RANGEIN_START> ( goop1=<RANGEIN_GOOP>|goop1=<RANGEIN_QUOTED> ) |
| + [ <RANGEIN_TO> ] ( goop2=<RANGEIN_GOOP>|goop2=<RANGEIN_QUOTED> ) |
| + <RANGEIN_END> ) |
| + [ <CARAT> boost=<NUMBER> ] |
| + { |
| + if (goop1.kind == RANGEIN_QUOTED) { |
| + goop1.image = goop1.image.substring(1, goop1.image.length()-1); |
| + } |
| + if (goop2.kind == RANGEIN_QUOTED) { |
| + goop2.image = goop2.image.substring(1, goop2.image.length()-1); |
| + } |
| + |
| + qLower = new ParametricQueryNode(field, ParametricQueryNode.CompareOperator.GE, |
| + EscapeQuerySyntaxImpl.discardEscapeChar(goop1.image), goop1.beginColumn, goop1.endColumn); |
| + qUpper = new ParametricQueryNode(field, ParametricQueryNode.CompareOperator.LE, |
| + EscapeQuerySyntaxImpl.discardEscapeChar(goop2.image), goop2.beginColumn, goop2.endColumn); |
| + q = new ParametricRangeQueryNode(qLower, qUpper); |
| + } |
| + | ( <RANGEEX_START> ( goop1=<RANGEEX_GOOP>|goop1=<RANGEEX_QUOTED> ) |
| + [ <RANGEEX_TO> ] ( goop2=<RANGEEX_GOOP>|goop2=<RANGEEX_QUOTED> ) |
| + <RANGEEX_END> ) |
| + [ <CARAT> boost=<NUMBER> ] |
| + { |
| + if (goop1.kind == RANGEEX_QUOTED) { |
| + goop1.image = goop1.image.substring(1, goop1.image.length()-1); |
| + } |
| + if (goop2.kind == RANGEEX_QUOTED) { |
| + goop2.image = goop2.image.substring(1, goop2.image.length()-1); |
| + } |
| + qLower = new ParametricQueryNode(field, ParametricQueryNode.CompareOperator.GT, |
| + EscapeQuerySyntaxImpl.discardEscapeChar(goop1.image), goop1.beginColumn, goop1.endColumn); |
| + qUpper = new ParametricQueryNode(field, ParametricQueryNode.CompareOperator.LT, |
| + EscapeQuerySyntaxImpl.discardEscapeChar(goop2.image), goop2.beginColumn, goop2.endColumn); |
| + q = new ParametricRangeQueryNode(qLower, qUpper); |
| + } |
| + | term=<QUOTED> {q = new QuotedFieldQueryNode(field, EscapeQuerySyntaxImpl.discardEscapeChar(term.image.substring(1, term.image.length()-1)), term.beginColumn + 1, term.endColumn - 1);} |
| + [ fuzzySlop=<FUZZY_SLOP> ] |
| + [ <CARAT> boost=<NUMBER> ] |
| + { |
| + int phraseSlop = 0; |
| + |
| + if (fuzzySlop != null) { |
| + try { |
| + phraseSlop = Float.valueOf(fuzzySlop.image.substring(1)).intValue(); |
| + q = new SlopQueryNode(q, phraseSlop); |
| + } |
| + catch (Exception ignored) { |
| + /* Should this be handled somehow? (defaults to "no PhraseSlop", if |
| + * slop number is invalid) |
| + */ |
| + } |
| + } |
| + |
| + } |
| + ) |
| + { |
| + if (boost != null) { |
| + float f = (float)1.0; |
| + try { |
| + f = Float.valueOf(boost.image).floatValue(); |
| + // avoid boosting null queries, such as those caused by stop words |
| + if (q != null) { |
| + q = new BoostQueryNode(q, f); |
| + } |
| + } catch (Exception ignored) { |
| + /* Should this be handled somehow? (defaults to "no boost", if |
| + * boost number is invalid) |
| + */ |
| + } |
| + } |
| + return q; |
| + } |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/ParseException.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/ParseException.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/ParseException.java (revision 0) |
| @@ -0,0 +1,197 @@ |
| +/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 4.1 */ |
| +/* JavaCCOptions:KEEP_LINE_COL=null */ |
| +package org.apache.lucene.queryParser.original.parser; |
| + |
| +/** |
| + * 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.messages.Message; |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeParseException; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| + |
| +/** |
| + * This exception is thrown when parse errors are encountered. You can |
| + * explicitly create objects of this exception type by calling the method |
| + * generateParseException in the generated parser. |
| + * |
| + * You can modify this class to customize your error reporting mechanisms so |
| + * long as you retain the public fields. |
| + */ |
| +public class ParseException extends QueryNodeParseException { |
| + |
| + /** |
| + * The version identifier for this Serializable class. Increment only if the |
| + * <i>serialized</i> form of the class changes. |
| + */ |
| + private static final long serialVersionUID = 1L; |
| + |
| + /** |
| + * This constructor is used by the method "generateParseException" in the |
| + * generated parser. Calling this constructor generates a new object of this |
| + * type with the fields "currentToken", "expectedTokenSequences", and |
| + * "tokenImage" set. |
| + */ |
| + public ParseException(Token currentTokenVal, |
| + int[][] expectedTokenSequencesVal, String[] tokenImageVal) { |
| + super(new MessageImpl(QueryParserMessages.INVALID_SYNTAX, initialise( |
| + currentTokenVal, expectedTokenSequencesVal, tokenImageVal))); |
| + this.currentToken = currentTokenVal; |
| + this.expectedTokenSequences = expectedTokenSequencesVal; |
| + this.tokenImage = tokenImageVal; |
| + } |
| + |
| + public ParseException(Message message) { |
| + super(message); |
| + } |
| + |
| + public ParseException() { |
| + super(new MessageImpl(QueryParserMessages.INVALID_SYNTAX, "Error")); |
| + } |
| + |
| + /** |
| + * This is the last token that has been consumed successfully. If this object |
| + * has been created due to a parse error, the token followng this token will |
| + * (therefore) be the first error token. |
| + */ |
| + @SuppressWarnings("unused") |
| + private Token currentToken; |
| + |
| + /** |
| + * Each entry in this array is an array of integers. Each array of integers |
| + * represents a sequence of tokens (by their ordinal values) that is expected |
| + * at this point of the parse. |
| + */ |
| + @SuppressWarnings("unused") |
| + private int[][] expectedTokenSequences; |
| + |
| + /** |
| + * This is a reference to the "tokenImage" array of the generated parser |
| + * within which the parse error occurred. This array is defined in the |
| + * generated ...Constants interface. |
| + */ |
| + @SuppressWarnings("unused") |
| + private String[] tokenImage; |
| + |
| + /** |
| + * It uses "currentToken" and "expectedTokenSequences" to generate a parse |
| + * error message and returns it. If this object has been created due to a |
| + * parse error, and you do not catch it (it gets thrown from the parser) the |
| + * correct error message gets displayed. |
| + */ |
| + private static String initialise(Token currentToken, |
| + int[][] expectedTokenSequences, String[] tokenImage) { |
| + String eol = System.getProperty("line.separator", "\n"); |
| + StringBuffer expected = new StringBuffer(); |
| + int maxSize = 0; |
| + for (int i = 0; i < expectedTokenSequences.length; i++) { |
| + if (maxSize < expectedTokenSequences[i].length) { |
| + maxSize = expectedTokenSequences[i].length; |
| + } |
| + for (int j = 0; j < expectedTokenSequences[i].length; j++) { |
| + expected.append(tokenImage[expectedTokenSequences[i][j]]).append(' '); |
| + } |
| + if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) { |
| + expected.append("..."); |
| + } |
| + expected.append(eol).append(" "); |
| + } |
| + String retval = "Encountered \""; |
| + Token tok = currentToken.next; |
| + for (int i = 0; i < maxSize; i++) { |
| + if (i != 0) |
| + retval += " "; |
| + if (tok.kind == 0) { |
| + retval += tokenImage[0]; |
| + break; |
| + } |
| + retval += " " + tokenImage[tok.kind]; |
| + retval += " \""; |
| + retval += add_escapes(tok.image); |
| + retval += " \""; |
| + tok = tok.next; |
| + } |
| + retval += "\" at line " + currentToken.next.beginLine + ", column " |
| + + currentToken.next.beginColumn; |
| + retval += "." + eol; |
| + if (expectedTokenSequences.length == 1) { |
| + retval += "Was expecting:" + eol + " "; |
| + } else { |
| + retval += "Was expecting one of:" + eol + " "; |
| + } |
| + retval += expected.toString(); |
| + return retval; |
| + } |
| + |
| + /** |
| + * The end of line string for this machine. |
| + */ |
| + @SuppressWarnings("unused") |
| + private String eol = System.getProperty("line.separator", "\n"); |
| + |
| + /** |
| + * Used to convert raw characters to their escaped version when these raw |
| + * version cannot be used as part of an ASCII string literal. |
| + */ |
| + static private String add_escapes(String str) { |
| + StringBuffer retval = new StringBuffer(); |
| + char ch; |
| + for (int i = 0; i < str.length(); i++) { |
| + switch (str.charAt(i)) { |
| + case 0: |
| + continue; |
| + case '\b': |
| + retval.append("\\b"); |
| + continue; |
| + case '\t': |
| + retval.append("\\t"); |
| + continue; |
| + case '\n': |
| + retval.append("\\n"); |
| + continue; |
| + case '\f': |
| + retval.append("\\f"); |
| + continue; |
| + case '\r': |
| + retval.append("\\r"); |
| + continue; |
| + case '\"': |
| + retval.append("\\\""); |
| + continue; |
| + case '\'': |
| + retval.append("\\\'"); |
| + continue; |
| + case '\\': |
| + retval.append("\\\\"); |
| + continue; |
| + default: |
| + if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { |
| + String s = "0000" + Integer.toString(ch, 16); |
| + retval.append("\\u" + s.substring(s.length() - 4, s.length())); |
| + } else { |
| + retval.append(ch); |
| + } |
| + continue; |
| + } |
| + } |
| + return retval.toString(); |
| + } |
| + |
| +} |
| +/* |
| + * JavaCC - OriginalChecksum=c04ac45b94787832e67e6d1b49d8774c (do not edit this |
| + * line) |
| + */ |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/EscapeQuerySyntaxImpl.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/EscapeQuerySyntaxImpl.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/EscapeQuerySyntaxImpl.java (revision 0) |
| @@ -0,0 +1,296 @@ |
| +package org.apache.lucene.queryParser.original.parser; |
| + |
| +/** |
| + * 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 java.util.Locale; |
| + |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax; |
| +import org.apache.lucene.queryParser.util.UnescapedCharSequence; |
| + |
| +/** |
| + */ |
| +public class EscapeQuerySyntaxImpl implements EscapeQuerySyntax { |
| + |
| + private static final char[] wildcardChars = { '*', '?' }; |
| + |
| + private static final String[] escapableTermExtraFirstChars = { "+", "-", "@" }; |
| + |
| + private static final String[] escapableTermChars = { "\"", "<", ">", "=", |
| + "!", "(", ")", "^", "[", "{", ":", "]", "}", "~" }; |
| + |
| + // TODO: check what to do with these "*", "?", "\\" |
| + private static final String[] escapableQuotedChars = { "\"" }; |
| + private static final String[] escapableWhiteChars = { " ", "\t", "\n", "\r", |
| + "\f", "\b", "\u3000" }; |
| + private static final String[] escapableWordTokens = { "AND", "OR", "NOT", |
| + "TO", "WITHIN", "SENTENCE", "PARAGRAPH", "INORDER" }; |
| + |
| + private static final CharSequence escapeChar(CharSequence str, Locale locale) { |
| + if (str == null || str.length() == 0) |
| + return str; |
| + |
| + CharSequence buffer = str; |
| + |
| + // regular escapable Char for terms |
| + for (int i = 0; i < escapableTermChars.length; i++) { |
| + buffer = replaceIgnoreCase(buffer, escapableTermChars[i].toLowerCase(), |
| + "\\", locale); |
| + } |
| + |
| + // First Character of a term as more escaping chars |
| + for (int i = 0; i < escapableTermExtraFirstChars.length; i++) { |
| + if (buffer.charAt(0) == escapableTermExtraFirstChars[i].charAt(0)) { |
| + buffer = "\\" + buffer.charAt(0) |
| + + buffer.subSequence(1, buffer.length()); |
| + break; |
| + } |
| + } |
| + |
| + return buffer; |
| + } |
| + |
| + private final CharSequence escapeQuoted(CharSequence str, Locale locale) { |
| + if (str == null || str.length() == 0) |
| + return str; |
| + |
| + CharSequence buffer = str; |
| + |
| + for (int i = 0; i < escapableQuotedChars.length; i++) { |
| + buffer = replaceIgnoreCase(buffer, escapableTermChars[i].toLowerCase(), |
| + "\\", locale); |
| + } |
| + return buffer; |
| + } |
| + |
| + private static final CharSequence escapeTerm(CharSequence term, Locale locale) { |
| + if (term == null) |
| + return term; |
| + |
| + // Escape single Chars |
| + term = escapeChar(term, locale); |
| + term = escapeWhiteChar(term, locale); |
| + |
| + // Escape Parser Words |
| + for (int i = 0; i < escapableWordTokens.length; i++) { |
| + if (escapableWordTokens[i].equalsIgnoreCase(term.toString())) |
| + return "\\" + term; |
| + } |
| + return term; |
| + } |
| + |
| + /** |
| + * replace with ignore case |
| + * |
| + * @param stringOrig |
| + * string to get replaced |
| + * @param sequence1 |
| + * the old character sequence in lowercase |
| + * @param escapeChar |
| + * the new character to prefix sequence1 in return string. |
| + * @return the new String |
| + */ |
| + private static CharSequence replaceIgnoreCase(CharSequence string, |
| + CharSequence sequence1, CharSequence escapeChar, Locale locale) { |
| + if (escapeChar == null || sequence1 == null || string == null) |
| + throw new NullPointerException(); |
| + |
| + // empty string case |
| + int count = string.length(); |
| + int sequence1Length = sequence1.length(); |
| + if (sequence1Length == 0) { |
| + StringBuilder result = new StringBuilder((count + 1) |
| + * escapeChar.length()); |
| + result.append(escapeChar); |
| + for (int i = 0; i < count; i++) { |
| + result.append(string.charAt(i)); |
| + result.append(escapeChar); |
| + } |
| + return result.toString(); |
| + } |
| + |
| + // normal case |
| + StringBuilder result = new StringBuilder(); |
| + char first = sequence1.charAt(0); |
| + int start = 0, copyStart = 0, firstIndex; |
| + while (start < count) { |
| + if ((firstIndex = string.toString().toLowerCase(locale).indexOf(first, |
| + start)) == -1) |
| + break; |
| + boolean found = true; |
| + if (sequence1.length() > 1) { |
| + if (firstIndex + sequence1Length > count) |
| + break; |
| + for (int i = 1; i < sequence1Length; i++) { |
| + if (string.toString().toLowerCase(locale).charAt(firstIndex + i) != sequence1 |
| + .charAt(i)) { |
| + found = false; |
| + break; |
| + } |
| + } |
| + } |
| + if (found) { |
| + result.append(string.toString().substring(copyStart, firstIndex)); |
| + result.append(escapeChar); |
| + result.append(string.toString().substring(firstIndex, |
| + firstIndex + sequence1Length)); |
| + copyStart = start = firstIndex + sequence1Length; |
| + } else { |
| + start = firstIndex + 1; |
| + } |
| + } |
| + if (result.length() == 0 && copyStart == 0) |
| + return string; |
| + result.append(string.toString().substring(copyStart)); |
| + return result.toString(); |
| + } |
| + |
| + /** |
| + * escape all tokens that are part of the parser syntax on a given string |
| + * |
| + * @param string |
| + * string to get replaced |
| + * @param locale |
| + * locale to be used when performing string compares |
| + * @return the new String |
| + */ |
| + private static final CharSequence escapeWhiteChar(CharSequence str, |
| + Locale locale) { |
| + if (str == null || str.length() == 0) |
| + return str; |
| + |
| + CharSequence buffer = str; |
| + |
| + for (int i = 0; i < escapableWhiteChars.length; i++) { |
| + buffer = replaceIgnoreCase(buffer, escapableWhiteChars[i].toLowerCase(), |
| + "\\", locale); |
| + } |
| + return buffer; |
| + } |
| + |
| + public CharSequence escape(CharSequence text, Locale locale, Type type) { |
| + if (text == null || text.length() == 0) |
| + return text; |
| + |
| + // escape wildcards and the escape char (this has to be perform before |
| + // anything else) |
| + // since we need to preserve the UnescapedCharSequence and escape the |
| + // original escape chars |
| + if (text instanceof UnescapedCharSequence) { |
| + text = ((UnescapedCharSequence) text).toStringEscaped(wildcardChars); |
| + } else { |
| + text = new UnescapedCharSequence(text).toStringEscaped(wildcardChars); |
| + } |
| + |
| + if (type == Type.STRING) { |
| + return escapeQuoted(text, locale); |
| + } else { |
| + return escapeTerm(text, locale); |
| + } |
| + } |
| + |
| + /** |
| + * Returns a String where the escape char has been removed, or kept only once |
| + * if there was a double escape. |
| + * |
| + * Supports escaped unicode characters, e. g. translates <code>A</code> to |
| + * <code>A</code>. |
| + * |
| + */ |
| + public static UnescapedCharSequence discardEscapeChar(CharSequence input) |
| + throws ParseException { |
| + // Create char array to hold unescaped char sequence |
| + char[] output = new char[input.length()]; |
| + boolean[] wasEscaped = new boolean[input.length()]; |
| + |
| + // The length of the output can be less than the input |
| + // due to discarded escape chars. This variable holds |
| + // the actual length of the output |
| + int length = 0; |
| + |
| + // We remember whether the last processed character was |
| + // an escape character |
| + boolean lastCharWasEscapeChar = false; |
| + |
| + // The multiplier the current unicode digit must be multiplied with. |
| + // E. g. the first digit must be multiplied with 16^3, the second with |
| + // 16^2... |
| + int codePointMultiplier = 0; |
| + |
| + // Used to calculate the codepoint of the escaped unicode character |
| + int codePoint = 0; |
| + |
| + for (int i = 0; i < input.length(); i++) { |
| + char curChar = input.charAt(i); |
| + if (codePointMultiplier > 0) { |
| + codePoint += hexToInt(curChar) * codePointMultiplier; |
| + codePointMultiplier >>>= 4; |
| + if (codePointMultiplier == 0) { |
| + output[length++] = (char) codePoint; |
| + codePoint = 0; |
| + } |
| + } else if (lastCharWasEscapeChar) { |
| + if (curChar == 'u') { |
| + // found an escaped unicode character |
| + codePointMultiplier = 16 * 16 * 16; |
| + } else { |
| + // this character was escaped |
| + output[length] = curChar; |
| + wasEscaped[length] = true; |
| + length++; |
| + } |
| + lastCharWasEscapeChar = false; |
| + } else { |
| + if (curChar == '\\') { |
| + lastCharWasEscapeChar = true; |
| + } else { |
| + output[length] = curChar; |
| + length++; |
| + } |
| + } |
| + } |
| + |
| + if (codePointMultiplier > 0) { |
| + throw new ParseException(new MessageImpl( |
| + QueryParserMessages.INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION)); |
| + } |
| + |
| + if (lastCharWasEscapeChar) { |
| + throw new ParseException(new MessageImpl( |
| + QueryParserMessages.INVALID_SYNTAX_ESCAPE_CHARACTER)); |
| + } |
| + |
| + return new UnescapedCharSequence(output, wasEscaped, 0, length); |
| + } |
| + |
| + /** Returns the numeric value of the hexadecimal character */ |
| + private static final int hexToInt(char c) throws ParseException { |
| + if ('0' <= c && c <= '9') { |
| + return c - '0'; |
| + } else if ('a' <= c && c <= 'f') { |
| + return c - 'a' + 10; |
| + } else if ('A' <= c && c <= 'F') { |
| + return c - 'A' + 10; |
| + } else { |
| + throw new ParseException(new MessageImpl( |
| + QueryParserMessages.INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE, c)); |
| + } |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/TokenMgrError.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/TokenMgrError.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/TokenMgrError.java (revision 0) |
| @@ -0,0 +1,168 @@ |
| +/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 4.1 */ |
| +/* JavaCCOptions: */ |
| +package org.apache.lucene.queryParser.original.parser; |
| + |
| +/** |
| + * 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. |
| + */ |
| + |
| +/** Token Manager Error. */ |
| +public class TokenMgrError extends Error { |
| + |
| + /** |
| + * The version identifier for this Serializable class. Increment only if the |
| + * <i>serialized</i> form of the class changes. |
| + */ |
| + private static final long serialVersionUID = 1L; |
| + |
| + /* |
| + * Ordinals for various reasons why an Error of this type can be thrown. |
| + */ |
| + |
| + /** |
| + * Lexical error occurred. |
| + */ |
| + static final int LEXICAL_ERROR = 0; |
| + |
| + /** |
| + * An attempt was made to create a second instance of a static token manager. |
| + */ |
| + static final int STATIC_LEXER_ERROR = 1; |
| + |
| + /** |
| + * Tried to change to an invalid lexical state. |
| + */ |
| + static final int INVALID_LEXICAL_STATE = 2; |
| + |
| + /** |
| + * Detected (and bailed out of) an infinite loop in the token manager. |
| + */ |
| + static final int LOOP_DETECTED = 3; |
| + |
| + /** |
| + * Indicates the reason why the exception is thrown. It will have one of the |
| + * above 4 values. |
| + */ |
| + int errorCode; |
| + |
| + /** |
| + * Replaces unprintable characters by their escaped (or unicode escaped) |
| + * equivalents in the given string |
| + */ |
| + protected static final String addEscapes(String str) { |
| + StringBuffer retval = new StringBuffer(); |
| + char ch; |
| + for (int i = 0; i < str.length(); i++) { |
| + switch (str.charAt(i)) { |
| + case 0: |
| + continue; |
| + case '\b': |
| + retval.append("\\b"); |
| + continue; |
| + case '\t': |
| + retval.append("\\t"); |
| + continue; |
| + case '\n': |
| + retval.append("\\n"); |
| + continue; |
| + case '\f': |
| + retval.append("\\f"); |
| + continue; |
| + case '\r': |
| + retval.append("\\r"); |
| + continue; |
| + case '\"': |
| + retval.append("\\\""); |
| + continue; |
| + case '\'': |
| + retval.append("\\\'"); |
| + continue; |
| + case '\\': |
| + retval.append("\\\\"); |
| + continue; |
| + default: |
| + if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { |
| + String s = "0000" + Integer.toString(ch, 16); |
| + retval.append("\\u" + s.substring(s.length() - 4, s.length())); |
| + } else { |
| + retval.append(ch); |
| + } |
| + continue; |
| + } |
| + } |
| + return retval.toString(); |
| + } |
| + |
| + /** |
| + * Returns a detailed message for the Error when it is thrown by the token |
| + * manager to indicate a lexical error. Parameters : EOFSeen : indicates if |
| + * EOF caused the lexical error curLexState : lexical state in which this |
| + * error occurred errorLine : line number when the error occurred errorColumn |
| + * : column number when the error occurred errorAfter : prefix that was seen |
| + * before this error occurred curchar : the offending character Note: You can |
| + * customize the lexical error message by modifying this method. |
| + */ |
| + protected static String LexicalError(boolean EOFSeen, int lexState, |
| + int errorLine, int errorColumn, String errorAfter, char curChar) { |
| + return ("Lexical error at line " |
| + + errorLine |
| + + ", column " |
| + + errorColumn |
| + + ". Encountered: " |
| + + (EOFSeen ? "<EOF> " |
| + : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" |
| + + (int) curChar + "), ") + "after : \"" |
| + + addEscapes(errorAfter) + "\""); |
| + } |
| + |
| + /** |
| + * You can also modify the body of this method to customize your error |
| + * messages. For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE |
| + * are not of end-users concern, so you can return something like : |
| + * |
| + * "Internal Error : Please file a bug report .... " |
| + * |
| + * from this method for such cases in the release version of your parser. |
| + */ |
| + public String getMessage() { |
| + return super.getMessage(); |
| + } |
| + |
| + /* |
| + * Constructors of various flavors follow. |
| + */ |
| + |
| + /** No arg constructor. */ |
| + public TokenMgrError() { |
| + } |
| + |
| + /** Constructor with message and reason. */ |
| + public TokenMgrError(String message, int reason) { |
| + super(message); |
| + errorCode = reason; |
| + } |
| + |
| + /** Full Constructor. */ |
| + public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, |
| + int errorColumn, String errorAfter, char curChar, int reason) { |
| + this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, |
| + curChar), reason); |
| + } |
| +} |
| +/* |
| + * JavaCC - OriginalChecksum=300228b3ff2a8227a4e823b29d23ad93 (do not edit this |
| + * line) |
| + */ |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/JavaCharStream.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/JavaCharStream.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/JavaCharStream.java (revision 0) |
| @@ -0,0 +1,591 @@ |
| +/* Generated By:JavaCC: Do not edit this line. JavaCharStream.java Version 4.1 */ |
| +/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ |
| +package org.apache.lucene.queryParser.original.parser; |
| + |
| +/** |
| + * 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. |
| + */ |
| + |
| +/** |
| + * An implementation of interface CharStream, where the stream is assumed to |
| + * contain only ASCII characters (with java-like unicode escape processing). |
| + */ |
| + |
| +public class JavaCharStream { |
| + /** Whether parser is static. */ |
| + public static final boolean staticFlag = false; |
| + |
| + static final int hexval(char c) throws java.io.IOException { |
| + switch (c) { |
| + case '0': |
| + return 0; |
| + case '1': |
| + return 1; |
| + case '2': |
| + return 2; |
| + case '3': |
| + return 3; |
| + case '4': |
| + return 4; |
| + case '5': |
| + return 5; |
| + case '6': |
| + return 6; |
| + case '7': |
| + return 7; |
| + case '8': |
| + return 8; |
| + case '9': |
| + return 9; |
| + |
| + case 'a': |
| + case 'A': |
| + return 10; |
| + case 'b': |
| + case 'B': |
| + return 11; |
| + case 'c': |
| + case 'C': |
| + return 12; |
| + case 'd': |
| + case 'D': |
| + return 13; |
| + case 'e': |
| + case 'E': |
| + return 14; |
| + case 'f': |
| + case 'F': |
| + return 15; |
| + } |
| + |
| + throw new java.io.IOException(); // Should never come here |
| + } |
| + |
| + /** Position in buffer. */ |
| + public int bufpos = -1; |
| + int bufsize; |
| + int available; |
| + int tokenBegin; |
| + protected int bufline[]; |
| + protected int bufcolumn[]; |
| + |
| + protected int column = 0; |
| + protected int line = 1; |
| + |
| + protected boolean prevCharIsCR = false; |
| + protected boolean prevCharIsLF = false; |
| + |
| + protected java.io.Reader inputStream; |
| + |
| + protected char[] nextCharBuf; |
| + protected char[] buffer; |
| + protected int maxNextCharInd = 0; |
| + protected int nextCharInd = -1; |
| + protected int inBuf = 0; |
| + protected int tabSize = 8; |
| + |
| + protected void setTabSize(int i) { |
| + tabSize = i; |
| + } |
| + |
| + protected int getTabSize(int i) { |
| + return tabSize; |
| + } |
| + |
| + protected void ExpandBuff(boolean wrapAround) { |
| + char[] newbuffer = new char[bufsize + 2048]; |
| + int newbufline[] = new int[bufsize + 2048]; |
| + int newbufcolumn[] = new int[bufsize + 2048]; |
| + |
| + try { |
| + if (wrapAround) { |
| + System |
| + .arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); |
| + System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos); |
| + buffer = newbuffer; |
| + |
| + System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize |
| + - tokenBegin); |
| + System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); |
| + bufline = newbufline; |
| + |
| + System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize |
| + - tokenBegin); |
| + System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, |
| + bufpos); |
| + bufcolumn = newbufcolumn; |
| + |
| + bufpos += (bufsize - tokenBegin); |
| + } else { |
| + System |
| + .arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); |
| + buffer = newbuffer; |
| + |
| + System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize |
| + - tokenBegin); |
| + bufline = newbufline; |
| + |
| + System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize |
| + - tokenBegin); |
| + bufcolumn = newbufcolumn; |
| + |
| + bufpos -= tokenBegin; |
| + } |
| + } catch (Throwable t) { |
| + throw new Error(t.getMessage()); |
| + } |
| + |
| + available = (bufsize += 2048); |
| + tokenBegin = 0; |
| + } |
| + |
| + protected void FillBuff() throws java.io.IOException { |
| + int i; |
| + if (maxNextCharInd == 4096) |
| + maxNextCharInd = nextCharInd = 0; |
| + |
| + try { |
| + if ((i = inputStream.read(nextCharBuf, maxNextCharInd, |
| + 4096 - maxNextCharInd)) == -1) { |
| + inputStream.close(); |
| + throw new java.io.IOException(); |
| + } else |
| + maxNextCharInd += i; |
| + return; |
| + } catch (java.io.IOException e) { |
| + if (bufpos != 0) { |
| + --bufpos; |
| + backup(0); |
| + } else { |
| + bufline[bufpos] = line; |
| + bufcolumn[bufpos] = column; |
| + } |
| + throw e; |
| + } |
| + } |
| + |
| + protected char ReadByte() throws java.io.IOException { |
| + if (++nextCharInd >= maxNextCharInd) |
| + FillBuff(); |
| + |
| + return nextCharBuf[nextCharInd]; |
| + } |
| + |
| + /** @return starting character for token. */ |
| + public char BeginToken() throws java.io.IOException { |
| + if (inBuf > 0) { |
| + --inBuf; |
| + |
| + if (++bufpos == bufsize) |
| + bufpos = 0; |
| + |
| + tokenBegin = bufpos; |
| + return buffer[bufpos]; |
| + } |
| + |
| + tokenBegin = 0; |
| + bufpos = -1; |
| + |
| + return readChar(); |
| + } |
| + |
| + protected void AdjustBuffSize() { |
| + if (available == bufsize) { |
| + if (tokenBegin > 2048) { |
| + bufpos = 0; |
| + available = tokenBegin; |
| + } else |
| + ExpandBuff(false); |
| + } else if (available > tokenBegin) |
| + available = bufsize; |
| + else if ((tokenBegin - available) < 2048) |
| + ExpandBuff(true); |
| + else |
| + available = tokenBegin; |
| + } |
| + |
| + protected void UpdateLineColumn(char c) { |
| + column++; |
| + |
| + if (prevCharIsLF) { |
| + prevCharIsLF = false; |
| + line += (column = 1); |
| + } else if (prevCharIsCR) { |
| + prevCharIsCR = false; |
| + if (c == '\n') { |
| + prevCharIsLF = true; |
| + } else |
| + line += (column = 1); |
| + } |
| + |
| + switch (c) { |
| + case '\r': |
| + prevCharIsCR = true; |
| + break; |
| + case '\n': |
| + prevCharIsLF = true; |
| + break; |
| + case '\t': |
| + column--; |
| + column += (tabSize - (column % tabSize)); |
| + break; |
| + default: |
| + break; |
| + } |
| + |
| + bufline[bufpos] = line; |
| + bufcolumn[bufpos] = column; |
| + } |
| + |
| + /** Read a character. */ |
| + public char readChar() throws java.io.IOException { |
| + if (inBuf > 0) { |
| + --inBuf; |
| + |
| + if (++bufpos == bufsize) |
| + bufpos = 0; |
| + |
| + return buffer[bufpos]; |
| + } |
| + |
| + char c; |
| + |
| + if (++bufpos == available) |
| + AdjustBuffSize(); |
| + |
| + if ((buffer[bufpos] = c = ReadByte()) == '\\') { |
| + UpdateLineColumn(c); |
| + |
| + int backSlashCnt = 1; |
| + |
| + for (;;) // Read all the backslashes |
| + { |
| + if (++bufpos == available) |
| + AdjustBuffSize(); |
| + |
| + try { |
| + if ((buffer[bufpos] = c = ReadByte()) != '\\') { |
| + UpdateLineColumn(c); |
| + // found a non-backslash char. |
| + if ((c == 'u') && ((backSlashCnt & 1) == 1)) { |
| + if (--bufpos < 0) |
| + bufpos = bufsize - 1; |
| + |
| + break; |
| + } |
| + |
| + backup(backSlashCnt); |
| + return '\\'; |
| + } |
| + } catch (java.io.IOException e) { |
| + // We are returning one backslash so we should only backup (count-1) |
| + if (backSlashCnt > 1) |
| + backup(backSlashCnt - 1); |
| + |
| + return '\\'; |
| + } |
| + |
| + UpdateLineColumn(c); |
| + backSlashCnt++; |
| + } |
| + |
| + // Here, we have seen an odd number of backslash's followed by a 'u' |
| + try { |
| + while ((c = ReadByte()) == 'u') |
| + ++column; |
| + |
| + buffer[bufpos] = c = (char) (hexval(c) << 12 | hexval(ReadByte()) << 8 |
| + | hexval(ReadByte()) << 4 | hexval(ReadByte())); |
| + |
| + column += 4; |
| + } catch (java.io.IOException e) { |
| + throw new Error("Invalid escape character at line " + line + " column " |
| + + column + "."); |
| + } |
| + |
| + if (backSlashCnt == 1) |
| + return c; |
| + else { |
| + backup(backSlashCnt - 1); |
| + return '\\'; |
| + } |
| + } else { |
| + UpdateLineColumn(c); |
| + return c; |
| + } |
| + } |
| + |
| + @Deprecated |
| + /* |
| + * * |
| + * |
| + * @deprecated |
| + * |
| + * @see #getEndColumn |
| + */ |
| + public int getColumn() { |
| + return bufcolumn[bufpos]; |
| + } |
| + |
| + @Deprecated |
| + /* |
| + * * |
| + * |
| + * @deprecated |
| + * |
| + * @see #getEndLine |
| + */ |
| + public int getLine() { |
| + return bufline[bufpos]; |
| + } |
| + |
| + /** Get end column. */ |
| + public int getEndColumn() { |
| + return bufcolumn[bufpos]; |
| + } |
| + |
| + /** Get end line. */ |
| + public int getEndLine() { |
| + return bufline[bufpos]; |
| + } |
| + |
| + /** @return column of token start */ |
| + public int getBeginColumn() { |
| + return bufcolumn[tokenBegin]; |
| + } |
| + |
| + /** @return line number of token start */ |
| + public int getBeginLine() { |
| + return bufline[tokenBegin]; |
| + } |
| + |
| + /** Retreat. */ |
| + public void backup(int amount) { |
| + |
| + inBuf += amount; |
| + if ((bufpos -= amount) < 0) |
| + bufpos += bufsize; |
| + } |
| + |
| + /** Constructor. */ |
| + public JavaCharStream(java.io.Reader dstream, int startline, int startcolumn, |
| + int buffersize) { |
| + inputStream = dstream; |
| + line = startline; |
| + column = startcolumn - 1; |
| + |
| + available = bufsize = buffersize; |
| + buffer = new char[buffersize]; |
| + bufline = new int[buffersize]; |
| + bufcolumn = new int[buffersize]; |
| + nextCharBuf = new char[4096]; |
| + } |
| + |
| + /** Constructor. */ |
| + public JavaCharStream(java.io.Reader dstream, int startline, int startcolumn) { |
| + this(dstream, startline, startcolumn, 4096); |
| + } |
| + |
| + /** Constructor. */ |
| + public JavaCharStream(java.io.Reader dstream) { |
| + this(dstream, 1, 1, 4096); |
| + } |
| + |
| + /** Reinitialise. */ |
| + public void ReInit(java.io.Reader dstream, int startline, int startcolumn, |
| + int buffersize) { |
| + inputStream = dstream; |
| + line = startline; |
| + column = startcolumn - 1; |
| + |
| + if (buffer == null || buffersize != buffer.length) { |
| + available = bufsize = buffersize; |
| + buffer = new char[buffersize]; |
| + bufline = new int[buffersize]; |
| + bufcolumn = new int[buffersize]; |
| + nextCharBuf = new char[4096]; |
| + } |
| + prevCharIsLF = prevCharIsCR = false; |
| + tokenBegin = inBuf = maxNextCharInd = 0; |
| + nextCharInd = bufpos = -1; |
| + } |
| + |
| + /** Reinitialise. */ |
| + public void ReInit(java.io.Reader dstream, int startline, int startcolumn) { |
| + ReInit(dstream, startline, startcolumn, 4096); |
| + } |
| + |
| + /** Reinitialise. */ |
| + public void ReInit(java.io.Reader dstream) { |
| + ReInit(dstream, 1, 1, 4096); |
| + } |
| + |
| + /** Constructor. */ |
| + public JavaCharStream(java.io.InputStream dstream, String encoding, |
| + int startline, int startcolumn, int buffersize) |
| + throws java.io.UnsupportedEncodingException { |
| + this(encoding == null ? new java.io.InputStreamReader(dstream) |
| + : new java.io.InputStreamReader(dstream, encoding), startline, |
| + startcolumn, buffersize); |
| + } |
| + |
| + /** Constructor. */ |
| + public JavaCharStream(java.io.InputStream dstream, int startline, |
| + int startcolumn, int buffersize) { |
| + this(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096); |
| + } |
| + |
| + /** Constructor. */ |
| + public JavaCharStream(java.io.InputStream dstream, String encoding, |
| + int startline, int startcolumn) |
| + throws java.io.UnsupportedEncodingException { |
| + this(dstream, encoding, startline, startcolumn, 4096); |
| + } |
| + |
| + /** Constructor. */ |
| + public JavaCharStream(java.io.InputStream dstream, int startline, |
| + int startcolumn) { |
| + this(dstream, startline, startcolumn, 4096); |
| + } |
| + |
| + /** Constructor. */ |
| + public JavaCharStream(java.io.InputStream dstream, String encoding) |
| + throws java.io.UnsupportedEncodingException { |
| + this(dstream, encoding, 1, 1, 4096); |
| + } |
| + |
| + /** Constructor. */ |
| + public JavaCharStream(java.io.InputStream dstream) { |
| + this(dstream, 1, 1, 4096); |
| + } |
| + |
| + /** Reinitialise. */ |
| + public void ReInit(java.io.InputStream dstream, String encoding, |
| + int startline, int startcolumn, int buffersize) |
| + throws java.io.UnsupportedEncodingException { |
| + ReInit(encoding == null ? new java.io.InputStreamReader(dstream) |
| + : new java.io.InputStreamReader(dstream, encoding), startline, |
| + startcolumn, buffersize); |
| + } |
| + |
| + /** Reinitialise. */ |
| + public void ReInit(java.io.InputStream dstream, int startline, |
| + int startcolumn, int buffersize) { |
| + ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, |
| + buffersize); |
| + } |
| + |
| + /** Reinitialise. */ |
| + public void ReInit(java.io.InputStream dstream, String encoding, |
| + int startline, int startcolumn) |
| + throws java.io.UnsupportedEncodingException { |
| + ReInit(dstream, encoding, startline, startcolumn, 4096); |
| + } |
| + |
| + /** Reinitialise. */ |
| + public void ReInit(java.io.InputStream dstream, int startline, int startcolumn) { |
| + ReInit(dstream, startline, startcolumn, 4096); |
| + } |
| + |
| + /** Reinitialise. */ |
| + public void ReInit(java.io.InputStream dstream, String encoding) |
| + throws java.io.UnsupportedEncodingException { |
| + ReInit(dstream, encoding, 1, 1, 4096); |
| + } |
| + |
| + /** Reinitialise. */ |
| + public void ReInit(java.io.InputStream dstream) { |
| + ReInit(dstream, 1, 1, 4096); |
| + } |
| + |
| + /** @return token image as String */ |
| + public String GetImage() { |
| + if (bufpos >= tokenBegin) |
| + return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); |
| + else |
| + return new String(buffer, tokenBegin, bufsize - tokenBegin) |
| + + new String(buffer, 0, bufpos + 1); |
| + } |
| + |
| + /** @return suffix */ |
| + public char[] GetSuffix(int len) { |
| + char[] ret = new char[len]; |
| + |
| + if ((bufpos + 1) >= len) |
| + System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); |
| + else { |
| + System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, len |
| + - bufpos - 1); |
| + System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); |
| + } |
| + |
| + return ret; |
| + } |
| + |
| + /** Set buffers back to null when finished. */ |
| + public void Done() { |
| + nextCharBuf = null; |
| + buffer = null; |
| + bufline = null; |
| + bufcolumn = null; |
| + } |
| + |
| + /** |
| + * Method to adjust line and column numbers for the start of a token. |
| + */ |
| + public void adjustBeginLineColumn(int newLine, int newCol) { |
| + int start = tokenBegin; |
| + int len; |
| + |
| + if (bufpos >= tokenBegin) { |
| + len = bufpos - tokenBegin + inBuf + 1; |
| + } else { |
| + len = bufsize - tokenBegin + bufpos + 1 + inBuf; |
| + } |
| + |
| + int i = 0, j = 0, k = 0; |
| + int nextColDiff = 0, columnDiff = 0; |
| + |
| + while (i < len |
| + && bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) { |
| + bufline[j] = newLine; |
| + nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; |
| + bufcolumn[j] = newCol + columnDiff; |
| + columnDiff = nextColDiff; |
| + i++; |
| + } |
| + |
| + if (i < len) { |
| + bufline[j] = newLine++; |
| + bufcolumn[j] = newCol + columnDiff; |
| + |
| + while (i++ < len) { |
| + if (bufline[j = start % bufsize] != bufline[++start % bufsize]) |
| + bufline[j] = newLine++; |
| + else |
| + bufline[j] = newLine; |
| + } |
| + } |
| + |
| + line = bufline[j]; |
| + column = bufcolumn[j]; |
| + } |
| + |
| +} |
| +/* |
| + * JavaCC - OriginalChecksum=e61bd5c730f749861216d7199a74d372 (do not edit this |
| + * line) |
| + */ |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/RangeQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/RangeQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/RangeQueryNode.java (revision 0) |
| @@ -0,0 +1,78 @@ |
| +package org.apache.lucene.queryParser.original.nodes; |
| + |
| +/** |
| + * 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 java.text.Collator; |
| + |
| +import org.apache.lucene.queryParser.nodes.ParametricQueryNode; |
| +import org.apache.lucene.queryParser.nodes.ParametricRangeQueryNode; |
| + |
| +/** |
| + * This query node represents a Lucene range query. It also holds which collator |
| + * will be used by the range query and if the constant score rewrite is enabled. <br/> |
| + * |
| + * @see org.apache.lucene.queryParser.original.QueryParserWrapper#setConstantScoreRewrite(boolean) |
| + * @see org.apache.lucene.queryParser.original.QueryParserWrapper#setRangeCollator(Collator) |
| + * @see org.apache.lucene.search.RangeQuery |
| + */ |
| +public class RangeQueryNode extends ParametricRangeQueryNode { |
| + |
| + private static final long serialVersionUID = 7400866652044314657L; |
| + |
| + private Collator collator; |
| + |
| + private boolean constantScoreRewrite; |
| + |
| + /** |
| + * @param lower |
| + * @param upper |
| + */ |
| + public RangeQueryNode(ParametricQueryNode lower, ParametricQueryNode upper, |
| + Collator collator, boolean constantScoreRewrite) { |
| + super(lower, upper); |
| + |
| + this.constantScoreRewrite = constantScoreRewrite; |
| + this.collator = collator; |
| + |
| + } |
| + |
| + public String toString() { |
| + StringBuilder sb = new StringBuilder("<range>\n\t"); |
| + sb.append(this.getUpperBound()).append("\n\t"); |
| + sb.append(this.getLowerBound()).append("\n"); |
| + sb.append("</range>\n"); |
| + |
| + return sb.toString(); |
| + |
| + } |
| + |
| + /** |
| + * @return the collator |
| + */ |
| + public Collator getCollator() { |
| + return this.collator; |
| + } |
| + |
| + /** |
| + * @return the constantScoreRewrite |
| + */ |
| + public boolean isConstantScoreRewrite() { |
| + return this.constantScoreRewrite; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/MultiPhraseQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/MultiPhraseQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/MultiPhraseQueryNode.java (revision 0) |
| @@ -0,0 +1,108 @@ |
| +package org.apache.lucene.queryParser.original.nodes; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.nodes.FieldableNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNodeImpl; |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax; |
| +import org.apache.lucene.search.MultiPhraseQuery; |
| +import org.apache.lucene.search.PhraseQuery; |
| + |
| +/** |
| + * A {@link MultiPhraseQueryNode} indicates that its children should be used to |
| + * build a {@link MultiPhraseQuery} instead of {@link PhraseQuery}. |
| + */ |
| +public class MultiPhraseQueryNode extends QueryNodeImpl implements |
| + FieldableNode { |
| + |
| + private static final long serialVersionUID = -2138501723963320158L; |
| + |
| + public MultiPhraseQueryNode() { |
| + setLeaf(false); |
| + allocate(); |
| + |
| + } |
| + |
| + public String toString() { |
| + if (getChildren() == null || getChildren().size() == 0) |
| + return "<multiPhrase/>"; |
| + StringBuilder sb = new StringBuilder(); |
| + sb.append("<multiPhrase>"); |
| + for (QueryNode child : getChildren()) { |
| + sb.append("\n"); |
| + sb.append(child.toString()); |
| + } |
| + sb.append("\n</multiPhrase>"); |
| + return sb.toString(); |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { |
| + if (getChildren() == null || getChildren().size() == 0) |
| + return ""; |
| + |
| + StringBuilder sb = new StringBuilder(); |
| + String filler = ""; |
| + for (QueryNode child : getChildren()) { |
| + sb.append(filler).append(child.toQueryString(escapeSyntaxParser)); |
| + filler = ","; |
| + } |
| + |
| + return "[MTP[" + sb.toString() + "]]"; |
| + } |
| + |
| + public QueryNode cloneTree() throws CloneNotSupportedException { |
| + MultiPhraseQueryNode clone = (MultiPhraseQueryNode) super.cloneTree(); |
| + |
| + // nothing to do |
| + |
| + return clone; |
| + } |
| + |
| + public CharSequence getField() { |
| + List<QueryNode> children = getChildren(); |
| + |
| + if (children == null || children.size() == 0) { |
| + return null; |
| + |
| + } else { |
| + return ((FieldableNode) children.get(0)).getField(); |
| + } |
| + |
| + } |
| + |
| + public void setField(CharSequence fieldName) { |
| + List<QueryNode> children = getChildren(); |
| + |
| + if (children != null) { |
| + |
| + for (QueryNode child : children) { |
| + |
| + if (child instanceof FieldableNode) { |
| + ((FieldableNode) child).setField(fieldName); |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| +} // end class MultitermQueryNode |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/package.html |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/package.html (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/package.html (revision 0) |
| @@ -0,0 +1,31 @@ |
| +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> |
| +<!-- |
| + 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. |
| +--> |
| +<html> |
| +<head> |
| + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| +</head> |
| +<body> |
| + |
| +<h2>Original Lucene Query Nodes</h2> |
| +<p> |
| +The package org.apache.lucene.queryParser.original.nodes contains QueryNode classes |
| +that are used specifically for Lucene query node tree. Any other generic QueryNode is |
| +defined under org.apache.lucene.queryParser.nodes. |
| +</p> |
| +</body> |
| +</html> |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/BooleanModifierNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/BooleanModifierNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/BooleanModifierNode.java (revision 0) |
| @@ -0,0 +1,39 @@ |
| +package org.apache.lucene.queryParser.original.nodes; |
| + |
| +/** |
| + * 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.nodes.ModifierQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.processors.GroupQueryNodeProcessor; |
| + |
| +/** |
| + * A {@link BooleanModifierNode} has the same behaviour as |
| + * {@link ModifierQueryNode}, it only indicates that this modifier was added by |
| + * {@link GroupQueryNodeProcessor} and not by the user. <br/> |
| + * |
| + * @see ModifierQueryNode |
| + */ |
| +public class BooleanModifierNode extends ModifierQueryNode { |
| + |
| + private static final long serialVersionUID = -557816496416587068L; |
| + |
| + public BooleanModifierNode(QueryNode node, Modifier mod) { |
| + super(node, mod); |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/LuceneBooleanQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/LuceneBooleanQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/LuceneBooleanQueryNode.java (revision 0) |
| @@ -0,0 +1,55 @@ |
| +package org.apache.lucene.queryParser.original.nodes; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.nodes.BooleanQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.search.BooleanQuery; |
| +import org.apache.lucene.search.Similarity; |
| + |
| +/** |
| + * A {@link LuceneBooleanQueryNode} has the same behavior as |
| + * {@link BooleanQueryNode}. It only indicates if the coord should be enabled or |
| + * not for this boolean query. <br/> |
| + * |
| + * @see Similarity#coord(int, int) |
| + * @see BooleanQuery |
| + */ |
| +public class LuceneBooleanQueryNode extends BooleanQueryNode { |
| + |
| + private static final long serialVersionUID = 1938287817191138787L; |
| + |
| + private boolean disableCoord; |
| + |
| + /** |
| + * @param clauses |
| + */ |
| + public LuceneBooleanQueryNode(List<QueryNode> clauses, boolean disableCoord) { |
| + super(clauses); |
| + |
| + this.disableCoord = disableCoord; |
| + |
| + } |
| + |
| + public boolean isDisableCoord() { |
| + return this.disableCoord; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/LuceneQueryParserHelper.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/LuceneQueryParserHelper.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/LuceneQueryParserHelper.java (revision 0) |
| @@ -0,0 +1,154 @@ |
| +package org.apache.lucene.queryParser.original; |
| + |
| +/** |
| + * 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.analysis.Analyzer; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.QueryParserHelper; |
| +import org.apache.lucene.queryParser.original.builders.LuceneQueryTreeBuilder; |
| +import org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.parser.TextParser; |
| +import org.apache.lucene.queryParser.original.processors.LuceneQueryNodeProcessorPipeline; |
| +import org.apache.lucene.search.Query; |
| + |
| +/** |
| + * <p> |
| + * This class is a helper that enables users to easily use the Lucene query |
| + * parser. |
| + * </p> |
| + * <p> |
| + * To construct a Query object from a query string, use the |
| + * {@link #parse(String, String)} method: |
| + * <ul> |
| + * LuceneQueryParserHelper queryParserHelper = new LuceneQueryParserHelper(); <br/> |
| + * Query query = queryParserHelper.parse("a AND b", "defaultField"); |
| + * </ul> |
| + * <p> |
| + * To change any configuration before parsing the query string do, for example: |
| + * <p/> |
| + * <ul> |
| + * // the query config handler returned by {@link LuceneQueryParserHelper} is a |
| + * {@link LuceneQueryConfigHandler} <br/> |
| + * queryParserHelper.getQueryConfigHandler().setAnalyzer(new |
| + * WhitespaceAnalyzer()); |
| + * </ul> |
| + * <p> |
| + * The syntax for query strings is as follows (copied from the old QueryParser |
| + * javadoc): |
| + * <ul> |
| + * A Query is a series of clauses. A clause may be prefixed by: |
| + * <ul> |
| + * <li>a plus (<code>+</code>) or a minus (<code>-</code>) sign, indicating that |
| + * the clause is required or prohibited respectively; or |
| + * <li>a term followed by a colon, indicating the field to be searched. This |
| + * enables one to construct queries which search multiple fields. |
| + * </ul> |
| + * |
| + * A clause may be either: |
| + * <ul> |
| + * <li>a term, indicating all the documents that contain this term; or |
| + * <li>a nested query, enclosed in parentheses. Note that this may be used with |
| + * a <code>+</code>/<code>-</code> prefix to require any of a set of terms. |
| + * </ul> |
| + * |
| + * Thus, in BNF, the query grammar is: |
| + * |
| + * <pre> |
| + * Query ::= ( Clause )* |
| + * Clause ::= ["+", "-"] [<TERM> ":"] ( <TERM> | "(" Query ")" ) |
| + * </pre> |
| + * |
| + * <p> |
| + * Examples of appropriately formatted queries can be found in the <a |
| + * href="../../../../../../queryparsersyntax.html">query syntax |
| + * documentation</a>. |
| + * </p> |
| + * </ul> |
| + * <p> |
| + * The text parser used by this helper is a {@link TextParser}. |
| + * <p/> |
| + * <p> |
| + * The query node processor used by this helper is a |
| + * {@link LuceneQueryNodeProcessorPipeline}. |
| + * <p/> |
| + * <p> |
| + * The builder used by this helper is a {@link LuceneQueryTreeBuilder}. |
| + * <p/> |
| + * |
| + * @see QueryParserHelper |
| + * @see LuceneQueryConfigHandler |
| + * @see TextParser |
| + * @see LuceneQueryNodeProcessorPipeline |
| + * @see LuceneQueryTreeBuilder |
| + */ |
| +public class LuceneQueryParserHelper |
| + extends |
| + QueryParserHelper<LuceneQueryConfigHandler, TextParser, LuceneQueryNodeProcessorPipeline, LuceneQueryTreeBuilder> { |
| + |
| + /** |
| + * Constructs a {@link LuceneQueryParserHelper} object. |
| + */ |
| + public LuceneQueryParserHelper() { |
| + super(new LuceneQueryConfigHandler(), new TextParser(), |
| + new LuceneQueryNodeProcessorPipeline(null), |
| + new LuceneQueryTreeBuilder()); |
| + } |
| + |
| + /** |
| + * Constructs a {@link LuceneQueryParserHelper} object and sets an |
| + * {@link Analyzer} to it. The same as: |
| + * |
| + * <ul> |
| + * LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + * qp.getQueryConfigHandler().setAnalyzer(analyzer); |
| + * </ul> |
| + * |
| + * @param analyzer |
| + * the analyzer to be used by this query parser helper |
| + */ |
| + public LuceneQueryParserHelper(Analyzer analyzer) { |
| + this(); |
| + |
| + getQueryConfigHandler().setAnalyzer(analyzer); |
| + |
| + } |
| + |
| + /** |
| + * Overrides {@link QueryParserHelper#parse(String, String)} so it casts the |
| + * return object to {@link Query}. For more reference about this method, check |
| + * {@link QueryParserHelper#parse(String, String)}. |
| + * |
| + * @param query |
| + * the query string |
| + * @param defaultField |
| + * the default field used by the text parser |
| + * |
| + * @return the object built from the query |
| + * |
| + * @throws QueryNodeException |
| + * if something wrong happens along the three phases |
| + */ |
| + @Override |
| + public Query parse(String query, String defaultField) |
| + throws QueryNodeException { |
| + |
| + return (Query) super.parse(query, defaultField); |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/LuceneQueryParserHelper.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/LuceneQueryNodeProcessorPipeline.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/LuceneQueryNodeProcessorPipeline.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/LuceneQueryNodeProcessorPipeline.java (revision 0) |
| @@ -0,0 +1,70 @@ |
| +package org.apache.lucene.queryParser.original.processors; |
| + |
| +/** |
| + * 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.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.builders.LuceneQueryTreeBuilder; |
| +import org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.parser.TextParser; |
| +import org.apache.lucene.queryParser.processors.NoChildOptimizationQueryNodeProcessor; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorPipeline; |
| +import org.apache.lucene.queryParser.processors.RemoveDeletedQueryNodesProcessor; |
| +import org.apache.lucene.search.Query; |
| + |
| +/** |
| + * This pipeline has all the processors needed to process a query node tree, |
| + * generated by {@link TextParser}, already assembled. <br/> |
| + * <br/> |
| + * The order they are assembled affects the results. <br/> |
| + * <br/> |
| + * This processor pipeline was designed to work with |
| + * {@link LuceneQueryConfigHandler}. <br/> |
| + * <br/> |
| + * The result query node tree can be used to build a {@link Query} object using |
| + * {@link LuceneQueryTreeBuilder}. <br/> |
| + * |
| + * @see LuceneQueryTreeBuilder |
| + * @see LuceneQueryConfigHandler |
| + * @see TextParser |
| + */ |
| +public class LuceneQueryNodeProcessorPipeline extends |
| + QueryNodeProcessorPipeline { |
| + |
| + public LuceneQueryNodeProcessorPipeline(QueryConfigHandler queryConfig) { |
| + super(queryConfig); |
| + |
| + addProcessor(new MultiFieldQueryNodeProcessor()); |
| + addProcessor(new FuzzyQueryNodeProcessor()); |
| + addProcessor(new MatchAllDocsQueryNodeProcessor()); |
| + addProcessor(new LowercaseExpandedTermsQueryNodeProcessor()); |
| + addProcessor(new ParametricRangeQueryNodeProcessor()); |
| + addProcessor(new AllowLeadingWildcardProcessor()); |
| + addProcessor(new PrefixWildcardQueryNodeProcessor()); |
| + addProcessor(new AnalyzerQueryNodeProcessor()); |
| + addProcessor(new PhraseSlopQueryNodeProcessor()); |
| + addProcessor(new GroupQueryNodeProcessor()); |
| + addProcessor(new NoChildOptimizationQueryNodeProcessor()); |
| + addProcessor(new RemoveDeletedQueryNodesProcessor()); |
| + addProcessor(new RemoveEmptyNonLeafQueryNodeProcessor()); |
| + addProcessor(new BooleanSingleChildOptimizationQueryNodeProcessor()); |
| + addProcessor(new DefaultPhraseSlopQueryNodeProcessor()); |
| + addProcessor(new BoostQueryNodeProcessor()); |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/LowercaseExpandedTermsQueryNodeProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/LowercaseExpandedTermsQueryNodeProcessor.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/LowercaseExpandedTermsQueryNodeProcessor.java (revision 0) |
| @@ -0,0 +1,96 @@ |
| +package org.apache.lucene.queryParser.original.processors; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.nodes.FieldQueryNode; |
| +import org.apache.lucene.queryParser.nodes.FuzzyQueryNode; |
| +import org.apache.lucene.queryParser.nodes.ParametricQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.WildcardQueryNode; |
| +import org.apache.lucene.queryParser.original.QueryParserWrapper; |
| +import org.apache.lucene.queryParser.original.config.LowercaseExpandedTermsAttribute; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| + |
| +/** |
| + * This processor verifies if the attribute |
| + * {@link LowercaseExpandedTermsAttribute} is defined in the |
| + * {@link QueryConfigHandler}. If it is and the expanded terms should be |
| + * lowercased, it looks for every {@link WildcardQueryNode}, |
| + * {@link FuzzyQueryNode} and {@link ParametricQueryNode} and lowercase its |
| + * term. <br/> |
| + * |
| + * @see QueryParserWrapper#setLowercaseExpandedTerms(boolean) |
| + * @see LowercaseExpandedTermsAttribute |
| + */ |
| +@SuppressWarnings("deprecation") |
| +public class LowercaseExpandedTermsQueryNodeProcessor extends |
| + QueryNodeProcessorImpl { |
| + |
| + public LowercaseExpandedTermsQueryNodeProcessor() { |
| + // empty constructor |
| + } |
| + |
| + public QueryNode process(QueryNode queryTree) throws QueryNodeException { |
| + |
| + if (getQueryConfigHandler().hasAttribute( |
| + LowercaseExpandedTermsAttribute.class)) { |
| + |
| + if (((LowercaseExpandedTermsAttribute) getQueryConfigHandler() |
| + .getAttribute(LowercaseExpandedTermsAttribute.class)) |
| + .isLowercaseExpandedTerms()) { |
| + return super.process(queryTree); |
| + } |
| + |
| + } |
| + |
| + return queryTree; |
| + |
| + } |
| + |
| + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + if (node instanceof WildcardQueryNode || node instanceof FuzzyQueryNode |
| + || node instanceof ParametricQueryNode) { |
| + |
| + FieldQueryNode fieldNode = (FieldQueryNode) node; |
| + fieldNode.setText(fieldNode.getText().toString().toLowerCase()); |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/AllowLeadingWildcardProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/AllowLeadingWildcardProcessor.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/AllowLeadingWildcardProcessor.java (revision 0) |
| @@ -0,0 +1,101 @@ |
| +package org.apache.lucene.queryParser.original.processors; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.WildcardQueryNode; |
| +import org.apache.lucene.queryParser.original.QueryParserWrapper; |
| +import org.apache.lucene.queryParser.original.config.AllowLeadingWildcardAttribute; |
| +import org.apache.lucene.queryParser.original.parser.EscapeQuerySyntaxImpl; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| + |
| +/** |
| + * This processor verifies if the attribute |
| + * {@link AllowLeadingWildcardAttribute} is defined in the |
| + * {@link QueryConfigHandler}. If it is and leading wildcard is not allowed, it |
| + * looks for every {@link WildcardQueryNode} contained in the query node tree |
| + * and throws an exception if any of them has a leading wildcard ('*' or '?'). <br/> |
| + * |
| + * @see QueryParserWrapper#setAllowLeadingWildcard(boolean) |
| + * @see AllowLeadingWildcardAttribute |
| + */ |
| +@SuppressWarnings("deprecation") |
| +public class AllowLeadingWildcardProcessor extends QueryNodeProcessorImpl { |
| + |
| + public AllowLeadingWildcardProcessor() { |
| + // empty constructor |
| + } |
| + |
| + public QueryNode process(QueryNode queryTree) throws QueryNodeException { |
| + |
| + if (getQueryConfigHandler().hasAttribute( |
| + AllowLeadingWildcardAttribute.class)) { |
| + |
| + if (!((AllowLeadingWildcardAttribute) getQueryConfigHandler() |
| + .getAttribute(AllowLeadingWildcardAttribute.class)) |
| + .isAllowLeadingWildcard()) { |
| + return super.process(queryTree); |
| + } |
| + |
| + } |
| + |
| + return queryTree; |
| + |
| + } |
| + |
| + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + if (node instanceof WildcardQueryNode) { |
| + WildcardQueryNode wildcardNode = (WildcardQueryNode) node; |
| + |
| + switch (wildcardNode.getText().charAt(0)) { |
| + |
| + case '*': |
| + case '?': |
| + throw new QueryNodeException(new MessageImpl( |
| + QueryParserMessages.LEADING_WILDCARD_NOT_ALLOWED, node |
| + .toQueryString(new EscapeQuerySyntaxImpl()))); |
| + |
| + } |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/RemoveEmptyNonLeafQueryNodeProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/RemoveEmptyNonLeafQueryNodeProcessor.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/RemoveEmptyNonLeafQueryNodeProcessor.java (revision 0) |
| @@ -0,0 +1,112 @@ |
| +package org.apache.lucene.queryParser.original.processors; |
| + |
| +/** |
| + * 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 java.util.LinkedList; |
| +import java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.nodes.GroupQueryNode; |
| +import org.apache.lucene.queryParser.nodes.MatchNoDocsQueryNode; |
| +import org.apache.lucene.queryParser.nodes.ModifierQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| + |
| +/** |
| + * This processor removes every {@link QueryNode} that is not a leaf and has not |
| + * children. If after processing the entire tree the root node is not a leaf and |
| + * has no children, a {@link MatchNoDocsQueryNode} object is returned. <br/> |
| + * <br/> |
| + * This processor is used at the end of a pipeline to avoid invalid query node |
| + * tree structures like a {@link GroupQueryNode} or {@link ModifierQueryNode} |
| + * with no children. <br/> |
| + * |
| + * @see QueryNode |
| + * @see MatchNoDocsQueryNode |
| + */ |
| +public class RemoveEmptyNonLeafQueryNodeProcessor extends |
| + QueryNodeProcessorImpl { |
| + |
| + private LinkedList<QueryNode> childrenBuffer = new LinkedList<QueryNode>(); |
| + |
| + public RemoveEmptyNonLeafQueryNodeProcessor() { |
| + // empty constructor |
| + } |
| + |
| + public QueryNode process(QueryNode queryTree) throws QueryNodeException { |
| + queryTree = super.process(queryTree); |
| + |
| + if (!queryTree.isLeaf()) { |
| + |
| + List<QueryNode> children = queryTree.getChildren(); |
| + |
| + if (children == null || children.size() == 0) { |
| + return new MatchNoDocsQueryNode(); |
| + } |
| + |
| + } |
| + |
| + return queryTree; |
| + |
| + } |
| + |
| + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + try { |
| + |
| + for (QueryNode child : children) { |
| + |
| + if (!child.isLeaf()) { |
| + |
| + List<QueryNode> grandChildren = child.getChildren(); |
| + |
| + if (grandChildren != null && grandChildren.size() > 0) { |
| + this.childrenBuffer.add(child); |
| + } |
| + |
| + } else { |
| + this.childrenBuffer.add(child); |
| + } |
| + |
| + } |
| + |
| + children.clear(); |
| + children.addAll(this.childrenBuffer); |
| + |
| + } finally { |
| + this.childrenBuffer.clear(); |
| + } |
| + |
| + return children; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/BoostQueryNodeProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/BoostQueryNodeProcessor.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/BoostQueryNodeProcessor.java (revision 0) |
| @@ -0,0 +1,84 @@ |
| +package org.apache.lucene.queryParser.original.processors; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.config.FieldConfig; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.nodes.BoostQueryNode; |
| +import org.apache.lucene.queryParser.nodes.FieldableNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.config.BoostAttribute; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| + |
| +/** |
| + * This processor iterates the query node tree looking for every |
| + * {@link FieldableNode} that has the attribute {@link BoostAttribute} in its |
| + * config. If there is, the boost is applied to that {@link FieldableNode}. <br/> |
| + * |
| + * @see BoostAttribute |
| + * @see QueryConfigHandler |
| + * @see FieldableNode |
| + */ |
| +public class BoostQueryNodeProcessor extends QueryNodeProcessorImpl { |
| + |
| + @Override |
| + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + if (node instanceof FieldableNode) { |
| + FieldableNode fieldNode = (FieldableNode) node; |
| + QueryConfigHandler config = getQueryConfigHandler(); |
| + |
| + if (config != null) { |
| + FieldConfig fieldConfig = config.getFieldConfig(fieldNode.getField()); |
| + |
| + if (fieldConfig != null |
| + && fieldConfig.hasAttribute(BoostAttribute.class)) { |
| + BoostAttribute boostAttr = (BoostAttribute) fieldConfig |
| + .getAttribute(BoostAttribute.class); |
| + |
| + return new BoostQueryNode(node, boostAttr.getBoost()); |
| + |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + @Override |
| + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + @Override |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/PhraseSlopQueryNodeProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/PhraseSlopQueryNodeProcessor.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/PhraseSlopQueryNodeProcessor.java (revision 0) |
| @@ -0,0 +1,71 @@ |
| +package org.apache.lucene.queryParser.original.processors; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.SlopQueryNode; |
| +import org.apache.lucene.queryParser.nodes.TokenizedPhraseQueryNode; |
| +import org.apache.lucene.queryParser.original.nodes.MultiPhraseQueryNode; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| + |
| +/** |
| + * This processor removes invalid {@link SlopQueryNode} objects in the query |
| + * node tree. A {@link SlopQueryNode} is invalid if its child is neither a |
| + * {@link TokenizedPhraseQueryNode} nor a {@link MultiPhraseQueryNode}. <br/> |
| + * |
| + * @see SlopQueryNode |
| + */ |
| +public class PhraseSlopQueryNodeProcessor extends QueryNodeProcessorImpl { |
| + |
| + public PhraseSlopQueryNodeProcessor() { |
| + // empty constructor |
| + } |
| + |
| + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + if (node instanceof SlopQueryNode) { |
| + SlopQueryNode phraseSlopNode = (SlopQueryNode) node; |
| + |
| + if (!(phraseSlopNode.getChild() instanceof TokenizedPhraseQueryNode) |
| + && !(phraseSlopNode.getChild() instanceof MultiPhraseQueryNode)) { |
| + return phraseSlopNode.getChild(); |
| + } |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/FuzzyQueryNodeProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/FuzzyQueryNodeProcessor.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/FuzzyQueryNodeProcessor.java (revision 0) |
| @@ -0,0 +1,86 @@ |
| +package org.apache.lucene.queryParser.original.processors; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.nodes.FuzzyQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.config.FuzzyAttribute; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| +import org.apache.lucene.search.FuzzyQuery; |
| + |
| +/** |
| + * This processor iterates the query node tree looking for every |
| + * {@link FuzzyQueryNode}, when this kind of node is found, it checks on the |
| + * query configuration for {@link FuzzyAttribute}, gets the fuzzy prefix length |
| + * and default similarity from it and set to the fuzzy node. For more |
| + * information about fuzzy prefix length check: {@link FuzzyQuery}. <br/> |
| + * |
| + * @see FuzzyAttribute |
| + * @see FuzzyQuery |
| + * @see FuzzyQueryNode |
| + */ |
| +public class FuzzyQueryNodeProcessor extends QueryNodeProcessorImpl { |
| + |
| + @Override |
| + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + @Override |
| + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + if (node instanceof FuzzyQueryNode) { |
| + FuzzyQueryNode fuzzyNode = (FuzzyQueryNode) node; |
| + QueryConfigHandler config = getQueryConfigHandler(); |
| + |
| + if (config != null && config.hasAttribute(FuzzyAttribute.class)) { |
| + FuzzyAttribute fuzzyAttr = (FuzzyAttribute) config |
| + .getAttribute(FuzzyAttribute.class); |
| + fuzzyNode.setPrefixLength(fuzzyAttr.getPrefixLength()); |
| + |
| + if (fuzzyNode.getSimilarity() < 0) { |
| + fuzzyNode.setSimilarity(fuzzyAttr.getFuzzyMinSimilarity()); |
| + |
| + } |
| + |
| + } else if (fuzzyNode.getSimilarity() < 0) { |
| + throw new IllegalArgumentException("No " |
| + + FuzzyAttribute.class.getName() + " set in the config"); |
| + } |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + @Override |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/MatchAllDocsQueryNodeProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/MatchAllDocsQueryNodeProcessor.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/MatchAllDocsQueryNodeProcessor.java (revision 0) |
| @@ -0,0 +1,73 @@ |
| +package org.apache.lucene.queryParser.original.processors; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.nodes.MatchAllDocsQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.WildcardQueryNode; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| +import org.apache.lucene.search.MatchAllDocsQuery; |
| + |
| +/** |
| + * This processor converts every {@link WildcardQueryNode} that is "*:*" to |
| + * {@link MatchAllDocsQueryNode}. |
| + * |
| + * @see MatchAllDocsQueryNode |
| + * @see MatchAllDocsQuery |
| + */ |
| +public class MatchAllDocsQueryNodeProcessor extends QueryNodeProcessorImpl { |
| + |
| + public MatchAllDocsQueryNodeProcessor() { |
| + // empty constructor |
| + } |
| + |
| + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + if (node instanceof WildcardQueryNode) { |
| + WildcardQueryNode wildcardNode = (WildcardQueryNode) node; |
| + |
| + if (wildcardNode.getField().toString().equals("*") |
| + && wildcardNode.getText().toString().equals("*")) { |
| + |
| + return new MatchAllDocsQueryNode(); |
| + |
| + } |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/AnalyzerQueryNodeProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/AnalyzerQueryNodeProcessor.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/AnalyzerQueryNodeProcessor.java (revision 0) |
| @@ -0,0 +1,337 @@ |
| +package org.apache.lucene.queryParser.original.processors; |
| + |
| +/** |
| + * 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 java.io.IOException; |
| +import java.io.StringReader; |
| +import java.util.ArrayList; |
| +import java.util.LinkedList; |
| +import java.util.List; |
| + |
| +import org.apache.lucene.analysis.Analyzer; |
| +import org.apache.lucene.analysis.CachingTokenFilter; |
| +import org.apache.lucene.analysis.TokenStream; |
| +import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute; |
| +import org.apache.lucene.analysis.tokenattributes.TermAttribute; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.nodes.FieldQueryNode; |
| +import org.apache.lucene.queryParser.nodes.FuzzyQueryNode; |
| +import org.apache.lucene.queryParser.nodes.GroupQueryNode; |
| +import org.apache.lucene.queryParser.nodes.NoTokenFoundQueryNode; |
| +import org.apache.lucene.queryParser.nodes.ParametricQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.TextableQueryNode; |
| +import org.apache.lucene.queryParser.nodes.TokenizedPhraseQueryNode; |
| +import org.apache.lucene.queryParser.nodes.WildcardQueryNode; |
| +import org.apache.lucene.queryParser.original.config.AnalyzerAttribute; |
| +import org.apache.lucene.queryParser.original.config.PositionIncrementsAttribute; |
| +import org.apache.lucene.queryParser.original.nodes.LuceneBooleanQueryNode; |
| +import org.apache.lucene.queryParser.original.nodes.MultiPhraseQueryNode; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| + |
| +/** |
| + * This processor verifies if the attribute {@link AnalyzerQueryNodeProcessor} |
| + * is defined in the {@link QueryConfigHandler}. If it is and the analyzer is |
| + * not <code>null</code>, it looks for every {@link FieldQueryNode} that is not |
| + * {@link WildcardQueryNode}, {@link FuzzyQueryNode} or |
| + * {@link ParametricQueryNode} contained in the query node tree, then it applies |
| + * the analyzer to that {@link FieldQueryNode} object. <br/> |
| + * <br/> |
| + * If the analyzer return only one term, the returned term is set to the |
| + * {@link FieldQueryNode} and it's returned. <br/> |
| + * <br/> |
| + * If the analyzer return more than one term, a {@link TokenizedPhraseQueryNode} |
| + * or {@link MultiPhraseQueryNode} is created, whether there is one or more |
| + * terms at the same position, and it's returned. <br/> |
| + * <br/> |
| + * If no term is returned by the analyzer a {@link NoTokenFoundQueryNode} object |
| + * is returned. <br/> |
| + * |
| + * @see Analyzer |
| + * @see TokenStream |
| + */ |
| +public class AnalyzerQueryNodeProcessor extends QueryNodeProcessorImpl { |
| + |
| + private Analyzer analyzer; |
| + |
| + private boolean positionIncrementsEnabled; |
| + |
| + public AnalyzerQueryNodeProcessor() { |
| + // empty constructor |
| + } |
| + |
| + public QueryNode process(QueryNode queryTree) throws QueryNodeException { |
| + |
| + if (getQueryConfigHandler().hasAttribute(AnalyzerAttribute.class)) { |
| + |
| + this.analyzer = ((AnalyzerAttribute) getQueryConfigHandler() |
| + .getAttribute(AnalyzerAttribute.class)).getAnalyzer(); |
| + |
| + this.positionIncrementsEnabled = false; |
| + |
| + if (getQueryConfigHandler().hasAttribute( |
| + PositionIncrementsAttribute.class)) { |
| + |
| + if (((PositionIncrementsAttribute) getQueryConfigHandler() |
| + .getAttribute(PositionIncrementsAttribute.class)) |
| + .isPositionIncrementsEnabled()) { |
| + |
| + this.positionIncrementsEnabled = true; |
| + |
| + } |
| + |
| + } |
| + |
| + if (this.analyzer != null) { |
| + return super.process(queryTree); |
| + } |
| + |
| + } |
| + |
| + return queryTree; |
| + |
| + } |
| + |
| + @Override |
| + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + if (node instanceof TextableQueryNode |
| + && !(node instanceof WildcardQueryNode) |
| + && !(node instanceof FuzzyQueryNode) |
| + && !(node instanceof ParametricQueryNode)) { |
| + |
| + FieldQueryNode fieldNode = ((FieldQueryNode) node); |
| + String text = fieldNode.getTextAsString(); |
| + String field = fieldNode.getFieldAsString(); |
| + |
| + TokenStream source = this.analyzer.tokenStream(field, new StringReader( |
| + text)); |
| + CachingTokenFilter buffer = new CachingTokenFilter(source); |
| + |
| + PositionIncrementAttribute posIncrAtt = null; |
| + int numTokens = 0; |
| + int positionCount = 0; |
| + boolean severalTokensAtSamePosition = false; |
| + |
| + if (buffer.hasAttribute(PositionIncrementAttribute.class)) { |
| + posIncrAtt = (PositionIncrementAttribute) buffer |
| + .getAttribute(PositionIncrementAttribute.class); |
| + } |
| + |
| + try { |
| + |
| + while (buffer.incrementToken()) { |
| + numTokens++; |
| + int positionIncrement = (posIncrAtt != null) ? posIncrAtt |
| + .getPositionIncrement() : 1; |
| + if (positionIncrement != 0) { |
| + positionCount += positionIncrement; |
| + |
| + } else { |
| + severalTokensAtSamePosition = true; |
| + } |
| + |
| + } |
| + |
| + } catch (IOException e) { |
| + // ignore |
| + } |
| + |
| + try { |
| + // rewind the buffer stream |
| + buffer.reset(); |
| + |
| + // close original stream - all tokens buffered |
| + source.close(); |
| + } catch (IOException e) { |
| + // ignore |
| + } |
| + |
| + if (!buffer.hasAttribute(TermAttribute.class)) { |
| + return new NoTokenFoundQueryNode(); |
| + } |
| + |
| + TermAttribute termAtt = (TermAttribute) buffer |
| + .getAttribute(TermAttribute.class); |
| + |
| + if (numTokens == 0) { |
| + return new NoTokenFoundQueryNode(); |
| + |
| + } else if (numTokens == 1) { |
| + String term = null; |
| + try { |
| + boolean hasNext; |
| + hasNext = buffer.incrementToken(); |
| + assert hasNext == true; |
| + term = termAtt.term(); |
| + |
| + } catch (IOException e) { |
| + // safe to ignore, because we know the number of tokens |
| + } |
| + |
| + fieldNode.setText(term); |
| + |
| + return fieldNode; |
| + |
| + } else if (severalTokensAtSamePosition) { |
| + if (positionCount == 1) { |
| + // no phrase query: |
| + LinkedList<QueryNode> children = new LinkedList<QueryNode>(); |
| + |
| + for (int i = 0; i < numTokens; i++) { |
| + String term = null; |
| + try { |
| + boolean hasNext = buffer.incrementToken(); |
| + assert hasNext == true; |
| + term = termAtt.term(); |
| + |
| + } catch (IOException e) { |
| + // safe to ignore, because we know the number of tokens |
| + } |
| + |
| + children.add(new FieldQueryNode(field, term, -1, -1)); |
| + |
| + } |
| + |
| + return new GroupQueryNode(new LuceneBooleanQueryNode(children, true)); |
| + |
| + } else { |
| + // phrase query: |
| + MultiPhraseQueryNode mpq = new MultiPhraseQueryNode(); |
| + |
| + List<FieldQueryNode> multiTerms = new ArrayList<FieldQueryNode>(); |
| + int position = -1; |
| + int i = 0; |
| + for (; i < numTokens; i++) { |
| + String term = null; |
| + int positionIncrement = 1; |
| + try { |
| + boolean hasNext = buffer.incrementToken(); |
| + assert hasNext == true; |
| + term = termAtt.term(); |
| + if (posIncrAtt != null) { |
| + positionIncrement = posIncrAtt.getPositionIncrement(); |
| + } |
| + |
| + } catch (IOException e) { |
| + // safe to ignore, because we know the number of tokens |
| + } |
| + |
| + if (positionIncrement > 0 && multiTerms.size() > 0) { |
| + |
| + for (FieldQueryNode termNode : multiTerms) { |
| + |
| + if (this.positionIncrementsEnabled) { |
| + termNode.setPositionIncrement(position); |
| + |
| + } else { |
| + termNode.setPositionIncrement(i); |
| + } |
| + |
| + mpq.add(termNode); |
| + |
| + } |
| + |
| + multiTerms.clear(); |
| + |
| + } |
| + |
| + position += positionIncrement; |
| + multiTerms.add(new FieldQueryNode(field, term, -1, -1)); |
| + |
| + } |
| + |
| + for (FieldQueryNode termNode : multiTerms) { |
| + |
| + if (this.positionIncrementsEnabled) { |
| + termNode.setPositionIncrement(position); |
| + |
| + } else { |
| + termNode.setPositionIncrement(i); |
| + } |
| + |
| + mpq.add(termNode); |
| + |
| + } |
| + |
| + return mpq; |
| + |
| + } |
| + |
| + } else { |
| + |
| + TokenizedPhraseQueryNode pq = new TokenizedPhraseQueryNode(); |
| + |
| + int position = -1; |
| + |
| + for (int i = 0; i < numTokens; i++) { |
| + String term = null; |
| + int positionIncrement = 1; |
| + |
| + try { |
| + boolean hasNext = buffer.incrementToken(); |
| + assert hasNext == true; |
| + term = termAtt.term(); |
| + |
| + if (posIncrAtt != null) { |
| + positionIncrement = posIncrAtt.getPositionIncrement(); |
| + } |
| + |
| + } catch (IOException e) { |
| + // safe to ignore, because we know the number of tokens |
| + } |
| + |
| + FieldQueryNode newFieldNode = new FieldQueryNode(field, term, -1, -1); |
| + |
| + if (this.positionIncrementsEnabled) { |
| + position += positionIncrement; |
| + newFieldNode.setPositionIncrement(position); |
| + |
| + } else { |
| + newFieldNode.setPositionIncrement(i); |
| + } |
| + |
| + pq.add(newFieldNode); |
| + |
| + } |
| + |
| + return pq; |
| + |
| + } |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/ParametricRangeQueryNodeProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/ParametricRangeQueryNodeProcessor.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/ParametricRangeQueryNodeProcessor.java (revision 0) |
| @@ -0,0 +1,187 @@ |
| +package org.apache.lucene.queryParser.original.processors; |
| + |
| +/** |
| + * 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 java.text.Collator; |
| +import java.text.DateFormat; |
| +import java.util.Calendar; |
| +import java.util.Date; |
| +import java.util.List; |
| +import java.util.Locale; |
| + |
| +import org.apache.lucene.document.DateField; |
| +import org.apache.lucene.document.DateTools; |
| +import org.apache.lucene.document.DateTools.Resolution; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.config.FieldConfig; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.nodes.ParametricQueryNode; |
| +import org.apache.lucene.queryParser.nodes.ParametricRangeQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.ParametricQueryNode.CompareOperator; |
| +import org.apache.lucene.queryParser.original.config.ConstantScoreRewriteAttribute; |
| +import org.apache.lucene.queryParser.original.config.DateResolutionAttribute; |
| +import org.apache.lucene.queryParser.original.config.LocaleAttribute; |
| +import org.apache.lucene.queryParser.original.config.RangeCollatorAttribute; |
| +import org.apache.lucene.queryParser.original.nodes.RangeQueryNode; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| + |
| +/** |
| + * This processor converts {@link ParametricRangeQueryNode} objects to |
| + * {@link RangeQueryNode} objects. It reads the lower and upper bounds value |
| + * from the {@link ParametricRangeQueryNode} object and try to parse their |
| + * values using a {@link DateFormat}. If the values cannot be parsed to a date |
| + * value, it will only create the {@link RangeQueryNode} using the non-parsed |
| + * values. <br/> |
| + * <br/> |
| + * If a {@link LocaleAttribute} is defined in the {@link QueryConfigHandler} it |
| + * will be used to parse the date, otherwise {@link Locale#getDefault()} will be |
| + * used. <br/> |
| + * <br/> |
| + * If a {@link DateResolutionAttribute} is defined and the {@link Resolution} is |
| + * not <code>null</code> it will also be used to parse the date value. <br/> |
| + * <br/> |
| + * This processor will also try to retrieve a {@link RangeCollatorAttribute} |
| + * from the {@link QueryConfigHandler}. If a {@link RangeCollatorAttribute} is |
| + * found and the {@link Collator} is not <code>null</code>, it's set on the |
| + * {@link RangeQueryNode}. <br/> |
| + * |
| + * @see RangeCollatorAttribute |
| + * @see DateResolutionAttribute |
| + * @see LocaleAttribute |
| + * @see RangeQueryNode |
| + * @see ParametricRangeQueryNode |
| + */ |
| +public class ParametricRangeQueryNodeProcessor extends QueryNodeProcessorImpl { |
| + |
| + public ParametricRangeQueryNodeProcessor() { |
| + // empty constructor |
| + } |
| + |
| + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + if (node instanceof ParametricRangeQueryNode) { |
| + ParametricRangeQueryNode parametricRangeNode = (ParametricRangeQueryNode) node; |
| + ParametricQueryNode upper = parametricRangeNode.getUpperBound(); |
| + ParametricQueryNode lower = parametricRangeNode.getLowerBound(); |
| + Locale locale = Locale.getDefault(); |
| + Collator collator = null; |
| + DateTools.Resolution dateRes = null; |
| + boolean inclusive = false; |
| + |
| + if (!getQueryConfigHandler().hasAttribute( |
| + ConstantScoreRewriteAttribute.class)) { |
| + throw new IllegalArgumentException( |
| + "ConstantScoreRewriteAttribute should be set on the QueryConfigHandler"); |
| + } |
| + |
| + boolean constantScoreRewrite = ((ConstantScoreRewriteAttribute) getQueryConfigHandler() |
| + .getAttribute(ConstantScoreRewriteAttribute.class)) |
| + .isConstantScoreRewrite(); |
| + |
| + if (getQueryConfigHandler().hasAttribute(RangeCollatorAttribute.class)) { |
| + collator = ((RangeCollatorAttribute) getQueryConfigHandler() |
| + .getAttribute(RangeCollatorAttribute.class)).getRangeCollator(); |
| + } |
| + |
| + if (getQueryConfigHandler().hasAttribute(LocaleAttribute.class)) { |
| + locale = ((LocaleAttribute) getQueryConfigHandler().getAttribute( |
| + LocaleAttribute.class)).getLocale(); |
| + } |
| + |
| + FieldConfig fieldConfig = getQueryConfigHandler().getFieldConfig( |
| + parametricRangeNode.getField()); |
| + |
| + if (fieldConfig != null) { |
| + |
| + if (fieldConfig.hasAttribute(DateResolutionAttribute.class)) { |
| + dateRes = ((DateResolutionAttribute) fieldConfig |
| + .getAttribute(DateResolutionAttribute.class)).getDateResolution(); |
| + } |
| + |
| + } |
| + |
| + if (upper.getOperator() == CompareOperator.LE) { |
| + inclusive = true; |
| + |
| + } else if (lower.getOperator() == CompareOperator.GE) { |
| + inclusive = true; |
| + } |
| + |
| + String part1 = lower.getTextAsString(); |
| + String part2 = upper.getTextAsString(); |
| + |
| + try { |
| + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, Locale |
| + .getDefault()); |
| + df.setLenient(true); |
| + Date d1 = df.parse(part1); |
| + Date d2 = df.parse(part2); |
| + if (inclusive) { |
| + // The user can only specify the date, not the time, so make sure |
| + // the time is set to the latest possible time of that date to really |
| + // include all documents: |
| + Calendar cal = Calendar.getInstance(locale); |
| + cal.setTime(d2); |
| + cal.set(Calendar.HOUR_OF_DAY, 23); |
| + cal.set(Calendar.MINUTE, 59); |
| + cal.set(Calendar.SECOND, 59); |
| + cal.set(Calendar.MILLISECOND, 999); |
| + d2 = cal.getTime(); |
| + } |
| + |
| + if (dateRes == null) { |
| + // no default or field specific date resolution has been set, |
| + // use deprecated DateField to maintain compatibilty with |
| + // pre-1.9 Lucene versions. |
| + part1 = DateField.dateToString(d1); |
| + part2 = DateField.dateToString(d2); |
| + |
| + } else { |
| + part1 = DateTools.dateToString(d1, dateRes); |
| + part2 = DateTools.dateToString(d2, dateRes); |
| + } |
| + } catch (Exception e) { |
| + // do nothing |
| + } |
| + |
| + lower.setText(part1); |
| + upper.setText(part2); |
| + |
| + return new RangeQueryNode(lower, upper, collator, constantScoreRewrite); |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/DefaultPhraseSlopQueryNodeProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/DefaultPhraseSlopQueryNodeProcessor.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/DefaultPhraseSlopQueryNodeProcessor.java (revision 0) |
| @@ -0,0 +1,118 @@ |
| +package org.apache.lucene.queryParser.original.processors; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.SlopQueryNode; |
| +import org.apache.lucene.queryParser.nodes.TokenizedPhraseQueryNode; |
| +import org.apache.lucene.queryParser.original.QueryParserWrapper; |
| +import org.apache.lucene.queryParser.original.config.DefaultPhraseSlopAttribute; |
| +import org.apache.lucene.queryParser.original.nodes.MultiPhraseQueryNode; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| + |
| +/** |
| + * This processor verifies if the attribute {@link DefaultPhraseSlopAttribute} |
| + * is defined in the {@link QueryConfigHandler}. If it is, it looks for every |
| + * {@link TokenizedPhraseQueryNode} and {@link MultiPhraseQueryNode} that does |
| + * not have any {@link SlopQueryNode} applied to it and creates an |
| + * {@link SlopQueryNode} and apply to it. The new {@link SlopQueryNode} has the |
| + * same slop value defined in the attribute. <br/> |
| + * |
| + * @see SlopQueryNode |
| + * @see DefaultPhraseSlopAttribute |
| + * @see QueryParserWrapper#setPhraseSlop(int) |
| + */ |
| +@SuppressWarnings("deprecation") |
| +public class DefaultPhraseSlopQueryNodeProcessor extends QueryNodeProcessorImpl { |
| + |
| + private boolean processChildren = true; |
| + |
| + private int defaultPhraseSlop; |
| + |
| + public DefaultPhraseSlopQueryNodeProcessor() { |
| + // empty constructor |
| + } |
| + |
| + public QueryNode process(QueryNode queryTree) throws QueryNodeException { |
| + QueryConfigHandler queryConfig = getQueryConfigHandler(); |
| + |
| + if (queryConfig != null) { |
| + |
| + if (queryConfig.hasAttribute(DefaultPhraseSlopAttribute.class)) { |
| + this.defaultPhraseSlop = ((DefaultPhraseSlopAttribute) queryConfig |
| + .getAttribute(DefaultPhraseSlopAttribute.class)) |
| + .getDefaultPhraseSlop(); |
| + |
| + return super.process(queryTree); |
| + |
| + } |
| + |
| + } |
| + |
| + return queryTree; |
| + |
| + } |
| + |
| + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + if (node instanceof TokenizedPhraseQueryNode |
| + || node instanceof MultiPhraseQueryNode) { |
| + |
| + return new SlopQueryNode(node, this.defaultPhraseSlop); |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + if (node instanceof SlopQueryNode) { |
| + this.processChildren = false; |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected void processChildren(QueryNode queryTree) throws QueryNodeException { |
| + |
| + if (this.processChildren) { |
| + super.processChildren(queryTree); |
| + |
| + } else { |
| + this.processChildren = true; |
| + } |
| + |
| + } |
| + |
| + @Override |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/package.html |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/package.html (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/package.html (revision 0) |
| @@ -0,0 +1,33 @@ |
| +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> |
| +<!-- |
| + 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. |
| +--> |
| +<html> |
| +<head> |
| + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| +</head> |
| +<body> |
| + |
| +<h2>Lucene Query Node Processors</h2> |
| +<p> |
| +The package org.apache.lucene.queryParser.original.processors contains every processor needed to assembly a pipeline |
| +that modifies the query node tree according to the actual Lucene queries. |
| +</p> |
| +<p> |
| +This processors are already assembled correctly in the LuceneQueryNodeProcessorPipeline. |
| +</p> |
| +</body> |
| +</html> |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/GroupQueryNodeProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/GroupQueryNodeProcessor.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/GroupQueryNodeProcessor.java (revision 0) |
| @@ -0,0 +1,220 @@ |
| +package org.apache.lucene.queryParser.original.processors; |
| + |
| +/** |
| + * 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 java.util.ArrayList; |
| +import java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.nodes.AndQueryNode; |
| +import org.apache.lucene.queryParser.nodes.BooleanQueryNode; |
| +import org.apache.lucene.queryParser.nodes.GroupQueryNode; |
| +import org.apache.lucene.queryParser.nodes.ModifierQueryNode; |
| +import org.apache.lucene.queryParser.nodes.OrQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.ModifierQueryNode.Modifier; |
| +import org.apache.lucene.queryParser.original.QueryParserWrapper; |
| +import org.apache.lucene.queryParser.original.config.DefaultOperatorAttribute; |
| +import org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler.Operator; |
| +import org.apache.lucene.queryParser.original.nodes.BooleanModifierNode; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessor; |
| + |
| +/** |
| + * The {@link org.apache.lucene.queryParser.original.parser.TextParser} |
| + * generates query node trees that consider the boolean operator precedence, but |
| + * Lucene current syntax does not support boolean precedence, so this processor |
| + * remove all the precedence and apply the equivalent modifier according to the |
| + * boolean operation defined on an specific query node. <br/> |
| + * <br/> |
| + * If there is a {@link GroupQueryNode} in the query node tree, the query node |
| + * tree is not merged with the one above it. |
| + * |
| + * Example: TODO: describe a good example to show how this processor works |
| + * |
| + * @see QueryParserWrapper |
| + */ |
| +@SuppressWarnings("deprecation") |
| +public class GroupQueryNodeProcessor implements QueryNodeProcessor { |
| + |
| + private ArrayList<QueryNode> queryNodeList; |
| + |
| + private boolean latestNodeVerified; |
| + |
| + private QueryConfigHandler queryConfig; |
| + |
| + private Boolean usingAnd = false; |
| + |
| + public GroupQueryNodeProcessor() { |
| + // empty constructor |
| + } |
| + |
| + public QueryNode process(QueryNode queryTree) throws QueryNodeException { |
| + |
| + if (!getQueryConfigHandler().hasAttribute(DefaultOperatorAttribute.class)) { |
| + throw new IllegalArgumentException( |
| + "DefaultOperatorAttribute should be set on the QueryConfigHandler"); |
| + } |
| + |
| + usingAnd = Operator.AND == ((DefaultOperatorAttribute) getQueryConfigHandler() |
| + .getAttribute(DefaultOperatorAttribute.class)).getOperator(); |
| + |
| + if (queryTree instanceof GroupQueryNode) { |
| + queryTree = ((GroupQueryNode) queryTree).getChild(); |
| + } |
| + |
| + this.queryNodeList = new ArrayList<QueryNode>(); |
| + this.latestNodeVerified = false; |
| + readTree(queryTree); |
| + |
| + List<QueryNode> actualQueryNodeList = this.queryNodeList; |
| + |
| + for (int i = 0; i < actualQueryNodeList.size(); i++) { |
| + QueryNode node = actualQueryNodeList.get(i); |
| + |
| + if (node instanceof GroupQueryNode) { |
| + actualQueryNodeList.set(i, process(node)); |
| + } |
| + |
| + } |
| + |
| + this.usingAnd = false; |
| + |
| + if (queryTree instanceof BooleanQueryNode) { |
| + queryTree.set(actualQueryNodeList); |
| + |
| + return queryTree; |
| + |
| + } else { |
| + return new BooleanQueryNode(actualQueryNodeList); |
| + } |
| + |
| + } |
| + |
| + /** |
| + * @param node |
| + * @return |
| + */ |
| + private QueryNode applyModifier(QueryNode node, QueryNode parent) { |
| + |
| + if (this.usingAnd) { |
| + |
| + if (parent instanceof OrQueryNode) { |
| + |
| + if (node instanceof ModifierQueryNode) { |
| + |
| + ModifierQueryNode modNode = (ModifierQueryNode) node; |
| + |
| + if (modNode.getModifier() == Modifier.MOD_REQ) { |
| + return modNode.getChild(); |
| + } |
| + |
| + } |
| + |
| + } else { |
| + |
| + if (node instanceof ModifierQueryNode) { |
| + |
| + ModifierQueryNode modNode = (ModifierQueryNode) node; |
| + |
| + if (modNode.getModifier() == Modifier.MOD_NONE) { |
| + return new BooleanModifierNode(modNode.getChild(), Modifier.MOD_REQ); |
| + } |
| + |
| + } else { |
| + return new BooleanModifierNode(node, Modifier.MOD_REQ); |
| + } |
| + |
| + } |
| + |
| + } else { |
| + |
| + if (node.getParent() instanceof AndQueryNode) { |
| + |
| + if (node instanceof ModifierQueryNode) { |
| + |
| + ModifierQueryNode modNode = (ModifierQueryNode) node; |
| + |
| + if (modNode.getModifier() == Modifier.MOD_NONE) { |
| + return new BooleanModifierNode(modNode.getChild(), Modifier.MOD_REQ); |
| + } |
| + |
| + } else { |
| + return new BooleanModifierNode(node, Modifier.MOD_REQ); |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + private void readTree(QueryNode node) { |
| + |
| + if (node instanceof BooleanQueryNode) { |
| + List<QueryNode> children = node.getChildren(); |
| + |
| + if (children != null && children.size() > 0) { |
| + |
| + for (int i = 0; i < children.size() - 1; i++) { |
| + readTree(children.get(i)); |
| + } |
| + |
| + processNode(node); |
| + readTree(children.get(children.size() - 1)); |
| + |
| + } else { |
| + processNode(node); |
| + } |
| + |
| + } else { |
| + processNode(node); |
| + } |
| + |
| + } |
| + |
| + private void processNode(QueryNode node) { |
| + |
| + if (node instanceof AndQueryNode || node instanceof OrQueryNode) { |
| + |
| + if (!this.latestNodeVerified && !this.queryNodeList.isEmpty()) { |
| + this.queryNodeList.add(applyModifier(this.queryNodeList |
| + .remove(this.queryNodeList.size() - 1), node)); |
| + this.latestNodeVerified = true; |
| + |
| + } |
| + |
| + } else if (!(node instanceof BooleanQueryNode)) { |
| + this.queryNodeList.add(applyModifier(node, node.getParent())); |
| + this.latestNodeVerified = false; |
| + |
| + } |
| + |
| + } |
| + |
| + public QueryConfigHandler getQueryConfigHandler() { |
| + return this.queryConfig; |
| + } |
| + |
| + public void setQueryConfigHandler(QueryConfigHandler queryConfigHandler) { |
| + this.queryConfig = queryConfigHandler; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/BooleanSingleChildOptimizationQueryNodeProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/BooleanSingleChildOptimizationQueryNodeProcessor.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/BooleanSingleChildOptimizationQueryNodeProcessor.java (revision 0) |
| @@ -0,0 +1,88 @@ |
| +package org.apache.lucene.queryParser.original.processors; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.nodes.BooleanQueryNode; |
| +import org.apache.lucene.queryParser.nodes.ModifierQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.ModifierQueryNode.Modifier; |
| +import org.apache.lucene.queryParser.original.nodes.BooleanModifierNode; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| + |
| +/** |
| + * This processor removes every {@link BooleanQueryNode} that contains only one |
| + * child and returns this child. If this child is {@link ModifierQueryNode} that |
| + * was defined by the user. A modifier is not defined by the user when it's a |
| + * {@link BooleanModifierNode} <br/> |
| + * |
| + * @see ModifierQueryNode |
| + */ |
| +public class BooleanSingleChildOptimizationQueryNodeProcessor extends |
| + QueryNodeProcessorImpl { |
| + |
| + public BooleanSingleChildOptimizationQueryNodeProcessor() { |
| + // empty constructor |
| + } |
| + |
| + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + if (node instanceof BooleanQueryNode) { |
| + List<QueryNode> children = node.getChildren(); |
| + |
| + if (children != null && children.size() == 1) { |
| + QueryNode child = children.get(0); |
| + |
| + if (child instanceof ModifierQueryNode) { |
| + ModifierQueryNode modNode = (ModifierQueryNode) child; |
| + |
| + if (modNode instanceof BooleanModifierNode |
| + || modNode.getModifier() == Modifier.MOD_NONE) { |
| + |
| + return child; |
| + |
| + } |
| + |
| + } else { |
| + return child; |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/MultiFieldQueryNodeProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/MultiFieldQueryNodeProcessor.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/MultiFieldQueryNodeProcessor.java (revision 0) |
| @@ -0,0 +1,134 @@ |
| +package org.apache.lucene.queryParser.original.processors; |
| + |
| +/** |
| + * 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 java.util.LinkedList; |
| +import java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.nodes.BooleanQueryNode; |
| +import org.apache.lucene.queryParser.nodes.FieldableNode; |
| +import org.apache.lucene.queryParser.nodes.GroupQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.MultiFieldQueryParserWrapper; |
| +import org.apache.lucene.queryParser.original.config.MultiFieldAttribute; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| + |
| +/** |
| + * This processor is used to expand terms so the query looks for the same term |
| + * in different fields. It also boosts a query based on its field. <br/> |
| + * <br/> |
| + * This processor looks for every {@link FieldableNode} contained in the query |
| + * node tree. If a {@link FieldableNode} is found, it checks if there is a |
| + * {@link MultiFieldAttribute} defined in the {@link QueryConfigHandler}. If |
| + * there is, the {@link FieldableNode} is cloned N times and the clones are |
| + * added to a {@link BooleanQueryNode} together with the original node. N is |
| + * defined by the number of fields that it will be expanded to. The |
| + * {@link BooleanQueryNode} is returned. <br/> |
| + * |
| + * @see MultiFieldAttribute |
| + * @see MultiFieldQueryParserWrapper |
| + */ |
| +@SuppressWarnings("deprecation") |
| +public class MultiFieldQueryNodeProcessor extends QueryNodeProcessorImpl { |
| + |
| + private boolean processChildren = true; |
| + |
| + public MultiFieldQueryNodeProcessor() { |
| + // empty constructor |
| + } |
| + |
| + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected void processChildren(QueryNode queryTree) throws QueryNodeException { |
| + |
| + if (this.processChildren) { |
| + super.processChildren(queryTree); |
| + |
| + } else { |
| + this.processChildren = true; |
| + } |
| + |
| + } |
| + |
| + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + if (node instanceof FieldableNode) { |
| + this.processChildren = false; |
| + FieldableNode fieldNode = (FieldableNode) node; |
| + |
| + if (fieldNode.getField() == null) { |
| + |
| + if (!getQueryConfigHandler().hasAttribute(MultiFieldAttribute.class)) { |
| + throw new IllegalArgumentException( |
| + "MultiFieldAttribute should be set on the QueryConfigHandler"); |
| + } |
| + |
| + CharSequence[] fields = ((MultiFieldAttribute) getQueryConfigHandler() |
| + .getAttribute(MultiFieldAttribute.class)).getFields(); |
| + |
| + if (fields != null && fields.length > 0) { |
| + fieldNode.setField(fields[0]); |
| + |
| + if (fields.length == 1) { |
| + return fieldNode; |
| + |
| + } else { |
| + LinkedList<QueryNode> children = new LinkedList<QueryNode>(); |
| + children.add(fieldNode); |
| + |
| + for (int i = 1; i < fields.length; i++) { |
| + try { |
| + fieldNode = (FieldableNode) fieldNode.cloneTree(); |
| + fieldNode.setField(fields[i]); |
| + |
| + children.add(fieldNode); |
| + |
| + } catch (CloneNotSupportedException e) { |
| + // should never happen |
| + } |
| + |
| + } |
| + |
| + return new GroupQueryNode(new BooleanQueryNode(children)); |
| + |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/PrefixWildcardQueryNodeProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/PrefixWildcardQueryNodeProcessor.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/PrefixWildcardQueryNodeProcessor.java (revision 0) |
| @@ -0,0 +1,72 @@ |
| +package org.apache.lucene.queryParser.original.processors; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.nodes.PrefixWildcardQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.parser.TextParser; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| +import org.apache.lucene.search.PrefixQuery; |
| + |
| +/** |
| + * The {@link TextParser} creates {@link PrefixWildcardQueryNode} nodes which |
| + * have values containing the prefixed wildcard. However, Lucene |
| + * {@link PrefixQuery} cannot contain the prefixed wildcard. So, this processor |
| + * basically removed the prefixed wildcard from the |
| + * {@link PrefixWildcardQueryNode} value. <br/> |
| + * |
| + * @see PrefixQuery |
| + * @see PrefixWildcardQueryNode |
| + */ |
| +public class PrefixWildcardQueryNodeProcessor extends QueryNodeProcessorImpl { |
| + |
| + public PrefixWildcardQueryNodeProcessor() { |
| + // empty constructor |
| + } |
| + |
| + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + if (node instanceof PrefixWildcardQueryNode) { |
| + PrefixWildcardQueryNode prefixWildcardNode = (PrefixWildcardQueryNode) node; |
| + CharSequence text = prefixWildcardNode.getText(); |
| + |
| + prefixWildcardNode.setText(text.subSequence(0, text.length() - 1)); |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/PositionIncrementsAttribute.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/PositionIncrementsAttribute.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/PositionIncrementsAttribute.java (revision 0) |
| @@ -0,0 +1,80 @@ |
| +package org.apache.lucene.queryParser.original.config; |
| + |
| +/** |
| + * 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.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.processors.AnalyzerQueryNodeProcessor; |
| +import org.apache.lucene.util.Attribute; |
| + |
| +/** |
| + * This attribute is used by {@link AnalyzerQueryNodeProcessor} processor and |
| + * must be defined in the {@link QueryConfigHandler}. This attribute tells the |
| + * processor if the position increment is enabled. <br/> |
| + * |
| + * @see org.apache.lucene.queryParser.original.QueryParserWrapper#setEnablePositionIncrements(boolean) |
| + */ |
| +public class PositionIncrementsAttribute extends Attribute { |
| + |
| + private static final long serialVersionUID = -2804763012793049527L; |
| + |
| + private boolean positionIncrementsEnabled = true; |
| + |
| + public PositionIncrementsAttribute() { |
| + // empty constructor |
| + } |
| + |
| + void setPositionIncrementsEnabled(boolean positionIncrementsEnabled) { |
| + this.positionIncrementsEnabled = positionIncrementsEnabled; |
| + } |
| + |
| + public boolean isPositionIncrementsEnabled() { |
| + return this.positionIncrementsEnabled; |
| + } |
| + |
| + public void clear() { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public void copyTo(Attribute target) { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public boolean equals(Object other) { |
| + |
| + if (other instanceof PositionIncrementsAttribute |
| + && other != null |
| + && ((PositionIncrementsAttribute) other).positionIncrementsEnabled == this.positionIncrementsEnabled) { |
| + |
| + return true; |
| + |
| + } |
| + |
| + return false; |
| + |
| + } |
| + |
| + public int hashCode() { |
| + return this.positionIncrementsEnabled ? -1 : Integer.MAX_VALUE; |
| + } |
| + |
| + public String toString() { |
| + return "<positionIncrements positionIncrementsEnabled=" |
| + + this.positionIncrementsEnabled + "/>"; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AllowLeadingWildcardAttribute.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AllowLeadingWildcardAttribute.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AllowLeadingWildcardAttribute.java (revision 0) |
| @@ -0,0 +1,79 @@ |
| +package org.apache.lucene.queryParser.original.config; |
| + |
| +/** |
| + * 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.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.processors.AllowLeadingWildcardProcessor; |
| +import org.apache.lucene.util.Attribute; |
| + |
| +/** |
| + * This attribute is used by {@link AllowLeadingWildcardProcessor} processor and |
| + * must be defined in the {@link QueryConfigHandler}. It basically tells the |
| + * processor if it should allow leading wildcard. <br/> |
| + * |
| + * @see org.apache.lucene.queryParser.original.QueryParserWrapper#setAllowLeadingWildcard(boolean) |
| + */ |
| +public class AllowLeadingWildcardAttribute extends Attribute { |
| + |
| + private static final long serialVersionUID = -2804763012723049527L; |
| + |
| + private boolean allowLeadingWildcard = true; |
| + |
| + public AllowLeadingWildcardAttribute() { |
| + // empty constructor |
| + } |
| + |
| + public void setAllowLeadingWildcard(boolean allowLeadingWildcard) { |
| + this.allowLeadingWildcard = allowLeadingWildcard; |
| + } |
| + |
| + public boolean isAllowLeadingWildcard() { |
| + return this.allowLeadingWildcard; |
| + } |
| + |
| + public void clear() { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public void copyTo(Attribute target) { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public boolean equals(Object other) { |
| + |
| + if (other instanceof AllowLeadingWildcardAttribute |
| + && ((AllowLeadingWildcardAttribute) other).allowLeadingWildcard == this.allowLeadingWildcard) { |
| + |
| + return true; |
| + |
| + } |
| + |
| + return false; |
| + |
| + } |
| + |
| + public int hashCode() { |
| + return this.allowLeadingWildcard ? -1 : Integer.MAX_VALUE; |
| + } |
| + |
| + public String toString() { |
| + return "<allowLeadingWildcard allowLeadingWildcard=" |
| + + this.allowLeadingWildcard + "/>"; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DateResolutionAttribute.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DateResolutionAttribute.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DateResolutionAttribute.java (revision 0) |
| @@ -0,0 +1,86 @@ |
| +package org.apache.lucene.queryParser.original.config; |
| + |
| +/** |
| + * 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.document.DateTools; |
| +import org.apache.lucene.document.DateTools.Resolution; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor; |
| +import org.apache.lucene.util.Attribute; |
| + |
| +/** |
| + * This attribute is used by {@link ParametricRangeQueryNodeProcessor} processor |
| + * and must be defined in the {@link QueryConfigHandler}. This attribute tells |
| + * the processor which {@link Resolution} to use when parsing the date. <br/> |
| + * |
| + * @see org.apache.lucene.queryParser.original.QueryParserWrapper#setDateResolution(DateTools.Resolution) |
| + */ |
| +public class DateResolutionAttribute extends Attribute { |
| + |
| + private static final long serialVersionUID = -6804360312723049526L; |
| + |
| + private DateTools.Resolution dateResolution; |
| + |
| + public DateResolutionAttribute() { |
| + // empty constructor |
| + } |
| + |
| + void setDateResolution(DateTools.Resolution dateResolution) { |
| + this.dateResolution = dateResolution; |
| + } |
| + |
| + public DateTools.Resolution getDateResolution() { |
| + return this.dateResolution; |
| + } |
| + |
| + public void clear() { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public void copyTo(Attribute target) { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public boolean equals(Object other) { |
| + |
| + if (other instanceof DateResolutionAttribute) { |
| + DateResolutionAttribute dateResAttr = (DateResolutionAttribute) other; |
| + |
| + if (dateResAttr.getDateResolution() == getDateResolution() |
| + || dateResAttr.getDateResolution().equals(getDateResolution())) { |
| + |
| + return true; |
| + |
| + } |
| + |
| + } |
| + |
| + return false; |
| + |
| + } |
| + |
| + public int hashCode() { |
| + return (this.dateResolution == null) ? 0 : this.dateResolution.hashCode(); |
| + } |
| + |
| + public String toString() { |
| + return "<dateResolutionAttribute dateResolution='" + this.dateResolution |
| + + "'/>"; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiFieldAttribute.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiFieldAttribute.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiFieldAttribute.java (revision 0) |
| @@ -0,0 +1,80 @@ |
| +package org.apache.lucene.queryParser.original.config; |
| + |
| +/** |
| + * 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 java.util.Arrays; |
| + |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.processors.MultiFieldQueryNodeProcessor; |
| +import org.apache.lucene.util.Attribute; |
| + |
| +/** |
| + * This attribute is used by {@link MultiFieldQueryNodeProcessor} processor and |
| + * must be defined in the {@link QueryConfigHandler}. This attribute tells the |
| + * processor to which fields the terms in the query should be expanded. <br/> |
| + * |
| + * @see org.apache.lucene.queryParser.original.MultiFieldQueryParserWrapper |
| + */ |
| +public class MultiFieldAttribute extends Attribute { |
| + |
| + private static final long serialVersionUID = -6809760312720049526L; |
| + |
| + private CharSequence[] fields; |
| + |
| + public MultiFieldAttribute() { |
| + // empty constructor |
| + } |
| + |
| + void setFields(CharSequence[] fields) { |
| + this.fields = fields; |
| + } |
| + |
| + public CharSequence[] getFields() { |
| + return this.fields; |
| + } |
| + |
| + public void clear() { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public void copyTo(Attribute target) { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public boolean equals(Object other) { |
| + |
| + if (other instanceof MultiFieldAttribute) { |
| + MultiFieldAttribute fieldsAttr = (MultiFieldAttribute) other; |
| + |
| + return Arrays.equals(this.fields, fieldsAttr.fields); |
| + |
| + } |
| + |
| + return false; |
| + |
| + } |
| + |
| + public int hashCode() { |
| + return Arrays.hashCode(this.fields); |
| + } |
| + |
| + public String toString() { |
| + return "<fieldsAttribute fields=" + Arrays.toString(this.fields) + "/>"; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/package.html |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/package.html (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/package.html (revision 0) |
| @@ -0,0 +1,34 @@ |
| +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> |
| +<!-- |
| + 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. |
| +--> |
| +<html> |
| +<head> |
| + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| +</head> |
| +<body> |
| + |
| +<h2>Original Lucene Query Configuration</h2> |
| +<p> |
| +The package org.apache.lucene.queryParser.original.config contains the Lucene |
| +query configuration handler and all the attributes used by it. This configuration |
| +handler reproduces almost everything that could be set on the old query parser. |
| +</p> |
| +<p> |
| +LuceneQueryConfigHandler is the class that should be used to configure the LuceneQueryNodeProcessorPipeline. |
| +</p> |
| +</body> |
| +</html> |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldBoostConfigListener.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldBoostConfigListener.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldBoostConfigListener.java (revision 0) |
| @@ -0,0 +1,77 @@ |
| +package org.apache.lucene.queryParser.original.config; |
| + |
| +/** |
| + * 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 java.util.HashMap; |
| +import java.util.Map; |
| + |
| +import org.apache.lucene.queryParser.config.FieldConfig; |
| +import org.apache.lucene.queryParser.config.FieldConfigListener; |
| + |
| +/** |
| + * This listener listens for every field configuration request and assign a |
| + * {@link BoostAttribute} to the equivalent {@link FieldConfig} based on a |
| + * defined map: fieldName -> boostValue |
| + * |
| + * @see BoostAttribute |
| + * @see Map |
| + * @see FieldConfig |
| + * @see FieldConfigListener |
| + */ |
| +public class FieldBoostConfigListener extends HashMap<String, Float> implements |
| + FieldConfigListener { |
| + |
| + private static final long serialVersionUID = -5929802948798314067L; |
| + |
| + public FieldBoostConfigListener() { |
| + // empty constructor |
| + } |
| + |
| + public FieldBoostConfigListener( |
| + Map<? extends String, ? extends Float> boostMap) { |
| + super(boostMap); |
| + } |
| + |
| + public void getQueryConfig(FieldConfig fieldConfig) { |
| + CharSequence fieldName = fieldConfig.getFieldName(); |
| + |
| + if (fieldName != null) { |
| + |
| + Float boost = get(fieldName.toString()); |
| + BoostAttribute boostAttr; |
| + |
| + if (boost != null) { |
| + |
| + if (fieldConfig.hasAttribute(BoostAttribute.class)) { |
| + boostAttr = (BoostAttribute) fieldConfig |
| + .getAttribute(BoostAttribute.class); |
| + |
| + } else { |
| + boostAttr = (BoostAttribute) fieldConfig |
| + .addAttribute(BoostAttribute.class); |
| + } |
| + |
| + boostAttr.setBoost(boost.floatValue()); |
| + |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AnalyzerAttribute.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AnalyzerAttribute.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AnalyzerAttribute.java (revision 0) |
| @@ -0,0 +1,86 @@ |
| +package org.apache.lucene.queryParser.original.config; |
| + |
| +/** |
| + * 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.analysis.Analyzer; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.processors.AnalyzerQueryNodeProcessor; |
| +import org.apache.lucene.util.Attribute; |
| + |
| +/** |
| + * This attribute is used by {@link AnalyzerQueryNodeProcessor} processor and |
| + * must be defined in the {@link QueryConfigHandler}. It provides to this |
| + * processor the {@link Analyzer}, if there is one, which will be used to |
| + * analyze the query terms. <br/> |
| + * |
| + * @see org.apache.lucene.queryParser.original.QueryParserWrapper#getAnalyzer() |
| + */ |
| +public class AnalyzerAttribute extends Attribute { |
| + |
| + private static final long serialVersionUID = -6804760312723049526L; |
| + |
| + private Analyzer analyzer; |
| + |
| + public AnalyzerAttribute() { |
| + // empty constructor |
| + } |
| + |
| + void setAnalyzer(Analyzer analyzer) { |
| + this.analyzer = analyzer; |
| + } |
| + |
| + public Analyzer getAnalyzer() { |
| + return this.analyzer; |
| + } |
| + |
| + public void clear() { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public void copyTo(Attribute target) { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public boolean equals(Object other) { |
| + |
| + if (other instanceof AnalyzerAttribute) { |
| + AnalyzerAttribute analyzerAttr = (AnalyzerAttribute) other; |
| + |
| + if (analyzerAttr.analyzer == this.analyzer |
| + || (this.analyzer != null && analyzerAttr.analyzer != null && this.analyzer |
| + .equals(analyzerAttr.analyzer))) { |
| + |
| + return true; |
| + |
| + } |
| + |
| + } |
| + |
| + return false; |
| + |
| + } |
| + |
| + public int hashCode() { |
| + return (this.analyzer == null) ? 0 : this.analyzer.hashCode(); |
| + } |
| + |
| + public String toString() { |
| + return "<analyzerAttribute analyzer='" + this.analyzer + "'/>"; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LuceneQueryConfigHandler.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LuceneQueryConfigHandler.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LuceneQueryConfigHandler.java (revision 0) |
| @@ -0,0 +1,425 @@ |
| +package org.apache.lucene.queryParser.original.config; |
| + |
| +/** |
| + * 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 java.text.Collator; |
| +import java.util.HashMap; |
| +import java.util.Locale; |
| +import java.util.Map; |
| +import java.util.TooManyListenersException; |
| + |
| +import org.apache.lucene.analysis.Analyzer; |
| +import org.apache.lucene.document.DateTools; |
| +import org.apache.lucene.queryParser.QueryParser; |
| +import org.apache.lucene.queryParser.config.DefaultQueryConfigHandler; |
| +import org.apache.lucene.queryParser.config.FieldConfig; |
| +import org.apache.lucene.queryParser.config.FieldConfigListener; |
| +import org.apache.lucene.queryParser.original.nodes.RangeQueryNode; |
| +import org.apache.lucene.queryParser.original.processors.LuceneQueryNodeProcessorPipeline; |
| +import org.apache.lucene.search.FuzzyQuery; |
| + |
| +/** |
| + * This query configuration handler is used for almost every processor defined |
| + * in the {@link LuceneQueryNodeProcessorPipeline} processor pipeline. It holds |
| + * attributes that reproduces the configuration that could be set on the old |
| + * query parser: {@link QueryParser}. <br/> |
| + * |
| + * @see LuceneQueryNodeProcessorPipeline |
| + * @see org.apache.lucene.queryParser.original.QueryParserWrapper |
| + */ |
| +public class LuceneQueryConfigHandler extends DefaultQueryConfigHandler |
| + implements FieldConfigListener { |
| + |
| + public static enum Operator { |
| + AND, OR; |
| + } |
| + |
| + private Map<CharSequence, Float> boosts; |
| + |
| + private LowercaseExpandedTermsAttribute lowercaseExpandedTermsAttr; |
| + |
| + private DefaultOperatorAttribute defaultOperatorAttribute; |
| + |
| + private AllowLeadingWildcardAttribute allowLeadingWildcardAttribute; |
| + |
| + private DefaultPhraseSlopAttribute defaultPhraseSlopAttribute; |
| + |
| + private PositionIncrementsAttribute positionIncrementsAttribute; |
| + |
| + private ConstantScoreRewriteAttribute constantScoreRewriteAttribute; |
| + |
| + private RangeCollatorAttribute rangeCollatorAttribute; |
| + |
| + private DateTools.Resolution defaultDateResolution; |
| + |
| + private AnalyzerAttribute analyzerAttr; |
| + |
| + private LocaleAttribute localeAttribute; |
| + |
| + private FuzzyAttribute fuzzyAttribute; |
| + |
| + private HashMap<CharSequence, DateTools.Resolution> dateResolutions; |
| + |
| + public LuceneQueryConfigHandler() { |
| + addFieldConfigListener(this); |
| + |
| + // setting the old QueryParser default values |
| + Collator collator = null; |
| + Locale locale = Locale.getDefault(); |
| + int defaultPhraseSlop = 0; |
| + boolean lowercaseExpandedTerms = true; |
| + boolean allowLeadingWildcard = true; |
| + boolean constantScoreRewrite = true; |
| + boolean positionIncrementsEnabled = false; |
| + this.defaultDateResolution = null; |
| + |
| + this.rangeCollatorAttribute = ((RangeCollatorAttribute) addAttribute(RangeCollatorAttribute.class)); |
| + this.rangeCollatorAttribute.setDateResolution(collator); |
| + |
| + this.defaultOperatorAttribute = ((DefaultOperatorAttribute) addAttribute(DefaultOperatorAttribute.class)); |
| + |
| + this.analyzerAttr = ((AnalyzerAttribute) addAttribute(AnalyzerAttribute.class)); |
| + this.analyzerAttr.setAnalyzer(null); |
| + |
| + this.fuzzyAttribute = ((FuzzyAttribute) addAttribute(FuzzyAttribute.class)); |
| + |
| + this.lowercaseExpandedTermsAttr = ((LowercaseExpandedTermsAttribute) addAttribute(LowercaseExpandedTermsAttribute.class)); |
| + this.lowercaseExpandedTermsAttr |
| + .setLowercaseExpandedTerms(lowercaseExpandedTerms); |
| + |
| + this.constantScoreRewriteAttribute = ((ConstantScoreRewriteAttribute) addAttribute(ConstantScoreRewriteAttribute.class)); |
| + this.constantScoreRewriteAttribute |
| + .setConstantScoreRewrite(constantScoreRewrite); |
| + |
| + this.allowLeadingWildcardAttribute = ((AllowLeadingWildcardAttribute) addAttribute(AllowLeadingWildcardAttribute.class)); |
| + this.allowLeadingWildcardAttribute |
| + .setAllowLeadingWildcard(allowLeadingWildcard); |
| + |
| + this.positionIncrementsAttribute = ((PositionIncrementsAttribute) addAttribute(PositionIncrementsAttribute.class)); |
| + this.positionIncrementsAttribute |
| + .setPositionIncrementsEnabled(positionIncrementsEnabled); |
| + |
| + this.localeAttribute = ((LocaleAttribute) addAttribute(LocaleAttribute.class)); |
| + this.localeAttribute.setLocale(locale); |
| + |
| + this.defaultPhraseSlopAttribute = ((DefaultPhraseSlopAttribute) addAttribute(DefaultPhraseSlopAttribute.class)); |
| + this.defaultPhraseSlopAttribute.setDefaultPhraseSlop(defaultPhraseSlop); |
| + |
| + } |
| + |
| + /** |
| + * Gets implicit operator setting, which will be either {@link Operator#AND} |
| + * or {@link Operator#OR}. |
| + */ |
| + public Operator getDefaultOperator() { |
| + return this.defaultOperatorAttribute.getOperator(); |
| + } |
| + |
| + /** |
| + * Sets the collator used to determine index term inclusion in ranges for |
| + * RangeQuerys. |
| + * <p/> |
| + * <strong>WARNING:</strong> Setting the rangeCollator to a non-null collator |
| + * using this method will cause every single index Term in the Field |
| + * referenced by lowerTerm and/or upperTerm to be examined. Depending on the |
| + * number of index Terms in this Field, the operation could be very slow. |
| + * |
| + * @param collator |
| + * the collator to use when constructing {@link RangeQueryNode}s |
| + */ |
| + public void setRangeCollator(Collator collator) { |
| + this.rangeCollatorAttribute.setDateResolution(collator); |
| + } |
| + |
| + /** |
| + * @return the collator used to determine index term inclusion in ranges for |
| + * RangeQuerys. |
| + */ |
| + public Collator getRangeCollator() { |
| + return this.rangeCollatorAttribute.getRangeCollator(); |
| + } |
| + |
| + /** |
| + * Sets the boolean operator of the QueryParser. In default mode ( |
| + * {@link Operator#OR}) terms without any modifiers are considered optional: |
| + * for example <code>capital of Hungary</code> is equal to |
| + * <code>capital OR of OR Hungary</code>.<br/> |
| + * In {@link Operator#AND} mode terms are considered to be in conjunction: the |
| + * above mentioned query is parsed as <code>capital AND of AND Hungary</code> |
| + */ |
| + public void setDefaultOperator(Operator operator) { |
| + this.defaultOperatorAttribute.setOperator(operator); |
| + } |
| + |
| + /** |
| + * Set to <code>true</code> to allow leading wildcard characters. |
| + * <p> |
| + * When set, <code>*</code> or <code>?</code> are allowed as the first |
| + * character of a PrefixQuery and WildcardQuery. Note that this can produce |
| + * very slow queries on big indexes. |
| + * <p> |
| + * Default: false. |
| + */ |
| + public void setLowercaseExpandedTerms(boolean lowercaseExpandedTerms) { |
| + this.lowercaseExpandedTermsAttr |
| + .setLowercaseExpandedTerms(lowercaseExpandedTerms); |
| + } |
| + |
| + /** |
| + * @see #setLowercaseExpandedTerms(boolean) |
| + */ |
| + public boolean getLowercaseExpandedTerms() { |
| + return this.lowercaseExpandedTermsAttr.isLowercaseExpandedTerms(); |
| + } |
| + |
| + /** |
| + * Set to <code>true</code> to allow leading wildcard characters. |
| + * <p> |
| + * When set, <code>*</code> or <code>?</code> are allowed as the first |
| + * character of a PrefixQuery and WildcardQuery. Note that this can produce |
| + * very slow queries on big indexes. |
| + * <p> |
| + * Default: false. |
| + */ |
| + public void setAllowLeadingWildcard(boolean allowLeadingWildcard) { |
| + this.allowLeadingWildcardAttribute |
| + .setAllowLeadingWildcard(allowLeadingWildcard); |
| + } |
| + |
| + /** |
| + * Set to <code>true</code> to enable position increments in result query. |
| + * <p> |
| + * When set, result phrase and multi-phrase queries will be aware of position |
| + * increments. Useful when e.g. a StopFilter increases the position increment |
| + * of the token that follows an omitted token. |
| + * <p> |
| + * Default: false. |
| + */ |
| + public void setEnablePositionIncrements(boolean enabled) { |
| + this.positionIncrementsAttribute.setPositionIncrementsEnabled(enabled); |
| + } |
| + |
| + /** |
| + * @see #setEnablePositionIncrements(boolean) |
| + */ |
| + public boolean getEnablePositionIncrements() { |
| + return this.positionIncrementsAttribute.isPositionIncrementsEnabled(); |
| + } |
| + |
| + /** |
| + * By default, it uses constant-score rewriting when creating a prefix, |
| + * wildcard and range queries. This implementation is generally preferable |
| + * because it a) Runs faster b) Does not have the scarcity of terms unduly |
| + * influence score c) avoids any {@link TooManyListenersException} exception. |
| + * However, if your application really needs to use the old-fashioned boolean |
| + * queries expansion rewriting and the above points are not relevant then set |
| + * this option to <code>true</code> Default is <code>false</code>. |
| + */ |
| + public void setConstantScoreRewrite(boolean constantScoreRewrite) { |
| + this.constantScoreRewriteAttribute |
| + .setConstantScoreRewrite(constantScoreRewrite); |
| + } |
| + |
| + /** |
| + * @see #setConstantScoreRewrite(boolean) |
| + */ |
| + public boolean getConstantScoreRewrite() { |
| + return this.constantScoreRewriteAttribute.isConstantScoreRewrite(); |
| + } |
| + |
| + public void setFieldsBoost(Map<CharSequence, Float> boosts) { |
| + this.boosts = boosts; |
| + } |
| + |
| + public void setMultiFields(CharSequence[] fields) { |
| + |
| + if (fields == null) { |
| + fields = new CharSequence[0]; |
| + } |
| + |
| + MultiFieldAttribute multiFieldAttr = (MultiFieldAttribute) addAttribute(MultiFieldAttribute.class); |
| + multiFieldAttr.setFields(fields); |
| + |
| + } |
| + |
| + /** |
| + * Returns the date resolution that is used by {@link RangeQueryNode}s for the |
| + * given field. Returns <code>null</code>, if no default or field specific |
| + * date resolution has been set for the given field. |
| + * |
| + */ |
| + public DateTools.Resolution getDateResolution(String fieldName) { |
| + if (fieldName == null) { |
| + throw new IllegalArgumentException("Field cannot be null."); |
| + } |
| + |
| + if (this.dateResolutions == null) { |
| + // no field specific date resolutions set; return default date |
| + // resolution instead |
| + return this.defaultDateResolution; |
| + } |
| + |
| + DateTools.Resolution resolution = (DateTools.Resolution) this.dateResolutions |
| + .get(fieldName); |
| + if (resolution == null) { |
| + // no date resolutions set for the given field; return default date |
| + // resolution instead |
| + resolution = this.defaultDateResolution; |
| + } |
| + |
| + return resolution; |
| + } |
| + |
| + /** |
| + * Sets the default date resolution used by {@link RangeQueryNode}s for fields |
| + * for which no specific date resolutions has been set. Field specific |
| + * resolutions can be set with |
| + * {@link #setDateResolution(String, DateTools.Resolution)}. |
| + * |
| + * @param dateResolution |
| + * the default date resolution to set |
| + */ |
| + public void setDateResolution(DateTools.Resolution dateResolution) { |
| + this.defaultDateResolution = dateResolution; |
| + } |
| + |
| + /** |
| + * Set the prefix length for fuzzy queries. Default is 0. |
| + * |
| + * @param fuzzyPrefixLength |
| + * The fuzzyPrefixLength to set. |
| + */ |
| + public void setFuzzyPrefixLength(int fuzzyPrefixLength) { |
| + this.fuzzyAttribute.setPrefixLength(fuzzyPrefixLength); |
| + } |
| + |
| + /** |
| + * Set locale used by date range parsing. |
| + */ |
| + public void setLocale(Locale locale) { |
| + this.localeAttribute.setLocale(locale); |
| + } |
| + |
| + /** |
| + * Returns current locale, allowing access by subclasses. |
| + */ |
| + public Locale getLocale() { |
| + return this.localeAttribute.getLocale(); |
| + } |
| + |
| + /** |
| + * Sets the default slop for phrases. If zero, then exact phrase matches are |
| + * required. Default value is zero. |
| + */ |
| + public void setDefaultPhraseSlop(int defaultPhraseSlop) { |
| + this.defaultPhraseSlopAttribute.setDefaultPhraseSlop(defaultPhraseSlop); |
| + } |
| + |
| + public void setAnalyzer(Analyzer analyzer) { |
| + this.analyzerAttr.setAnalyzer(analyzer); |
| + } |
| + |
| + /** |
| + * Sets the default date resolution used by {@link RangeQueryNode}s for fields |
| + * for which no specific date resolutions has been set. Field specific |
| + * resolutions can be set with |
| + * {@link #setDateResolution(String, DateTools.Resolution)}. |
| + * |
| + * @param dateResolution |
| + * the default date resolution to set |
| + */ |
| + public void setDateResolution(String fieldName, |
| + DateTools.Resolution dateResolution) { |
| + |
| + if (this.dateResolutions == null) { |
| + this.dateResolutions = new HashMap<CharSequence, DateTools.Resolution>(); |
| + } |
| + |
| + if (fieldName != null) { |
| + this.dateResolutions.put(fieldName.toString(), dateResolution); |
| + } |
| + |
| + } |
| + |
| + /** |
| + * @see #setAllowLeadingWildcard(boolean) |
| + */ |
| + public boolean getAllowLeadingWildcard() { |
| + return this.allowLeadingWildcardAttribute.isAllowLeadingWildcard(); |
| + } |
| + |
| + /** |
| + * Get the minimal similarity for fuzzy queries. |
| + */ |
| + public float getFuzzyMinSim() { |
| + return this.fuzzyAttribute.getFuzzyMinSimilarity(); |
| + } |
| + |
| + /** |
| + * Get the prefix length for fuzzy queries. |
| + * |
| + * @return Returns the fuzzyPrefixLength. |
| + */ |
| + public int getFuzzyPrefixLength() { |
| + return this.fuzzyAttribute.getPrefixLength(); |
| + } |
| + |
| + /** |
| + * Gets the default slop for phrases. |
| + */ |
| + public int getPhraseSlop() { |
| + return this.defaultPhraseSlopAttribute.getDefaultPhraseSlop(); |
| + } |
| + |
| + /** |
| + * Set the minimum similarity for fuzzy queries. Default is defined on |
| + * {@link FuzzyQuery#defaultMinSimilarity}. |
| + */ |
| + public void setFuzzyMinSim(float fuzzyMinSim) { |
| + this.fuzzyAttribute.setFuzzyMinSimilarity(fuzzyMinSim); |
| + } |
| + |
| + public void getQueryConfig(FieldConfig fieldConfig) { |
| + DateResolutionAttribute dateResolutionAttr = (DateResolutionAttribute) fieldConfig |
| + .addAttribute(DateResolutionAttribute.class); |
| + DateTools.Resolution dateRes = null; |
| + |
| + if (this.dateResolutions != null) { |
| + dateRes = this.dateResolutions.get(fieldConfig.getFieldName().toString()); |
| + } |
| + |
| + if (dateRes == null) { |
| + dateRes = this.defaultDateResolution; |
| + } |
| + |
| + dateResolutionAttr.setDateResolution(dateRes); |
| + |
| + if (this.boosts != null) { |
| + BoostAttribute boostAttr = (BoostAttribute) fieldConfig |
| + .addAttribute(BoostAttribute.class); |
| + Float boost = this.boosts.get(fieldConfig.getFieldName()); |
| + |
| + if (boost != null) { |
| + boostAttr.setBoost(boost.floatValue()); |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/BoostAttribute.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/BoostAttribute.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/BoostAttribute.java (revision 0) |
| @@ -0,0 +1,80 @@ |
| +package org.apache.lucene.queryParser.original.config; |
| + |
| +/** |
| + * 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.config.FieldConfig; |
| +import org.apache.lucene.queryParser.original.processors.MultiFieldQueryNodeProcessor; |
| +import org.apache.lucene.util.Attribute; |
| + |
| +/** |
| + * This attribute is used by {@link MultiFieldQueryNodeProcessor} processor and |
| + * it should be defined in a {@link FieldConfig}. This processor uses this |
| + * attribute to define which boost a specific field should have when none is |
| + * defined to it. <br/> |
| + * <br/> |
| + * |
| + * @see org.apache.lucene.queryParser.original.MultiFieldQueryParserWrapper |
| + */ |
| +public class BoostAttribute extends Attribute { |
| + |
| + private static final long serialVersionUID = -2104763012523049527L; |
| + |
| + private float boost = 1.0f; |
| + |
| + public BoostAttribute() { |
| + // empty constructor |
| + } |
| + |
| + void setBoost(float boost) { |
| + this.boost = boost; |
| + } |
| + |
| + public float getBoost() { |
| + return this.boost; |
| + } |
| + |
| + public void clear() { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public void copyTo(Attribute target) { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public boolean equals(Object other) { |
| + |
| + if (other instanceof BoostAttribute && other != null |
| + && ((BoostAttribute) other).boost == this.boost) { |
| + |
| + return true; |
| + |
| + } |
| + |
| + return false; |
| + |
| + } |
| + |
| + public int hashCode() { |
| + return Float.valueOf(this.boost).hashCode(); |
| + } |
| + |
| + public String toString() { |
| + return "<boost boost=" + this.boost + "/>"; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/RangeCollatorAttribute.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/RangeCollatorAttribute.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/RangeCollatorAttribute.java (revision 0) |
| @@ -0,0 +1,88 @@ |
| +package org.apache.lucene.queryParser.original.config; |
| + |
| +/** |
| + * 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 java.text.Collator; |
| + |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor; |
| +import org.apache.lucene.search.TermRangeQuery; |
| +import org.apache.lucene.util.Attribute; |
| + |
| +/** |
| + * This attribute is used by {@link ParametricRangeQueryNodeProcessor} processor |
| + * and must be defined in the {@link QueryConfigHandler}. This attribute tells |
| + * the processor which {@link Collator} should be used for a |
| + * {@link TermRangeQuery} <br/> |
| + * |
| + * @see org.apache.lucene.queryParser.original.QueryParserWrapper#setRangeCollator(Collator) |
| + */ |
| +public class RangeCollatorAttribute extends Attribute { |
| + |
| + private static final long serialVersionUID = -6804360312723049526L; |
| + |
| + private Collator rangeCollator; |
| + |
| + public RangeCollatorAttribute() { |
| + // empty constructor |
| + } |
| + |
| + void setDateResolution(Collator rangeCollator) { |
| + this.rangeCollator = rangeCollator; |
| + } |
| + |
| + public Collator getRangeCollator() { |
| + return this.rangeCollator; |
| + } |
| + |
| + public void clear() { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public void copyTo(Attribute target) { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public boolean equals(Object other) { |
| + |
| + if (other instanceof RangeCollatorAttribute) { |
| + RangeCollatorAttribute rangeCollatorAttr = (RangeCollatorAttribute) other; |
| + |
| + if (rangeCollatorAttr.rangeCollator == this.rangeCollator |
| + || rangeCollatorAttr.rangeCollator.equals(this.rangeCollator)) { |
| + |
| + return true; |
| + |
| + } |
| + |
| + } |
| + |
| + return false; |
| + |
| + } |
| + |
| + public int hashCode() { |
| + return (this.rangeCollator == null) ? 0 : this.rangeCollator.hashCode(); |
| + } |
| + |
| + public String toString() { |
| + return "<rangeCollatorAttribute rangeCollator='" + this.rangeCollator |
| + + "'/>"; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LocaleAttribute.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LocaleAttribute.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LocaleAttribute.java (revision 0) |
| @@ -0,0 +1,86 @@ |
| +package org.apache.lucene.queryParser.original.config; |
| + |
| +/** |
| + * 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 java.util.Locale; |
| + |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor; |
| +import org.apache.lucene.util.Attribute; |
| + |
| +/** |
| + * This attribute is used by processor {@link ParametricRangeQueryNodeProcessor} |
| + * and must be defined in the {@link QueryConfigHandler}. This attribute tells |
| + * the processor what is the default {@link Locale} used to parse a date. <br/> |
| + * |
| + * @see org.apache.lucene.queryParser.original.QueryParserWrapper#setLocale(Locale) |
| + */ |
| +public class LocaleAttribute extends Attribute { |
| + |
| + private static final long serialVersionUID = -6804760312720049526L; |
| + |
| + private Locale locale = Locale.getDefault(); |
| + |
| + public LocaleAttribute() { |
| + // empty constructor |
| + } |
| + |
| + void setLocale(Locale locale) { |
| + this.locale = locale; |
| + } |
| + |
| + public Locale getLocale() { |
| + return this.locale; |
| + } |
| + |
| + public void clear() { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public void copyTo(Attribute target) { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public boolean equals(Object other) { |
| + |
| + if (other instanceof LocaleAttribute) { |
| + LocaleAttribute localeAttr = (LocaleAttribute) other; |
| + |
| + if (localeAttr.locale == this.locale |
| + || (this.locale != null && localeAttr.locale != null && this.locale |
| + .equals(localeAttr.locale))) { |
| + |
| + return true; |
| + |
| + } |
| + |
| + } |
| + |
| + return false; |
| + |
| + } |
| + |
| + public int hashCode() { |
| + return (this.locale == null) ? 0 : this.locale.hashCode(); |
| + } |
| + |
| + public String toString() { |
| + return "<localeAttribute locale=" + this.locale + "/>"; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultPhraseSlopAttribute.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultPhraseSlopAttribute.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultPhraseSlopAttribute.java (revision 0) |
| @@ -0,0 +1,81 @@ |
| +package org.apache.lucene.queryParser.original.config; |
| + |
| +/** |
| + * 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.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.processors.PhraseSlopQueryNodeProcessor; |
| +import org.apache.lucene.util.Attribute; |
| + |
| +/** |
| + * This attribute is used by {@link PhraseSlopQueryNodeProcessor} processor and |
| + * must be defined in the {@link QueryConfigHandler}. This attribute tells the |
| + * processor what is the default phrase slop when no slop is defined in a |
| + * phrase. <br/> |
| + * |
| + * @see org.apache.lucene.queryParser.original.QueryParserWrapper#setPhraseSlop(int) |
| + */ |
| +public class DefaultPhraseSlopAttribute extends Attribute { |
| + |
| + private static final long serialVersionUID = -2104763012527049527L; |
| + |
| + private int defaultPhraseSlop = 1; |
| + |
| + public DefaultPhraseSlopAttribute() { |
| + // empty constructor |
| + } |
| + |
| + void setDefaultPhraseSlop(int defaultPhraseSlop) { |
| + this.defaultPhraseSlop = defaultPhraseSlop; |
| + } |
| + |
| + public int getDefaultPhraseSlop() { |
| + return this.defaultPhraseSlop; |
| + } |
| + |
| + public void clear() { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public void copyTo(Attribute target) { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public boolean equals(Object other) { |
| + |
| + if (other instanceof DefaultPhraseSlopAttribute |
| + && other != null |
| + && ((DefaultPhraseSlopAttribute) other).defaultPhraseSlop == this.defaultPhraseSlop) { |
| + |
| + return true; |
| + |
| + } |
| + |
| + return false; |
| + |
| + } |
| + |
| + public int hashCode() { |
| + return Integer.valueOf(this.defaultPhraseSlop).hashCode(); |
| + } |
| + |
| + public String toString() { |
| + return "<defaultPhraseSlop defaultPhraseSlop=" + this.defaultPhraseSlop |
| + + "/>"; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/ConstantScoreRewriteAttribute.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/ConstantScoreRewriteAttribute.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/ConstantScoreRewriteAttribute.java (revision 0) |
| @@ -0,0 +1,80 @@ |
| +package org.apache.lucene.queryParser.original.config; |
| + |
| +/** |
| + * 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.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor; |
| +import org.apache.lucene.util.Attribute; |
| + |
| +/** |
| + * This attribute is used by {@link ParametricRangeQueryNodeProcessor} processor |
| + * and should be defined in the {@link QueryConfigHandler} used by this |
| + * processor. It basically tells the processor if the constant score rewrite is |
| + * enabled. <br/> |
| + * |
| + * @see org.apache.lucene.queryParser.original.QueryParserWrapper#setConstantScoreRewrite(boolean) |
| + */ |
| +public class ConstantScoreRewriteAttribute extends Attribute { |
| + |
| + private static final long serialVersionUID = -2104763012723049527L; |
| + |
| + private boolean constantScoreRewrite = true; |
| + |
| + public ConstantScoreRewriteAttribute() { |
| + // empty constructor |
| + } |
| + |
| + void setConstantScoreRewrite(boolean constantScoreRewrite) { |
| + this.constantScoreRewrite = constantScoreRewrite; |
| + } |
| + |
| + public boolean isConstantScoreRewrite() { |
| + return this.constantScoreRewrite; |
| + } |
| + |
| + public void clear() { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public void copyTo(Attribute target) { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public boolean equals(Object other) { |
| + |
| + if (other instanceof ConstantScoreRewriteAttribute |
| + && ((ConstantScoreRewriteAttribute) other).constantScoreRewrite == this.constantScoreRewrite) { |
| + |
| + return true; |
| + |
| + } |
| + |
| + return false; |
| + |
| + } |
| + |
| + public int hashCode() { |
| + return this.constantScoreRewrite ? -1 : Integer.MAX_VALUE; |
| + } |
| + |
| + public String toString() { |
| + return "<constantScoreRewrite constantScoreRewrite=" |
| + + this.constantScoreRewrite + "/>"; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FuzzyAttribute.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FuzzyAttribute.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FuzzyAttribute.java (revision 0) |
| @@ -0,0 +1,90 @@ |
| +package org.apache.lucene.queryParser.original.config; |
| + |
| +/** |
| + * 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.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.processors.PhraseSlopQueryNodeProcessor; |
| +import org.apache.lucene.search.FuzzyQuery; |
| +import org.apache.lucene.util.Attribute; |
| + |
| +/** |
| + * This attribute is used by {@link PhraseSlopQueryNodeProcessor} processor and |
| + * must be defined in the {@link QueryConfigHandler}. This attribute tells the |
| + * processor what is the default phrase slop when no slop is defined in a |
| + * phrase. <br/> |
| + * |
| + * @see org.apache.lucene.queryParser.original.QueryParserWrapper#setPhraseSlop(int) |
| + */ |
| +public class FuzzyAttribute extends Attribute { |
| + |
| + private static final long serialVersionUID = -2104763012527049527L; |
| + |
| + private int prefixLength = FuzzyQuery.defaultPrefixLength; |
| + |
| + private float minSimilarity = FuzzyQuery.defaultMinSimilarity; |
| + |
| + public FuzzyAttribute() { |
| + // empty constructor |
| + } |
| + |
| + void setPrefixLength(int prefixLength) { |
| + this.prefixLength = prefixLength; |
| + } |
| + |
| + public int getPrefixLength() { |
| + return this.prefixLength; |
| + } |
| + |
| + public void setFuzzyMinSimilarity(float minSimilarity) { |
| + this.minSimilarity = minSimilarity; |
| + } |
| + |
| + public float getFuzzyMinSimilarity() { |
| + return this.minSimilarity; |
| + } |
| + |
| + public void clear() { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public void copyTo(Attribute target) { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public boolean equals(Object other) { |
| + |
| + if (other instanceof FuzzyAttribute && other != null |
| + && ((FuzzyAttribute) other).prefixLength == this.prefixLength) { |
| + |
| + return true; |
| + |
| + } |
| + |
| + return false; |
| + |
| + } |
| + |
| + public int hashCode() { |
| + return Integer.valueOf(this.prefixLength).hashCode(); |
| + } |
| + |
| + public String toString() { |
| + return "<fuzzyAttribute prefixLength=" + this.prefixLength + "/>"; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultOperatorAttribute.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultOperatorAttribute.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultOperatorAttribute.java (revision 0) |
| @@ -0,0 +1,91 @@ |
| +package org.apache.lucene.queryParser.original.config; |
| + |
| +/** |
| + * 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.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.QueryParserWrapper; |
| +import org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler.Operator; |
| +import org.apache.lucene.queryParser.original.processors.GroupQueryNodeProcessor; |
| +import org.apache.lucene.util.Attribute; |
| + |
| +/** |
| + * This attribute is used by {@link GroupQueryNodeProcessor} processor and must |
| + * be defined in the {@link QueryConfigHandler}. This attribute tells the |
| + * processor which is the default boolean operator when no operator is defined |
| + * between terms. <br/> |
| + * |
| + * @see QueryParserWrapper#setDefaultOperator(org.apache.lucene.queryParser.QueryParser.Operator) |
| + */ |
| +@SuppressWarnings("deprecation") |
| +public class DefaultOperatorAttribute extends Attribute { |
| + |
| + private static final long serialVersionUID = -6804760312723049526L; |
| + |
| + private Operator operator = Operator.OR; |
| + |
| + public DefaultOperatorAttribute() { |
| + // empty constructor |
| + } |
| + |
| + public void setOperator(Operator operator) { |
| + |
| + if (operator == null) { |
| + throw new IllegalArgumentException("default operator cannot be null!"); |
| + } |
| + |
| + this.operator = operator; |
| + |
| + } |
| + |
| + public Operator getOperator() { |
| + return this.operator; |
| + } |
| + |
| + public void clear() { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public void copyTo(Attribute target) { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public boolean equals(Object other) { |
| + |
| + if (other instanceof DefaultOperatorAttribute) { |
| + DefaultOperatorAttribute defaultOperatorAttr = (DefaultOperatorAttribute) other; |
| + |
| + if (defaultOperatorAttr.getOperator() == this.getOperator()) { |
| + return true; |
| + |
| + } |
| + |
| + } |
| + |
| + return false; |
| + |
| + } |
| + |
| + public int hashCode() { |
| + return getOperator().hashCode() * 31; |
| + } |
| + |
| + public String toString() { |
| + return "<defaultOperatorAttribute operator=" + this.operator.name() + "/>"; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LowercaseExpandedTermsAttribute.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LowercaseExpandedTermsAttribute.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LowercaseExpandedTermsAttribute.java (revision 0) |
| @@ -0,0 +1,81 @@ |
| +package org.apache.lucene.queryParser.original.config; |
| + |
| +/** |
| + * 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 java.util.Locale; |
| + |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor; |
| +import org.apache.lucene.util.Attribute; |
| + |
| +/** |
| + * This attribute is used by processor {@link ParametricRangeQueryNodeProcessor} |
| + * and must be defined in the {@link QueryConfigHandler}. This attribute tells |
| + * the processor what is the default {@link Locale} used to parse a date. <br/> |
| + * |
| + * @see org.apache.lucene.queryParser.original.QueryParserWrapper#setLowercaseExpandedTerms(boolean) |
| + */ |
| +public class LowercaseExpandedTermsAttribute extends Attribute { |
| + |
| + private static final long serialVersionUID = -2804760312723049527L; |
| + |
| + private boolean lowercaseExpandedTerms = true; |
| + |
| + public LowercaseExpandedTermsAttribute() { |
| + // empty constructor |
| + } |
| + |
| + void setLowercaseExpandedTerms(boolean lowercaseExpandedTerms) { |
| + this.lowercaseExpandedTerms = lowercaseExpandedTerms; |
| + } |
| + |
| + public boolean isLowercaseExpandedTerms() { |
| + return this.lowercaseExpandedTerms; |
| + } |
| + |
| + public void clear() { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public void copyTo(Attribute target) { |
| + throw new UnsupportedOperationException(); |
| + } |
| + |
| + public boolean equals(Object other) { |
| + |
| + if (other instanceof LowercaseExpandedTermsAttribute |
| + && ((LowercaseExpandedTermsAttribute) other).lowercaseExpandedTerms == this.lowercaseExpandedTerms) { |
| + |
| + return true; |
| + |
| + } |
| + |
| + return false; |
| + |
| + } |
| + |
| + public int hashCode() { |
| + return this.lowercaseExpandedTerms ? -1 : Integer.MAX_VALUE; |
| + } |
| + |
| + public String toString() { |
| + return "<lowercaseExpandedTerms lowercaseExpandedTerms=" |
| + + this.lowercaseExpandedTerms + "/>"; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/parser/Parser.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/parser/Parser.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/parser/Parser.java (revision 0) |
| @@ -0,0 +1,36 @@ |
| +package org.apache.lucene.queryParser.parser; |
| + |
| +/** |
| + * 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.QueryNodeParseException; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| + |
| +/** |
| + * A parser needs to implement {@link Parser} interface |
| + */ |
| +public interface Parser { |
| + /** |
| + * @param query |
| + * - query data to be parsed |
| + * @param field |
| + * - default field name |
| + * @return QueryNode tree |
| + */ |
| + public QueryNode parse(CharSequence query, CharSequence field) |
| + throws QueryNodeParseException; |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/parser/Parser.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/parser/EscapeQuerySyntax.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/parser/EscapeQuerySyntax.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/parser/EscapeQuerySyntax.java (revision 0) |
| @@ -0,0 +1,41 @@ |
| +package org.apache.lucene.queryParser.parser; |
| + |
| +/** |
| + * 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 java.util.Locale; |
| + |
| +/** |
| + * A parser needs to implement {@link EscapeQuerySyntax} to allow the QueryNode |
| + * to escape the queries, when the toQueryString method is called. |
| + */ |
| +public interface EscapeQuerySyntax { |
| + public enum Type { |
| + STRING, NORMAL; |
| + } |
| + |
| + /** |
| + * @param text |
| + * - text to be escaped |
| + * @param locale |
| + * - locale for the current query |
| + * @param type |
| + * - select the type of escape operation to use |
| + * @return escaped text |
| + */ |
| + CharSequence escape(CharSequence text, Locale locale, Type type); |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/parser/EscapeQuerySyntax.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/parser/package.html |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/parser/package.html (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/parser/package.html (revision 0) |
| @@ -0,0 +1,41 @@ |
| +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> |
| +<!-- |
| + 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. |
| +--> |
| +<html> |
| +<head> |
| + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| +</head> |
| +<body> |
| +<h2>Parser</h2> |
| +<p> |
| +The package <tt>org.apache.lucene.queryParser.parser</tt> contains interfaces |
| +that should be implemented by the parsers. |
| + |
| +Parsers produce QueryNode Trees from a string object. |
| +These package still needs some work to add support to for multiple parsers. |
| + |
| +Features that should be supported for the future, related with the parser: |
| +- QueryNode tree should be able convertible to any parser syntax. |
| +- The query syntax should support calling other parsers. |
| +- QueryNode tree created by multiple parsers. |
| + |
| +</p> |
| +<p> |
| + |
| +</p> |
| +</body> |
| +</html> |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/parser/package.html |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/QueryNodeException.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/QueryNodeException.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/QueryNodeException.java (revision 0) |
| @@ -0,0 +1,87 @@ |
| +package org.apache.lucene.queryParser; |
| + |
| +/** |
| + * 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 java.util.Locale; |
| + |
| +import org.apache.lucene.messages.Message; |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.messages.NLS; |
| +import org.apache.lucene.messages.NLSException; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| + |
| +/** |
| + * <p> |
| + * This exception should be thrown if something wrong happens when dealing with |
| + * {@link QueryNode}s. |
| + * </p> |
| + * <p> |
| + * It also supports NLS messages. |
| + * </p> |
| + * |
| + * @see Message |
| + * @see NLS |
| + * @see NLSException |
| + * @see QueryNode |
| + */ |
| +public class QueryNodeException extends Exception implements NLSException { |
| + |
| + private static final long serialVersionUID = -5962648855261624214L; |
| + |
| + protected Message message = new MessageImpl(QueryParserMessages.EMPTY_MESSAGE); |
| + |
| + public QueryNodeException(Message message) { |
| + super(message.getKey()); |
| + |
| + this.message = message; |
| + |
| + } |
| + |
| + public QueryNodeException(Throwable throwable) { |
| + super(throwable); |
| + } |
| + |
| + public QueryNodeException(Message message, Throwable throwable) { |
| + super(message.getKey(), throwable); |
| + |
| + this.message = message; |
| + |
| + } |
| + |
| + public Message getMessageObject() { |
| + return this.message; |
| + } |
| + |
| + public String getMessage() { |
| + return getLocalizedMessage(); |
| + } |
| + |
| + public String getLocalizedMessage() { |
| + return getLocalizedMessage(Locale.getDefault()); |
| + } |
| + |
| + public String getLocalizedMessage(Locale locale) { |
| + return this.message.getLocalizedMessage(locale); |
| + } |
| + |
| + public String toString() { |
| + return this.message.getKey() + ": " + getLocalizedMessage(); |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/QueryNodeException.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/MatchNoDocsQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/MatchNoDocsQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/MatchNoDocsQueryNode.java (revision 0) |
| @@ -0,0 +1,37 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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. |
| + */ |
| + |
| +/** |
| + * A {@link MatchNoDocsQueryNode} indicates that a query node tree or subtree |
| + * will not match any documents if executed in the index. |
| + * |
| + */ |
| +public class MatchNoDocsQueryNode extends DeletedQueryNode { |
| + |
| + private static final long serialVersionUID = 8081805751679581497L; |
| + |
| + public MatchNoDocsQueryNode() { |
| + // empty constructor |
| + } |
| + |
| + public String toString() { |
| + return "<matchNoDocsQueryNode/>"; |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/MatchNoDocsQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/OpaqueQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/OpaqueQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/OpaqueQueryNode.java (revision 0) |
| @@ -0,0 +1,80 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link OpaqueQueryNode} is used for specify values that are not supposed to |
| + * be parsed by the parser. For example: and XPATH query in the middle of a |
| + * query string a b @xpath:'/bookstore/book[1]/title' c d |
| + */ |
| +public class OpaqueQueryNode extends QueryNodeImpl { |
| + |
| + private static final long serialVersionUID = 0L; |
| + |
| + private CharSequence schema = null; |
| + |
| + private CharSequence value = null; |
| + |
| + /** |
| + * @param schema |
| + * - schema identifier |
| + * @param value |
| + * - value that was not parsed |
| + */ |
| + public OpaqueQueryNode(CharSequence schema, CharSequence value) { |
| + this.setLeaf(true); |
| + |
| + this.schema = schema; |
| + this.value = value; |
| + |
| + } |
| + |
| + public String toString() { |
| + return "<opaque schema='" + this.schema + "' value='" + this.value + "'/>"; |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { |
| + return "@" + this.schema + ":'" + this.value + "'"; |
| + } |
| + |
| + public QueryNode cloneTree() throws CloneNotSupportedException { |
| + OpaqueQueryNode clone = (OpaqueQueryNode) super.cloneTree(); |
| + |
| + clone.schema = this.schema; |
| + clone.value = this.value; |
| + |
| + return clone; |
| + } |
| + |
| + /** |
| + * @return the schema |
| + */ |
| + public CharSequence getSchema() { |
| + return this.schema; |
| + } |
| + |
| + /** |
| + * @return the value |
| + */ |
| + public CharSequence getValue() { |
| + return this.value; |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/OpaqueQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/MatchAllDocsQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/MatchAllDocsQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/MatchAllDocsQueryNode.java (revision 0) |
| @@ -0,0 +1,49 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link MatchAllDocsQueryNode} indicates that a query node tree or subtree |
| + * will match all documents if executed in the index. |
| + */ |
| +public class MatchAllDocsQueryNode extends QueryNodeImpl { |
| + |
| + private static final long serialVersionUID = -7050381275423477809L; |
| + |
| + public MatchAllDocsQueryNode() { |
| + // empty constructor |
| + } |
| + |
| + public String toString() { |
| + return "<matchAllDocs field='*' term='*'>"; |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { |
| + return "*:*"; |
| + } |
| + |
| + public MatchAllDocsQueryNode cloneTree() throws CloneNotSupportedException { |
| + MatchAllDocsQueryNode clone = (MatchAllDocsQueryNode) super.cloneTree(); |
| + |
| + // nothing to clone |
| + |
| + return clone; |
| + } |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/MatchAllDocsQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/AnyQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/AnyQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/AnyQueryNode.java (revision 0) |
| @@ -0,0 +1,143 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link AnyQueryNode} represents an ANY operator performed on a list of |
| + * nodes. |
| + */ |
| +public class AnyQueryNode extends AndQueryNode { |
| + private static final long serialVersionUID = 1000791433562954187L; |
| + |
| + private CharSequence field = null; |
| + private int minimumMatchingmElements = 0; |
| + |
| + /** |
| + * @param clauses |
| + * - the query nodes to be or'ed |
| + */ |
| + public AnyQueryNode(List<QueryNode> clauses, CharSequence field, |
| + int minimumMatchingElements) { |
| + super(clauses); |
| + this.field = field; |
| + this.minimumMatchingmElements = minimumMatchingElements; |
| + |
| + if (clauses != null) { |
| + |
| + for (QueryNode clause : clauses) { |
| + |
| + if (clause instanceof FieldQueryNode) { |
| + |
| + if (clause instanceof QueryNodeImpl) { |
| + ((QueryNodeImpl) clause).toQueryStringIgnoreFields = true; |
| + } |
| + |
| + if (clause instanceof FieldableNode) { |
| + ((FieldableNode) clause).setField(field); |
| + } |
| + |
| + } |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + public int getMinimumMatchingElements() { |
| + return this.minimumMatchingmElements; |
| + } |
| + |
| + /** |
| + * returns null if the field was not specified |
| + * |
| + * @return the field |
| + */ |
| + public CharSequence getField() { |
| + return this.field; |
| + } |
| + |
| + /** |
| + * returns - null if the field was not specified |
| + * |
| + * @return the field as a String |
| + */ |
| + public String getFieldAsString() { |
| + if (this.field == null) |
| + return null; |
| + else |
| + return this.field.toString(); |
| + } |
| + |
| + /** |
| + * @param field |
| + * - the field to set |
| + */ |
| + public void setField(CharSequence field) { |
| + this.field = field; |
| + } |
| + |
| + public QueryNode cloneTree() throws CloneNotSupportedException { |
| + AnyQueryNode clone = (AnyQueryNode) super.cloneTree(); |
| + |
| + clone.field = this.field; |
| + clone.minimumMatchingmElements = this.minimumMatchingmElements; |
| + |
| + return clone; |
| + } |
| + |
| + public String toString() { |
| + if (getChildren() == null || getChildren().size() == 0) |
| + return "<any field='" + this.field + "' matchelements=" |
| + + this.minimumMatchingmElements + "/>"; |
| + StringBuilder sb = new StringBuilder(); |
| + sb.append("<any field='" + this.field + "' matchelements=" |
| + + this.minimumMatchingmElements + ">"); |
| + for (QueryNode clause : getChildren()) { |
| + sb.append("\n"); |
| + sb.append(clause.toString()); |
| + } |
| + sb.append("\n</any>"); |
| + return sb.toString(); |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { |
| + String anySTR = "ANY " + this.minimumMatchingmElements; |
| + |
| + StringBuilder sb = new StringBuilder(); |
| + if (getChildren() == null || getChildren().size() == 0) { |
| + // no childs case |
| + } else { |
| + String filler = ""; |
| + for (QueryNode clause : getChildren()) { |
| + sb.append(filler).append(clause.toQueryString(escapeSyntaxParser)); |
| + filler = " "; |
| + } |
| + } |
| + |
| + if (isDefaultField(this.field)) { |
| + return "( " + sb.toString() + " ) " + anySTR; |
| + } else { |
| + return this.field + ":(( " + sb.toString() + " ) " + anySTR + ")"; |
| + } |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/AnyQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/package.html |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/package.html (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/package.html (revision 0) |
| @@ -0,0 +1,86 @@ |
| +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> |
| +<!-- |
| + 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. |
| +--> |
| +<html> |
| +<head> |
| + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| +</head> |
| +<body> |
| +<h2>QueryNodes</h2> |
| +<p> |
| +The package <tt>org.apache.lucene.queryParser.nodes</tt> contains all the basic query nodes. The interface |
| +that represents a query node is {@link org.apache.lucene.queryParser.nodes.QueryNode}. Every query node must be serializable. |
| +</p> |
| +<p> |
| +{@link org.apache.lucene.queryParser.nodes.QueryNode}s are used by the text parser to create a syntax tree. |
| +These nodes are designed to be used by UI or other text parsers. |
| +The default Lucene text parser is {@link org.apache.lucene.queryParser.original.parser.TextParser}, |
| +it implements original syntax. |
| +</p> |
| +<p> |
| +{@link org.apache.lucene.queryParser.nodes.QueryNode} interface should be implemented by all query nodes, |
| +the class {@link org.apache.lucene.queryParser.nodes.QueryNodeImpl} implements {@link org.apache.lucene.queryParser.nodes.QueryNode} and is extended |
| +by all current query node implementations. |
| +</p> |
| +<p> |
| +A query node tree can be printed to the a stream, and it generates a pseudo XML representation |
| +with all the nodes. |
| +</p> |
| +<p> |
| +A query node tree can also generate a query string that can be parsed back by the original text parser, |
| +at this point only the original lucene syntax is supported. |
| +</p> |
| +<p> |
| +Grouping nodes: |
| +<ul> |
| +<li>AndQueryNode - used for AND operator</li> |
| +<li>AnyQueryNode - used for ANY operator</li> |
| +<li>OrQueryNode - used for OR operator</li> |
| +<li>BooleanQueryNode - used when no operator is specified</li> |
| +<li>ModifierQueryNode - used for modifier operator</li> |
| +<li>GroupQueryNode - used for parenthesis</li> |
| +<li>BoostQueryNode - used for boost operator</li> |
| +<li>SlopQueryNode - phrase slop</li> |
| +<li>FuzzyQueryNode - fuzzy node</li> |
| +<li>ParametricRangeQueryNode - used for parametric field:[low_value TO high_value]</li> |
| +<li>ProximityQueryNode - used for proximity search</li> |
| +<li>TokenizedPhraseQueryNode - used by tokenizers/lemmatizers/analizers for phrases/autophrases</li> |
| +</ul> |
| +</p> |
| +<p> |
| +Leaf Nodes: |
| +<ul> |
| +<li>FieldQueryNode - field/value node</li> |
| +<li>PathQueryNode - {@link org.apache.lucene.queryParser.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>ParametricQueryNode - used for parametric field [>=|<=|=|<|>] value</li> |
| +<li>PrefixWildcardQueryNode - non-phrase wildcard query</li> |
| +<li>QuotedFieldQUeryNode - regular phrase node</li> |
| +<li>WildcardQueryNode - non-phrase wildcard query</li> |
| +</ul> |
| +</p> |
| +<p> |
| +Utility Nodes: |
| +<ul> |
| +<li>DeletedQueryNode - used by processors on optimizations</li> |
| +<li>MatchAllDocsQueryNode - used by processors on optimizations</li> |
| +<li>MatchNoDocsQueryNode - used by processors on optimizations</li> |
| +<li>NoTokenFoundQueryNode - used by tokenizers/lemmatizers/analizers</li> |
| +</ul> |
| +</p> |
| +</body> |
| +</html> |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/package.html |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/QuotedFieldQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/QuotedFieldQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/QuotedFieldQueryNode.java (revision 0) |
| @@ -0,0 +1,64 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link QuotedFieldQueryNode} represents phrase query. Example: |
| + * "life is great" |
| + */ |
| +public class QuotedFieldQueryNode extends FieldQueryNode { |
| + |
| + private static final long serialVersionUID = -6675157780051428987L; |
| + |
| + /** |
| + * @param field |
| + * - field name |
| + * @param text |
| + * - value |
| + * @param begin |
| + * - position in the query string |
| + * @param end |
| + * - position in the query string |
| + */ |
| + public QuotedFieldQueryNode(CharSequence field, CharSequence text, int begin, |
| + int end) { |
| + super(field, text, begin, end); |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escaper) { |
| + if (isDefaultField(this.field)) { |
| + return "\"" + getTermEscapeQuoted(escaper) + "\""; |
| + } else { |
| + return this.field + ":" + "\"" + getTermEscapeQuoted(escaper) + "\""; |
| + } |
| + } |
| + |
| + public String toString() { |
| + return "<quotedfield start='" + this.begin + "' end='" + this.end |
| + + "' field='" + this.field + "' term='" + this.text + "'/>"; |
| + } |
| + |
| + public QuotedFieldQueryNode cloneTree() throws CloneNotSupportedException { |
| + QuotedFieldQueryNode clone = (QuotedFieldQueryNode) super.cloneTree(); |
| + // nothing to do here |
| + return clone; |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/QuotedFieldQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/ParametricRangeQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/ParametricRangeQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/ParametricRangeQueryNode.java (revision 0) |
| @@ -0,0 +1,120 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.nodes.ParametricQueryNode.CompareOperator; |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link ParametricRangeQueryNode} represents LE, LT, GE, GT, EQ, NE query. |
| + * Example: date >= "2009-10-10" OR price = 200 |
| + */ |
| +public class ParametricRangeQueryNode extends QueryNodeImpl implements |
| + FieldableNode { |
| + |
| + private static final long serialVersionUID = 7120958816535573935L; |
| + |
| + public ParametricRangeQueryNode(ParametricQueryNode lowerBound, |
| + ParametricQueryNode upperBound) { |
| + |
| + if (upperBound.getOperator() != CompareOperator.LE |
| + && upperBound.getOperator() != CompareOperator.LT) { |
| + throw new IllegalArgumentException("upper bound should have " |
| + + CompareOperator.LE + " or " + CompareOperator.LT); |
| + } |
| + |
| + if (lowerBound.getOperator() != CompareOperator.GE |
| + && lowerBound.getOperator() != CompareOperator.GT) { |
| + throw new IllegalArgumentException("lower bound should have " |
| + + CompareOperator.GE + " or " + CompareOperator.GT); |
| + } |
| + |
| + if (upperBound.getField() != lowerBound.getField() |
| + || (upperBound.getField() != null && !upperBound.getField().equals( |
| + lowerBound.getField()))) { |
| + |
| + throw new IllegalArgumentException( |
| + "lower and upper bounds should have the same field name!"); |
| + |
| + } |
| + |
| + allocate(); |
| + setLeaf(false); |
| + |
| + add(lowerBound); |
| + add(upperBound); |
| + |
| + } |
| + |
| + public ParametricQueryNode getUpperBound() { |
| + return (ParametricQueryNode) getChildren().get(1); |
| + } |
| + |
| + public ParametricQueryNode getLowerBound() { |
| + return (ParametricQueryNode) getChildren().get(0); |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { |
| + return getLowerBound().toQueryString(escapeSyntaxParser) + " AND " |
| + + getUpperBound().toQueryString(escapeSyntaxParser); |
| + } |
| + |
| + public CharSequence getField() { |
| + return getLowerBound().getField(); |
| + } |
| + |
| + @Override |
| + public String toString() { |
| + StringBuilder sb = new StringBuilder("<parametricRange>\n\t"); |
| + sb.append(getUpperBound()).append("\n\t"); |
| + sb.append(getLowerBound()).append("\n"); |
| + sb.append("</parametricRange>\n"); |
| + |
| + return sb.toString(); |
| + |
| + } |
| + |
| + public ParametricRangeQueryNode cloneTree() throws CloneNotSupportedException { |
| + ParametricRangeQueryNode clone = (ParametricRangeQueryNode) super |
| + .cloneTree(); |
| + |
| + // nothing to do here |
| + |
| + return clone; |
| + } |
| + |
| + public void setField(CharSequence fieldName) { |
| + List<QueryNode> children = getChildren(); |
| + |
| + if (children != null) { |
| + |
| + for (QueryNode child : getChildren()) { |
| + |
| + if (child instanceof FieldableNode) { |
| + ((FieldableNode) child).setField(fieldName); |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/ParametricRangeQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/QueryNodeImpl.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/QueryNodeImpl.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/QueryNodeImpl.java (revision 0) |
| @@ -0,0 +1,225 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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 java.util.ArrayList; |
| +import java.util.Hashtable; |
| +import java.util.List; |
| +import java.util.Map; |
| +import java.util.ResourceBundle; |
| + |
| +import org.apache.lucene.messages.NLS; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| + |
| +/** |
| + * A {@link QueryNodeImpl} is the default implementation of the interface |
| + * {@link QueryNode} |
| + */ |
| +public abstract class QueryNodeImpl implements QueryNode, Cloneable { |
| + |
| + private static final long serialVersionUID = 5569870883474845989L; |
| + |
| + /* index default field */ |
| + // TODO remove PLAINTEXT_FIELD_NAME replacing it with configuration APIs |
| + public static final String PLAINTEXT_FIELD_NAME = "_plain"; |
| + |
| + private boolean isLeaf = true; |
| + |
| + private Hashtable<CharSequence, Object> tags = new Hashtable<CharSequence, Object>(); |
| + |
| + private List<QueryNode> clauses = null; |
| + |
| + protected void allocate() { |
| + |
| + if (this.clauses == null) { |
| + this.clauses = new ArrayList<QueryNode>(); |
| + |
| + } else { |
| + this.clauses.clear(); |
| + } |
| + |
| + } |
| + |
| + public final void add(QueryNode child) { |
| + |
| + if (isLeaf() || this.clauses == null || child == null) { |
| + throw new IllegalArgumentException(NLS |
| + .getLocalizedMessage(QueryParserMessages.NODE_ACTION_NOT_SUPPORTED)); |
| + } |
| + |
| + this.clauses.add(child); |
| + ((QueryNodeImpl) child).setParent(this); |
| + |
| + } |
| + |
| + public final void add(List<QueryNode> children) { |
| + |
| + if (isLeaf() || this.clauses == null) { |
| + throw new IllegalArgumentException(NLS |
| + .getLocalizedMessage(QueryParserMessages.NODE_ACTION_NOT_SUPPORTED)); |
| + } |
| + |
| + for (QueryNode child : getChildren()) { |
| + add(child); |
| + } |
| + |
| + } |
| + |
| + public boolean isLeaf() { |
| + return this.isLeaf; |
| + } |
| + |
| + public final void set(List<QueryNode> children) { |
| + |
| + if (isLeaf() || this.clauses == null) { |
| + ResourceBundle bundle = ResourceBundle |
| + .getBundle("org.apache.lucene.queryParser.messages.QueryParserMessages"); |
| + String message = bundle.getObject("Q0008E.NODE_ACTION_NOT_SUPPORTED") |
| + .toString(); |
| + |
| + throw new IllegalArgumentException(message); |
| + |
| + } |
| + |
| + // reset parent value |
| + for (QueryNode child : children) { |
| + |
| + ((QueryNodeImpl) child).setParent(null); |
| + |
| + } |
| + |
| + // allocate new children list |
| + allocate(); |
| + |
| + // add new childs and set parent |
| + for (QueryNode child : children) { |
| + add(child); |
| + } |
| + } |
| + |
| + public QueryNode cloneTree() throws CloneNotSupportedException { |
| + QueryNodeImpl clone = (QueryNodeImpl) super.clone(); |
| + clone.isLeaf = this.isLeaf; |
| + |
| + // Reset all tags |
| + clone.tags = new Hashtable<CharSequence, Object>(); |
| + |
| + // copy children |
| + if (this.clauses != null) { |
| + List<QueryNode> localClauses = new ArrayList<QueryNode>(); |
| + for (QueryNode clause : this.clauses) { |
| + localClauses.add(clause.cloneTree()); |
| + } |
| + clone.clauses = localClauses; |
| + } |
| + |
| + return clone; |
| + } |
| + |
| + public Object clone() throws CloneNotSupportedException { |
| + return cloneTree(); |
| + } |
| + |
| + protected void setLeaf(boolean isLeaf) { |
| + this.isLeaf = isLeaf; |
| + } |
| + |
| + /** |
| + * @return a List for QueryNode object. Returns null, for nodes that do not |
| + * contain children. All leaf Nodes return null. |
| + */ |
| + public final List<QueryNode> getChildren() { |
| + if (isLeaf() || this.clauses == null) { |
| + return null; |
| + } |
| + return this.clauses; |
| + } |
| + |
| + public void setTag(CharSequence tagName, Object value) { |
| + this.tags.put(tagName.toString().toLowerCase(), value); |
| + } |
| + |
| + public void unsetTag(CharSequence tagName) { |
| + this.tags.remove(tagName.toString().toLowerCase()); |
| + } |
| + |
| + public boolean containsTag(CharSequence tagName) { |
| + return this.tags.containsKey(tagName.toString().toLowerCase()); |
| + } |
| + |
| + public Object getTag(CharSequence tagName) { |
| + return this.tags.get(tagName.toString().toLowerCase()); |
| + } |
| + |
| + private QueryNode parent = null; |
| + |
| + private void setParent(QueryNode parent) { |
| + this.parent = parent; |
| + } |
| + |
| + public QueryNode getParent() { |
| + return this.parent; |
| + } |
| + |
| + protected boolean isRoot() { |
| + return getParent() == null; |
| + } |
| + |
| + /** |
| + * If set to true the the method toQueryString will not write field names |
| + */ |
| + protected boolean toQueryStringIgnoreFields = false; |
| + |
| + /** |
| + * This method is use toQueryString to detect if fld is the default field |
| + * |
| + * @param fld |
| + * - field name |
| + * @return true if fld is the default field |
| + */ |
| + protected boolean isDefaultField(CharSequence fld) { |
| + if (this.toQueryStringIgnoreFields) |
| + return true; |
| + if (fld == null) |
| + return true; |
| + if (QueryNodeImpl.PLAINTEXT_FIELD_NAME.equals(fld.toString())) |
| + return true; |
| + return false; |
| + } |
| + |
| + /** |
| + * Every implementation of this class should return pseudo xml like this: |
| + * |
| + * For FieldQueryNode: <field start='1' end='2' field='subject' text='foo'/> |
| + * |
| + * @see org.apache.lucene.queryParser.nodes.QueryNode#toString() |
| + */ |
| + public String toString() { |
| + return super.toString(); |
| + } |
| + |
| + /** |
| + * @see org.apache.lucene.queryParser.nodes.QueryNode#getTag(CharSequence) |
| + * @return a Map with all tags for this QueryNode |
| + */ |
| + @SuppressWarnings( { "unchecked" }) |
| + public Map<CharSequence, Object> getTags() { |
| + return (Map<CharSequence, Object>) this.tags.clone(); |
| + } |
| + |
| +} // end class QueryNodeImpl |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/QueryNodeImpl.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/GroupQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/GroupQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/GroupQueryNode.java (revision 0) |
| @@ -0,0 +1,83 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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 java.util.ArrayList; |
| +import java.util.List; |
| + |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeError; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link GroupQueryNode} represents a location where the original user typed |
| + * real parenthesis on the query string. This class is useful for queries like: |
| + * a) a AND b OR c b) ( a AND b) OR c |
| + * |
| + * Parenthesis might be used to define the boolean operation precedence. |
| + */ |
| +public class GroupQueryNode extends QueryNodeImpl { |
| + |
| + private static final long serialVersionUID = -9204673493869114999L; |
| + |
| + /** |
| + * This QueryNode is used to identify parenthesis on the original query string |
| + */ |
| + public GroupQueryNode(QueryNode query) { |
| + if (query == null) { |
| + throw new QueryNodeError(new MessageImpl( |
| + QueryParserMessages.PARAMETER_VALUE_NOT_SUPPORTED, "query", "null")); |
| + } |
| + |
| + allocate(); |
| + setLeaf(false); |
| + add(query); |
| + } |
| + |
| + public QueryNode getChild() { |
| + return getChildren().get(0); |
| + } |
| + |
| + public String toString() { |
| + return "<group>" + "\n" + getChild().toString() + "\n</group>"; |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { |
| + if (getChild() == null) |
| + return ""; |
| + |
| + return "( " + getChild().toQueryString(escapeSyntaxParser) + " )"; |
| + } |
| + |
| + public QueryNode cloneTree() throws CloneNotSupportedException { |
| + GroupQueryNode clone = (GroupQueryNode) super.cloneTree(); |
| + |
| + return clone; |
| + } |
| + |
| + /** |
| + * @param child |
| + */ |
| + public void setChild(QueryNode child) { |
| + List<QueryNode> list = new ArrayList<QueryNode>(); |
| + list.add(child); |
| + this.set(list); |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/GroupQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/TextableQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/TextableQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/TextableQueryNode.java (revision 0) |
| @@ -0,0 +1,26 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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. |
| + */ |
| + |
| +public interface TextableQueryNode { |
| + |
| + CharSequence getText(); |
| + |
| + void setText(CharSequence text); |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/TextableQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/ProximityQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/ProximityQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/ProximityQueryNode.java (revision 0) |
| @@ -0,0 +1,251 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeError; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link ProximityQueryNode} represents a query where the terms should meet |
| + * specific distance conditions. (a b c) WITHIN [SENTENCE|PARAGRAPH|NUMBER] |
| + * [INORDER] ("a" "b" "c") WITHIN [SENTENCE|PARAGRAPH|NUMBER] [INORDER] |
| + * |
| + * TODO: Add this to the future original Lucene parser/processor/builder |
| + */ |
| +public class ProximityQueryNode extends BooleanQueryNode { |
| + |
| + private static final long serialVersionUID = 9018220596680832916L; |
| + |
| + public enum Type { |
| + PARAGRAPH, SENTENCE, NUMBER; |
| + |
| + CharSequence toQueryString() { |
| + switch (this) { |
| + case PARAGRAPH: |
| + return "WITHIN PARAGRAPH"; |
| + case SENTENCE: |
| + return "WITHIN SENTENCE"; |
| + case NUMBER: |
| + return "WITHIN"; |
| + default: |
| + return "WITHIN SENTENCE"; |
| + } |
| + } |
| + |
| + public String toString() { |
| + switch (this) { |
| + case PARAGRAPH: |
| + return "PARAGRAPH"; |
| + case SENTENCE: |
| + return "SENTENCE"; |
| + case NUMBER: |
| + return "NUMBER"; |
| + default: |
| + return "NUMBER"; |
| + } |
| + } |
| + } |
| + |
| + // utility class |
| + static public class ProximityType { |
| + int pDistance = 0; |
| + |
| + Type pType = null; |
| + |
| + public ProximityType(Type type) { |
| + this(type, 0); |
| + } |
| + |
| + public ProximityType(Type type, int distance) { |
| + this.pType = type; |
| + this.pDistance = distance; |
| + } |
| + } |
| + |
| + private Type proximityType = Type.SENTENCE; |
| + private int distance = -1; |
| + private boolean inorder = false; |
| + private CharSequence field = null; |
| + |
| + /** |
| + * @param clauses |
| + * - QueryNode children |
| + * @param field |
| + * - field name |
| + * @param type |
| + * - type of proximity query |
| + * @param distance |
| + * - positive integer that specifies the distance |
| + * @param inorder |
| + * - true, if the tokens should be matched in the order of the |
| + * clauses |
| + */ |
| + public ProximityQueryNode(List<QueryNode> clauses, CharSequence field, |
| + Type type, int distance, boolean inorder) { |
| + super(clauses); |
| + setLeaf(false); |
| + this.proximityType = type; |
| + this.inorder = inorder; |
| + this.field = field; |
| + if (type == Type.NUMBER) { |
| + if (distance <= 0) { |
| + throw new QueryNodeError(new MessageImpl( |
| + QueryParserMessages.PARAMETER_VALUE_NOT_SUPPORTED, "distance", |
| + distance)); |
| + |
| + } else { |
| + this.distance = distance; |
| + } |
| + |
| + } |
| + clearFields(clauses, field); |
| + } |
| + |
| + /** |
| + * @param clauses |
| + * - QueryNode children |
| + * @param field |
| + * - field name |
| + * @param type |
| + * - type of proximity query |
| + * @param inorder |
| + * - true, if the tokens should be matched in the order of the |
| + * clauses |
| + */ |
| + public ProximityQueryNode(List<QueryNode> clauses, CharSequence field, |
| + Type type, boolean inorder) { |
| + this(clauses, field, type, -1, inorder); |
| + } |
| + |
| + static private void clearFields(List<QueryNode> nodes, CharSequence field) { |
| + if (nodes == null || nodes.size() == 0) |
| + return; |
| + |
| + for (QueryNode clause : nodes) { |
| + |
| + if (clause instanceof FieldQueryNode) { |
| + ((FieldQueryNode) clause).toQueryStringIgnoreFields = true; |
| + ((FieldQueryNode) clause).setField(field); |
| + } |
| + } |
| + } |
| + |
| + public Type getProximityType() { |
| + return this.proximityType; |
| + } |
| + |
| + public String toString() { |
| + String distanceSTR = ((this.distance == -1) ? ("") |
| + : (" distance='" + this.distance) + "'"); |
| + |
| + if (getChildren() == null || getChildren().size() == 0) |
| + return "<proximity field='" + this.field + "' inorder='" + this.inorder |
| + + "' type='" + this.proximityType.toString() + "'" + distanceSTR |
| + + "/>"; |
| + StringBuilder sb = new StringBuilder(); |
| + sb.append("<proximity field='" + this.field + "' inorder='" + this.inorder |
| + + "' type='" + this.proximityType.toString() + "'" + distanceSTR + ">"); |
| + for (QueryNode child : getChildren()) { |
| + sb.append("\n"); |
| + sb.append(child.toString()); |
| + } |
| + sb.append("\n</proximity>"); |
| + return sb.toString(); |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { |
| + String withinSTR = this.proximityType.toQueryString() |
| + + ((this.distance == -1) ? ("") : (" " + this.distance)) |
| + + ((this.inorder) ? (" INORDER") : ("")); |
| + |
| + StringBuilder sb = new StringBuilder(); |
| + if (getChildren() == null || getChildren().size() == 0) { |
| + // no children case |
| + } else { |
| + String filler = ""; |
| + for (QueryNode child : getChildren()) { |
| + sb.append(filler).append(child.toQueryString(escapeSyntaxParser)); |
| + filler = " "; |
| + } |
| + } |
| + |
| + if (isDefaultField(this.field)) { |
| + return "( " + sb.toString() + " ) " + withinSTR; |
| + } else { |
| + return this.field + ":(( " + sb.toString() + " ) " + withinSTR + ")"; |
| + } |
| + } |
| + |
| + public QueryNode cloneTree() throws CloneNotSupportedException { |
| + ProximityQueryNode clone = (ProximityQueryNode) super.cloneTree(); |
| + |
| + clone.proximityType = this.proximityType; |
| + clone.distance = this.distance; |
| + clone.field = this.field; |
| + |
| + return clone; |
| + } |
| + |
| + /** |
| + * @return the distance |
| + */ |
| + public int getDistance() { |
| + return this.distance; |
| + } |
| + |
| + /** |
| + * returns null if the field was not specified in the query string |
| + * |
| + * @return the field |
| + */ |
| + public CharSequence getField() { |
| + return this.field; |
| + } |
| + |
| + /** |
| + * returns null if the field was not specified in the query string |
| + * |
| + * @return the field |
| + */ |
| + public String getFieldAsString() { |
| + if (this.field == null) |
| + return null; |
| + else |
| + return this.field.toString(); |
| + } |
| + |
| + /** |
| + * @param field |
| + * the field to set |
| + */ |
| + public void setField(CharSequence field) { |
| + this.field = field; |
| + } |
| + |
| + /** |
| + * @return terms must be matched in the specified order |
| + */ |
| + public boolean isInOrder() { |
| + return this.inorder; |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/ProximityQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/OrQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/OrQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/OrQueryNode.java (revision 0) |
| @@ -0,0 +1,78 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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 java.util.Iterator; |
| +import java.util.List; |
| + |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link OrQueryNode} represents an OR boolean operation performed on a list |
| + * of nodes. |
| + * |
| + */ |
| +public class OrQueryNode extends BooleanQueryNode { |
| + |
| + private static final long serialVersionUID = -3692323307688017852L; |
| + |
| + /** |
| + * @param clauses |
| + * - the query nodes to be or'ed |
| + */ |
| + public OrQueryNode(List<QueryNode> clauses) { |
| + super(clauses); |
| + if ((clauses == null) || (clauses.size() == 0)) { |
| + throw new IllegalArgumentException( |
| + "OR query must have at least one clause"); |
| + } |
| + } |
| + |
| + public String toString() { |
| + if (getChildren() == null || getChildren().size() == 0) |
| + return "<boolean operation='or'/>"; |
| + StringBuilder sb = new StringBuilder(); |
| + sb.append("<boolean operation='or'>"); |
| + for (QueryNode child : getChildren()) { |
| + sb.append("\n"); |
| + sb.append(child.toString()); |
| + |
| + } |
| + sb.append("\n</boolean>"); |
| + return sb.toString(); |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { |
| + if (getChildren() == null || getChildren().size() == 0) |
| + return ""; |
| + |
| + StringBuilder sb = new StringBuilder(); |
| + String filler = ""; |
| + for (Iterator<QueryNode> it = getChildren().iterator(); it.hasNext();) { |
| + sb.append(filler).append(it.next().toQueryString(escapeSyntaxParser)); |
| + filler = " OR "; |
| + } |
| + |
| + // in case is root or the parent is a group node avoid parenthesis |
| + if ((getParent() != null && getParent() instanceof GroupQueryNode) |
| + || isRoot()) |
| + return sb.toString(); |
| + else |
| + return "( " + sb.toString() + " )"; |
| + } |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/OrQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/PathQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/PathQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/PathQueryNode.java (revision 0) |
| @@ -0,0 +1,214 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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 java.util.ArrayList; |
| +import java.util.List; |
| +import java.util.Locale; |
| + |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax; |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax.Type; |
| + |
| +/** |
| + * A {@link PathQueryNode} is used for to store queries like |
| + * /company/USA/California /product/shoes/brown QueryText are objects that |
| + * contain the text, begin position and end position in the query. |
| + * |
| + * Example how the text parser creates these objects: |
| + * |
| + * List values = ArrayList(); values.add(new PathQueryNode.QueryText("company", |
| + * 1, 7)); values.add(new PathQueryNode.QueryText("USA", 9, 12)); values.add(new |
| + * PathQueryNode.QueryText("California", 14, 23)); QueryNode q = new |
| + * PathQueryNode(values); |
| + * |
| + */ |
| +public class PathQueryNode extends QueryNodeImpl { |
| + |
| + private static final long serialVersionUID = -8325921322405804789L; |
| + |
| + public static class QueryText implements Cloneable { |
| + CharSequence value = null; |
| + /** |
| + * != null The term's begin position. |
| + */ |
| + int begin; |
| + |
| + /** |
| + * The term's end position. |
| + */ |
| + int end; |
| + |
| + /** |
| + * @param value |
| + * - text value |
| + * @param begin |
| + * - position in the query string |
| + * @param end |
| + * - position in the query string |
| + */ |
| + public QueryText(CharSequence value, int begin, int end) { |
| + super(); |
| + this.value = value; |
| + this.begin = begin; |
| + this.end = end; |
| + } |
| + |
| + public QueryText clone() throws CloneNotSupportedException { |
| + QueryText clone = (QueryText) super.clone(); |
| + clone.value = this.value; |
| + clone.begin = this.begin; |
| + clone.end = this.end; |
| + return clone; |
| + } |
| + |
| + /** |
| + * @return the value |
| + */ |
| + public CharSequence getValue() { |
| + return value; |
| + } |
| + |
| + /** |
| + * @return the begin |
| + */ |
| + public int getBegin() { |
| + return begin; |
| + } |
| + |
| + /** |
| + * @return the end |
| + */ |
| + public int getEnd() { |
| + return end; |
| + } |
| + |
| + public String toString() { |
| + return value + ", " + begin + ", " + end; |
| + } |
| + } |
| + |
| + private List<QueryText> values = null; |
| + |
| + /** |
| + * @param pathElements |
| + * - List of QueryText objects |
| + */ |
| + public PathQueryNode(List<QueryText> pathElements) { |
| + this.values = pathElements; |
| + if (pathElements.size() <= 1) { |
| + // this should not happen |
| + throw new RuntimeException( |
| + "PathQuerynode requires more 2 or more path elements."); |
| + } |
| + } |
| + |
| + /** |
| + * Returns the a List with all QueryText elements |
| + * |
| + * @return QueryText List size |
| + */ |
| + public List<QueryText> getPathElements() { |
| + return values; |
| + } |
| + |
| + /** |
| + * Returns the a List with all QueryText elements |
| + */ |
| + public void setPathElements(List<QueryText> elements) { |
| + this.values = elements; |
| + } |
| + |
| + /** |
| + * Returns the a specific QueryText element |
| + * |
| + * @return QueryText List size |
| + */ |
| + public QueryText getPathElement(int index) { |
| + return values.get(index); |
| + } |
| + |
| + /** |
| + * Returns the CharSequence value of a specific QueryText element |
| + * |
| + * @return the CharSequence for a specific QueryText element |
| + */ |
| + public CharSequence getFirstPathElement() { |
| + return values.get(0).value; |
| + } |
| + |
| + /** |
| + * Returns a List QueryText element from position startIndex |
| + * |
| + * @return a List QueryText element from position startIndex |
| + */ |
| + public List<QueryText> getPathElements(int startIndex) { |
| + List<PathQueryNode.QueryText> rValues = new ArrayList<PathQueryNode.QueryText>(); |
| + for (int i = startIndex; i < this.values.size(); i++) { |
| + try { |
| + rValues.add(this.values.get(i).clone()); |
| + } catch (CloneNotSupportedException e) { |
| + // this will not happen |
| + } |
| + } |
| + return rValues; |
| + } |
| + |
| + private CharSequence getPathString() { |
| + StringBuffer path = new StringBuffer(); |
| + |
| + for (QueryText pathelement : values) { |
| + path.append("/").append(pathelement.value); |
| + } |
| + return path.toString(); |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escaper) { |
| + StringBuffer path = new StringBuffer(); |
| + path.append("/").append(getFirstPathElement()); |
| + |
| + for (QueryText pathelement : getPathElements(1)) { |
| + CharSequence value = escaper.escape(pathelement.value, Locale |
| + .getDefault(), Type.STRING); |
| + path.append("/\"").append(value).append("\""); |
| + } |
| + return path.toString(); |
| + } |
| + |
| + public String toString() { |
| + QueryText text = this.values.get(0); |
| + |
| + return "<path start='" + text.begin + "' end='" + text.end + "' path='" |
| + + getPathString() + "'/>"; |
| + } |
| + |
| + public QueryNode cloneTree() throws CloneNotSupportedException { |
| + PathQueryNode clone = (PathQueryNode) super.cloneTree(); |
| + |
| + // copy children |
| + if (this.values != null) { |
| + List<QueryText> localValues = new ArrayList<QueryText>(); |
| + for (QueryText value : this.values) { |
| + localValues.add(value.clone()); |
| + } |
| + clone.values = localValues; |
| + } |
| + |
| + return clone; |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/PathQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/FuzzyQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/FuzzyQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/FuzzyQueryNode.java (revision 0) |
| @@ -0,0 +1,98 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link FuzzyQueryNode} represents a element that contains |
| + * field/text/similarity tuple |
| + */ |
| +public class FuzzyQueryNode extends FieldQueryNode { |
| + |
| + private static final long serialVersionUID = -1794537213032589441L; |
| + |
| + private float similarity; |
| + |
| + private int prefixLength; |
| + |
| + /** |
| + * @param field |
| + * Name of the field query will use. |
| + * @param termStr |
| + * Term token to use for building term for the query |
| + */ |
| + /** |
| + * @param field |
| + * - Field name |
| + * @param term |
| + * - Value |
| + * @param minSimilarity |
| + * - similarity value |
| + * @param begin |
| + * - position in the query string |
| + * @param end |
| + * - position in the query string |
| + */ |
| + public FuzzyQueryNode(CharSequence field, CharSequence term, |
| + float minSimilarity, int begin, int end) { |
| + super(field, term, begin, end); |
| + this.similarity = minSimilarity; |
| + setLeaf(true); |
| + } |
| + |
| + public void setPrefixLength(int prefixLength) { |
| + this.prefixLength = prefixLength; |
| + } |
| + |
| + public int getPrefixLength() { |
| + return this.prefixLength; |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escaper) { |
| + if (isDefaultField(this.field)) { |
| + return getTermEscaped(escaper) + "~" + this.similarity; |
| + } else { |
| + return this.field + ":" + getTermEscaped(escaper) + "~" + this.similarity; |
| + } |
| + } |
| + |
| + public String toString() { |
| + return "<fuzzy field='" + this.field + "' similarity='" + this.similarity |
| + + "' term='" + this.text + "'/>"; |
| + } |
| + |
| + public void setSimilarity(float similarity) { |
| + this.similarity = similarity; |
| + } |
| + |
| + public FuzzyQueryNode cloneTree() throws CloneNotSupportedException { |
| + FuzzyQueryNode clone = (FuzzyQueryNode) super.cloneTree(); |
| + |
| + clone.similarity = this.similarity; |
| + |
| + return clone; |
| + } |
| + |
| + /** |
| + * @return the similarity |
| + */ |
| + public float getSimilarity() { |
| + return this.similarity; |
| + } |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/FuzzyQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/ParametricQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/ParametricQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/ParametricQueryNode.java (revision 0) |
| @@ -0,0 +1,100 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link ParametricQueryNode} represents LE, LT, GE, GT, EQ, NE query. |
| + * Example: date >= "2009-10-10" OR price = 200 |
| + */ |
| +public class ParametricQueryNode extends FieldQueryNode { |
| + |
| + private static final long serialVersionUID = -5770038129741218116L; |
| + |
| + private CompareOperator operator; |
| + |
| + public enum CompareOperator { |
| + LE, LT, GE, GT, EQ, NE; |
| + |
| + public String toString() { |
| + if (LE.equals(this)) { |
| + return "<="; |
| + } else if (LT.equals(this)) { |
| + return "<"; |
| + } else if (GE.equals(this)) { |
| + return ">="; |
| + } else if (GT.equals(this)) { |
| + return ">"; |
| + } else if (EQ.equals(this)) { |
| + return "="; |
| + } else if (NE.equals(this)) { |
| + return "!="; |
| + } else { |
| + throw new IllegalArgumentException("Unknown operator"); |
| + } |
| + } |
| + } |
| + |
| + /** |
| + * @param field |
| + * - field name |
| + * @param comp |
| + * - CompareOperator |
| + * @param value |
| + * - text value |
| + * @param begin |
| + * - position in the query string |
| + * @param end |
| + * - position in the query string |
| + */ |
| + public ParametricQueryNode(CharSequence field, CompareOperator comp, |
| + CharSequence value, int begin, int end) { |
| + super(field, value, begin, end); |
| + this.operator = comp; |
| + setLeaf(true); |
| + } |
| + |
| + public CharSequence getOperand() { |
| + return getText(); |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { |
| + return this.field + "" + this.operator.toString() + "\"" + this.text + "\""; |
| + } |
| + |
| + public String toString() { |
| + return "<parametric field='" + this.field + "' operator='" |
| + + this.operator.toString() + "' text='" + this.text + "'/>"; |
| + } |
| + |
| + public ParametricQueryNode cloneTree() throws CloneNotSupportedException { |
| + ParametricQueryNode clone = (ParametricQueryNode) super.cloneTree(); |
| + |
| + clone.operator = this.operator; |
| + |
| + return clone; |
| + } |
| + |
| + /** |
| + * @return the operator |
| + */ |
| + public CompareOperator getOperator() { |
| + return this.operator; |
| + } |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/ParametricQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/PrefixWildcardQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/PrefixWildcardQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/PrefixWildcardQueryNode.java (revision 0) |
| @@ -0,0 +1,57 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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. |
| + */ |
| + |
| +/** |
| + * A {@link PrefixWildcardQueryNode} represents wildcardquery that matches abc* |
| + * or *. This does not apply to phrases, this is a special case on the original |
| + * lucene parser. TODO: refactor the code to remove this special case from the |
| + * parser. and probably do it on a Processor |
| + */ |
| +public class PrefixWildcardQueryNode extends WildcardQueryNode { |
| + |
| + private static final long serialVersionUID = 6851557641826407515L; |
| + |
| + /** |
| + * @param field |
| + * - field name |
| + * @param text |
| + * - value including the wildcard |
| + * @param begin |
| + * - position in the query string |
| + * @param end |
| + * - position in the query string |
| + */ |
| + public PrefixWildcardQueryNode(CharSequence field, CharSequence text, |
| + int begin, int end) { |
| + super(field, text, begin, end); |
| + } |
| + |
| + public String toString() { |
| + return "<prefixWildcard field='" + this.field + "' term='" + this.text |
| + + "'/>"; |
| + } |
| + |
| + public PrefixWildcardQueryNode cloneTree() throws CloneNotSupportedException { |
| + PrefixWildcardQueryNode clone = (PrefixWildcardQueryNode) super.cloneTree(); |
| + |
| + // nothing to do here |
| + |
| + return clone; |
| + } |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/PrefixWildcardQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/PhraseSlopQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/PhraseSlopQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/PhraseSlopQueryNode.java (revision 0) |
| @@ -0,0 +1,108 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeError; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax; |
| + |
| +public class PhraseSlopQueryNode extends QueryNodeImpl implements FieldableNode { |
| + |
| + private static final long serialVersionUID = 0L; |
| + |
| + private int value = 0; |
| + |
| + /** |
| + * @throws QueryNodeException |
| + * @throws QueryNodeParseException |
| + * @exception QueryNodeParseException |
| + * throw in overridden method to disallow |
| + */ |
| + public PhraseSlopQueryNode(QueryNode query, int value) |
| + throws QueryNodeException { |
| + if (query == null) { |
| + throw new QueryNodeError(new MessageImpl( |
| + QueryParserMessages.NODE_ACTION_NOT_SUPPORTED, "query", "null")); |
| + } |
| + |
| + this.value = value; |
| + setLeaf(false); |
| + allocate(); |
| + add(query); |
| + } |
| + |
| + public QueryNode getChild() { |
| + return getChildren().get(0); |
| + } |
| + |
| + public int getValue() { |
| + return this.value; |
| + } |
| + |
| + private CharSequence getValueString() { |
| + Float f = new Float(this.value); |
| + if (f == f.longValue()) |
| + return "" + f.longValue(); |
| + else |
| + return "" + f; |
| + |
| + } |
| + |
| + public String toString() { |
| + return "<phraseslop value='" + getValueString() + "'>" + "\n" |
| + + getChild().toString() + "\n</phraseslop>"; |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { |
| + if (getChild() == null) |
| + return ""; |
| + return getChild().toQueryString(escapeSyntaxParser) + "~" |
| + + getValueString(); |
| + } |
| + |
| + public QueryNode cloneTree() throws CloneNotSupportedException { |
| + PhraseSlopQueryNode clone = (PhraseSlopQueryNode) super.cloneTree(); |
| + |
| + clone.value = this.value; |
| + |
| + return clone; |
| + } |
| + |
| + public CharSequence getField() { |
| + QueryNode child = getChild(); |
| + |
| + if (child instanceof FieldableNode) { |
| + return ((FieldableNode) child).getField(); |
| + } |
| + |
| + return null; |
| + |
| + } |
| + |
| + public void setField(CharSequence fieldName) { |
| + QueryNode child = getChild(); |
| + |
| + if (child instanceof FieldableNode) { |
| + ((FieldableNode) child).setField(fieldName); |
| + } |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/PhraseSlopQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/TokenizedPhraseQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/TokenizedPhraseQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/TokenizedPhraseQueryNode.java (revision 0) |
| @@ -0,0 +1,104 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link TokenizedPhraseQueryNode} represents a node created by a code that |
| + * tokenizes/lemmatizes/analizes. |
| + */ |
| +public class TokenizedPhraseQueryNode extends QueryNodeImpl implements |
| + FieldableNode { |
| + |
| + private static final long serialVersionUID = -7185108320787917541L; |
| + |
| + public TokenizedPhraseQueryNode() { |
| + setLeaf(false); |
| + allocate(); |
| + } |
| + |
| + public String toString() { |
| + if (getChildren() == null || getChildren().size() == 0) |
| + return "<tokenizedphrase/>"; |
| + StringBuilder sb = new StringBuilder(); |
| + sb.append("<tokenizedtphrase>"); |
| + for (QueryNode child : getChildren()) { |
| + sb.append("\n"); |
| + sb.append(child.toString()); |
| + } |
| + sb.append("\n</tokenizedphrase>"); |
| + return sb.toString(); |
| + } |
| + |
| + // This text representation is not re-parseable |
| + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { |
| + if (getChildren() == null || getChildren().size() == 0) |
| + return ""; |
| + |
| + StringBuilder sb = new StringBuilder(); |
| + String filler = ""; |
| + for (QueryNode child : getChildren()) { |
| + sb.append(filler).append(child.toQueryString(escapeSyntaxParser)); |
| + filler = ","; |
| + } |
| + |
| + return "[TP[" + sb.toString() + "]]"; |
| + } |
| + |
| + public QueryNode cloneTree() throws CloneNotSupportedException { |
| + TokenizedPhraseQueryNode clone = (TokenizedPhraseQueryNode) super |
| + .cloneTree(); |
| + |
| + // nothing to do |
| + |
| + return clone; |
| + } |
| + |
| + public CharSequence getField() { |
| + List<QueryNode> children = getChildren(); |
| + |
| + if (children == null || children.size() == 0) { |
| + return null; |
| + |
| + } else { |
| + return ((FieldableNode) children.get(0)).getField(); |
| + } |
| + |
| + } |
| + |
| + public void setField(CharSequence fieldName) { |
| + List<QueryNode> children = getChildren(); |
| + |
| + if (children != null) { |
| + |
| + for (QueryNode child : getChildren()) { |
| + |
| + if (child instanceof FieldableNode) { |
| + ((FieldableNode) child).setField(fieldName); |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| +} // end class MultitermQueryNode |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/TokenizedPhraseQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/DeletedQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/DeletedQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/DeletedQueryNode.java (revision 0) |
| @@ -0,0 +1,51 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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.parser.EscapeQuerySyntax; |
| +import org.apache.lucene.queryParser.processors.RemoveDeletedQueryNodesProcessor; |
| + |
| +/** |
| + * A {@link DeletedQueryNode} represents a node that was deleted from the query |
| + * node tree. It can be removed from the tree using the |
| + * {@link RemoveDeletedQueryNodesProcessor} processor. |
| + */ |
| +public class DeletedQueryNode extends QueryNodeImpl { |
| + |
| + private static final long serialVersionUID = -9151675506000425293L; |
| + |
| + public DeletedQueryNode() { |
| + // empty constructor |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escaper) { |
| + return "[DELETEDCHILD]"; |
| + } |
| + |
| + public String toString() { |
| + return "<deleted/>"; |
| + } |
| + |
| + public QueryNode cloneTree() throws CloneNotSupportedException { |
| + DeletedQueryNode clone = (DeletedQueryNode) super.cloneTree(); |
| + |
| + return clone; |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/DeletedQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/QueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/QueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/QueryNode.java (revision 0) |
| @@ -0,0 +1,95 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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 java.io.Serializable; |
| +import java.util.List; |
| +import java.util.Map; |
| + |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link QueryNode} is a interface implemented by all nodes on a QueryNode |
| + * tree. |
| + */ |
| +public interface QueryNode extends Serializable { |
| + |
| + /** convert to a query string understood by the query parser */ |
| + // TODO: this interface might be changed in the future |
| + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser); |
| + |
| + /** for printing */ |
| + public String toString(); |
| + |
| + /** get Children nodes */ |
| + public List<QueryNode> getChildren(); |
| + |
| + /** verify if a node is a Leaf node */ |
| + public boolean isLeaf(); |
| + |
| + /** verify if a node contains a tag */ |
| + public boolean containsTag(CharSequence tagName); |
| + |
| + /** |
| + * @param tagName |
| + * @return of stored on under that tag name |
| + */ |
| + public Object getTag(CharSequence tagName); |
| + |
| + public QueryNode getParent(); |
| + |
| + /** |
| + * Recursive clone the QueryNode tree The tags are not copied to the new tree |
| + * when you call the cloneTree() method |
| + * |
| + * @return the cloned tree |
| + * @throws CloneNotSupportedException |
| + */ |
| + public QueryNode cloneTree() throws CloneNotSupportedException; |
| + |
| + // Below are the methods that can change state of a QueryNode |
| + // Write Operations (not Thread Safe) |
| + |
| + // add a new child to a non Leaf node |
| + public void add(QueryNode child); |
| + |
| + public void add(List<QueryNode> children); |
| + |
| + // reset the children of a node |
| + public void set(List<QueryNode> children); |
| + |
| + /** |
| + * Associate the specified value with the specified tagName. If the tagName |
| + * already exists, the old value is replaced. The tagName and value cannot be |
| + * null. tagName will be converted to lowercase. |
| + * |
| + * @param tagName |
| + * @param value |
| + */ |
| + public void setTag(CharSequence tagName, Object value); |
| + |
| + /** |
| + * Unset a tag. tagName will be converted to lowercase. |
| + * |
| + * @param tagName |
| + */ |
| + public void unsetTag(CharSequence tagName); |
| + |
| + public Map<CharSequence, Object> getTags(); |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/QueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/FieldQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/FieldQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/FieldQueryNode.java (revision 0) |
| @@ -0,0 +1,184 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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 java.util.Locale; |
| + |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax; |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax.Type; |
| + |
| +/** |
| + * A {@link FieldQueryNode} represents a element that contains field/text tuple |
| + */ |
| +public class FieldQueryNode extends QueryNodeImpl implements TextableQueryNode, |
| + FieldableNode { |
| + |
| + private static final long serialVersionUID = 3634521145130758265L; |
| + |
| + /** |
| + * The term's field |
| + */ |
| + protected CharSequence field; |
| + |
| + /** |
| + * The term's text. |
| + */ |
| + protected CharSequence text; |
| + |
| + /** |
| + * The term's begin position. |
| + */ |
| + protected int begin; |
| + |
| + /** |
| + * The term's end position. |
| + */ |
| + protected int end; |
| + |
| + /** |
| + * The term's position increment. |
| + */ |
| + protected int positionIncrement; |
| + |
| + /** |
| + * @param field |
| + * - field name |
| + * @param text |
| + * - value |
| + * @param begin |
| + * - position in the query string |
| + * @param end |
| + * - position in the query string |
| + */ |
| + public FieldQueryNode(CharSequence field, CharSequence text, int begin, |
| + int end) { |
| + this.field = field; |
| + this.text = text; |
| + this.begin = begin; |
| + this.end = end; |
| + this.setLeaf(true); |
| + |
| + } |
| + |
| + CharSequence getTermEscaped(EscapeQuerySyntax escaper) { |
| + return escaper.escape(this.text, Locale.getDefault(), Type.NORMAL); |
| + } |
| + |
| + CharSequence getTermEscapeQuoted(EscapeQuerySyntax escaper) { |
| + return escaper.escape(this.text, Locale.getDefault(), Type.STRING); |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escaper) { |
| + if (isDefaultField(this.field)) { |
| + return getTermEscaped(escaper); |
| + } else { |
| + return this.field + ":" + getTermEscaped(escaper); |
| + } |
| + } |
| + |
| + public String toString() { |
| + return "<field start='" + this.begin + "' end='" + this.end + "' field='" |
| + + this.field + "' text='" + this.text + "'/>"; |
| + } |
| + |
| + /** |
| + * @return the term |
| + */ |
| + public String getTextAsString() { |
| + if (this.text == null) |
| + return null; |
| + else |
| + return this.text.toString(); |
| + } |
| + |
| + /** |
| + * returns null if the field was not specified in the query string |
| + * |
| + * @return the field |
| + */ |
| + public String getFieldAsString() { |
| + if (this.field == null) |
| + return null; |
| + else |
| + return this.field.toString(); |
| + } |
| + |
| + public int getBegin() { |
| + return this.begin; |
| + } |
| + |
| + public void setBegin(int begin) { |
| + this.begin = begin; |
| + } |
| + |
| + public int getEnd() { |
| + return this.end; |
| + } |
| + |
| + public void setEnd(int end) { |
| + this.end = end; |
| + } |
| + |
| + public CharSequence getField() { |
| + return this.field; |
| + } |
| + |
| + public void setField(CharSequence field) { |
| + this.field = field; |
| + } |
| + |
| + public int getPositionIncrement() { |
| + return this.positionIncrement; |
| + } |
| + |
| + public void setPositionIncrement(int pi) { |
| + this.positionIncrement = pi; |
| + } |
| + |
| + /** |
| + * Returns the term. |
| + * |
| + * @return The "original" form of the term. |
| + */ |
| + public CharSequence getText() { |
| + return this.text; |
| + } |
| + |
| + /** |
| + * @param text |
| + * the text to set |
| + */ |
| + public void setText(CharSequence text) { |
| + this.text = text; |
| + } |
| + |
| + @Override |
| + public FieldQueryNode cloneTree() throws CloneNotSupportedException { |
| + FieldQueryNode fqn = (FieldQueryNode) super.cloneTree(); |
| + fqn.begin = this.begin; |
| + fqn.end = this.end; |
| + fqn.field = this.field; |
| + fqn.text = this.text; |
| + fqn.positionIncrement = this.positionIncrement; |
| + fqn.toQueryStringIgnoreFields = this.toQueryStringIgnoreFields; |
| + |
| + return fqn; |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/FieldQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/BoostQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/BoostQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/BoostQueryNode.java (revision 0) |
| @@ -0,0 +1,122 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeError; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link BoostQueryNode} boosts the QueryNode tree which is under this node. |
| + * So, it must only and always have one child. |
| + * |
| + * The boost value may vary from 0.0 to 1.0. |
| + * |
| + */ |
| +public class BoostQueryNode extends QueryNodeImpl { |
| + |
| + private static final long serialVersionUID = -3929082630855807593L; |
| + |
| + private float value = 0; |
| + |
| + /** |
| + * Constructs a boost node |
| + * |
| + * @param query |
| + * the query to be boosted |
| + * @param value |
| + * the boost value, it may vary from 0.0 to 1.0 |
| + * |
| + * @throws QueryNodeException |
| + */ |
| + public BoostQueryNode(QueryNode query, float value) throws QueryNodeException { |
| + if (query == null) { |
| + throw new QueryNodeError(new MessageImpl( |
| + QueryParserMessages.NODE_ACTION_NOT_SUPPORTED, "query", "null")); |
| + } |
| + |
| + this.value = value; |
| + setLeaf(false); |
| + allocate(); |
| + add(query); |
| + } |
| + |
| + /** |
| + * Returns the single child which this node boosts. |
| + * |
| + * @return the single child which this node boosts |
| + */ |
| + public QueryNode getChild() { |
| + List<QueryNode> children = getChildren(); |
| + |
| + if (children == null || children.size() == 0) { |
| + return null; |
| + } |
| + |
| + return children.get(0); |
| + |
| + } |
| + |
| + /** |
| + * Returns the boost value. It may vary from 0.0 to 1.0. |
| + * |
| + * @return the boost value |
| + */ |
| + public float getValue() { |
| + return this.value; |
| + } |
| + |
| + /** |
| + * Returns the boost value parsed to a string. |
| + * |
| + * @return the parsed value |
| + */ |
| + private CharSequence getValueString() { |
| + Float f = new Float(this.value); |
| + if (f == f.longValue()) |
| + return "" + f.longValue(); |
| + else |
| + return "" + f; |
| + |
| + } |
| + |
| + public String toString() { |
| + return "<boost value='" + getValueString() + "'>" + "\n" |
| + + getChild().toString() + "\n</boost>"; |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { |
| + if (getChild() == null) |
| + return ""; |
| + return getChild().toQueryString(escapeSyntaxParser) + "^" |
| + + getValueString(); |
| + } |
| + |
| + public QueryNode cloneTree() throws CloneNotSupportedException { |
| + BoostQueryNode clone = (BoostQueryNode) super.cloneTree(); |
| + |
| + clone.value = this.value; |
| + |
| + return clone; |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/BoostQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/SlopQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/SlopQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/SlopQueryNode.java (revision 0) |
| @@ -0,0 +1,116 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeError; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link SlopQueryNode} represents phrase query with a slop. |
| + * |
| + * From Lucene FAQ: Is there a way to use a proximity operator (like near or |
| + * within) with Lucene? There is a variable called slop that allows you to |
| + * perform NEAR/WITHIN-like queries. By default, slop is set to 0 so that only |
| + * exact phrases will match. When using TextParser you can use this syntax to |
| + * specify the slop: "doug cutting"~2 will find documents that contain |
| + * "doug cutting" as well as ones that contain "cutting doug". |
| + */ |
| +public class SlopQueryNode extends QueryNodeImpl implements FieldableNode { |
| + |
| + private static final long serialVersionUID = 0L; |
| + |
| + private int value = 0; |
| + |
| + /** |
| + * @param query |
| + * - QueryNode Tree with the phrase |
| + * @param value |
| + * - slop value |
| + */ |
| + public SlopQueryNode(QueryNode query, int value) { |
| + if (query == null) { |
| + throw new QueryNodeError(new MessageImpl( |
| + QueryParserMessages.NODE_ACTION_NOT_SUPPORTED, "query", "null")); |
| + } |
| + |
| + this.value = value; |
| + setLeaf(false); |
| + allocate(); |
| + add(query); |
| + } |
| + |
| + public QueryNode getChild() { |
| + return getChildren().get(0); |
| + } |
| + |
| + public int getValue() { |
| + return this.value; |
| + } |
| + |
| + private CharSequence getValueString() { |
| + Float f = new Float(this.value); |
| + if (f == f.longValue()) |
| + return "" + f.longValue(); |
| + else |
| + return "" + f; |
| + |
| + } |
| + |
| + public String toString() { |
| + return "<slop value='" + getValueString() + "'>" + "\n" |
| + + getChild().toString() + "\n</slop>"; |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { |
| + if (getChild() == null) |
| + return ""; |
| + return getChild().toQueryString(escapeSyntaxParser) + "~" |
| + + getValueString(); |
| + } |
| + |
| + public QueryNode cloneTree() throws CloneNotSupportedException { |
| + SlopQueryNode clone = (SlopQueryNode) super.cloneTree(); |
| + |
| + clone.value = this.value; |
| + |
| + return clone; |
| + } |
| + |
| + public CharSequence getField() { |
| + QueryNode child = getChild(); |
| + |
| + if (child instanceof FieldableNode) { |
| + return ((FieldableNode) child).getField(); |
| + } |
| + |
| + return null; |
| + |
| + } |
| + |
| + public void setField(CharSequence fieldName) { |
| + QueryNode child = getChild(); |
| + |
| + if (child instanceof FieldableNode) { |
| + ((FieldableNode) child).setField(fieldName); |
| + } |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/SlopQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/AndQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/AndQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/AndQueryNode.java (revision 0) |
| @@ -0,0 +1,77 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link AndQueryNode} represents an AND boolean operation performed on a |
| + * list of nodes. |
| + */ |
| +public class AndQueryNode extends BooleanQueryNode { |
| + |
| + private static final long serialVersionUID = 118496077529151825L; |
| + |
| + /** |
| + * @param clauses |
| + * - the query nodes to be and'ed |
| + */ |
| + public AndQueryNode(List<QueryNode> clauses) { |
| + super(clauses); |
| + if ((clauses == null) || (clauses.size() == 0)) { |
| + throw new IllegalArgumentException( |
| + "AND query must have at least one clause"); |
| + } |
| + } |
| + |
| + public String toString() { |
| + if (getChildren() == null || getChildren().size() == 0) |
| + return "<boolean operation='and'/>"; |
| + StringBuilder sb = new StringBuilder(); |
| + sb.append("<boolean operation='and'>"); |
| + for (QueryNode child : getChildren()) { |
| + sb.append("\n"); |
| + sb.append(child.toString()); |
| + |
| + } |
| + sb.append("\n</boolean>"); |
| + return sb.toString(); |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { |
| + if (getChildren() == null || getChildren().size() == 0) |
| + return ""; |
| + |
| + StringBuilder sb = new StringBuilder(); |
| + String filler = ""; |
| + for (QueryNode child : getChildren()) { |
| + sb.append(filler).append(child.toQueryString(escapeSyntaxParser)); |
| + filler = " AND "; |
| + } |
| + |
| + // in case is root or the parent is a group node avoid parenthesis |
| + if ((getParent() != null && getParent() instanceof GroupQueryNode) |
| + || isRoot()) |
| + return sb.toString(); |
| + else |
| + return "( " + sb.toString() + " )"; |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/AndQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/BooleanQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/BooleanQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/BooleanQueryNode.java (revision 0) |
| @@ -0,0 +1,83 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link BooleanQueryNode} represents a list of elements which do not have an |
| + * explicit boolean operator defined between them. It can be used to express a |
| + * boolean query that intends to use the default boolean operator. |
| + */ |
| +public class BooleanQueryNode extends QueryNodeImpl { |
| + |
| + private static final long serialVersionUID = -2206623652088638072L; |
| + |
| + /** |
| + * @param clauses |
| + * - the query nodes to be and'ed |
| + */ |
| + public BooleanQueryNode(List<QueryNode> clauses) { |
| + setLeaf(false); |
| + allocate(); |
| + set(clauses); |
| + } |
| + |
| + public String toString() { |
| + if (getChildren() == null || getChildren().size() == 0) |
| + return "<boolean operation='default'/>"; |
| + StringBuilder sb = new StringBuilder(); |
| + sb.append("<boolean operation='default'>"); |
| + for (QueryNode child : getChildren()) { |
| + sb.append("\n"); |
| + sb.append(child.toString()); |
| + } |
| + sb.append("\n</boolean>"); |
| + return sb.toString(); |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { |
| + if (getChildren() == null || getChildren().size() == 0) |
| + return ""; |
| + |
| + StringBuilder sb = new StringBuilder(); |
| + String filler = ""; |
| + for (QueryNode child : getChildren()) { |
| + sb.append(filler).append(child.toQueryString(escapeSyntaxParser)); |
| + filler = " "; |
| + } |
| + |
| + // in case is root or the parent is a group node avoid parenthesis |
| + if ((getParent() != null && getParent() instanceof GroupQueryNode) |
| + || isRoot()) |
| + return sb.toString(); |
| + else |
| + return "( " + sb.toString() + " )"; |
| + } |
| + |
| + public QueryNode cloneTree() throws CloneNotSupportedException { |
| + BooleanQueryNode clone = (BooleanQueryNode) super.cloneTree(); |
| + |
| + // nothing to do here |
| + |
| + return clone; |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/BooleanQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/FieldableNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/FieldableNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/FieldableNode.java (revision 0) |
| @@ -0,0 +1,45 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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. |
| + */ |
| + |
| +/** |
| + * A query node implements {@link FieldableNode} interface to indicate that its |
| + * children and itself are associated to a specific field. |
| + * |
| + * If it has any children which also implements this interface, it must ensure |
| + * the children are associated to the same field. |
| + * |
| + */ |
| +public interface FieldableNode extends QueryNode { |
| + |
| + /** |
| + * Returns the field associated to the node and every node under it. |
| + * |
| + * @return the field name |
| + */ |
| + CharSequence getField(); |
| + |
| + /** |
| + * Associates the node to a field. |
| + * |
| + * @param fieldName |
| + * the field name |
| + */ |
| + void setField(CharSequence fieldName); |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/FieldableNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/ModifierQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/ModifierQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/ModifierQueryNode.java (revision 0) |
| @@ -0,0 +1,156 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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 java.util.ArrayList; |
| +import java.util.List; |
| + |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeError; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link ModifierQueryNode} indicates the modifier value (+,-,?,NONE) for |
| + * each term on the query string for example "+t1 -t2 t3" will have a tree of |
| + * <BooleanQueryNode> <ModifierQueryNode modifier="MOD_REQ"> <t1/> |
| + * </ModifierQueryNode> <ModifierQueryNode modifier="MOD_NOT"> <t2/> |
| + * </ModifierQueryNode> <t3/> </BooleanQueryNode> |
| + * |
| + */ |
| +public class ModifierQueryNode extends QueryNodeImpl { |
| + |
| + private static final long serialVersionUID = -391209837953928169L; |
| + |
| + public enum Modifier { |
| + MOD_NONE, MOD_NOT, MOD_REQ; |
| + |
| + public String toString() { |
| + switch (this) { |
| + case MOD_NONE: |
| + return "MOD_NONE"; |
| + case MOD_NOT: |
| + return "MOD_NOT"; |
| + case MOD_REQ: |
| + return "MOD_REQ"; |
| + } |
| + // this code is never executed |
| + return "MOD_DEFAULT"; |
| + } |
| + |
| + public String toDigitString() { |
| + switch (this) { |
| + case MOD_NONE: |
| + return ""; |
| + case MOD_NOT: |
| + return "-"; |
| + case MOD_REQ: |
| + return "+"; |
| + } |
| + // this code is never executed |
| + return ""; |
| + } |
| + |
| + public String toLargeString() { |
| + switch (this) { |
| + case MOD_NONE: |
| + return ""; |
| + case MOD_NOT: |
| + return "NOT "; |
| + case MOD_REQ: |
| + return "+"; |
| + } |
| + // this code is never executed |
| + return ""; |
| + } |
| + } |
| + |
| + private Modifier modifier = Modifier.MOD_NONE; |
| + |
| + /** |
| + * Used to store the modifier value on the original query string |
| + * |
| + * @param query |
| + * - QueryNode subtree |
| + * @param mod |
| + * - Modifier Value |
| + */ |
| + public ModifierQueryNode(QueryNode query, Modifier mod) { |
| + if (query == null) { |
| + throw new QueryNodeError(new MessageImpl( |
| + QueryParserMessages.PARAMETER_VALUE_NOT_SUPPORTED, "query", "null")); |
| + } |
| + |
| + allocate(); |
| + setLeaf(false); |
| + add(query); |
| + this.modifier = mod; |
| + } |
| + |
| + public QueryNode getChild() { |
| + return getChildren().get(0); |
| + } |
| + |
| + public Modifier getModifier() { |
| + return this.modifier; |
| + } |
| + |
| + public String toString() { |
| + return "<modifier operation='" + this.modifier.toString() + "'>" + "\n" |
| + + getChild().toString() + "\n</modifier>"; |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { |
| + if (getChild() == null) |
| + return ""; |
| + |
| + String leftParenthensis = ""; |
| + String rightParenthensis = ""; |
| + |
| + if (getChild() != null && getChild() instanceof ModifierQueryNode) { |
| + leftParenthensis = "("; |
| + rightParenthensis = ")"; |
| + } |
| + |
| + if (getChild() instanceof BooleanQueryNode) { |
| + return this.modifier.toLargeString() + leftParenthensis |
| + + getChild().toQueryString(escapeSyntaxParser) + rightParenthensis; |
| + } else { |
| + return this.modifier.toDigitString() + leftParenthensis |
| + + getChild().toQueryString(escapeSyntaxParser) + rightParenthensis; |
| + } |
| + } |
| + |
| + public QueryNode cloneTree() throws CloneNotSupportedException { |
| + ModifierQueryNode clone = (ModifierQueryNode) super.cloneTree(); |
| + |
| + clone.modifier = this.modifier; |
| + |
| + return clone; |
| + } |
| + |
| + /** |
| + * @param child |
| + */ |
| + public void setChild(QueryNode child) { |
| + List<QueryNode> list = new ArrayList<QueryNode>(); |
| + list.add(child); |
| + this.set(list); |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/ModifierQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/WildcardQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/WildcardQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/WildcardQueryNode.java (revision 0) |
| @@ -0,0 +1,63 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link WildcardQueryNode} represents wildcard query This does not apply to |
| + * phrases. Examples: a*b*c Fl?w? m?ke*g |
| + */ |
| +public class WildcardQueryNode extends FieldQueryNode { |
| + private static final long serialVersionUID = 0L; |
| + |
| + /** |
| + * @param field |
| + * - field name |
| + * @param text |
| + * - value that contains one or more wild card characters (? or *) |
| + * @param begin |
| + * - position in the query string |
| + * @param end |
| + * - position in the query string |
| + */ |
| + public WildcardQueryNode(CharSequence field, CharSequence text, int begin, |
| + int end) { |
| + super(field, text, begin, end); |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escaper) { |
| + if (isDefaultField(this.field)) { |
| + return getTermEscaped(escaper); |
| + } else { |
| + return this.field + ":" + getTermEscaped(escaper); |
| + } |
| + } |
| + |
| + public String toString() { |
| + return "<wildcard field='" + this.field + "' term='" + this.text + "'/>"; |
| + } |
| + |
| + public WildcardQueryNode cloneTree() throws CloneNotSupportedException { |
| + WildcardQueryNode clone = (WildcardQueryNode) super.cloneTree(); |
| + |
| + // nothing to do here |
| + |
| + return clone; |
| + } |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/WildcardQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/NoTokenFoundQueryNode.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/NoTokenFoundQueryNode.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/NoTokenFoundQueryNode.java (revision 0) |
| @@ -0,0 +1,49 @@ |
| +package org.apache.lucene.queryParser.nodes; |
| + |
| +/** |
| + * 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.parser.EscapeQuerySyntax; |
| + |
| +/** |
| + * A {@link NoTokenFoundQueryNode} is used if a term is convert into no tokens |
| + * by the tokenizer/lemmatizer/analyzer (null). |
| + */ |
| +public class NoTokenFoundQueryNode extends DeletedQueryNode { |
| + |
| + private static final long serialVersionUID = 7332975497586993833L; |
| + |
| + public NoTokenFoundQueryNode() { |
| + super(); |
| + } |
| + |
| + public CharSequence toQueryString(EscapeQuerySyntax escaper) { |
| + return "[NTF]"; |
| + } |
| + |
| + public String toString() { |
| + return "<notokenfound/>"; |
| + } |
| + |
| + public QueryNode cloneTree() throws CloneNotSupportedException { |
| + NoTokenFoundQueryNode clone = (NoTokenFoundQueryNode) super.cloneTree(); |
| + |
| + // nothing to do here |
| + |
| + return clone; |
| + } |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/queryParser/nodes/NoTokenFoundQueryNode.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/messages/MessageImpl.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/messages/MessageImpl.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/messages/MessageImpl.java (revision 0) |
| @@ -0,0 +1,70 @@ |
| +package org.apache.lucene.messages; |
| + |
| +/** |
| + * 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 java.util.Locale; |
| + |
| +/** |
| + * For Native Language Support (NLS), system of software internationalization. |
| + */ |
| +public class MessageImpl implements Message { |
| + |
| + private static final long serialVersionUID = -3077643314630884523L; |
| + |
| + private String key; |
| + |
| + private Object[] arguments = new Object[0]; |
| + |
| + public MessageImpl(String key) { |
| + this.key = key; |
| + |
| + } |
| + |
| + public MessageImpl(String key, Object... args) { |
| + this(key); |
| + this.arguments = args; |
| + } |
| + |
| + public Object[] getArguments() { |
| + return this.arguments; |
| + } |
| + |
| + public String getKey() { |
| + return this.key; |
| + } |
| + |
| + public String getLocalizedMessage() { |
| + return getLocalizedMessage(Locale.getDefault()); |
| + } |
| + |
| + public String getLocalizedMessage(Locale locale) { |
| + return NLS.getLocalizedMessage(getKey(), locale, getArguments()); |
| + } |
| + |
| + public String toString() { |
| + Object[] args = getArguments(); |
| + String argsString = ""; |
| + if (args != null) { |
| + for (int i = 0; i < args.length; i++) { |
| + argsString += args[i] + (i < args.length ? "" : ", "); |
| + } |
| + } |
| + return getKey() + " " + argsString; |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/messages/MessageImpl.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/messages/NLS.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/messages/NLS.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/messages/NLS.java (revision 0) |
| @@ -0,0 +1,206 @@ |
| +package org.apache.lucene.messages; |
| + |
| +/** |
| + * 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 java.lang.reflect.Field; |
| +import java.lang.reflect.Modifier; |
| +import java.security.AccessController; |
| +import java.security.PrivilegedAction; |
| +import java.text.MessageFormat; |
| +import java.util.HashMap; |
| +import java.util.Iterator; |
| +import java.util.Locale; |
| +import java.util.Map; |
| +import java.util.MissingResourceException; |
| +import java.util.ResourceBundle; |
| + |
| +/** |
| + * For Native Language Support (NLS), system of software internationalization. |
| + * This interface is similar to the NLS class in eclipse.osgi.util.NLS class - |
| + * initializeMessages() method resets the values of all static strings, should |
| + * only be called by classes that extend from NLS (see TestMessages.java for |
| + * reference) - performs validation of all message in a bundle, at class load |
| + * time - performs per message validation at runtime - see NLSTest.java for |
| + * usage reference |
| + * |
| + * Client may subclass this type. |
| + */ |
| +public class NLS { |
| + |
| + private static Map<String, Class<Object>> bundles = new HashMap<String, Class<Object>>( |
| + 0); |
| + |
| + protected NLS() { |
| + // Do not instantiate |
| + } |
| + |
| + public static String getLocalizedMessage(String key) { |
| + return getLocalizedMessage(key, Locale.getDefault()); |
| + } |
| + |
| + public static String getLocalizedMessage(String key, Locale locale) { |
| + Object message = getResourceBundleObject(key, locale); |
| + if (message == null) { |
| + return "Message with key:" + key + " and locale: " + locale |
| + + " not found."; |
| + } |
| + return message.toString(); |
| + } |
| + |
| + public static String getLocalizedMessage(String key, Locale locale, |
| + Object... args) { |
| + String str = getLocalizedMessage(key, locale); |
| + |
| + if (args.length > 0) { |
| + str = MessageFormat.format(str, args); |
| + } |
| + |
| + return str; |
| + } |
| + |
| + public static String getLocalizedMessage(String key, Object... args) { |
| + return getLocalizedMessage(key, Locale.getDefault(), args); |
| + } |
| + |
| + /** |
| + * Initialize a given class with the message bundle Keys Should be called from |
| + * a class that extends NLS in a static block at class load time. |
| + * |
| + * @param bundleName |
| + * Property file with that contains the message bundle |
| + * @param clazz |
| + * where constants will reside |
| + */ |
| + @SuppressWarnings("unchecked") |
| + protected static void initializeMessages(String bundleName, Class clazz) { |
| + try { |
| + load(clazz); |
| + if (!bundles.containsKey(bundleName)) |
| + bundles.put(bundleName, clazz); |
| + } catch (Throwable e) { |
| + // ignore all errors and exceptions |
| + // because this function is supposed to be called at class load time. |
| + } |
| + } |
| + |
| + private static Object getResourceBundleObject(String messageKey, Locale locale) { |
| + |
| + // slow resource checking |
| + // need to loop thru all registered resource bundles |
| + for (Iterator<String> it = bundles.keySet().iterator(); it.hasNext();) { |
| + Class<Object> clazz = bundles.get(it.next()); |
| + ResourceBundle resourceBundle = ResourceBundle.getBundle(clazz.getName(), |
| + locale); |
| + if (resourceBundle != null) { |
| + try { |
| + Object obj = resourceBundle.getObject(messageKey); |
| + if (obj != null) |
| + return obj; |
| + } catch (MissingResourceException e) { |
| + // just continue it might be on the next resource bundle |
| + } |
| + } |
| + } |
| + // if resource is not found |
| + return null; |
| + } |
| + |
| + /** |
| + * @param bundleName |
| + * @param clazz |
| + */ |
| + private static void load(Class<Object> clazz) { |
| + final Field[] fieldArray = clazz.getDeclaredFields(); |
| + |
| + boolean isFieldAccessible = (clazz.getModifiers() & Modifier.PUBLIC) != 0; |
| + |
| + // build a map of field names to Field objects |
| + final int len = fieldArray.length; |
| + Map<String, Field> fields = new HashMap<String, Field>(len * 2); |
| + for (int i = 0; i < len; i++) { |
| + fields.put(fieldArray[i].getName(), fieldArray[i]); |
| + loadfieldValue(fieldArray[i], isFieldAccessible, clazz); |
| + } |
| + } |
| + |
| + /** |
| + * @param field |
| + * @param isFieldAccessible |
| + */ |
| + private static void loadfieldValue(Field field, boolean isFieldAccessible, |
| + Class<Object> clazz) { |
| + int MOD_EXPECTED = Modifier.PUBLIC | Modifier.STATIC; |
| + int MOD_MASK = MOD_EXPECTED | Modifier.FINAL; |
| + if ((field.getModifiers() & MOD_MASK) != MOD_EXPECTED) |
| + return; |
| + |
| + // Set a value for this empty field. |
| + if (!isFieldAccessible) |
| + makeAccessible(field); |
| + try { |
| + field.set(null, field.getName()); |
| + validateMessage(field.getName(), clazz); |
| + } catch (IllegalArgumentException e) { |
| + // should not happen |
| + } catch (IllegalAccessException e) { |
| + // should not happen |
| + } |
| + } |
| + |
| + /** |
| + * @param key |
| + * - Message Key |
| + */ |
| + private static void validateMessage(String key, Class<Object> clazz) { |
| + // Test if the message is present in the resource bundle |
| + try { |
| + ResourceBundle resourceBundle = ResourceBundle.getBundle(clazz.getName(), |
| + Locale.getDefault()); |
| + if (resourceBundle != null) { |
| + Object obj = resourceBundle.getObject(key); |
| + if (obj == null) |
| + System.err.println("WARN: Message with key:" + key + " and locale: " |
| + + Locale.getDefault() + " not found."); |
| + } |
| + } catch (MissingResourceException e) { |
| + System.err.println("WARN: Message with key:" + key + " and locale: " |
| + + Locale.getDefault() + " not found."); |
| + } catch (Throwable e) { |
| + // ignore all other errors and exceptions |
| + // since this code is just a test to see if the message is present on the |
| + // system |
| + } |
| + } |
| + |
| + /* |
| + * Make a class field accessible |
| + */ |
| + @SuppressWarnings("unchecked") |
| + private static void makeAccessible(final Field field) { |
| + if (System.getSecurityManager() == null) { |
| + field.setAccessible(true); |
| + } else { |
| + AccessController.doPrivileged(new PrivilegedAction() { |
| + public Object run() { |
| + field.setAccessible(true); |
| + return null; |
| + } |
| + }); |
| + } |
| + } |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/messages/NLS.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/messages/NLSException.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/messages/NLSException.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/messages/NLSException.java (revision 0) |
| @@ -0,0 +1,31 @@ |
| +package org.apache.lucene.messages; |
| + |
| +/** |
| + * 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. |
| + */ |
| + |
| +/** |
| + * For Native Language Support (NLS), system of software internationalization. |
| + * This Interface should be implemented by all exceptions that require |
| + * translation |
| + * |
| + */ |
| +public interface NLSException { |
| + /** |
| + * @return a instance of a class that implements the Message interface |
| + */ |
| + public Message getMessageObject(); |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/messages/NLSException.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/java/org/apache/lucene/messages/Message.java |
| =================================================================== |
| --- contrib/queryparser/src/java/org/apache/lucene/messages/Message.java (revision 0) |
| +++ contrib/queryparser/src/java/org/apache/lucene/messages/Message.java (revision 0) |
| @@ -0,0 +1,36 @@ |
| +package org.apache.lucene.messages; |
| + |
| +/** |
| + * 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 java.io.Serializable; |
| +import java.util.Locale; |
| + |
| +/** |
| + * For Native Language Support (NLS), system of software internationalization. |
| + */ |
| +public interface Message extends Serializable { |
| + |
| + public String getKey(); |
| + |
| + public Object[] getArguments(); |
| + |
| + public String getLocalizedMessage(); |
| + |
| + public String getLocalizedMessage(Locale locale); |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/java/org/apache/lucene/messages/Message.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/test/org/apache/lucene/messages/TestNLS.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/messages/TestNLS.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/messages/TestNLS.java (revision 0) |
| @@ -0,0 +1,81 @@ |
| +package org.apache.lucene.messages; |
| + |
| +/** |
| + * 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 java.util.Locale; |
| + |
| +import junit.framework.TestCase; |
| + |
| +/** |
| + */ |
| +public class TestNLS extends TestCase { |
| + public void testMessageLoading() { |
| + Message invalidSyntax = new MessageImpl( |
| + MessagesTestBundle.Q0001E_INVALID_SYNTAX, "XXX"); |
| + assertEquals("Syntax Error: XXX", invalidSyntax.getLocalizedMessage()); |
| + } |
| + |
| + public void testMessageLoading_ja() { |
| + Message invalidSyntax = new MessageImpl( |
| + MessagesTestBundle.Q0001E_INVALID_SYNTAX, "XXX"); |
| + assertEquals("構文エラー: XXX", invalidSyntax |
| + .getLocalizedMessage(Locale.JAPANESE)); |
| + } |
| + |
| + public void testNLSLoading() { |
| + String message = NLS |
| + .getLocalizedMessage(MessagesTestBundle.Q0004E_INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION); |
| + assertEquals("Truncated unicode escape sequence.", message); |
| + |
| + message = NLS.getLocalizedMessage(MessagesTestBundle.Q0001E_INVALID_SYNTAX, |
| + "XXX"); |
| + assertEquals("Syntax Error: XXX", message); |
| + } |
| + |
| + public void testNLSLoading_ja() { |
| + String message = NLS.getLocalizedMessage( |
| + MessagesTestBundle.Q0004E_INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION, |
| + Locale.JAPANESE); |
| + assertEquals("切り捨てられたユニコード・エスケープ・シーケンス。", message); |
| + |
| + message = NLS.getLocalizedMessage(MessagesTestBundle.Q0001E_INVALID_SYNTAX, |
| + Locale.JAPANESE, "XXX"); |
| + assertEquals("構文エラー: XXX", message); |
| + } |
| + |
| + public void testNLSLoading_xx_XX() { |
| + Locale locale = new Locale("xx", "XX", ""); |
| + String message = NLS.getLocalizedMessage( |
| + MessagesTestBundle.Q0004E_INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION, |
| + locale); |
| + assertEquals("Truncated unicode escape sequence.", message); |
| + |
| + message = NLS.getLocalizedMessage(MessagesTestBundle.Q0001E_INVALID_SYNTAX, |
| + locale, "XXX"); |
| + assertEquals("Syntax Error: XXX", message); |
| + } |
| + |
| + public void testMissingMessage() { |
| + Locale locale = Locale.ENGLISH; |
| + String message = NLS.getLocalizedMessage( |
| + MessagesTestBundle.Q0005E_MESSAGE_NOT_IN_BUNDLE, locale); |
| + |
| + assertEquals("Message with key:Q0005E_MESSAGE_NOT_IN_BUNDLE and locale: " |
| + + locale.toString() + " not found.", message); |
| + } |
| +} |
| |
| Property changes on: contrib/queryparser/src/test/org/apache/lucene/messages/TestNLS.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle.java (revision 0) |
| @@ -0,0 +1,40 @@ |
| +package org.apache.lucene.messages; |
| + |
| +/** |
| + * 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. |
| + */ |
| + |
| +public class MessagesTestBundle extends NLS { |
| + |
| + private static final String BUNDLE_NAME = MessagesTestBundle.class.getName(); |
| + |
| + private MessagesTestBundle() { |
| + // should never be instantiated |
| + } |
| + |
| + static { |
| + // register all string ids with NLS class and initialize static string |
| + // values |
| + NLS.initializeMessages(BUNDLE_NAME, MessagesTestBundle.class); |
| + } |
| + |
| + // static string must match the strings in the property files. |
| + public static String Q0001E_INVALID_SYNTAX; |
| + public static String Q0004E_INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION; |
| + |
| + // this message is missing from the properties file |
| + public static String Q0005E_MESSAGE_NOT_IN_BUNDLE; |
| +} |
| |
| Property changes on: contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle.properties |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle.properties (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle.properties (revision 0) |
| @@ -0,0 +1,3 @@ |
| +Q0001E_INVALID_SYNTAX = Syntax Error: {0} |
| + |
| +Q0004E_INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION = Truncated unicode escape sequence. |
| |
| Property changes on: contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle.properties |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle_ja.properties |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle_ja.properties (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle_ja.properties (revision 0) |
| @@ -0,0 +1,3 @@ |
| +Q0001E_INVALID_SYNTAX = \u69cb\u6587\u30a8\u30e9\u30fc: {0} |
| + |
| +Q0004E_INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION = \u5207\u308a\u6368\u3066\u3089\u308c\u305f\u30e6\u30cb\u30b3\u30fc\u30c9\u30fb\u30a8\u30b9\u30b1\u30fc\u30d7\u30fb\u30b7\u30fc\u30b1\u30f3\u30b9\u3002 |
| |
| Property changes on: contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle_ja.properties |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansQueryConfigHandler.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansQueryConfigHandler.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansQueryConfigHandler.java (revision 0) |
| @@ -0,0 +1,43 @@ |
| +package org.apache.lucene.queryParser.spans; |
| + |
| +/** |
| + * 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.config.FieldConfig; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| + |
| +/** |
| + * This query config handler only adds the {@link UniqueFieldAttribute} to it.<br/> |
| + * <br/> |
| + * |
| + * It does not return any configuration for a field in specific. |
| + */ |
| +public class SpansQueryConfigHandler extends QueryConfigHandler { |
| + |
| + public SpansQueryConfigHandler() { |
| + addAttribute(UniqueFieldAttribute.class); |
| + } |
| + |
| + @Override |
| + public FieldConfig getFieldConfig(CharSequence fieldName) { |
| + |
| + // there is no field configuration, always return null |
| + return null; |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansQueryConfigHandler.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/TestSpanQueryParserSimpleSample.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/TestSpanQueryParserSimpleSample.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/TestSpanQueryParserSimpleSample.java (revision 0) |
| @@ -0,0 +1,155 @@ |
| +package org.apache.lucene.queryParser.spans; |
| + |
| +/** |
| + * 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 javax.management.Query; |
| + |
| +import junit.framework.TestCase; |
| + |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.nodes.OrQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.parser.TextParser; |
| +import org.apache.lucene.queryParser.parser.Parser; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorPipeline; |
| +import org.apache.lucene.search.spans.SpanQuery; |
| +import org.apache.lucene.search.spans.SpanTermQuery; |
| + |
| +/** |
| + * This test case demonstrates how the new query parser can be used.<br/> |
| + * <br/> |
| + * |
| + * It tests queries likes "term", "field:term" "term1 term2" "term1 OR term2", |
| + * which are all already supported by the current syntax parser ( |
| + * {@link TextParser}).<br/> |
| + * <br/> |
| + * |
| + * The goals is to create a new query parser that supports only the pair |
| + * "field:term" or a list of pairs separated or not by an OR operator, and from |
| + * this query generate {@link SpanQuery} objects instead of the regular |
| + * {@link Query} objects. Basically, every pair will be converted to a |
| + * {@link SpanTermQuery} object and if there are more than one pair they will be |
| + * grouped by an {@link OrQueryNode}.<br/> |
| + * <br/> |
| + * |
| + * Another functionality that will be added is the ability to convert every |
| + * field defined in the query to an unique specific field.<br/> |
| + * <br/> |
| + * |
| + * The query generation is divided in three different steps: parsing (syntax), |
| + * processing (semantic) and building.<br/> |
| + * <br/> |
| + * |
| + * The parsing phase, as already mentioned will be performed by the current |
| + * query parser: {@link TextParser}.<br/> |
| + * <br/> |
| + * |
| + * The processing phase will be performed by a processor pipeline which is |
| + * compound by 2 processors: {@link SpansValidatorQueryNodeProcessor} and |
| + * {@link UniqueFieldQueryNodeProcessor}. |
| + * |
| + * <pre> |
| + * |
| + * {@link SpansValidatorQueryNodeProcessor}: as it's going to use the current |
| + * query parser to parse the syntax, it will support more features than we want, |
| + * this processor basically validates the query node tree generated by the parser |
| + * and just let got through the elements we want, all the other elements as |
| + * wildcards, range queries, etc...if found, an exception is thrown. |
| + * |
| + * {@link UniqueFieldQueryNodeProcessor}: this processor will take care of reading |
| + * what is the "unique field" from the configuration and convert every field defined |
| + * in every pair to this "unique field". For that, a {@link SpansQueryConfigHandler} is |
| + * used, which has the {@link UniqueFieldAttribute} defined in it. |
| + * </pre> |
| + * |
| + * The building phase is performed by the {@link SpansQueryTreeBuilder}, which |
| + * basically contains a map that defines which builder will be used to generate |
| + * {@link SpanQuery} objects from {@link QueryNode} objects.<br/> |
| + * <br/> |
| + * |
| + * @see TestSpanQueryParser for a more advanced example |
| + * |
| + * @see SpansQueryConfigHandler |
| + * @see SpansQueryTreeBuilder |
| + * @see SpansValidatorQueryNodeProcessor |
| + * @see SpanOrQueryNodeBuilder |
| + * @see SpanTermQueryNodeBuilder |
| + * @see TextParser |
| + * @see UniqueFieldQueryNodeProcessor |
| + * @see UniqueFieldAttribute |
| + * |
| + */ |
| +public class TestSpanQueryParserSimpleSample extends TestCase { |
| + |
| + public TestSpanQueryParserSimpleSample() { |
| + // empty constructor |
| + } |
| + |
| + public TestSpanQueryParserSimpleSample(String testName) { |
| + super(testName); |
| + } |
| + |
| + public static junit.framework.Test suite() { |
| + junit.framework.TestSuite suite = new junit.framework.TestSuite( |
| + TestSpanQueryParserSimpleSample.class); |
| + return suite; |
| + } |
| + |
| + public void testBasicDemo() throws Exception { |
| + Parser queryParser = new TextParser(); |
| + |
| + // convert the CharSequence into a QueryNode tree |
| + QueryNode queryTree = queryParser.parse("body:text", null); |
| + |
| + // create a config handler with a attribute used in |
| + // UniqueFieldQueryNodeProcessor |
| + QueryConfigHandler spanQueryConfigHandler = new SpansQueryConfigHandler(); |
| + UniqueFieldAttribute uniqueFieldAtt = (UniqueFieldAttribute) spanQueryConfigHandler |
| + .getAttribute(UniqueFieldAttribute.class); |
| + uniqueFieldAtt.setUniqueField("index"); |
| + |
| + // set up the processor pipeline with the ConfigHandler |
| + // and create the pipeline for this simple demo |
| + QueryNodeProcessorPipeline spanProcessorPipeline = new QueryNodeProcessorPipeline( |
| + spanQueryConfigHandler); |
| + // @see SpansValidatorQueryNodeProcessor |
| + spanProcessorPipeline.addProcessor(new SpansValidatorQueryNodeProcessor()); |
| + // @see UniqueFieldQueryNodeProcessor |
| + spanProcessorPipeline.addProcessor(new UniqueFieldQueryNodeProcessor()); |
| + |
| + // print to show out the QueryNode tree before being processed |
| + System.out.println(queryTree); |
| + |
| + // Process the QueryTree using our new Processors |
| + queryTree = spanProcessorPipeline.process(queryTree); |
| + |
| + // print to show out the QueryNode tree after being processed |
| + System.out.println(queryTree); |
| + |
| + // create a instance off the Builder |
| + SpansQueryTreeBuilder spansQueryTreeBuilder = new SpansQueryTreeBuilder(); |
| + |
| + // convert QueryNode tree to span query Objects |
| + SpanQuery spanquery = spansQueryTreeBuilder.build(queryTree); |
| + |
| + assertTrue(spanquery instanceof SpanTermQuery); |
| + assertEquals(spanquery.toString(), "index:text"); |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/TestSpanQueryParserSimpleSample.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldAttribute.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldAttribute.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldAttribute.java (revision 0) |
| @@ -0,0 +1,92 @@ |
| +package org.apache.lucene.queryParser.spans; |
| + |
| +/** |
| + * 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.nodes.FieldableNode; |
| +import org.apache.lucene.util.Attribute; |
| + |
| +/** |
| + * This attribute is used by the {@link UniqueFieldQueryNodeProcessor} |
| + * processor. It holds a value that defines which is the unique field name that |
| + * should be set in every {@link FieldableNode}.<br/> |
| + * <br/> |
| + * |
| + * @see UniqueFieldQueryNodeProcessor |
| + */ |
| +public class UniqueFieldAttribute extends Attribute { |
| + |
| + private static final long serialVersionUID = 8553318595851064232L; |
| + |
| + private CharSequence uniqueField; |
| + |
| + public UniqueFieldAttribute() { |
| + clear(); |
| + } |
| + |
| + @Override |
| + public void clear() { |
| + this.uniqueField = ""; |
| + } |
| + |
| + public void setUniqueField(CharSequence uniqueField) { |
| + this.uniqueField = uniqueField; |
| + } |
| + |
| + public CharSequence getUniqueField() { |
| + return this.uniqueField; |
| + } |
| + |
| + @Override |
| + public void copyTo(Attribute target) { |
| + |
| + if (!(target instanceof UniqueFieldAttribute)) { |
| + throw new IllegalArgumentException( |
| + "cannot copy the values from attribute UniqueFieldAttribute to an instance of " |
| + + target.getClass().getName()); |
| + } |
| + |
| + UniqueFieldAttribute uniqueFieldAttr = (UniqueFieldAttribute) target; |
| + uniqueFieldAttr.uniqueField = uniqueField.toString(); |
| + |
| + } |
| + |
| + @Override |
| + public boolean equals(Object other) { |
| + |
| + if (other instanceof UniqueFieldAttribute) { |
| + |
| + return ((UniqueFieldAttribute) other).uniqueField |
| + .equals(this.uniqueField); |
| + |
| + } |
| + |
| + return false; |
| + |
| + } |
| + |
| + @Override |
| + public int hashCode() { |
| + return this.uniqueField.hashCode(); |
| + } |
| + |
| + @Override |
| + public String toString() { |
| + return "<uniqueField uniqueField='" + this.uniqueField + "'/>"; |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldAttribute.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpanTermQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpanTermQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpanTermQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,41 @@ |
| +package org.apache.lucene.queryParser.spans; |
| + |
| +/** |
| + * 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.Term; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.nodes.FieldQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.builders.LuceneQueryBuilder; |
| +import org.apache.lucene.search.spans.SpanTermQuery; |
| + |
| +/** |
| + * This builder creates {@link SpanTermQuery}s from a {@link FieldQueryNode} |
| + * object. |
| + */ |
| +public class SpanTermQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public SpanTermQuery build(QueryNode node) throws QueryNodeException { |
| + FieldQueryNode fieldQueryNode = (FieldQueryNode) node; |
| + |
| + return new SpanTermQuery(new Term(fieldQueryNode.getFieldAsString(), |
| + fieldQueryNode.getTextAsString())); |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpanTermQueryNodeBuilder.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldQueryNodeProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldQueryNodeProcessor.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldQueryNodeProcessor.java (revision 0) |
| @@ -0,0 +1,84 @@ |
| +package org.apache.lucene.queryParser.spans; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.config.QueryConfigHandler; |
| +import org.apache.lucene.queryParser.nodes.FieldableNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| + |
| +/** |
| + * This processor changes every field name of each {@link FieldableNode} query |
| + * node contained in the query tree to the field name defined in the |
| + * {@link UniqueFieldAttribute}. So, the {@link UniqueFieldAttribute} must be |
| + * defined in the {@link QueryConfigHandler} object set in this processor, |
| + * otherwise it throws an exception.<br/> |
| + * <br/> |
| + * |
| + * @see UniqueFieldAttribute |
| + */ |
| +public class UniqueFieldQueryNodeProcessor extends QueryNodeProcessorImpl { |
| + |
| + @Override |
| + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + @Override |
| + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + if (node instanceof FieldableNode) { |
| + FieldableNode fieldNode = (FieldableNode) node; |
| + |
| + QueryConfigHandler queryConfig = getQueryConfigHandler(); |
| + |
| + if (queryConfig == null) { |
| + throw new IllegalArgumentException( |
| + "A config handler is expected by the processor UniqueFieldQueryNodeProcessor!"); |
| + } |
| + |
| + if (!queryConfig.hasAttribute(UniqueFieldAttribute.class)) { |
| + throw new IllegalArgumentException( |
| + "UniqueFieldAttribute should be defined in the config handler!"); |
| + } |
| + |
| + CharSequence uniqueField = ((UniqueFieldAttribute) queryConfig |
| + .getAttribute(UniqueFieldAttribute.class)).getUniqueField(); |
| + |
| + fieldNode.setField(uniqueField); |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + @Override |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldQueryNodeProcessor.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/TestSpanQueryParser.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/TestSpanQueryParser.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/TestSpanQueryParser.java (revision 0) |
| @@ -0,0 +1,232 @@ |
| +package org.apache.lucene.queryParser.spans; |
| + |
| +/** |
| + * 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 javax.management.Query; |
| + |
| +import junit.framework.TestCase; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.nodes.OrQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.parser.TextParser; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorPipeline; |
| +import org.apache.lucene.search.spans.SpanOrQuery; |
| +import org.apache.lucene.search.spans.SpanQuery; |
| +import org.apache.lucene.search.spans.SpanTermQuery; |
| + |
| +/** |
| + * This test case demonstrates how the new query parser can be used.<br/> |
| + * <br/> |
| + * |
| + * It tests queries likes "term", "field:term" "term1 term2" "term1 OR term2", |
| + * which are all already supported by the current syntax parser ( |
| + * {@link TextParser}).<br/> |
| + * <br/> |
| + * |
| + * The goals is to create a new query parser that supports only the pair |
| + * "field:term" or a list of pairs separated or not by an OR operator, and from |
| + * this query generate {@link SpanQuery} objects instead of the regular |
| + * {@link Query} objects. Basically, every pair will be converted to a |
| + * {@link SpanTermQuery} object and if there are more than one pair they will be |
| + * grouped by an {@link OrQueryNode}.<br/> |
| + * <br/> |
| + * |
| + * Another functionality that will be added is the ability to convert every |
| + * field defined in the query to an unique specific field.<br/> |
| + * <br/> |
| + * |
| + * The query generation is divided in three different steps: parsing (syntax), |
| + * processing (semantic) and building.<br/> |
| + * <br/> |
| + * |
| + * The parsing phase, as already mentioned will be performed by the current |
| + * query parser: {@link TextParser}.<br/> |
| + * <br/> |
| + * |
| + * The processing phase will be performed by a processor pipeline which is |
| + * compound by 2 processors: {@link SpansValidatorQueryNodeProcessor} and |
| + * {@link UniqueFieldQueryNodeProcessor}. |
| + * |
| + * <pre> |
| + * |
| + * {@link SpansValidatorQueryNodeProcessor}: as it's going to use the current |
| + * query parser to parse the syntax, it will support more features than we want, |
| + * this processor basically validates the query node tree generated by the parser |
| + * and just let got through the elements we want, all the other elements as |
| + * wildcards, range queries, etc...if found, an exception is thrown. |
| + * |
| + * {@link UniqueFieldQueryNodeProcessor}: this processor will take care of reading |
| + * what is the "unique field" from the configuration and convert every field defined |
| + * in every pair to this "unique field". For that, a {@link SpansQueryConfigHandler} is |
| + * used, which has the {@link UniqueFieldAttribute} defined in it. |
| + * </pre> |
| + * |
| + * The building phase is performed by the {@link SpansQueryTreeBuilder}, which |
| + * basically contains a map that defines which builder will be used to generate |
| + * {@link SpanQuery} objects from {@link QueryNode} objects.<br/> |
| + * <br/> |
| + * |
| + * @see SpansQueryConfigHandler |
| + * @see SpansQueryTreeBuilder |
| + * @see SpansValidatorQueryNodeProcessor |
| + * @see SpanOrQueryNodeBuilder |
| + * @see SpanTermQueryNodeBuilder |
| + * @see TextParser |
| + * @see UniqueFieldQueryNodeProcessor |
| + * @see UniqueFieldAttribute |
| + */ |
| +public class TestSpanQueryParser extends TestCase { |
| + |
| + private QueryNodeProcessorPipeline spanProcessorPipeline; |
| + |
| + private SpansQueryConfigHandler spanQueryConfigHandler; |
| + |
| + private SpansQueryTreeBuilder spansQueryTreeBuilder; |
| + |
| + private TextParser queryParser = new TextParser(); |
| + |
| + public TestSpanQueryParser() { |
| + // empty constructor |
| + } |
| + |
| + @Override |
| + protected void setUp() throws Exception { |
| + super.setUp(); |
| + |
| + this.spanProcessorPipeline = new QueryNodeProcessorPipeline(); |
| + this.spanQueryConfigHandler = new SpansQueryConfigHandler(); |
| + this.spansQueryTreeBuilder = new SpansQueryTreeBuilder(); |
| + |
| + // set up the processor pipeline |
| + this.spanProcessorPipeline |
| + .setQueryConfigHandler(this.spanQueryConfigHandler); |
| + |
| + this.spanProcessorPipeline |
| + .addProcessor(new SpansValidatorQueryNodeProcessor()); |
| + this.spanProcessorPipeline |
| + .addProcessor(new UniqueFieldQueryNodeProcessor()); |
| + |
| + } |
| + |
| + public SpanQuery getSpanQuery(CharSequence query) throws QueryNodeException { |
| + return getSpanQuery("", query); |
| + } |
| + |
| + public SpanQuery getSpanQuery(CharSequence uniqueField, CharSequence query) |
| + throws QueryNodeException { |
| + UniqueFieldAttribute uniqueFieldAtt = (UniqueFieldAttribute) this.spanQueryConfigHandler |
| + .getAttribute(UniqueFieldAttribute.class); |
| + uniqueFieldAtt.setUniqueField(uniqueField); |
| + |
| + QueryNode queryTree = this.queryParser.parse(query, "defaultField"); |
| + queryTree = this.spanProcessorPipeline.process(queryTree); |
| + |
| + return this.spansQueryTreeBuilder.build(queryTree); |
| + |
| + } |
| + |
| + public void testTermSpans() throws Exception { |
| + assertEquals(getSpanQuery("field:term").toString(), "term"); |
| + assertEquals(getSpanQuery("term").toString(), "term"); |
| + |
| + assertTrue(getSpanQuery("field:term") instanceof SpanTermQuery); |
| + assertTrue(getSpanQuery("term") instanceof SpanTermQuery); |
| + |
| + } |
| + |
| + public void testUniqueField() throws Exception { |
| + assertEquals(getSpanQuery("field", "term").toString(), "field:term"); |
| + assertEquals(getSpanQuery("field", "field:term").toString(), "field:term"); |
| + assertEquals(getSpanQuery("field", "anotherField:term").toString(), |
| + "field:term"); |
| + |
| + } |
| + |
| + public void testOrSpans() throws Exception { |
| + assertEquals(getSpanQuery("term1 term2").toString(), |
| + "spanOr([term1, term2])"); |
| + assertEquals(getSpanQuery("term1 OR term2").toString(), |
| + "spanOr([term1, term2])"); |
| + |
| + assertTrue(getSpanQuery("term1 term2") instanceof SpanOrQuery); |
| + assertTrue(getSpanQuery("term1 term2") instanceof SpanOrQuery); |
| + |
| + } |
| + |
| + public void testQueryValidator() throws QueryNodeException { |
| + |
| + try { |
| + getSpanQuery("term*"); |
| + fail("QueryNodeException was expected, wildcard queries should not be supported"); |
| + |
| + } catch (QueryNodeException ex) { |
| + // expected exception |
| + } |
| + |
| + try { |
| + getSpanQuery("[a TO z]"); |
| + fail("QueryNodeException was expected, range queries should not be supported"); |
| + |
| + } catch (QueryNodeException ex) { |
| + // expected exception |
| + } |
| + |
| + try { |
| + getSpanQuery("a~0.5"); |
| + fail("QueryNodeException was expected, boost queries should not be supported"); |
| + |
| + } catch (QueryNodeException ex) { |
| + // expected exception |
| + } |
| + |
| + try { |
| + getSpanQuery("a^0.5"); |
| + fail("QueryNodeException was expected, fuzzy queries should not be supported"); |
| + |
| + } catch (QueryNodeException ex) { |
| + // expected exception |
| + } |
| + |
| + try { |
| + getSpanQuery("\"a b\""); |
| + fail("QueryNodeException was expected, quoted queries should not be supported"); |
| + |
| + } catch (QueryNodeException ex) { |
| + // expected exception |
| + } |
| + |
| + try { |
| + getSpanQuery("(a b)"); |
| + fail("QueryNodeException was expected, parenthesized queries should not be supported"); |
| + |
| + } catch (QueryNodeException ex) { |
| + // expected exception |
| + } |
| + |
| + try { |
| + getSpanQuery("a AND b"); |
| + fail("QueryNodeException was expected, and queries should not be supported"); |
| + |
| + } catch (QueryNodeException ex) { |
| + // expected exception |
| + } |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/TestSpanQueryParser.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansQueryTreeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansQueryTreeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansQueryTreeBuilder.java (revision 0) |
| @@ -0,0 +1,51 @@ |
| +package org.apache.lucene.queryParser.spans; |
| + |
| +/** |
| + * 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.QueryNodeException; |
| +import org.apache.lucene.queryParser.builders.QueryTreeBuilder; |
| +import org.apache.lucene.queryParser.nodes.BooleanQueryNode; |
| +import org.apache.lucene.queryParser.nodes.FieldQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.builders.LuceneQueryBuilder; |
| +import org.apache.lucene.search.spans.SpanQuery; |
| + |
| +/** |
| + * Sets up a query tree builder to build a span query tree from a query node |
| + * tree.<br/> |
| + * <br/> |
| + * |
| + * The defined map is:<br/> |
| + * - every BooleanQueryNode instance is delegated to the SpanOrQueryNodeBuilder<br/> |
| + * - every FieldQueryNode instance is delegated to the SpanTermQueryNodeBuilder <br/> |
| + * |
| + */ |
| +public class SpansQueryTreeBuilder extends QueryTreeBuilder implements |
| + LuceneQueryBuilder { |
| + |
| + public SpansQueryTreeBuilder() { |
| + setBuilder(BooleanQueryNode.class, new SpanOrQueryNodeBuilder()); |
| + setBuilder(FieldQueryNode.class, new SpanTermQueryNodeBuilder()); |
| + |
| + } |
| + |
| + public SpanQuery build(QueryNode queryTree) throws QueryNodeException { |
| + return (SpanQuery) super.build(queryTree); |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansQueryTreeBuilder.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpanOrQueryNodeBuilder.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpanOrQueryNodeBuilder.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpanOrQueryNodeBuilder.java (revision 0) |
| @@ -0,0 +1,56 @@ |
| +package org.apache.lucene.queryParser.spans; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.builders.QueryTreeBuilder; |
| +import org.apache.lucene.queryParser.nodes.BooleanQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.builders.LuceneQueryBuilder; |
| +import org.apache.lucene.search.spans.SpanOrQuery; |
| +import org.apache.lucene.search.spans.SpanQuery; |
| + |
| +/** |
| + * This builder creates {@link SpanOrQuery}s from a {@link BooleanQueryNode}.<br/> |
| + * <br/> |
| + * |
| + * It assumes that the {@link BooleanQueryNode} instance has at least one child. |
| + */ |
| +public class SpanOrQueryNodeBuilder implements LuceneQueryBuilder { |
| + |
| + public SpanOrQuery build(QueryNode node) throws QueryNodeException { |
| + |
| + // validates node |
| + BooleanQueryNode booleanNode = (BooleanQueryNode) node; |
| + |
| + List<QueryNode> children = booleanNode.getChildren(); |
| + SpanQuery[] spanQueries = new SpanQuery[children.size()]; |
| + |
| + int i = 0; |
| + for (QueryNode child : children) { |
| + spanQueries[i++] = (SpanQuery) child |
| + .getTag(QueryTreeBuilder.QUERY_TREE_BUILDER_TAGID); |
| + } |
| + |
| + return new SpanOrQuery(spanQueries); |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpanOrQueryNodeBuilder.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansValidatorQueryNodeProcessor.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansValidatorQueryNodeProcessor.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansValidatorQueryNodeProcessor.java (revision 0) |
| @@ -0,0 +1,72 @@ |
| +package org.apache.lucene.queryParser.spans; |
| + |
| +/** |
| + * 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 java.util.List; |
| + |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.nodes.AndQueryNode; |
| +import org.apache.lucene.queryParser.nodes.BooleanQueryNode; |
| +import org.apache.lucene.queryParser.nodes.FieldQueryNode; |
| +import org.apache.lucene.queryParser.nodes.OrQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| + |
| +/** |
| + * Validates every query node in a query node tree. This processor will pass |
| + * fine if the query nodes are only {@link BooleanQueryNode}s, |
| + * {@link OrQueryNode}s or {@link FieldQueryNode}s, otherwise an exception will |
| + * be thrown. <br/> |
| + * <br/> |
| + * |
| + * If they are {@link AndQueryNode} or an instance of anything else that |
| + * implements {@link FieldQueryNode} the exception will also be thrown. |
| + */ |
| +public class SpansValidatorQueryNodeProcessor extends QueryNodeProcessorImpl { |
| + |
| + @Override |
| + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + @Override |
| + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { |
| + |
| + if (!((node instanceof BooleanQueryNode && !(node instanceof AndQueryNode)) || node |
| + .getClass() == FieldQueryNode.class)) { |
| + throw new QueryNodeException(new MessageImpl( |
| + QueryParserMessages.NODE_ACTION_NOT_SUPPORTED)); |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + @Override |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| +} |
| |
| Property changes on: contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansValidatorQueryNodeProcessor.java |
| ___________________________________________________________________ |
| Added: svn:mime-type |
| + text/plain |
| |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiFieldQPHelper.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiFieldQPHelper.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiFieldQPHelper.java (revision 0) |
| @@ -0,0 +1,369 @@ |
| +package org.apache.lucene.queryParser.original; |
| + |
| +/** |
| + * 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 java.io.Reader; |
| +import java.util.HashMap; |
| +import java.util.Map; |
| + |
| +import org.apache.lucene.analysis.Analyzer; |
| +import org.apache.lucene.analysis.Token; |
| +import org.apache.lucene.analysis.TokenStream; |
| +import org.apache.lucene.analysis.standard.StandardAnalyzer; |
| +import org.apache.lucene.document.Document; |
| +import org.apache.lucene.document.Field; |
| +import org.apache.lucene.index.IndexWriter; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler.Operator; |
| +import org.apache.lucene.search.BooleanClause; |
| +import org.apache.lucene.search.IndexSearcher; |
| +import org.apache.lucene.search.Query; |
| +import org.apache.lucene.search.ScoreDoc; |
| +import org.apache.lucene.search.BooleanClause.Occur; |
| +import org.apache.lucene.store.Directory; |
| +import org.apache.lucene.store.RAMDirectory; |
| +import org.apache.lucene.util.LuceneTestCase; |
| + |
| +/** |
| + * This test case is a copy of the core Lucene query parser test, it was adapted |
| + * to use new QueryParserHelper instead of the old query parser. |
| + * |
| + * Tests QueryParser. |
| + */ |
| +public class TestMultiFieldQPHelper extends LuceneTestCase { |
| + |
| + /** |
| + * test stop words arsing for both the non static form, and for the |
| + * corresponding static form (qtxt, fields[]). |
| + */ |
| + public void tesStopwordsParsing() throws Exception { |
| + assertStopQueryEquals("one", "b:one t:one"); |
| + assertStopQueryEquals("one stop", "b:one t:one"); |
| + assertStopQueryEquals("one (stop)", "b:one t:one"); |
| + assertStopQueryEquals("one ((stop))", "b:one t:one"); |
| + assertStopQueryEquals("stop", null); |
| + assertStopQueryEquals("(stop)", null); |
| + assertStopQueryEquals("((stop))", null); |
| + } |
| + |
| + // verify parsing of query using a stopping analyzer |
| + private void assertStopQueryEquals(String qtxt, String expectedRes) |
| + throws Exception { |
| + String[] fields = { "b", "t" }; |
| + Occur occur[] = { Occur.SHOULD, Occur.SHOULD }; |
| + TestQueryParser.QPTestAnalyzer a = new TestQueryParser.QPTestAnalyzer(); |
| + LuceneQueryParserHelper mfqp = new LuceneQueryParserHelper(); |
| + mfqp.getQueryConfigHandler().setMultiFields(fields); |
| + mfqp.getQueryConfigHandler().setAnalyzer(a); |
| + |
| + Query q = mfqp.parse(qtxt, null); |
| + assertEquals(expectedRes, q.toString()); |
| + |
| + q = QueryParserUtil.parse(qtxt, fields, occur, a); |
| + assertEquals(expectedRes, q.toString()); |
| + } |
| + |
| + public void testSimple() throws Exception { |
| + String[] fields = { "b", "t" }; |
| + LuceneQueryParserHelper mfqp = new LuceneQueryParserHelper(); |
| + mfqp.getQueryConfigHandler().setMultiFields(fields); |
| + mfqp.getQueryConfigHandler().setAnalyzer(new StandardAnalyzer()); |
| + |
| + Query q = mfqp.parse("one", null); |
| + assertEquals("b:one t:one", q.toString()); |
| + |
| + q = mfqp.parse("one two", null); |
| + assertEquals("(b:one t:one) (b:two t:two)", q.toString()); |
| + |
| + q = mfqp.parse("+one +two", null); |
| + assertEquals("+(b:one t:one) +(b:two t:two)", q.toString()); |
| + |
| + q = mfqp.parse("+one -two -three", null); |
| + assertEquals("+(b:one t:one) -(b:two t:two) -(b:three t:three)", q |
| + .toString()); |
| + |
| + q = mfqp.parse("one^2 two", null); |
| + assertEquals("((b:one t:one)^2.0) (b:two t:two)", q.toString()); |
| + |
| + q = mfqp.parse("one~ two", null); |
| + assertEquals("(b:one~0.5 t:one~0.5) (b:two t:two)", q.toString()); |
| + |
| + q = mfqp.parse("one~0.8 two^2", null); |
| + assertEquals("(b:one~0.8 t:one~0.8) ((b:two t:two)^2.0)", q.toString()); |
| + |
| + q = mfqp.parse("one* two*", null); |
| + assertEquals("(b:one* t:one*) (b:two* t:two*)", q.toString()); |
| + |
| + q = mfqp.parse("[a TO c] two", null); |
| + assertEquals("(b:[a TO c] t:[a TO c]) (b:two t:two)", q.toString()); |
| + |
| + q = mfqp.parse("w?ldcard", null); |
| + assertEquals("b:w?ldcard t:w?ldcard", q.toString()); |
| + |
| + q = mfqp.parse("\"foo bar\"", null); |
| + assertEquals("b:\"foo bar\" t:\"foo bar\"", q.toString()); |
| + |
| + q = mfqp.parse("\"aa bb cc\" \"dd ee\"", null); |
| + assertEquals("(b:\"aa bb cc\" t:\"aa bb cc\") (b:\"dd ee\" t:\"dd ee\")", q |
| + .toString()); |
| + |
| + q = mfqp.parse("\"foo bar\"~4", null); |
| + assertEquals("b:\"foo bar\"~4 t:\"foo bar\"~4", q.toString()); |
| + |
| + // LUCENE-1213: LuceneQueryParserHelper was ignoring slop when phrase |
| + // had a field. |
| + q = mfqp.parse("b:\"foo bar\"~4", null); |
| + assertEquals("b:\"foo bar\"~4", q.toString()); |
| + |
| + // make sure that terms which have a field are not touched: |
| + q = mfqp.parse("one f:two", null); |
| + assertEquals("(b:one t:one) f:two", q.toString()); |
| + |
| + // AND mode: |
| + mfqp.getQueryConfigHandler().setDefaultOperator(Operator.AND); |
| + q = mfqp.parse("one two", null); |
| + assertEquals("+(b:one t:one) +(b:two t:two)", q.toString()); |
| + q = mfqp.parse("\"aa bb cc\" \"dd ee\"", null); |
| + assertEquals("+(b:\"aa bb cc\" t:\"aa bb cc\") +(b:\"dd ee\" t:\"dd ee\")", |
| + q.toString()); |
| + |
| + } |
| + |
| + public void testBoostsSimple() throws Exception { |
| + Map boosts = new HashMap(); |
| + boosts.put("b", new Float(5)); |
| + boosts.put("t", new Float(10)); |
| + String[] fields = { "b", "t" }; |
| + LuceneQueryParserHelper mfqp = new LuceneQueryParserHelper(); |
| + mfqp.getQueryConfigHandler().setMultiFields(fields); |
| + mfqp.getQueryConfigHandler().setFieldsBoost(boosts); |
| + mfqp.getQueryConfigHandler().setAnalyzer(new StandardAnalyzer()); |
| + |
| + // Check for simple |
| + Query q = mfqp.parse("one", null); |
| + assertEquals("b:one^5.0 t:one^10.0", q.toString()); |
| + |
| + // Check for AND |
| + q = mfqp.parse("one AND two", null); |
| + assertEquals("+(b:one^5.0 t:one^10.0) +(b:two^5.0 t:two^10.0)", q |
| + .toString()); |
| + |
| + // Check for OR |
| + q = mfqp.parse("one OR two", null); |
| + assertEquals("(b:one^5.0 t:one^10.0) (b:two^5.0 t:two^10.0)", q.toString()); |
| + |
| + // Check for AND and a field |
| + q = mfqp.parse("one AND two AND foo:test", null); |
| + assertEquals("+(b:one^5.0 t:one^10.0) +(b:two^5.0 t:two^10.0) +foo:test", q |
| + .toString()); |
| + |
| + q = mfqp.parse("one^3 AND two^4", null); |
| + assertEquals("+((b:one^5.0 t:one^10.0)^3.0) +((b:two^5.0 t:two^10.0)^4.0)", |
| + q.toString()); |
| + } |
| + |
| + public void testStaticMethod1() throws QueryNodeException { |
| + String[] fields = { "b", "t" }; |
| + String[] queries = { "one", "two" }; |
| + Query q = QueryParserUtil.parse(queries, fields, new StandardAnalyzer()); |
| + assertEquals("b:one t:two", q.toString()); |
| + |
| + String[] queries2 = { "+one", "+two" }; |
| + q = QueryParserUtil.parse(queries2, fields, new StandardAnalyzer()); |
| + assertEquals("(+b:one) (+t:two)", q.toString()); |
| + |
| + String[] queries3 = { "one", "+two" }; |
| + q = QueryParserUtil.parse(queries3, fields, new StandardAnalyzer()); |
| + assertEquals("b:one (+t:two)", q.toString()); |
| + |
| + String[] queries4 = { "one +more", "+two" }; |
| + q = QueryParserUtil.parse(queries4, fields, new StandardAnalyzer()); |
| + assertEquals("(b:one +b:more) (+t:two)", q.toString()); |
| + |
| + String[] queries5 = { "blah" }; |
| + try { |
| + q = QueryParserUtil.parse(queries5, fields, new StandardAnalyzer()); |
| + fail(); |
| + } catch (IllegalArgumentException e) { |
| + // expected exception, array length differs |
| + } |
| + |
| + // check also with stop words for this static form (qtxts[], fields[]). |
| + TestQueryParser.QPTestAnalyzer stopA = new TestQueryParser.QPTestAnalyzer(); |
| + |
| + String[] queries6 = { "((+stop))", "+((stop))" }; |
| + q = QueryParserUtil.parse(queries6, fields, stopA); |
| + assertEquals("", q.toString()); |
| + |
| + String[] queries7 = { "one ((+stop)) +more", "+((stop)) +two" }; |
| + q = QueryParserUtil.parse(queries7, fields, stopA); |
| + assertEquals("(b:one +b:more) (+t:two)", q.toString()); |
| + |
| + } |
| + |
| + public void testStaticMethod2() throws QueryNodeException { |
| + String[] fields = { "b", "t" }; |
| + BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST, |
| + BooleanClause.Occur.MUST_NOT }; |
| + Query q = QueryParserUtil.parse("one", fields, flags, |
| + new StandardAnalyzer()); |
| + assertEquals("+b:one -t:one", q.toString()); |
| + |
| + q = QueryParserUtil.parse("one two", fields, flags, new StandardAnalyzer()); |
| + assertEquals("+(b:one b:two) -(t:one t:two)", q.toString()); |
| + |
| + try { |
| + BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST }; |
| + q = QueryParserUtil.parse("blah", fields, flags2, new StandardAnalyzer()); |
| + fail(); |
| + } catch (IllegalArgumentException e) { |
| + // expected exception, array length differs |
| + } |
| + } |
| + |
| + public void testStaticMethod2Old() throws QueryNodeException { |
| + String[] fields = { "b", "t" }; |
| + // int[] flags = {LuceneQueryParserHelper.REQUIRED_FIELD, |
| + // LuceneQueryParserHelper.PROHIBITED_FIELD}; |
| + BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST, |
| + BooleanClause.Occur.MUST_NOT }; |
| + LuceneQueryParserHelper parser = new LuceneQueryParserHelper(); |
| + parser.getQueryConfigHandler().setMultiFields(fields); |
| + parser.getQueryConfigHandler().setAnalyzer(new StandardAnalyzer()); |
| + |
| + Query q = QueryParserUtil.parse("one", fields, flags, |
| + new StandardAnalyzer());// , fields, flags, new |
| + // StandardAnalyzer()); |
| + assertEquals("+b:one -t:one", q.toString()); |
| + |
| + q = QueryParserUtil.parse("one two", fields, flags, new StandardAnalyzer()); |
| + assertEquals("+(b:one b:two) -(t:one t:two)", q.toString()); |
| + |
| + try { |
| + BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST }; |
| + q = QueryParserUtil.parse("blah", fields, flags2, new StandardAnalyzer()); |
| + fail(); |
| + } catch (IllegalArgumentException e) { |
| + // expected exception, array length differs |
| + } |
| + } |
| + |
| + public void testStaticMethod3() throws QueryNodeException { |
| + String[] queries = { "one", "two", "three" }; |
| + String[] fields = { "f1", "f2", "f3" }; |
| + BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST, |
| + BooleanClause.Occur.MUST_NOT, BooleanClause.Occur.SHOULD }; |
| + Query q = QueryParserUtil.parse(queries, fields, flags, |
| + new StandardAnalyzer()); |
| + assertEquals("+f1:one -f2:two f3:three", q.toString()); |
| + |
| + try { |
| + BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST }; |
| + q = QueryParserUtil |
| + .parse(queries, fields, flags2, new StandardAnalyzer()); |
| + fail(); |
| + } catch (IllegalArgumentException e) { |
| + // expected exception, array length differs |
| + } |
| + } |
| + |
| + public void testStaticMethod3Old() throws QueryNodeException { |
| + String[] queries = { "one", "two" }; |
| + String[] fields = { "b", "t" }; |
| + BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST, |
| + BooleanClause.Occur.MUST_NOT }; |
| + Query q = QueryParserUtil.parse(queries, fields, flags, |
| + new StandardAnalyzer()); |
| + assertEquals("+b:one -t:two", q.toString()); |
| + |
| + try { |
| + BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST }; |
| + q = QueryParserUtil |
| + .parse(queries, fields, flags2, new StandardAnalyzer()); |
| + fail(); |
| + } catch (IllegalArgumentException e) { |
| + // expected exception, array length differs |
| + } |
| + } |
| + |
| + public void testAnalyzerReturningNull() throws QueryNodeException { |
| + String[] fields = new String[] { "f1", "f2", "f3" }; |
| + LuceneQueryParserHelper parser = new LuceneQueryParserHelper(); |
| + parser.getQueryConfigHandler().setMultiFields(fields); |
| + parser.getQueryConfigHandler().setAnalyzer(new AnalyzerReturningNull()); |
| + |
| + Query q = parser.parse("bla AND blo", null); |
| + assertEquals("+(f2:bla f3:bla) +(f2:blo f3:blo)", q.toString()); |
| + // the following queries are not affected as their terms are not |
| + // analyzed anyway: |
| + q = parser.parse("bla*", null); |
| + assertEquals("f1:bla* f2:bla* f3:bla*", q.toString()); |
| + q = parser.parse("bla~", null); |
| + assertEquals("f1:bla~0.5 f2:bla~0.5 f3:bla~0.5", q.toString()); |
| + q = parser.parse("[a TO c]", null); |
| + assertEquals("f1:[a TO c] f2:[a TO c] f3:[a TO c]", q.toString()); |
| + } |
| + |
| + public void testStopWordSearching() throws Exception { |
| + Analyzer analyzer = new StandardAnalyzer(); |
| + Directory ramDir = new RAMDirectory(); |
| + IndexWriter iw = new IndexWriter(ramDir, analyzer, true, |
| + IndexWriter.MaxFieldLength.LIMITED); |
| + Document doc = new Document(); |
| + doc.add(new Field("body", "blah the footest blah", Field.Store.NO, |
| + Field.Index.ANALYZED)); |
| + iw.addDocument(doc); |
| + iw.close(); |
| + |
| + LuceneQueryParserHelper mfqp = new LuceneQueryParserHelper(); |
| + |
| + mfqp.getQueryConfigHandler().setMultiFields(new String[] { "body" }); |
| + mfqp.getQueryConfigHandler().setAnalyzer(analyzer); |
| + mfqp.getQueryConfigHandler().setDefaultOperator(Operator.AND); |
| + Query q = mfqp.parse("the footest", null); |
| + IndexSearcher is = new IndexSearcher(ramDir); |
| + ScoreDoc[] hits = is.search(q, null, 1000).scoreDocs; |
| + assertEquals(1, hits.length); |
| + is.close(); |
| + } |
| + |
| + /** |
| + * Return empty tokens for field "f1". |
| + */ |
| + private static class AnalyzerReturningNull extends Analyzer { |
| + StandardAnalyzer stdAnalyzer = new StandardAnalyzer(); |
| + |
| + public AnalyzerReturningNull() { |
| + } |
| + |
| + public TokenStream tokenStream(String fieldName, Reader reader) { |
| + if ("f1".equals(fieldName)) { |
| + return new EmptyTokenStream(); |
| + } else { |
| + return stdAnalyzer.tokenStream(fieldName, reader); |
| + } |
| + } |
| + |
| + private static class EmptyTokenStream extends TokenStream { |
| + public Token next(final Token reusableToken) { |
| + return null; |
| + } |
| + } |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiAnalyzer.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiAnalyzer.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiAnalyzer.java (revision 0) |
| @@ -0,0 +1,347 @@ |
| +package org.apache.lucene.queryParser.original; |
| + |
| +/** |
| + * 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 java.io.IOException; |
| +import java.io.Reader; |
| + |
| +import org.apache.lucene.analysis.Analyzer; |
| +import org.apache.lucene.analysis.LowerCaseFilter; |
| +import org.apache.lucene.analysis.Token; |
| +import org.apache.lucene.analysis.TokenFilter; |
| +import org.apache.lucene.analysis.TokenStream; |
| +import org.apache.lucene.analysis.standard.StandardTokenizer; |
| +import org.apache.lucene.analysis.tokenattributes.OffsetAttribute; |
| +import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute; |
| +import org.apache.lucene.analysis.tokenattributes.TermAttribute; |
| +import org.apache.lucene.analysis.tokenattributes.TypeAttribute; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.builders.LuceneQueryTreeBuilder; |
| +import org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler.Operator; |
| +import org.apache.lucene.queryParser.original.parser.TextParser; |
| +import org.apache.lucene.queryParser.original.processors.LuceneQueryNodeProcessorPipeline; |
| +import org.apache.lucene.util.LuceneTestCase; |
| + |
| +/** |
| + * This test case is a copy of the core Lucene query parser test, it was adapted |
| + * to use the new query parser instead of the old one. |
| + * |
| + * Test TextParser's ability to deal with Analyzers that return more than one |
| + * token per position or that return tokens with a position increment > 1. |
| + */ |
| +public class TestMultiAnalyzer extends LuceneTestCase { |
| + |
| + private static int multiToken = 0; |
| + |
| + private String parse(LuceneQueryConfigHandler config, String queryString) |
| + throws QueryNodeException { |
| + |
| + TextParser textParser = new TextParser(); |
| + QueryNode queryTree = textParser.parse(queryString, ""); |
| + |
| + LuceneQueryNodeProcessorPipeline processor = new LuceneQueryNodeProcessorPipeline( |
| + config); |
| + queryTree = processor.process(queryTree); |
| + |
| + LuceneQueryTreeBuilder builder = new LuceneQueryTreeBuilder(); |
| + |
| + return builder.build(queryTree).toString(); |
| + |
| + } |
| + |
| + public void testMultiAnalyzer() throws QueryNodeException { |
| + |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + config.setAnalyzer(new MultiAnalyzer()); |
| + |
| + // trivial, no multiple tokens: |
| + assertEquals("foo", parse(config, "foo").toString()); |
| + assertEquals("foo", parse(config, "\"foo\"").toString()); |
| + assertEquals("foo foobar", parse(config, "foo foobar".toString())); |
| + assertEquals("\"foo foobar\"", parse(config, "\"foo foobar\"".toString())); |
| + assertEquals("\"foo foobar blah\"", parse(config, "\"foo foobar blah\"" |
| + .toString())); |
| + |
| + // two tokens at the same position: |
| + assertEquals("(multi multi2) foo", parse(config, "multi foo".toString())); |
| + assertEquals("foo (multi multi2)", parse(config, "foo multi".toString())); |
| + assertEquals("(multi multi2) (multi multi2)", parse(config, "multi multi" |
| + .toString())); |
| + assertEquals("+(foo (multi multi2)) +(bar (multi multi2))", parse(config, |
| + "+(foo multi) +(bar multi)".toString())); |
| + assertEquals("+(foo (multi multi2)) field:\"bar (multi multi2)\"", parse( |
| + config, "+(foo multi) field:\"bar multi\"".toString())); |
| + |
| + // phrases: |
| + assertEquals("\"(multi multi2) foo\"", parse(config, "\"multi foo\"" |
| + .toString())); |
| + assertEquals("\"foo (multi multi2)\"", parse(config, "\"foo multi\"" |
| + .toString())); |
| + assertEquals("\"foo (multi multi2) foobar (multi multi2)\"", parse(config, |
| + "\"foo multi foobar multi\"".toString())); |
| + |
| + // fields: |
| + assertEquals("(field:multi field:multi2) field:foo", parse(config, |
| + "field:multi field:foo").toString()); |
| + assertEquals("field:\"(multi multi2) foo\"", parse(config, |
| + "field:\"multi foo\"").toString()); |
| + |
| + // three tokens at one position: |
| + assertEquals("triplemulti multi3 multi2", parse(config, "triplemulti") |
| + .toString()); |
| + assertEquals("foo (triplemulti multi3 multi2) foobar", parse(config, |
| + "foo triplemulti foobar").toString()); |
| + |
| + // phrase with non-default slop: |
| + assertEquals("\"(multi multi2) foo\"~10", parse(config, "\"multi foo\"~10") |
| + .toString()); |
| + |
| + // phrase with non-default boost: |
| + assertEquals("\"(multi multi2) foo\"^2.0", parse(config, "\"multi foo\"^2") |
| + .toString()); |
| + |
| + // phrase after changing default slop |
| + config.setDefaultPhraseSlop(99); |
| + |
| + assertEquals("\"(multi multi2) foo\"~99 bar", parse(config, |
| + "\"multi foo\" bar").toString()); |
| + assertEquals("\"(multi multi2) foo\"~99 \"foo bar\"~2", parse(config, |
| + "\"multi foo\" \"foo bar\"~2").toString()); |
| + config.setDefaultPhraseSlop(0); |
| + |
| + // non-default operator: |
| + config.setDefaultOperator(Operator.AND); |
| + assertEquals("+(multi multi2) +foo", parse(config, "multi foo").toString()); |
| + |
| + } |
| + |
| + // public void testMultiAnalyzerWithSubclassOfQueryParser() throws |
| + // ParseException { |
| + // this test doesn't make sense when using the new QueryParser API |
| + // DumbQueryParser qp = new DumbQueryParser("", new MultiAnalyzer()); |
| + // qp.setPhraseSlop(99); // modified default slop |
| + // |
| + // // direct call to (super's) getFieldQuery to demonstrate differnce |
| + // // between phrase and multiphrase with modified default slop |
| + // assertEquals("\"foo bar\"~99", |
| + // qp.getSuperFieldQuery("","foo bar").toString()); |
| + // assertEquals("\"(multi multi2) bar\"~99", |
| + // qp.getSuperFieldQuery("","multi bar").toString()); |
| + // |
| + // |
| + // // ask sublcass to parse phrase with modified default slop |
| + // assertEquals("\"(multi multi2) foo\"~99 bar", |
| + // qp.parse("\"multi foo\" bar").toString()); |
| + // |
| + // } |
| + |
| + public void testPosIncrementAnalyzer() throws QueryNodeException { |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + config.setAnalyzer(new PosIncrementAnalyzer()); |
| + |
| + assertEquals("quick brown", parse(config, "the quick brown").toString()); |
| + assertEquals("\"quick brown\"", parse(config, "\"the quick brown\"") |
| + .toString()); |
| + assertEquals("quick brown fox", parse(config, "the quick brown fox") |
| + .toString()); |
| + assertEquals("\"quick brown fox\"", |
| + parse(config, "\"the quick brown fox\"").toString()); |
| + } |
| + |
| + /** |
| + * Expands "multi" to "multi" and "multi2", both at the same position, and |
| + * expands "triplemulti" to "triplemulti", "multi3", and "multi2". |
| + */ |
| + private class MultiAnalyzer extends Analyzer { |
| + |
| + public MultiAnalyzer() { |
| + } |
| + |
| + public TokenStream tokenStream(String fieldName, Reader reader) { |
| + TokenStream result = new StandardTokenizer(reader); |
| + result = new TestFilter(result); |
| + result = new LowerCaseFilter(result); |
| + return result; |
| + } |
| + } |
| + |
| + private final class TestFilter extends TokenFilter { |
| + |
| + private String prevType; |
| + private int prevStartOffset; |
| + private int prevEndOffset; |
| + |
| + TermAttribute termAtt; |
| + PositionIncrementAttribute posIncrAtt; |
| + OffsetAttribute offsetAtt; |
| + TypeAttribute typeAtt; |
| + |
| + public TestFilter(TokenStream in) { |
| + super(in); |
| + termAtt = (TermAttribute) addAttribute(TermAttribute.class); |
| + posIncrAtt = (PositionIncrementAttribute) addAttribute(PositionIncrementAttribute.class); |
| + offsetAtt = (OffsetAttribute) addAttribute(OffsetAttribute.class); |
| + typeAtt = (TypeAttribute) addAttribute(TypeAttribute.class); |
| + |
| + } |
| + |
| + /* |
| + * (non-Javadoc) |
| + * |
| + * @see |
| + * org.apache.lucene.analysis.TokenStream#next(org.apache.lucene.analysis |
| + * .Token) |
| + */ |
| + @Override |
| + public Token next(Token reusableToken) throws IOException { |
| + |
| + if (multiToken > 0) { |
| + reusableToken.setTermBuffer("multi" + (multiToken + 1)); |
| + reusableToken.setStartOffset(prevStartOffset); |
| + reusableToken.setEndOffset(prevEndOffset); |
| + reusableToken.setType(prevType); |
| + reusableToken.setPositionIncrement(0); |
| + multiToken--; |
| + return reusableToken; |
| + } else { |
| + boolean next = (reusableToken = input.next(token)) != null; |
| + if (next == false) { |
| + return null; |
| + } |
| + prevType = reusableToken.type(); |
| + prevStartOffset = reusableToken.startOffset(); |
| + prevEndOffset = reusableToken.endOffset(); |
| + String text = reusableToken.term(); |
| + if (text.equals("triplemulti")) { |
| + multiToken = 2; |
| + return reusableToken; |
| + } else if (text.equals("multi")) { |
| + multiToken = 1; |
| + return reusableToken; |
| + } else { |
| + return reusableToken; |
| + } |
| + } |
| + |
| + } |
| + |
| + private Token token = new Token(); |
| + |
| + public final boolean incrementToken() throws java.io.IOException { |
| + if (multiToken > 0) { |
| + termAtt.setTermBuffer("multi" + (multiToken + 1)); |
| + offsetAtt.setOffset(prevStartOffset, prevEndOffset); |
| + typeAtt.setType(prevType); |
| + posIncrAtt.setPositionIncrement(0); |
| + multiToken--; |
| + return true; |
| + } else { |
| + boolean next = input.incrementToken(); |
| + if (next == false) { |
| + return false; |
| + } |
| + prevType = typeAtt.type(); |
| + prevStartOffset = offsetAtt.startOffset(); |
| + prevEndOffset = offsetAtt.endOffset(); |
| + String text = termAtt.term(); |
| + if (text.equals("triplemulti")) { |
| + multiToken = 2; |
| + return true; |
| + } else if (text.equals("multi")) { |
| + multiToken = 1; |
| + return true; |
| + } else { |
| + return true; |
| + } |
| + } |
| + } |
| + |
| + } |
| + |
| + /** |
| + * Analyzes "the quick brown" as: quick(incr=2) brown(incr=1). Does not work |
| + * correctly for input other than "the quick brown ...". |
| + */ |
| + private class PosIncrementAnalyzer extends Analyzer { |
| + |
| + public PosIncrementAnalyzer() { |
| + } |
| + |
| + public TokenStream tokenStream(String fieldName, Reader reader) { |
| + TokenStream result = new StandardTokenizer(reader); |
| + result = new TestPosIncrementFilter(result); |
| + result = new LowerCaseFilter(result); |
| + return result; |
| + } |
| + } |
| + |
| + private class TestPosIncrementFilter extends TokenFilter { |
| + |
| + TermAttribute termAtt; |
| + PositionIncrementAttribute posIncrAtt; |
| + |
| + public TestPosIncrementFilter(TokenStream in) { |
| + super(in); |
| + termAtt = (TermAttribute) addAttribute(TermAttribute.class); |
| + posIncrAtt = (PositionIncrementAttribute) addAttribute(PositionIncrementAttribute.class); |
| + } |
| + |
| + private Token token = new Token(); |
| + |
| + /* |
| + * (non-Javadoc) |
| + * |
| + * @see org.apache.lucene.analysis.TokenStream#next() |
| + */ |
| + @Override |
| + public Token next(Token reusableToken) throws IOException { |
| + while (null != (reusableToken = input.next(token))) { |
| + String term = reusableToken.term(); |
| + if (term.equals("the")) { |
| + // stopword, do nothing |
| + } else if (term.equals("quick")) { |
| + reusableToken.setPositionIncrement(2); |
| + return reusableToken; |
| + } else { |
| + reusableToken.setPositionIncrement(1); |
| + return reusableToken; |
| + } |
| + } |
| + return null; |
| + } |
| + |
| + public final boolean incrementToken() throws java.io.IOException { |
| + while (input.incrementToken()) { |
| + if (termAtt.term().equals("the")) { |
| + // stopword, do nothing |
| + } else if (termAtt.term().equals("quick")) { |
| + posIncrAtt.setPositionIncrement(2); |
| + return true; |
| + } else { |
| + posIncrAtt.setPositionIncrement(1); |
| + return true; |
| + } |
| + } |
| + return false; |
| + } |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiFieldQueryParser.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiFieldQueryParser.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiFieldQueryParser.java (revision 0) |
| @@ -0,0 +1,501 @@ |
| +package org.apache.lucene.queryParser.original; |
| + |
| +/** |
| + * 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 java.io.Reader; |
| +import java.util.HashMap; |
| +import java.util.Map; |
| + |
| +import org.apache.lucene.analysis.Analyzer; |
| +import org.apache.lucene.analysis.SimpleAnalyzer; |
| +import org.apache.lucene.analysis.Token; |
| +import org.apache.lucene.analysis.TokenStream; |
| +import org.apache.lucene.analysis.standard.StandardAnalyzer; |
| +import org.apache.lucene.document.Document; |
| +import org.apache.lucene.document.Field; |
| +import org.apache.lucene.index.IndexWriter; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.original.builders.LuceneQueryTreeBuilder; |
| +import org.apache.lucene.queryParser.original.config.AnalyzerAttribute; |
| +import org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler.Operator; |
| +import org.apache.lucene.queryParser.original.parser.TextParser; |
| +import org.apache.lucene.queryParser.original.processors.LuceneQueryNodeProcessorPipeline; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorPipeline; |
| +import org.apache.lucene.search.BooleanClause; |
| +import org.apache.lucene.search.BooleanQuery; |
| +import org.apache.lucene.search.IndexSearcher; |
| +import org.apache.lucene.search.Query; |
| +import org.apache.lucene.search.ScoreDoc; |
| +import org.apache.lucene.search.BooleanClause.Occur; |
| +import org.apache.lucene.store.Directory; |
| +import org.apache.lucene.store.RAMDirectory; |
| +import org.apache.lucene.util.LuceneTestCase; |
| + |
| +/** |
| + * This test case is a copy of the core Lucene query parser test, it was adapted |
| + * to use the new query parser instead of the old one. |
| + * |
| + * Tests QueryParser. |
| + */ |
| +public class TestMultiFieldQueryParser extends LuceneTestCase { |
| + |
| + /** |
| + * test stop words arsing for both the non static form, and for the |
| + * corresponding static form (qtxt, fields[]). |
| + */ |
| + public void tesStopwordsParsing() throws Exception { |
| + assertStopQueryEquals("one", "b:one t:one"); |
| + assertStopQueryEquals("one stop", "b:one t:one"); |
| + assertStopQueryEquals("one (stop)", "b:one t:one"); |
| + assertStopQueryEquals("one ((stop))", "b:one t:one"); |
| + assertStopQueryEquals("stop", ""); |
| + assertStopQueryEquals("(stop)", ""); |
| + assertStopQueryEquals("((stop))", ""); |
| + } |
| + |
| + // verify parsing of query using a stopping analyzer |
| + private void assertStopQueryEquals(String qtxt, String expectedRes) |
| + throws Exception { |
| + String[] fields = { "b", "t" }; |
| + Occur occur[] = { Occur.SHOULD, Occur.SHOULD }; |
| + TestQueryParser.QPTestAnalyzer a = new TestQueryParser.QPTestAnalyzer(); |
| + |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + config.setMultiFields(fields); |
| + config.setAnalyzer(a); |
| + |
| + Query q = getQuery(config, qtxt); |
| + assertEquals(expectedRes, q.toString()); |
| + |
| + q = parse(qtxt, fields, occur, a); |
| + assertEquals(expectedRes, q.toString()); |
| + } |
| + |
| + private static Query getQuery(LuceneQueryConfigHandler config, |
| + String defaultField, String query) throws QueryNodeException { |
| + |
| + TextParser textParser = new TextParser(); |
| + |
| + if (((AnalyzerAttribute) config.getAttribute(AnalyzerAttribute.class)) |
| + .getAnalyzer() == null) { |
| + config.setAnalyzer(new SimpleAnalyzer()); |
| + } |
| + |
| + QueryNode queryTree = textParser.parse(query, null); |
| + |
| + QueryNodeProcessorPipeline processor = new LuceneQueryNodeProcessorPipeline( |
| + config); |
| + queryTree = processor.process(queryTree); |
| + |
| + LuceneQueryTreeBuilder builder = new LuceneQueryTreeBuilder(); |
| + |
| + return builder.build(queryTree); |
| + |
| + } |
| + |
| + private static Query getQuery(LuceneQueryConfigHandler config, String query) |
| + throws QueryNodeException { |
| + return getQuery(config, "", query); |
| + } |
| + |
| + public void testSimple() throws Exception { |
| + String[] fields = { "b", "t" }; |
| + |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + config.setMultiFields(fields); |
| + config.setAnalyzer(new StandardAnalyzer()); |
| + |
| + Query q = getQuery(config, "one"); |
| + assertEquals("b:one t:one", q.toString()); |
| + |
| + q = getQuery(config, "one two"); |
| + assertEquals("(b:one t:one) (b:two t:two)", q.toString()); |
| + |
| + q = getQuery(config, "+one +two"); |
| + assertEquals("+(b:one t:one) +(b:two t:two)", q.toString()); |
| + |
| + q = getQuery(config, "+one -two -three"); |
| + assertEquals("+(b:one t:one) -(b:two t:two) -(b:three t:three)", q |
| + .toString()); |
| + |
| + q = getQuery(config, "one^2 two"); |
| + assertEquals("((b:one t:one)^2.0) (b:two t:two)", q.toString()); |
| + |
| + q = getQuery(config, "one~ two"); |
| + assertEquals("(b:one~0.5 t:one~0.5) (b:two t:two)", q.toString()); |
| + |
| + q = getQuery(config, "one~0.8 two^2"); |
| + assertEquals("(b:one~0.8 t:one~0.8) ((b:two t:two)^2.0)", q.toString()); |
| + |
| + q = getQuery(config, "one* two*"); |
| + assertEquals("(b:one* t:one*) (b:two* t:two*)", q.toString()); |
| + |
| + q = getQuery(config, "[a TO c] two"); |
| + assertEquals("(b:[a TO c] t:[a TO c]) (b:two t:two)", q.toString()); |
| + |
| + q = getQuery(config, "w?ldcard"); |
| + assertEquals("b:w?ldcard t:w?ldcard", q.toString()); |
| + |
| + q = getQuery(config, "\"foo bar\""); |
| + assertEquals("b:\"foo bar\" t:\"foo bar\"", q.toString()); |
| + |
| + q = getQuery(config, "\"aa bb cc\" \"dd ee\""); |
| + assertEquals("(b:\"aa bb cc\" t:\"aa bb cc\") (b:\"dd ee\" t:\"dd ee\")", q |
| + .toString()); |
| + |
| + q = getQuery(config, "\"foo bar\"~4"); |
| + assertEquals("b:\"foo bar\"~4 t:\"foo bar\"~4", q.toString()); |
| + |
| + // LUCENE-1213: MultiFieldQueryParserWrapper was ignoring slop when |
| + // phrase had a field. |
| + q = getQuery(config, "b:\"foo bar\"~4"); |
| + assertEquals("b:\"foo bar\"~4", q.toString()); |
| + |
| + // make sure that terms which have a field are not touched: |
| + q = getQuery(config, "one f:two"); |
| + assertEquals("(b:one t:one) f:two", q.toString()); |
| + |
| + // AND mode: |
| + config.setDefaultOperator(Operator.AND); |
| + q = getQuery(config, "one two"); |
| + assertEquals("+(b:one t:one) +(b:two t:two)", q.toString()); |
| + q = getQuery(config, "\"aa bb cc\" \"dd ee\""); |
| + assertEquals("+(b:\"aa bb cc\" t:\"aa bb cc\") +(b:\"dd ee\" t:\"dd ee\")", |
| + q.toString()); |
| + |
| + } |
| + |
| + public void testBoostsSimple() throws Exception { |
| + Map boosts = new HashMap(); |
| + boosts.put("b", new Float(5)); |
| + boosts.put("t", new Float(10)); |
| + String[] fields = { "b", "t" }; |
| + |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + config.setMultiFields(fields); |
| + config.setFieldsBoost(boosts); |
| + config.setAnalyzer(new StandardAnalyzer()); |
| + |
| + // Check for simple |
| + Query q = getQuery(config, "one"); |
| + assertEquals("b:one^5.0 t:one^10.0", q.toString()); |
| + |
| + // Check for AND |
| + q = getQuery(config, "one AND two"); |
| + assertEquals("+(b:one^5.0 t:one^10.0) +(b:two^5.0 t:two^10.0)", q |
| + .toString()); |
| + |
| + // Check for OR |
| + q = getQuery(config, "one OR two"); |
| + assertEquals("(b:one^5.0 t:one^10.0) (b:two^5.0 t:two^10.0)", q.toString()); |
| + |
| + // Check for AND and a field |
| + q = getQuery(config, "one AND two AND foo:test"); |
| + assertEquals("+(b:one^5.0 t:one^10.0) +(b:two^5.0 t:two^10.0) +foo:test", q |
| + .toString()); |
| + |
| + q = getQuery(config, "one^3 AND two^4"); |
| + assertEquals("+((b:one^5.0 t:one^10.0)^3.0) +((b:two^5.0 t:two^10.0)^4.0)", |
| + q.toString()); |
| + } |
| + |
| + public void testStaticMethod1() throws QueryNodeException { |
| + String[] fields = { "b", "t" }; |
| + String[] queries = { "one", "two" }; |
| + |
| + Query q = parse(queries, fields, new StandardAnalyzer()); |
| + assertEquals("b:one t:two", q.toString()); |
| + |
| + String[] queries2 = { "+one", "+two" }; |
| + q = parse(queries2, fields, new StandardAnalyzer()); |
| + assertEquals("(+b:one) (+t:two)", q.toString()); |
| + |
| + String[] queries3 = { "one", "+two" }; |
| + q = parse(queries3, fields, new StandardAnalyzer()); |
| + assertEquals("b:one (+t:two)", q.toString()); |
| + |
| + String[] queries4 = { "one +more", "+two" }; |
| + q = parse(queries4, fields, new StandardAnalyzer()); |
| + assertEquals("(b:one +b:more) (+t:two)", q.toString()); |
| + |
| + String[] queries5 = { "blah" }; |
| + try { |
| + q = parse(queries5, fields, new StandardAnalyzer()); |
| + fail(); |
| + } catch (IllegalArgumentException e) { |
| + // expected exception, array length differs |
| + } |
| + |
| + // check also with stop words for this static form (qtxts[], fields[]). |
| + TestQueryParser.QPTestAnalyzer stopA = new TestQueryParser.QPTestAnalyzer(); |
| + |
| + String[] queries6 = { "((+stop))", "+((stop))" }; |
| + q = parse(queries6, fields, stopA); |
| + assertEquals("", q.toString()); |
| + |
| + String[] queries7 = { "one ((+stop)) +more", "+((stop)) +two" }; |
| + q = parse(queries7, fields, stopA); |
| + assertEquals("(b:one +b:more) (+t:two)", q.toString()); |
| + |
| + } |
| + |
| + public void testStaticMethod2() throws QueryNodeException { |
| + String[] fields = { "b", "t" }; |
| + BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST, |
| + BooleanClause.Occur.MUST_NOT }; |
| + Query q = parse("one", fields, flags, new StandardAnalyzer()); |
| + assertEquals("+b:one -t:one", q.toString()); |
| + |
| + q = parse("one two", fields, flags, new StandardAnalyzer()); |
| + assertEquals("+(b:one b:two) -(t:one t:two)", q.toString()); |
| + |
| + try { |
| + BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST }; |
| + q = parse("blah", fields, flags2, new StandardAnalyzer()); |
| + fail(); |
| + } catch (IllegalArgumentException e) { |
| + // expected exception, array length differs |
| + } |
| + } |
| + |
| + public void testStaticMethod2Old() throws QueryNodeException { |
| + String[] fields = { "b", "t" }; |
| + // int[] flags = {MultiFieldQueryParserWrapper.REQUIRED_FIELD, |
| + // MultiFieldQueryParserWrapper.PROHIBITED_FIELD}; |
| + BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST, |
| + BooleanClause.Occur.MUST_NOT }; |
| + |
| + Query q = parse("one", fields, flags, new StandardAnalyzer());// , |
| + // fields, |
| + // flags, |
| + // new |
| + // StandardAnalyzer()); |
| + assertEquals("+b:one -t:one", q.toString()); |
| + |
| + q = parse("one two", fields, flags, new StandardAnalyzer()); |
| + assertEquals("+(b:one b:two) -(t:one t:two)", q.toString()); |
| + |
| + try { |
| + BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST }; |
| + q = parse("blah", fields, flags2, new StandardAnalyzer()); |
| + fail(); |
| + } catch (IllegalArgumentException e) { |
| + // expected exception, array length differs |
| + } |
| + } |
| + |
| + public void testStaticMethod3() throws QueryNodeException { |
| + String[] queries = { "one", "two", "three" }; |
| + String[] fields = { "f1", "f2", "f3" }; |
| + BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST, |
| + BooleanClause.Occur.MUST_NOT, BooleanClause.Occur.SHOULD }; |
| + Query q = parse(queries, fields, flags, new StandardAnalyzer()); |
| + assertEquals("+f1:one -f2:two f3:three", q.toString()); |
| + |
| + try { |
| + BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST }; |
| + q = parse(queries, fields, flags2, new StandardAnalyzer()); |
| + fail(); |
| + } catch (IllegalArgumentException e) { |
| + // expected exception, array length differs |
| + } |
| + } |
| + |
| + public void testStaticMethod3Old() throws QueryNodeException { |
| + String[] queries = { "one", "two" }; |
| + String[] fields = { "b", "t" }; |
| + BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST, |
| + BooleanClause.Occur.MUST_NOT }; |
| + Query q = parse(queries, fields, flags, new StandardAnalyzer()); |
| + assertEquals("+b:one -t:two", q.toString()); |
| + |
| + try { |
| + BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST }; |
| + q = parse(queries, fields, flags2, new StandardAnalyzer()); |
| + fail(); |
| + } catch (IllegalArgumentException e) { |
| + // expected exception, array length differs |
| + } |
| + } |
| + |
| + public void testAnalyzerReturningNull() throws QueryNodeException { |
| + String[] fields = new String[] { "f1", "f2", "f3" }; |
| + |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + config.setMultiFields(fields); |
| + config.setAnalyzer(new AnalyzerReturningNull()); |
| + |
| + Query q = getQuery(config, "bla AND blo"); |
| + assertEquals("+(f2:bla f3:bla) +(f2:blo f3:blo)", q.toString()); |
| + // the following queries are not affected as their terms are not |
| + // analyzed anyway: |
| + q = getQuery(config, "bla*"); |
| + assertEquals("f1:bla* f2:bla* f3:bla*", q.toString()); |
| + q = getQuery(config, "bla~"); |
| + assertEquals("f1:bla~0.5 f2:bla~0.5 f3:bla~0.5", q.toString()); |
| + q = getQuery(config, "[a TO c]"); |
| + assertEquals("f1:[a TO c] f2:[a TO c] f3:[a TO c]", q.toString()); |
| + } |
| + |
| + public void testStopWordSearching() throws Exception { |
| + Analyzer analyzer = new StandardAnalyzer(); |
| + Directory ramDir = new RAMDirectory(); |
| + IndexWriter iw = new IndexWriter(ramDir, analyzer, true, |
| + IndexWriter.MaxFieldLength.LIMITED); |
| + Document doc = new Document(); |
| + doc.add(new Field("body", "blah the footest blah", Field.Store.NO, |
| + Field.Index.ANALYZED)); |
| + iw.addDocument(doc); |
| + iw.close(); |
| + |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + config.setMultiFields(new String[] { "body" }); |
| + config.setAnalyzer(analyzer); |
| + config.setDefaultOperator(Operator.AND); |
| + |
| + Query q = getQuery(config, "the footest"); |
| + IndexSearcher is = new IndexSearcher(ramDir); |
| + ScoreDoc[] hits = is.search(q, null, 1000).scoreDocs; |
| + assertEquals(1, hits.length); |
| + is.close(); |
| + } |
| + |
| + /** |
| + * Return empty tokens for field "f1". |
| + */ |
| + private static class AnalyzerReturningNull extends Analyzer { |
| + StandardAnalyzer stdAnalyzer = new StandardAnalyzer(); |
| + |
| + public AnalyzerReturningNull() { |
| + } |
| + |
| + public TokenStream tokenStream(String fieldName, Reader reader) { |
| + if ("f1".equals(fieldName)) { |
| + return new EmptyTokenStream(); |
| + } else { |
| + return stdAnalyzer.tokenStream(fieldName, reader); |
| + } |
| + } |
| + |
| + private static class EmptyTokenStream extends TokenStream { |
| + public Token next(final Token reusableToken) { |
| + return null; |
| + } |
| + } |
| + } |
| + |
| + public static Query parse(String[] queries, String[] fields, Analyzer analyzer) |
| + throws QueryNodeException { |
| + |
| + TextParser textParser = new TextParser(); |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + LuceneQueryTreeBuilder builder = new LuceneQueryTreeBuilder(); |
| + LuceneQueryNodeProcessorPipeline processor = new LuceneQueryNodeProcessorPipeline( |
| + config); |
| + |
| + if (analyzer == null) { |
| + analyzer = new SimpleAnalyzer(); |
| + } |
| + |
| + config.setAnalyzer(analyzer); |
| + |
| + if (queries.length != fields.length) |
| + throw new IllegalArgumentException("queries.length != fields.length"); |
| + BooleanQuery bQuery = new BooleanQuery(); |
| + for (int i = 0; i < fields.length; i++) { |
| + QueryNode queryTree = textParser.parse(queries[i], fields[i]); |
| + |
| + queryTree = processor.process(queryTree); |
| + Query q = builder.build(queryTree); |
| + |
| + if (q != null && // q never null, just being defensive |
| + (!(q instanceof BooleanQuery) || ((BooleanQuery) q).getClauses().length > 0)) { |
| + bQuery.add(q, BooleanClause.Occur.SHOULD); |
| + } |
| + } |
| + return bQuery; |
| + } |
| + |
| + public static Query parse(String query, String[] fields, |
| + BooleanClause.Occur[] flags, Analyzer analyzer) throws QueryNodeException { |
| + |
| + TextParser textParser = new TextParser(); |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + LuceneQueryTreeBuilder builder = new LuceneQueryTreeBuilder(); |
| + LuceneQueryNodeProcessorPipeline processor = new LuceneQueryNodeProcessorPipeline( |
| + config); |
| + |
| + if (analyzer == null) { |
| + analyzer = new SimpleAnalyzer(); |
| + } |
| + |
| + config.setAnalyzer(analyzer); |
| + |
| + if (fields.length != flags.length) |
| + throw new IllegalArgumentException("fields.length != flags.length"); |
| + BooleanQuery bQuery = new BooleanQuery(); |
| + for (int i = 0; i < fields.length; i++) { |
| + QueryNode queryTree = textParser.parse(query, fields[i]); |
| + |
| + queryTree = processor.process(queryTree); |
| + Query q = builder.build(queryTree); |
| + |
| + if (q != null && // q never null, just being defensive |
| + (!(q instanceof BooleanQuery) || ((BooleanQuery) q).getClauses().length > 0)) { |
| + bQuery.add(q, flags[i]); |
| + } |
| + } |
| + return bQuery; |
| + } |
| + |
| + public static Query parse(String[] queries, String[] fields, |
| + BooleanClause.Occur[] flags, Analyzer analyzer) throws QueryNodeException { |
| + |
| + TextParser textParser = new TextParser(); |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + LuceneQueryTreeBuilder builder = new LuceneQueryTreeBuilder(); |
| + LuceneQueryNodeProcessorPipeline processor = new LuceneQueryNodeProcessorPipeline( |
| + config); |
| + |
| + if (analyzer == null) { |
| + analyzer = new SimpleAnalyzer(); |
| + } |
| + |
| + config.setAnalyzer(analyzer); |
| + |
| + if (!(queries.length == fields.length && queries.length == flags.length)) |
| + throw new IllegalArgumentException( |
| + "queries, fields, and flags array have have different length"); |
| + BooleanQuery bQuery = new BooleanQuery(); |
| + for (int i = 0; i < fields.length; i++) { |
| + QueryNode queryTree = textParser.parse(queries[i], fields[i]); |
| + |
| + queryTree = processor.process(queryTree); |
| + Query q = builder.build(queryTree); |
| + |
| + if (q != null && // q never null, just being defensive |
| + (!(q instanceof BooleanQuery) || ((BooleanQuery) q).getClauses().length > 0)) { |
| + bQuery.add(q, flags[i]); |
| + } |
| + } |
| + return bQuery; |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestQPHelper.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestQPHelper.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestQPHelper.java (revision 0) |
| @@ -0,0 +1,1128 @@ |
| +package org.apache.lucene.queryParser.original; |
| + |
| +/** |
| + * 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 java.io.IOException; |
| +import java.io.Reader; |
| +import java.text.Collator; |
| +import java.text.DateFormat; |
| +import java.util.Calendar; |
| +import java.util.Date; |
| +import java.util.List; |
| +import java.util.Locale; |
| + |
| +import org.apache.lucene.analysis.Analyzer; |
| +import org.apache.lucene.analysis.KeywordAnalyzer; |
| +import org.apache.lucene.analysis.LowerCaseTokenizer; |
| +import org.apache.lucene.analysis.SimpleAnalyzer; |
| +import org.apache.lucene.analysis.StopAnalyzer; |
| +import org.apache.lucene.analysis.StopFilter; |
| +import org.apache.lucene.analysis.Token; |
| +import org.apache.lucene.analysis.TokenFilter; |
| +import org.apache.lucene.analysis.TokenStream; |
| +import org.apache.lucene.analysis.WhitespaceAnalyzer; |
| +import org.apache.lucene.analysis.standard.StandardAnalyzer; |
| +import org.apache.lucene.analysis.tokenattributes.OffsetAttribute; |
| +import org.apache.lucene.analysis.tokenattributes.TermAttribute; |
| +import org.apache.lucene.document.DateField; |
| +import org.apache.lucene.document.DateTools; |
| +import org.apache.lucene.document.Document; |
| +import org.apache.lucene.document.Field; |
| +import org.apache.lucene.index.IndexWriter; |
| +import org.apache.lucene.index.Term; |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.nodes.FuzzyQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.WildcardQueryNode; |
| +import org.apache.lucene.queryParser.original.LuceneQueryParserHelper; |
| +import org.apache.lucene.queryParser.original.QueryParserWrapper; |
| +import org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler.Operator; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| +import org.apache.lucene.search.BooleanQuery; |
| +import org.apache.lucene.search.FuzzyQuery; |
| +import org.apache.lucene.search.IndexSearcher; |
| +import org.apache.lucene.search.MatchAllDocsQuery; |
| +import org.apache.lucene.search.PhraseQuery; |
| +import org.apache.lucene.search.PrefixQuery; |
| +import org.apache.lucene.search.Query; |
| +import org.apache.lucene.search.ScoreDoc; |
| +import org.apache.lucene.search.TermQuery; |
| +import org.apache.lucene.search.TermRangeQuery; |
| +import org.apache.lucene.search.WildcardQuery; |
| +import org.apache.lucene.store.RAMDirectory; |
| +import org.apache.lucene.util.LuceneTestCase; |
| + |
| +/** |
| + * This test case is a copy of the core Lucene query parser test, it was adapted |
| + * to use new QueryParserHelper instead of the old query parser. |
| + * |
| + * Tests QueryParser. |
| + */ |
| +public class TestQPHelper extends LuceneTestCase { |
| + |
| + public static Analyzer qpAnalyzer = new QPTestAnalyzer(); |
| + |
| + public static class QPTestFilter extends TokenFilter { |
| + TermAttribute termAtt; |
| + OffsetAttribute offsetAtt; |
| + |
| + /** |
| + * Filter which discards the token 'stop' and which expands the token |
| + * 'phrase' into 'phrase1 phrase2' |
| + */ |
| + public QPTestFilter(TokenStream in) { |
| + super(in); |
| + termAtt = (TermAttribute) addAttribute(TermAttribute.class); |
| + offsetAtt = (OffsetAttribute) addAttribute(OffsetAttribute.class); |
| + } |
| + |
| + boolean inPhrase = false; |
| + int savedStart = 0, savedEnd = 0; |
| + |
| + public Token next(Token reusableToken) throws IOException { |
| + Token token = reusableToken; |
| + |
| + if (inPhrase) { |
| + inPhrase = false; |
| + token.setTermBuffer("phrase2"); |
| + token.setStartOffset(savedStart); |
| + token.setEndOffset(savedEnd); |
| + return reusableToken; |
| + } else |
| + while ((token = this.input.next(reusableToken)) != null) { |
| + if (token.term().equals("phrase")) { |
| + inPhrase = true; |
| + savedStart = token.startOffset(); |
| + savedEnd = token.endOffset(); |
| + token.setTermBuffer("phrase1"); |
| + token.setStartOffset(savedStart); |
| + token.setEndOffset(savedEnd); |
| + return token; |
| + } else if (!token.term().equals("stop")) |
| + return token; |
| + } |
| + |
| + return null; |
| + |
| + } |
| + |
| + public boolean incrementToken() throws IOException { |
| + if (inPhrase) { |
| + inPhrase = false; |
| + termAtt.setTermBuffer("phrase2"); |
| + offsetAtt.setOffset(savedStart, savedEnd); |
| + return true; |
| + } else |
| + while (input.incrementToken()) { |
| + if (termAtt.term().equals("phrase")) { |
| + inPhrase = true; |
| + savedStart = offsetAtt.startOffset(); |
| + savedEnd = offsetAtt.endOffset(); |
| + termAtt.setTermBuffer("phrase1"); |
| + offsetAtt.setOffset(savedStart, savedEnd); |
| + return true; |
| + } else if (!termAtt.term().equals("stop")) |
| + return true; |
| + } |
| + return false; |
| + } |
| + } |
| + |
| + public static class QPTestAnalyzer extends Analyzer { |
| + |
| + /** Filters LowerCaseTokenizer with StopFilter. */ |
| + public final TokenStream tokenStream(String fieldName, Reader reader) { |
| + return new QPTestFilter(new LowerCaseTokenizer(reader)); |
| + } |
| + } |
| + |
| + public static class QPTestParser extends LuceneQueryParserHelper { |
| + public QPTestParser(Analyzer a) { |
| + getQueryNodeProcessor() |
| + .addProcessor(new QPTestParserQueryNodeProcessor()); |
| + getQueryConfigHandler().setAnalyzer(a); |
| + |
| + } |
| + |
| + private static class QPTestParserQueryNodeProcessor extends |
| + QueryNodeProcessorImpl { |
| + |
| + protected QueryNode postProcessNode(QueryNode node) |
| + throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected QueryNode preProcessNode(QueryNode node) |
| + throws QueryNodeException { |
| + |
| + if (node instanceof WildcardQueryNode || node instanceof FuzzyQueryNode) { |
| + |
| + throw new QueryNodeException(new MessageImpl( |
| + QueryParserMessages.EMPTY_MESSAGE)); |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + private int originalMaxClauses; |
| + |
| + public void setUp() throws Exception { |
| + super.setUp(); |
| + originalMaxClauses = BooleanQuery.getMaxClauseCount(); |
| + } |
| + |
| + public LuceneQueryParserHelper getParser(Analyzer a) throws Exception { |
| + if (a == null) |
| + a = new SimpleAnalyzer(); |
| + LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + qp.getQueryConfigHandler().setAnalyzer(a); |
| + |
| + qp.getQueryConfigHandler().setDefaultOperator(Operator.OR); |
| + |
| + return qp; |
| + |
| + } |
| + |
| + public Query getQuery(String query, Analyzer a) throws Exception { |
| + return getParser(a).parse(query, "field"); |
| + } |
| + |
| + public void assertQueryEquals(String query, Analyzer a, String result) |
| + throws Exception { |
| + Query q = getQuery(query, a); |
| + String s = q.toString("field"); |
| + if (!s.equals(result)) { |
| + fail("Query /" + query + "/ yielded /" + s + "/, expecting /" + result |
| + + "/"); |
| + } |
| + } |
| + |
| + public void assertQueryEquals(LuceneQueryParserHelper qp, String field, |
| + String query, String result) throws Exception { |
| + Query q = qp.parse(query, field); |
| + String s = q.toString(field); |
| + if (!s.equals(result)) { |
| + fail("Query /" + query + "/ yielded /" + s + "/, expecting /" + result |
| + + "/"); |
| + } |
| + } |
| + |
| + public void assertEscapedQueryEquals(String query, Analyzer a, String result) |
| + throws Exception { |
| + String escapedQuery = QueryParserWrapper.escape(query); |
| + if (!escapedQuery.equals(result)) { |
| + fail("Query /" + query + "/ yielded /" + escapedQuery + "/, expecting /" |
| + + result + "/"); |
| + } |
| + } |
| + |
| + public void assertWildcardQueryEquals(String query, boolean lowercase, |
| + String result, boolean allowLeadingWildcard) throws Exception { |
| + LuceneQueryParserHelper qp = getParser(null); |
| + qp.getQueryConfigHandler().setLowercaseExpandedTerms(lowercase); |
| + qp.getQueryConfigHandler().setAllowLeadingWildcard(allowLeadingWildcard); |
| + Query q = qp.parse(query, "field"); |
| + String s = q.toString("field"); |
| + if (!s.equals(result)) { |
| + fail("WildcardQuery /" + query + "/ yielded /" + s + "/, expecting /" |
| + + result + "/"); |
| + } |
| + } |
| + |
| + public void assertWildcardQueryEquals(String query, boolean lowercase, |
| + String result) throws Exception { |
| + assertWildcardQueryEquals(query, lowercase, result, false); |
| + } |
| + |
| + public void assertWildcardQueryEquals(String query, String result) |
| + throws Exception { |
| + LuceneQueryParserHelper qp = getParser(null); |
| + Query q = qp.parse(query, "field"); |
| + String s = q.toString("field"); |
| + if (!s.equals(result)) { |
| + fail("WildcardQuery /" + query + "/ yielded /" + s + "/, expecting /" |
| + + result + "/"); |
| + } |
| + } |
| + |
| + public Query getQueryDOA(String query, Analyzer a) throws Exception { |
| + if (a == null) |
| + a = new SimpleAnalyzer(); |
| + LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + qp.getQueryConfigHandler().setAnalyzer(a); |
| + qp.getQueryConfigHandler().setDefaultOperator(Operator.AND); |
| + |
| + return qp.parse(query, "field"); |
| + |
| + } |
| + |
| + public void assertQueryEqualsDOA(String query, Analyzer a, String result) |
| + throws Exception { |
| + Query q = getQueryDOA(query, a); |
| + String s = q.toString("field"); |
| + if (!s.equals(result)) { |
| + fail("Query /" + query + "/ yielded /" + s + "/, expecting /" + result |
| + + "/"); |
| + } |
| + } |
| + |
| + public void testCJK() throws Exception { |
| + // Test Ideographic Space - As wide as a CJK character cell (fullwidth) |
| + // used google to translate the word "term" to japanese -> 用語 |
| + assertQueryEquals("term\u3000term\u3000term", null, |
| + "term\u0020term\u0020term"); |
| + assertQueryEquals("用語\u3000用語\u3000用語", null, "用語\u0020用語\u0020用語"); |
| + } |
| + |
| + public void testSimple() throws Exception { |
| + assertQueryEquals("\"term germ\"~2", null, "\"term germ\"~2"); |
| + assertQueryEquals("term term term", null, "term term term"); |
| + assertQueryEquals("türm term term", new WhitespaceAnalyzer(), |
| + "türm term term"); |
| + assertQueryEquals("ümlaut", new WhitespaceAnalyzer(), "ümlaut"); |
| + |
| + assertQueryEquals("\"\"", new KeywordAnalyzer(), ""); |
| + assertQueryEquals("foo:\"\"", new KeywordAnalyzer(), "foo:"); |
| + |
| + assertQueryEquals("a AND b", null, "+a +b"); |
| + assertQueryEquals("(a AND b)", null, "+a +b"); |
| + assertQueryEquals("c OR (a AND b)", null, "c (+a +b)"); |
| + |
| + assertQueryEquals("a AND NOT b", null, "+a -b"); |
| + |
| + assertQueryEquals("a AND -b", null, "+a -b"); |
| + |
| + assertQueryEquals("a AND !b", null, "+a -b"); |
| + |
| + assertQueryEquals("a && b", null, "+a +b"); |
| + |
| + assertQueryEquals("a && ! b", null, "+a -b"); |
| + |
| + assertQueryEquals("a OR b", null, "a b"); |
| + assertQueryEquals("a || b", null, "a b"); |
| + |
| + assertQueryEquals("a OR !b", null, "a -b"); |
| + |
| + assertQueryEquals("a OR ! b", null, "a -b"); |
| + |
| + assertQueryEquals("a OR -b", null, "a -b"); |
| + |
| + assertQueryEquals("+term -term term", null, "+term -term term"); |
| + assertQueryEquals("foo:term AND field:anotherTerm", null, |
| + "+foo:term +anotherterm"); |
| + assertQueryEquals("term AND \"phrase phrase\"", null, |
| + "+term +\"phrase phrase\""); |
| + assertQueryEquals("\"hello there\"", null, "\"hello there\""); |
| + assertTrue(getQuery("a AND b", null) instanceof BooleanQuery); |
| + assertTrue(getQuery("hello", null) instanceof TermQuery); |
| + assertTrue(getQuery("\"hello there\"", null) instanceof PhraseQuery); |
| + |
| + assertQueryEquals("germ term^2.0", null, "germ term^2.0"); |
| + assertQueryEquals("(term)^2.0", null, "term^2.0"); |
| + assertQueryEquals("(germ term)^2.0", null, "(germ term)^2.0"); |
| + assertQueryEquals("term^2.0", null, "term^2.0"); |
| + assertQueryEquals("term^2", null, "term^2.0"); |
| + assertQueryEquals("\"germ term\"^2.0", null, "\"germ term\"^2.0"); |
| + assertQueryEquals("\"term germ\"^2", null, "\"term germ\"^2.0"); |
| + |
| + assertQueryEquals("(foo OR bar) AND (baz OR boo)", null, |
| + "+(foo bar) +(baz boo)"); |
| + assertQueryEquals("((a OR b) AND NOT c) OR d", null, "(+(a b) -c) d"); |
| + assertQueryEquals("+(apple \"steve jobs\") -(foo bar baz)", null, |
| + "+(apple \"steve jobs\") -(foo bar baz)"); |
| + assertQueryEquals("+title:(dog OR cat) -author:\"bob dole\"", null, |
| + "+(title:dog title:cat) -author:\"bob dole\""); |
| + |
| + } |
| + |
| + public void testPunct() throws Exception { |
| + Analyzer a = new WhitespaceAnalyzer(); |
| + assertQueryEquals("a&b", a, "a&b"); |
| + assertQueryEquals("a&&b", a, "a&&b"); |
| + assertQueryEquals(".NET", a, ".NET"); |
| + } |
| + |
| + public void testSlop() throws Exception { |
| + |
| + assertQueryEquals("\"term germ\"~2", null, "\"term germ\"~2"); |
| + assertQueryEquals("\"term germ\"~2 flork", null, "\"term germ\"~2 flork"); |
| + assertQueryEquals("\"term\"~2", null, "term"); |
| + assertQueryEquals("\" \"~2 germ", null, "germ"); |
| + assertQueryEquals("\"term germ\"~2^2", null, "\"term germ\"~2^2.0"); |
| + } |
| + |
| + public void testNumber() throws Exception { |
| + // The numbers go away because SimpleAnalzyer ignores them |
| + assertQueryEquals("3", null, ""); |
| + assertQueryEquals("term 1.0 1 2", null, "term"); |
| + assertQueryEquals("term term1 term2", null, "term term term"); |
| + |
| + Analyzer a = new StandardAnalyzer(); |
| + assertQueryEquals("3", a, "3"); |
| + assertQueryEquals("term 1.0 1 2", a, "term 1.0 1 2"); |
| + assertQueryEquals("term term1 term2", a, "term term1 term2"); |
| + } |
| + |
| + public void testWildcard() throws Exception { |
| + assertQueryEquals("term*", null, "term*"); |
| + assertQueryEquals("term*^2", null, "term*^2.0"); |
| + assertQueryEquals("term~", null, "term~0.5"); |
| + assertQueryEquals("term~0.7", null, "term~0.7"); |
| + |
| + assertQueryEquals("term~^2", null, "term~0.5^2.0"); |
| + |
| + assertQueryEquals("term^2~", null, "term~0.5^2.0"); |
| + assertQueryEquals("term*germ", null, "term*germ"); |
| + assertQueryEquals("term*germ^3", null, "term*germ^3.0"); |
| + |
| + assertTrue(getQuery("term*", null) instanceof PrefixQuery); |
| + assertTrue(getQuery("term*^2", null) instanceof PrefixQuery); |
| + assertTrue(getQuery("term~", null) instanceof FuzzyQuery); |
| + assertTrue(getQuery("term~0.7", null) instanceof FuzzyQuery); |
| + FuzzyQuery fq = (FuzzyQuery) getQuery("term~0.7", null); |
| + assertEquals(0.7f, fq.getMinSimilarity(), 0.1f); |
| + assertEquals(FuzzyQuery.defaultPrefixLength, fq.getPrefixLength()); |
| + fq = (FuzzyQuery) getQuery("term~", null); |
| + assertEquals(0.5f, fq.getMinSimilarity(), 0.1f); |
| + assertEquals(FuzzyQuery.defaultPrefixLength, fq.getPrefixLength()); |
| + |
| + assertQueryNodeException("term~1.1"); // value > 1, throws exception |
| + |
| + assertTrue(getQuery("term*germ", null) instanceof WildcardQuery); |
| + |
| + /* |
| + * Tests to see that wild card terms are (or are not) properly lower-cased |
| + * with propery parser configuration |
| + */ |
| + // First prefix queries: |
| + // by default, convert to lowercase: |
| + assertWildcardQueryEquals("Term*", true, "term*"); |
| + // explicitly set lowercase: |
| + assertWildcardQueryEquals("term*", true, "term*"); |
| + assertWildcardQueryEquals("Term*", true, "term*"); |
| + assertWildcardQueryEquals("TERM*", true, "term*"); |
| + // explicitly disable lowercase conversion: |
| + assertWildcardQueryEquals("term*", false, "term*"); |
| + assertWildcardQueryEquals("Term*", false, "Term*"); |
| + assertWildcardQueryEquals("TERM*", false, "TERM*"); |
| + // Then 'full' wildcard queries: |
| + // by default, convert to lowercase: |
| + assertWildcardQueryEquals("Te?m", "te?m"); |
| + // explicitly set lowercase: |
| + assertWildcardQueryEquals("te?m", true, "te?m"); |
| + assertWildcardQueryEquals("Te?m", true, "te?m"); |
| + assertWildcardQueryEquals("TE?M", true, "te?m"); |
| + assertWildcardQueryEquals("Te?m*gerM", true, "te?m*germ"); |
| + // explicitly disable lowercase conversion: |
| + assertWildcardQueryEquals("te?m", false, "te?m"); |
| + assertWildcardQueryEquals("Te?m", false, "Te?m"); |
| + assertWildcardQueryEquals("TE?M", false, "TE?M"); |
| + assertWildcardQueryEquals("Te?m*gerM", false, "Te?m*gerM"); |
| + // Fuzzy queries: |
| + assertWildcardQueryEquals("Term~", "term~0.5"); |
| + assertWildcardQueryEquals("Term~", true, "term~0.5"); |
| + assertWildcardQueryEquals("Term~", false, "Term~0.5"); |
| + // Range queries: |
| + |
| + // TODO: implement this on QueryParser |
| + // Q0002E_INVALID_SYNTAX_CANNOT_PARSE: Syntax Error, cannot parse '[A TO |
| + // C]': Lexical error at line 1, column 1. Encountered: "[" (91), after |
| + // : "" |
| + assertWildcardQueryEquals("[A TO C]", "[a TO c]"); |
| + assertWildcardQueryEquals("[A TO C]", true, "[a TO c]"); |
| + assertWildcardQueryEquals("[A TO C]", false, "[A TO C]"); |
| + // Test suffix queries: first disallow |
| + try { |
| + assertWildcardQueryEquals("*Term", true, "*term"); |
| + fail(); |
| + } catch (QueryNodeException pe) { |
| + // expected exception |
| + } |
| + try { |
| + assertWildcardQueryEquals("?Term", true, "?term"); |
| + fail(); |
| + } catch (QueryNodeException pe) { |
| + // expected exception |
| + } |
| + // Test suffix queries: then allow |
| + assertWildcardQueryEquals("*Term", true, "*term", true); |
| + assertWildcardQueryEquals("?Term", true, "?term", true); |
| + } |
| + |
| + public void testLeadingWildcardType() throws Exception { |
| + LuceneQueryParserHelper qp = getParser(null); |
| + qp.getQueryConfigHandler().setAllowLeadingWildcard(true); |
| + assertEquals(WildcardQuery.class, qp.parse("t*erm*", "field").getClass()); |
| + assertEquals(WildcardQuery.class, qp.parse("?term*", "field").getClass()); |
| + assertEquals(WildcardQuery.class, qp.parse("*term*", "field").getClass()); |
| + } |
| + |
| + public void testQPA() throws Exception { |
| + assertQueryEquals("term term^3.0 term", qpAnalyzer, "term term^3.0 term"); |
| + assertQueryEquals("term stop^3.0 term", qpAnalyzer, "term term"); |
| + |
| + assertQueryEquals("term term term", qpAnalyzer, "term term term"); |
| + assertQueryEquals("term +stop term", qpAnalyzer, "term term"); |
| + assertQueryEquals("term -stop term", qpAnalyzer, "term term"); |
| + |
| + assertQueryEquals("drop AND (stop) AND roll", qpAnalyzer, "+drop +roll"); |
| + assertQueryEquals("term +(stop) term", qpAnalyzer, "term term"); |
| + assertQueryEquals("term -(stop) term", qpAnalyzer, "term term"); |
| + |
| + assertQueryEquals("drop AND stop AND roll", qpAnalyzer, "+drop +roll"); |
| + assertQueryEquals("term phrase term", qpAnalyzer, |
| + "term \"phrase1 phrase2\" term"); |
| + |
| + assertQueryEquals("term AND NOT phrase term", qpAnalyzer, |
| + "+term -\"phrase1 phrase2\" term"); |
| + |
| + assertQueryEquals("stop^3", qpAnalyzer, ""); |
| + assertQueryEquals("stop", qpAnalyzer, ""); |
| + assertQueryEquals("(stop)^3", qpAnalyzer, ""); |
| + assertQueryEquals("((stop))^3", qpAnalyzer, ""); |
| + assertQueryEquals("(stop^3)", qpAnalyzer, ""); |
| + assertQueryEquals("((stop)^3)", qpAnalyzer, ""); |
| + assertQueryEquals("(stop)", qpAnalyzer, ""); |
| + assertQueryEquals("((stop))", qpAnalyzer, ""); |
| + assertTrue(getQuery("term term term", qpAnalyzer) instanceof BooleanQuery); |
| + assertTrue(getQuery("term +stop", qpAnalyzer) instanceof TermQuery); |
| + } |
| + |
| + public void testRange() throws Exception { |
| + assertQueryEquals("[ a TO z]", null, "[a TO z]"); |
| + assertTrue(((TermRangeQuery) getQuery("[ a TO z]", null)) |
| + .getConstantScoreRewrite()); |
| + |
| + LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + qp.getQueryConfigHandler().setConstantScoreRewrite(false); |
| + |
| + assertFalse(((TermRangeQuery) qp.parse("[ a TO z]", "field")) |
| + .getConstantScoreRewrite()); |
| + |
| + assertQueryEquals("[ a TO z ]", null, "[a TO z]"); |
| + assertQueryEquals("{ a TO z}", null, "{a TO z}"); |
| + assertQueryEquals("{ a TO z }", null, "{a TO z}"); |
| + assertQueryEquals("{ a TO z }^2.0", null, "{a TO z}^2.0"); |
| + assertQueryEquals("[ a TO z] OR bar", null, "[a TO z] bar"); |
| + assertQueryEquals("[ a TO z] AND bar", null, "+[a TO z] +bar"); |
| + assertQueryEquals("( bar blar { a TO z}) ", null, "bar blar {a TO z}"); |
| + assertQueryEquals("gack ( bar blar { a TO z}) ", null, |
| + "gack (bar blar {a TO z})"); |
| + } |
| + |
| + public void testFarsiRangeCollating() throws Exception { |
| + |
| + RAMDirectory ramDir = new RAMDirectory(); |
| + IndexWriter iw = new IndexWriter(ramDir, new WhitespaceAnalyzer(), true, |
| + IndexWriter.MaxFieldLength.LIMITED); |
| + Document doc = new Document(); |
| + doc.add(new Field("content", "\u0633\u0627\u0628", Field.Store.YES, |
| + Field.Index.UN_TOKENIZED)); |
| + iw.addDocument(doc); |
| + iw.close(); |
| + IndexSearcher is = new IndexSearcher(ramDir); |
| + |
| + LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + qp.getQueryConfigHandler().setAnalyzer(new WhitespaceAnalyzer()); |
| + |
| + // Neither Java 1.4.2 nor 1.5.0 has Farsi Locale collation available in |
| + // RuleBasedCollator. However, the Arabic Locale seems to order the |
| + // Farsi |
| + // characters properly. |
| + Collator c = Collator.getInstance(new Locale("ar")); |
| + qp.getQueryConfigHandler().setRangeCollator(c); |
| + |
| + // Unicode order would include U+0633 in [ U+062F - U+0698 ], but Farsi |
| + // orders the U+0698 character before the U+0633 character, so the |
| + // single |
| + // index Term below should NOT be returned by a ConstantScoreRangeQuery |
| + // with a Farsi Collator (or an Arabic one for the case when Farsi is |
| + // not |
| + // supported). |
| + |
| + // Test ConstantScoreRangeQuery |
| + qp.getQueryConfigHandler().setConstantScoreRewrite(true); |
| + ScoreDoc[] result = is.search(qp.parse("[ \u062F TO \u0698 ]", "content"), |
| + null, 1000).scoreDocs; |
| + assertEquals("The index Term should not be included.", 0, result.length); |
| + |
| + result = is.search(qp.parse("[ \u0633 TO \u0638 ]", "content"), null, 1000).scoreDocs; |
| + assertEquals("The index Term should be included.", 1, result.length); |
| + |
| + // Test RangeQuery |
| + qp.getQueryConfigHandler().setConstantScoreRewrite(false); |
| + result = is.search(qp.parse("[ \u062F TO \u0698 ]", "content"), null, 1000).scoreDocs; |
| + assertEquals("The index Term should not be included.", 0, result.length); |
| + |
| + result = is.search(qp.parse("[ \u0633 TO \u0638 ]", "content"), null, 1000).scoreDocs; |
| + assertEquals("The index Term should be included.", 1, result.length); |
| + |
| + is.close(); |
| + } |
| + |
| + /** for testing legacy DateField support */ |
| + private String getLegacyDate(String s) throws Exception { |
| + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); |
| + return DateField.dateToString(df.parse(s)); |
| + } |
| + |
| + /** for testing DateTools support */ |
| + private String getDate(String s, DateTools.Resolution resolution) |
| + throws Exception { |
| + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); |
| + return getDate(df.parse(s), resolution); |
| + } |
| + |
| + /** for testing DateTools support */ |
| + private String getDate(Date d, DateTools.Resolution resolution) |
| + throws Exception { |
| + if (resolution == null) { |
| + return DateField.dateToString(d); |
| + } else { |
| + return DateTools.dateToString(d, resolution); |
| + } |
| + } |
| + |
| + private String getLocalizedDate(int year, int month, int day, |
| + boolean extendLastDate) { |
| + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); |
| + Calendar calendar = Calendar.getInstance(); |
| + calendar.set(year, month, day); |
| + if (extendLastDate) { |
| + calendar.set(Calendar.HOUR_OF_DAY, 23); |
| + calendar.set(Calendar.MINUTE, 59); |
| + calendar.set(Calendar.SECOND, 59); |
| + calendar.set(Calendar.MILLISECOND, 999); |
| + } |
| + return df.format(calendar.getTime()); |
| + } |
| + |
| + /** for testing legacy DateField support */ |
| + public void testLegacyDateRange() throws Exception { |
| + String startDate = getLocalizedDate(2002, 1, 1, false); |
| + String endDate = getLocalizedDate(2002, 1, 4, false); |
| + Calendar endDateExpected = Calendar.getInstance(); |
| + endDateExpected.set(2002, 1, 4, 23, 59, 59); |
| + endDateExpected.set(Calendar.MILLISECOND, 999); |
| + assertQueryEquals("[ " + startDate + " TO " + endDate + "]", null, "[" |
| + + getLegacyDate(startDate) + " TO " |
| + + DateField.dateToString(endDateExpected.getTime()) + "]"); |
| + assertQueryEquals("{ " + startDate + " " + endDate + " }", null, "{" |
| + + getLegacyDate(startDate) + " TO " + getLegacyDate(endDate) + "}"); |
| + } |
| + |
| + public void testDateRange() throws Exception { |
| + String startDate = getLocalizedDate(2002, 1, 1, false); |
| + String endDate = getLocalizedDate(2002, 1, 4, false); |
| + Calendar endDateExpected = Calendar.getInstance(); |
| + endDateExpected.set(2002, 1, 4, 23, 59, 59); |
| + endDateExpected.set(Calendar.MILLISECOND, 999); |
| + final String defaultField = "default"; |
| + final String monthField = "month"; |
| + final String hourField = "hour"; |
| + LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + |
| + // Don't set any date resolution and verify if DateField is used |
| + assertDateRangeQueryEquals(qp, defaultField, startDate, endDate, |
| + endDateExpected.getTime(), null); |
| + |
| + // set a field specific date resolution |
| + qp.getQueryConfigHandler().setDateResolution(monthField, |
| + DateTools.Resolution.MONTH); |
| + |
| + // DateField should still be used for defaultField |
| + assertDateRangeQueryEquals(qp, defaultField, startDate, endDate, |
| + endDateExpected.getTime(), null); |
| + |
| + // set default date resolution to MILLISECOND |
| + qp.getQueryConfigHandler().setDateResolution( |
| + DateTools.Resolution.MILLISECOND); |
| + |
| + // set second field specific date resolution |
| + qp.getQueryConfigHandler().setDateResolution(hourField, |
| + DateTools.Resolution.HOUR); |
| + |
| + // for this field no field specific date resolution has been set, |
| + // so verify if the default resolution is used |
| + assertDateRangeQueryEquals(qp, defaultField, startDate, endDate, |
| + endDateExpected.getTime(), DateTools.Resolution.MILLISECOND); |
| + |
| + // verify if field specific date resolutions are used for these two |
| + // fields |
| + assertDateRangeQueryEquals(qp, monthField, startDate, endDate, |
| + endDateExpected.getTime(), DateTools.Resolution.MONTH); |
| + |
| + assertDateRangeQueryEquals(qp, hourField, startDate, endDate, |
| + endDateExpected.getTime(), DateTools.Resolution.HOUR); |
| + } |
| + |
| + public void assertDateRangeQueryEquals(LuceneQueryParserHelper qp, |
| + String field, String startDate, String endDate, Date endDateInclusive, |
| + DateTools.Resolution resolution) throws Exception { |
| + assertQueryEquals(qp, field, field + ":[" + startDate + " TO " + endDate |
| + + "]", "[" + getDate(startDate, resolution) + " TO " |
| + + getDate(endDateInclusive, resolution) + "]"); |
| + assertQueryEquals(qp, field, field + ":{" + startDate + " TO " + endDate |
| + + "}", "{" + getDate(startDate, resolution) + " TO " |
| + + getDate(endDate, resolution) + "}"); |
| + } |
| + |
| + public void testEscaped() throws Exception { |
| + Analyzer a = new WhitespaceAnalyzer(); |
| + |
| + /* |
| + * assertQueryEquals("\\[brackets", a, "\\[brackets"); |
| + * assertQueryEquals("\\[brackets", null, "brackets"); |
| + * assertQueryEquals("\\\\", a, "\\\\"); assertQueryEquals("\\+blah", a, |
| + * "\\+blah"); assertQueryEquals("\\(blah", a, "\\(blah"); |
| + * |
| + * assertQueryEquals("\\-blah", a, "\\-blah"); assertQueryEquals("\\!blah", |
| + * a, "\\!blah"); assertQueryEquals("\\{blah", a, "\\{blah"); |
| + * assertQueryEquals("\\}blah", a, "\\}blah"); assertQueryEquals("\\:blah", |
| + * a, "\\:blah"); assertQueryEquals("\\^blah", a, "\\^blah"); |
| + * assertQueryEquals("\\[blah", a, "\\[blah"); assertQueryEquals("\\]blah", |
| + * a, "\\]blah"); assertQueryEquals("\\\"blah", a, "\\\"blah"); |
| + * assertQueryEquals("\\(blah", a, "\\(blah"); assertQueryEquals("\\)blah", |
| + * a, "\\)blah"); assertQueryEquals("\\~blah", a, "\\~blah"); |
| + * assertQueryEquals("\\*blah", a, "\\*blah"); assertQueryEquals("\\?blah", |
| + * a, "\\?blah"); //assertQueryEquals("foo \\&\\& bar", a, |
| + * "foo \\&\\& bar"); //assertQueryEquals("foo \\|| bar", a, |
| + * "foo \\|| bar"); //assertQueryEquals("foo \\AND bar", a, |
| + * "foo \\AND bar"); |
| + */ |
| + |
| + assertQueryEquals("\\a", a, "a"); |
| + |
| + assertQueryEquals("a\\-b:c", a, "a-b:c"); |
| + assertQueryEquals("a\\+b:c", a, "a+b:c"); |
| + assertQueryEquals("a\\:b:c", a, "a:b:c"); |
| + assertQueryEquals("a\\\\b:c", a, "a\\b:c"); |
| + |
| + assertQueryEquals("a:b\\-c", a, "a:b-c"); |
| + assertQueryEquals("a:b\\+c", a, "a:b+c"); |
| + assertQueryEquals("a:b\\:c", a, "a:b:c"); |
| + assertQueryEquals("a:b\\\\c", a, "a:b\\c"); |
| + |
| + assertQueryEquals("a:b\\-c*", a, "a:b-c*"); |
| + assertQueryEquals("a:b\\+c*", a, "a:b+c*"); |
| + assertQueryEquals("a:b\\:c*", a, "a:b:c*"); |
| + |
| + assertQueryEquals("a:b\\\\c*", a, "a:b\\c*"); |
| + |
| + assertQueryEquals("a:b\\-?c", a, "a:b-?c"); |
| + assertQueryEquals("a:b\\+?c", a, "a:b+?c"); |
| + assertQueryEquals("a:b\\:?c", a, "a:b:?c"); |
| + |
| + assertQueryEquals("a:b\\\\?c", a, "a:b\\?c"); |
| + |
| + assertQueryEquals("a:b\\-c~", a, "a:b-c~0.5"); |
| + assertQueryEquals("a:b\\+c~", a, "a:b+c~0.5"); |
| + assertQueryEquals("a:b\\:c~", a, "a:b:c~0.5"); |
| + assertQueryEquals("a:b\\\\c~", a, "a:b\\c~0.5"); |
| + |
| + // TODO: implement Range queries on QueryParser |
| + assertQueryEquals("[ a\\- TO a\\+ ]", null, "[a- TO a+]"); |
| + assertQueryEquals("[ a\\: TO a\\~ ]", null, "[a: TO a~]"); |
| + assertQueryEquals("[ a\\\\ TO a\\* ]", null, "[a\\ TO a*]"); |
| + |
| + assertQueryEquals( |
| + "[\"c\\:\\\\temp\\\\\\~foo0.txt\" TO \"c\\:\\\\temp\\\\\\~foo9.txt\"]", |
| + a, "[c:\\temp\\~foo0.txt TO c:\\temp\\~foo9.txt]"); |
| + |
| + assertQueryEquals("a\\\\\\+b", a, "a\\+b"); |
| + |
| + assertQueryEquals("a \\\"b c\\\" d", a, "a \"b c\" d"); |
| + assertQueryEquals("\"a \\\"b c\\\" d\"", a, "\"a \"b c\" d\""); |
| + assertQueryEquals("\"a \\+b c d\"", a, "\"a +b c d\""); |
| + |
| + assertQueryEquals("c\\:\\\\temp\\\\\\~foo.txt", a, "c:\\temp\\~foo.txt"); |
| + |
| + assertQueryNodeException("XY\\"); // there must be a character after the |
| + // escape char |
| + |
| + // test unicode escaping |
| + assertQueryEquals("a\\u0062c", a, "abc"); |
| + assertQueryEquals("XY\\u005a", a, "XYZ"); |
| + assertQueryEquals("XY\\u005A", a, "XYZ"); |
| + assertQueryEquals("\"a \\\\\\u0028\\u0062\\\" c\"", a, "\"a \\(b\" c\""); |
| + |
| + assertQueryNodeException("XY\\u005G"); // test non-hex character in escaped |
| + // unicode sequence |
| + assertQueryNodeException("XY\\u005"); // test incomplete escaped unicode |
| + // sequence |
| + |
| + // Tests bug LUCENE-800 |
| + assertQueryEquals("(item:\\\\ item:ABCD\\\\)", a, "item:\\ item:ABCD\\"); |
| + assertQueryNodeException("(item:\\\\ item:ABCD\\\\))"); // unmatched closing |
| + // paranthesis |
| + assertQueryEquals("\\*", a, "*"); |
| + assertQueryEquals("\\\\", a, "\\"); // escaped backslash |
| + |
| + assertQueryNodeException("\\"); // a backslash must always be escaped |
| + |
| + // LUCENE-1189 |
| + assertQueryEquals("(\"a\\\\\") or (\"b\")", a, "a\\ or b"); |
| + } |
| + |
| + public void testQueryStringEscaping() throws Exception { |
| + Analyzer a = new WhitespaceAnalyzer(); |
| + |
| + assertEscapedQueryEquals("a-b:c", a, "a\\-b\\:c"); |
| + assertEscapedQueryEquals("a+b:c", a, "a\\+b\\:c"); |
| + assertEscapedQueryEquals("a:b:c", a, "a\\:b\\:c"); |
| + assertEscapedQueryEquals("a\\b:c", a, "a\\\\b\\:c"); |
| + |
| + assertEscapedQueryEquals("a:b-c", a, "a\\:b\\-c"); |
| + assertEscapedQueryEquals("a:b+c", a, "a\\:b\\+c"); |
| + assertEscapedQueryEquals("a:b:c", a, "a\\:b\\:c"); |
| + assertEscapedQueryEquals("a:b\\c", a, "a\\:b\\\\c"); |
| + |
| + assertEscapedQueryEquals("a:b-c*", a, "a\\:b\\-c\\*"); |
| + assertEscapedQueryEquals("a:b+c*", a, "a\\:b\\+c\\*"); |
| + assertEscapedQueryEquals("a:b:c*", a, "a\\:b\\:c\\*"); |
| + |
| + assertEscapedQueryEquals("a:b\\\\c*", a, "a\\:b\\\\\\\\c\\*"); |
| + |
| + assertEscapedQueryEquals("a:b-?c", a, "a\\:b\\-\\?c"); |
| + assertEscapedQueryEquals("a:b+?c", a, "a\\:b\\+\\?c"); |
| + assertEscapedQueryEquals("a:b:?c", a, "a\\:b\\:\\?c"); |
| + |
| + assertEscapedQueryEquals("a:b?c", a, "a\\:b\\?c"); |
| + |
| + assertEscapedQueryEquals("a:b-c~", a, "a\\:b\\-c\\~"); |
| + assertEscapedQueryEquals("a:b+c~", a, "a\\:b\\+c\\~"); |
| + assertEscapedQueryEquals("a:b:c~", a, "a\\:b\\:c\\~"); |
| + assertEscapedQueryEquals("a:b\\c~", a, "a\\:b\\\\c\\~"); |
| + |
| + assertEscapedQueryEquals("[ a - TO a+ ]", null, "\\[ a \\- TO a\\+ \\]"); |
| + assertEscapedQueryEquals("[ a : TO a~ ]", null, "\\[ a \\: TO a\\~ \\]"); |
| + assertEscapedQueryEquals("[ a\\ TO a* ]", null, "\\[ a\\\\ TO a\\* \\]"); |
| + |
| + // LUCENE-881 |
| + assertEscapedQueryEquals("|| abc ||", a, "\\|\\| abc \\|\\|"); |
| + assertEscapedQueryEquals("&& abc &&", a, "\\&\\& abc \\&\\&"); |
| + } |
| + |
| + public void testTabNewlineCarriageReturn() throws Exception { |
| + assertQueryEqualsDOA("+weltbank +worlbank", null, "+weltbank +worlbank"); |
| + |
| + assertQueryEqualsDOA("+weltbank\n+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \n+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \n +worlbank", null, "+weltbank +worlbank"); |
| + |
| + assertQueryEqualsDOA("+weltbank\r+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \r+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \r +worlbank", null, "+weltbank +worlbank"); |
| + |
| + assertQueryEqualsDOA("+weltbank\r\n+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \r\n+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \r\n +worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \r \n +worlbank", null, |
| + "+weltbank +worlbank"); |
| + |
| + assertQueryEqualsDOA("+weltbank\t+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \t+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \t +worlbank", null, "+weltbank +worlbank"); |
| + } |
| + |
| + public void testSimpleDAO() throws Exception { |
| + assertQueryEqualsDOA("term term term", null, "+term +term +term"); |
| + assertQueryEqualsDOA("term +term term", null, "+term +term +term"); |
| + assertQueryEqualsDOA("term term +term", null, "+term +term +term"); |
| + assertQueryEqualsDOA("term +term +term", null, "+term +term +term"); |
| + assertQueryEqualsDOA("-term term term", null, "-term +term +term"); |
| + } |
| + |
| + public void testBoost() throws Exception { |
| + StandardAnalyzer oneStopAnalyzer = new StandardAnalyzer( |
| + new String[] { "on" }); |
| + LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + qp.getQueryConfigHandler().setAnalyzer(oneStopAnalyzer); |
| + |
| + Query q = qp.parse("on^1.0", "field"); |
| + assertNotNull(q); |
| + q = qp.parse("\"hello\"^2.0", "field"); |
| + assertNotNull(q); |
| + assertEquals(q.getBoost(), (float) 2.0, (float) 0.5); |
| + q = qp.parse("hello^2.0", "field"); |
| + assertNotNull(q); |
| + assertEquals(q.getBoost(), (float) 2.0, (float) 0.5); |
| + q = qp.parse("\"on\"^1.0", "field"); |
| + assertNotNull(q); |
| + |
| + LuceneQueryParserHelper qp2 = new LuceneQueryParserHelper(); |
| + qp2.getQueryConfigHandler().setAnalyzer(new StandardAnalyzer()); |
| + |
| + q = qp2.parse("the^3", "field"); |
| + // "the" is a stop word so the result is an empty query: |
| + assertNotNull(q); |
| + assertEquals("", q.toString()); |
| + assertEquals(1.0f, q.getBoost(), 0.01f); |
| + } |
| + |
| + public void assertQueryNodeException(String queryString) throws Exception { |
| + try { |
| + getQuery(queryString, null); |
| + } catch (QueryNodeException expected) { |
| + return; |
| + } |
| + fail("ParseException expected, not thrown"); |
| + } |
| + |
| + public void testException() throws Exception { |
| + assertQueryNodeException("\"some phrase"); |
| + assertQueryNodeException("(foo bar"); |
| + assertQueryNodeException("foo bar))"); |
| + assertQueryNodeException("field:term:with:colon some more terms"); |
| + assertQueryNodeException("(sub query)^5.0^2.0 plus more"); |
| + assertQueryNodeException("secret AND illegal) AND access:confidential"); |
| + } |
| + |
| + public void testCustomQueryParserWildcard() { |
| + try { |
| + new QPTestParser(new WhitespaceAnalyzer()).parse("a?t", "contents"); |
| + fail("Wildcard queries should not be allowed"); |
| + } catch (QueryNodeException expected) { |
| + // expected exception |
| + } |
| + } |
| + |
| + public void testCustomQueryParserFuzzy() throws Exception { |
| + try { |
| + new QPTestParser(new WhitespaceAnalyzer()).parse("xunit~", "contents"); |
| + fail("Fuzzy queries should not be allowed"); |
| + } catch (QueryNodeException expected) { |
| + // expected exception |
| + } |
| + } |
| + |
| + public void testBooleanQuery() throws Exception { |
| + BooleanQuery.setMaxClauseCount(2); |
| + try { |
| + LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + qp.getQueryConfigHandler().setAnalyzer(new WhitespaceAnalyzer()); |
| + |
| + qp.parse("one two three", "field"); |
| + fail("ParseException expected due to too many boolean clauses"); |
| + } catch (QueryNodeException expected) { |
| + // too many boolean clauses, so ParseException is expected |
| + } |
| + } |
| + |
| + /** |
| + * This test differs from TestPrecedenceQueryParser |
| + */ |
| + public void testPrecedence() throws Exception { |
| + LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + qp.getQueryConfigHandler().setAnalyzer(new WhitespaceAnalyzer()); |
| + |
| + Query query1 = qp.parse("A AND B OR C AND D", "field"); |
| + Query query2 = qp.parse("+A +B +C +D", "field"); |
| + |
| + assertEquals(query1, query2); |
| + } |
| + |
| + public void testLocalDateFormat() throws IOException, QueryNodeException { |
| + |
| + RAMDirectory ramDir = new RAMDirectory(); |
| + IndexWriter iw = new IndexWriter(ramDir, new WhitespaceAnalyzer(), true, |
| + IndexWriter.MaxFieldLength.LIMITED); |
| + addDateDoc("a", 2005, 12, 2, 10, 15, 33, iw); |
| + addDateDoc("b", 2005, 12, 4, 22, 15, 00, iw); |
| + iw.close(); |
| + IndexSearcher is = new IndexSearcher(ramDir); |
| + assertHits(1, "[12/1/2005 TO 12/3/2005]", is); |
| + assertHits(2, "[12/1/2005 TO 12/4/2005]", is); |
| + assertHits(1, "[12/3/2005 TO 12/4/2005]", is); |
| + assertHits(1, "{12/1/2005 TO 12/3/2005}", is); |
| + assertHits(1, "{12/1/2005 TO 12/4/2005}", is); |
| + assertHits(0, "{12/3/2005 TO 12/4/2005}", is); |
| + is.close(); |
| + } |
| + |
| + public void testStarParsing() throws Exception { |
| + // final int[] type = new int[1]; |
| + // QueryParser qp = new LuceneQueryParserHelper("field", new |
| + // WhitespaceAnalyzer()) { |
| + // protected Query getWildcardQuery(String field, String termStr) throws |
| + // ParseException { |
| + // // override error checking of superclass |
| + // type[0]=1; |
| + // return new TermQuery(new Term(field,termStr)); |
| + // } |
| + // protected Query getPrefixQuery(String field, String termStr) throws |
| + // ParseException { |
| + // // override error checking of superclass |
| + // type[0]=2; |
| + // return new TermQuery(new Term(field,termStr)); |
| + // } |
| + // |
| + // protected Query getFieldQuery(String field, String queryText) throws |
| + // ParseException { |
| + // type[0]=3; |
| + // return super.getFieldQuery(field, queryText); |
| + // } |
| + // }; |
| + // |
| + // TermQuery tq; |
| + // |
| + // tq = (TermQuery)qp.parse("foo:zoo*"); |
| + // assertEquals("zoo",tq.getTerm().text()); |
| + // assertEquals(2,type[0]); |
| + // |
| + // tq = (TermQuery)qp.parse("foo:zoo*^2"); |
| + // assertEquals("zoo",tq.getTerm().text()); |
| + // assertEquals(2,type[0]); |
| + // assertEquals(tq.getBoost(),2,0); |
| + // |
| + // tq = (TermQuery)qp.parse("foo:*"); |
| + // assertEquals("*",tq.getTerm().text()); |
| + // assertEquals(1,type[0]); // could be a valid prefix query in the |
| + // future too |
| + // |
| + // tq = (TermQuery)qp.parse("foo:*^2"); |
| + // assertEquals("*",tq.getTerm().text()); |
| + // assertEquals(1,type[0]); |
| + // assertEquals(tq.getBoost(),2,0); |
| + // |
| + // tq = (TermQuery)qp.parse("*:foo"); |
| + // assertEquals("*",tq.getTerm().field()); |
| + // assertEquals("foo",tq.getTerm().text()); |
| + // assertEquals(3,type[0]); |
| + // |
| + // tq = (TermQuery)qp.parse("*:*"); |
| + // assertEquals("*",tq.getTerm().field()); |
| + // assertEquals("*",tq.getTerm().text()); |
| + // assertEquals(1,type[0]); // could be handled as a prefix query in the |
| + // future |
| + // |
| + // tq = (TermQuery)qp.parse("(*:*)"); |
| + // assertEquals("*",tq.getTerm().field()); |
| + // assertEquals("*",tq.getTerm().text()); |
| + // assertEquals(1,type[0]); |
| + |
| + } |
| + |
| + public void testStopwords() throws Exception { |
| + LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + qp.getQueryConfigHandler().setAnalyzer( |
| + new StopAnalyzer(new String[] { "the", "foo" })); |
| + |
| + Query result = qp.parse("a:the OR a:foo", "a"); |
| + assertNotNull("result is null and it shouldn't be", result); |
| + assertTrue("result is not a BooleanQuery", result instanceof BooleanQuery); |
| + assertTrue(((BooleanQuery) result).clauses().size() + " does not equal: " |
| + + 0, ((BooleanQuery) result).clauses().size() == 0); |
| + result = qp.parse("a:woo OR a:the", "a"); |
| + assertNotNull("result is null and it shouldn't be", result); |
| + assertTrue("result is not a TermQuery", result instanceof TermQuery); |
| + result = qp.parse( |
| + "(fieldX:xxxxx OR fieldy:xxxxxxxx)^2 AND (fieldx:the OR fieldy:foo)", |
| + "a"); |
| + assertNotNull("result is null and it shouldn't be", result); |
| + assertTrue("result is not a BooleanQuery", result instanceof BooleanQuery); |
| + System.out.println("Result: " + result); |
| + assertTrue(((BooleanQuery) result).clauses().size() + " does not equal: " |
| + + 2, ((BooleanQuery) result).clauses().size() == 2); |
| + } |
| + |
| + public void testPositionIncrement() throws Exception { |
| + boolean dflt = StopFilter.getEnablePositionIncrementsDefault(); |
| + StopFilter.setEnablePositionIncrementsDefault(true); |
| + try { |
| + LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + qp.getQueryConfigHandler().setAnalyzer( |
| + new StopAnalyzer(new String[] { "the", "in", "are", "this" })); |
| + |
| + qp.getQueryConfigHandler().setEnablePositionIncrements(true); |
| + |
| + String qtxt = "\"the words in poisitions pos02578 are stopped in this phrasequery\""; |
| + // 0 2 5 7 8 |
| + int expectedPositions[] = { 1, 3, 4, 6, 9 }; |
| + PhraseQuery pq = (PhraseQuery) qp.parse(qtxt, "a"); |
| + // System.out.println("Query text: "+qtxt); |
| + // System.out.println("Result: "+pq); |
| + Term t[] = pq.getTerms(); |
| + int pos[] = pq.getPositions(); |
| + for (int i = 0; i < t.length; i++) { |
| + // System.out.println(i+". "+t[i]+" pos: "+pos[i]); |
| + assertEquals("term " + i + " = " + t[i] + " has wrong term-position!", |
| + expectedPositions[i], pos[i]); |
| + } |
| + |
| + } finally { |
| + StopFilter.setEnablePositionIncrementsDefault(dflt); |
| + } |
| + } |
| + |
| + public void testMatchAllDocs() throws Exception { |
| + LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + qp.getQueryConfigHandler().setAnalyzer(new WhitespaceAnalyzer()); |
| + |
| + assertEquals(new MatchAllDocsQuery(), qp.parse("*:*", "field")); |
| + assertEquals(new MatchAllDocsQuery(), qp.parse("(*:*)", "field")); |
| + BooleanQuery bq = (BooleanQuery) qp.parse("+*:* -*:*", "field"); |
| + assertTrue(bq.getClauses()[0].getQuery() instanceof MatchAllDocsQuery); |
| + assertTrue(bq.getClauses()[1].getQuery() instanceof MatchAllDocsQuery); |
| + } |
| + |
| + private void assertHits(int expected, String query, IndexSearcher is) |
| + throws IOException, QueryNodeException { |
| + LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + qp.getQueryConfigHandler().setAnalyzer(new WhitespaceAnalyzer()); |
| + qp.getQueryConfigHandler().setLocale(Locale.ENGLISH); |
| + |
| + Query q = qp.parse(query, "date"); |
| + ScoreDoc[] hits = is.search(q, null, 1000).scoreDocs; |
| + assertEquals(expected, hits.length); |
| + } |
| + |
| + private static void addDateDoc(String content, int year, int month, int day, |
| + int hour, int minute, int second, IndexWriter iw) throws IOException { |
| + Document d = new Document(); |
| + d.add(new Field("f", content, Field.Store.YES, Field.Index.ANALYZED)); |
| + Calendar cal = Calendar.getInstance(); |
| + cal.set(year, month - 1, day, hour, minute, second); |
| + d.add(new Field("date", DateField.dateToString(cal.getTime()), |
| + Field.Store.YES, Field.Index.NOT_ANALYZED)); |
| + iw.addDocument(d); |
| + } |
| + |
| + public void tearDown() throws Exception { |
| + super.tearDown(); |
| + BooleanQuery.setMaxClauseCount(originalMaxClauses); |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiAnalyzerWrapper.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiAnalyzerWrapper.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiAnalyzerWrapper.java (revision 0) |
| @@ -0,0 +1,320 @@ |
| +package org.apache.lucene.queryParser.original; |
| + |
| +/** |
| + * 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 java.io.IOException; |
| +import java.io.Reader; |
| + |
| +import org.apache.lucene.analysis.Analyzer; |
| +import org.apache.lucene.analysis.LowerCaseFilter; |
| +import org.apache.lucene.analysis.Token; |
| +import org.apache.lucene.analysis.TokenFilter; |
| +import org.apache.lucene.analysis.TokenStream; |
| +import org.apache.lucene.analysis.standard.StandardTokenizer; |
| +import org.apache.lucene.analysis.tokenattributes.OffsetAttribute; |
| +import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute; |
| +import org.apache.lucene.analysis.tokenattributes.TermAttribute; |
| +import org.apache.lucene.analysis.tokenattributes.TypeAttribute; |
| +import org.apache.lucene.queryParser.ParseException; |
| +import org.apache.lucene.queryParser.original.QueryParserWrapper; |
| +import org.apache.lucene.util.LuceneTestCase; |
| + |
| +/** |
| + * This test case is a copy of the core Lucene query parser test, it was adapted |
| + * to use new QueryParserWrapper instead of the old query parser. |
| + * |
| + * Test QueryParser's ability to deal with Analyzers that return more than one |
| + * token per position or that return tokens with a position increment > 1. |
| + * |
| + */ |
| +public class TestMultiAnalyzerWrapper extends LuceneTestCase { |
| + |
| + private static int multiToken = 0; |
| + |
| + public void testMultiAnalyzer() throws ParseException { |
| + |
| + QueryParserWrapper qp = new QueryParserWrapper("", new MultiAnalyzer()); |
| + |
| + // trivial, no multiple tokens: |
| + assertEquals("foo", qp.parse("foo").toString()); |
| + assertEquals("foo", qp.parse("\"foo\"").toString()); |
| + assertEquals("foo foobar", qp.parse("foo foobar").toString()); |
| + assertEquals("\"foo foobar\"", qp.parse("\"foo foobar\"").toString()); |
| + assertEquals("\"foo foobar blah\"", qp.parse("\"foo foobar blah\"") |
| + .toString()); |
| + |
| + // two tokens at the same position: |
| + assertEquals("(multi multi2) foo", qp.parse("multi foo").toString()); |
| + assertEquals("foo (multi multi2)", qp.parse("foo multi").toString()); |
| + assertEquals("(multi multi2) (multi multi2)", qp.parse("multi multi") |
| + .toString()); |
| + assertEquals("+(foo (multi multi2)) +(bar (multi multi2))", qp.parse( |
| + "+(foo multi) +(bar multi)").toString()); |
| + assertEquals("+(foo (multi multi2)) field:\"bar (multi multi2)\"", qp |
| + .parse("+(foo multi) field:\"bar multi\"").toString()); |
| + |
| + // phrases: |
| + assertEquals("\"(multi multi2) foo\"", qp.parse("\"multi foo\"").toString()); |
| + assertEquals("\"foo (multi multi2)\"", qp.parse("\"foo multi\"").toString()); |
| + assertEquals("\"foo (multi multi2) foobar (multi multi2)\"", qp.parse( |
| + "\"foo multi foobar multi\"").toString()); |
| + |
| + // fields: |
| + assertEquals("(field:multi field:multi2) field:foo", qp.parse( |
| + "field:multi field:foo").toString()); |
| + assertEquals("field:\"(multi multi2) foo\"", qp |
| + .parse("field:\"multi foo\"").toString()); |
| + |
| + // three tokens at one position: |
| + assertEquals("triplemulti multi3 multi2", qp.parse("triplemulti") |
| + .toString()); |
| + assertEquals("foo (triplemulti multi3 multi2) foobar", qp.parse( |
| + "foo triplemulti foobar").toString()); |
| + |
| + // phrase with non-default slop: |
| + assertEquals("\"(multi multi2) foo\"~10", qp.parse("\"multi foo\"~10") |
| + .toString()); |
| + |
| + // phrase with non-default boost: |
| + assertEquals("\"(multi multi2) foo\"^2.0", qp.parse("\"multi foo\"^2") |
| + .toString()); |
| + |
| + // phrase after changing default slop |
| + qp.setPhraseSlop(99); |
| + assertEquals("\"(multi multi2) foo\"~99 bar", qp.parse("\"multi foo\" bar") |
| + .toString()); |
| + assertEquals("\"(multi multi2) foo\"~99 \"foo bar\"~2", qp.parse( |
| + "\"multi foo\" \"foo bar\"~2").toString()); |
| + qp.setPhraseSlop(0); |
| + |
| + // non-default operator: |
| + qp.setDefaultOperator(QueryParserWrapper.AND_OPERATOR); |
| + assertEquals("+(multi multi2) +foo", qp.parse("multi foo").toString()); |
| + |
| + } |
| + |
| + // public void testMultiAnalyzerWithSubclassOfQueryParser() throws |
| + // ParseException { |
| + // this test doesn't make sense when using the new QueryParser API |
| + // DumbQueryParser qp = new DumbQueryParser("", new MultiAnalyzer()); |
| + // qp.setPhraseSlop(99); // modified default slop |
| + // |
| + // // direct call to (super's) getFieldQuery to demonstrate differnce |
| + // // between phrase and multiphrase with modified default slop |
| + // assertEquals("\"foo bar\"~99", |
| + // qp.getSuperFieldQuery("","foo bar").toString()); |
| + // assertEquals("\"(multi multi2) bar\"~99", |
| + // qp.getSuperFieldQuery("","multi bar").toString()); |
| + // |
| + // |
| + // // ask sublcass to parse phrase with modified default slop |
| + // assertEquals("\"(multi multi2) foo\"~99 bar", |
| + // qp.parse("\"multi foo\" bar").toString()); |
| + // |
| + // } |
| + |
| + public void testPosIncrementAnalyzer() throws ParseException { |
| + QueryParserWrapper qp = new QueryParserWrapper("", |
| + new PosIncrementAnalyzer()); |
| + assertEquals("quick brown", qp.parse("the quick brown").toString()); |
| + assertEquals("\"quick brown\"", qp.parse("\"the quick brown\"").toString()); |
| + assertEquals("quick brown fox", qp.parse("the quick brown fox").toString()); |
| + assertEquals("\"quick brown fox\"", qp.parse("\"the quick brown fox\"") |
| + .toString()); |
| + } |
| + |
| + /** |
| + * Expands "multi" to "multi" and "multi2", both at the same position, and |
| + * expands "triplemulti" to "triplemulti", "multi3", and "multi2". |
| + */ |
| + private class MultiAnalyzer extends Analyzer { |
| + |
| + public MultiAnalyzer() { |
| + } |
| + |
| + public TokenStream tokenStream(String fieldName, Reader reader) { |
| + TokenStream result = new StandardTokenizer(reader); |
| + result = new TestFilter(result); |
| + result = new LowerCaseFilter(result); |
| + return result; |
| + } |
| + } |
| + |
| + private final class TestFilter extends TokenFilter { |
| + |
| + private String prevType; |
| + private int prevStartOffset; |
| + private int prevEndOffset; |
| + |
| + TermAttribute termAtt; |
| + PositionIncrementAttribute posIncrAtt; |
| + OffsetAttribute offsetAtt; |
| + TypeAttribute typeAtt; |
| + |
| + public TestFilter(TokenStream in) { |
| + super(in); |
| + termAtt = (TermAttribute) addAttribute(TermAttribute.class); |
| + posIncrAtt = (PositionIncrementAttribute) addAttribute(PositionIncrementAttribute.class); |
| + offsetAtt = (OffsetAttribute) addAttribute(OffsetAttribute.class); |
| + typeAtt = (TypeAttribute) addAttribute(TypeAttribute.class); |
| + |
| + } |
| + |
| + /* |
| + * (non-Javadoc) |
| + * |
| + * @see |
| + * org.apache.lucene.analysis.TokenStream#next(org.apache.lucene.analysis |
| + * .Token) |
| + */ |
| + @Override |
| + public Token next(Token reusableToken) throws IOException { |
| + |
| + if (multiToken > 0) { |
| + reusableToken.setTermBuffer("multi" + (multiToken + 1)); |
| + reusableToken.setStartOffset(prevStartOffset); |
| + reusableToken.setEndOffset(prevEndOffset); |
| + reusableToken.setType(prevType); |
| + reusableToken.setPositionIncrement(0); |
| + multiToken--; |
| + return reusableToken; |
| + } else { |
| + boolean next = (reusableToken = input.next(token)) != null; |
| + if (next == false) { |
| + return null; |
| + } |
| + prevType = reusableToken.type(); |
| + prevStartOffset = reusableToken.startOffset(); |
| + prevEndOffset = reusableToken.endOffset(); |
| + String text = reusableToken.term(); |
| + if (text.equals("triplemulti")) { |
| + multiToken = 2; |
| + return reusableToken; |
| + } else if (text.equals("multi")) { |
| + multiToken = 1; |
| + return reusableToken; |
| + } else { |
| + return reusableToken; |
| + } |
| + } |
| + |
| + } |
| + |
| + private Token token = new Token(); |
| + |
| + public final boolean incrementToken() throws java.io.IOException { |
| + if (multiToken > 0) { |
| + termAtt.setTermBuffer("multi" + (multiToken + 1)); |
| + offsetAtt.setOffset(prevStartOffset, prevEndOffset); |
| + typeAtt.setType(prevType); |
| + posIncrAtt.setPositionIncrement(0); |
| + multiToken--; |
| + return true; |
| + } else { |
| + boolean next = input.incrementToken(); |
| + if (next == false) { |
| + return false; |
| + } |
| + prevType = typeAtt.type(); |
| + prevStartOffset = offsetAtt.startOffset(); |
| + prevEndOffset = offsetAtt.endOffset(); |
| + String text = termAtt.term(); |
| + if (text.equals("triplemulti")) { |
| + multiToken = 2; |
| + return true; |
| + } else if (text.equals("multi")) { |
| + multiToken = 1; |
| + return true; |
| + } else { |
| + return true; |
| + } |
| + } |
| + } |
| + |
| + } |
| + |
| + /** |
| + * Analyzes "the quick brown" as: quick(incr=2) brown(incr=1). Does not work |
| + * correctly for input other than "the quick brown ...". |
| + */ |
| + private class PosIncrementAnalyzer extends Analyzer { |
| + |
| + public PosIncrementAnalyzer() { |
| + } |
| + |
| + public TokenStream tokenStream(String fieldName, Reader reader) { |
| + TokenStream result = new StandardTokenizer(reader); |
| + result = new TestPosIncrementFilter(result); |
| + result = new LowerCaseFilter(result); |
| + return result; |
| + } |
| + } |
| + |
| + private class TestPosIncrementFilter extends TokenFilter { |
| + |
| + TermAttribute termAtt; |
| + PositionIncrementAttribute posIncrAtt; |
| + |
| + public TestPosIncrementFilter(TokenStream in) { |
| + super(in); |
| + termAtt = (TermAttribute) addAttribute(TermAttribute.class); |
| + posIncrAtt = (PositionIncrementAttribute) addAttribute(PositionIncrementAttribute.class); |
| + } |
| + |
| + private Token token = new Token(); |
| + |
| + /* |
| + * (non-Javadoc) |
| + * |
| + * @see org.apache.lucene.analysis.TokenStream#next() |
| + */ |
| + @Override |
| + public Token next(Token reusableToken) throws IOException { |
| + while (null != (reusableToken = input.next(token))) { |
| + String term = reusableToken.term(); |
| + if (term.equals("the")) { |
| + // stopword, do nothing |
| + } else if (term.equals("quick")) { |
| + reusableToken.setPositionIncrement(2); |
| + return reusableToken; |
| + } else { |
| + reusableToken.setPositionIncrement(1); |
| + return reusableToken; |
| + } |
| + } |
| + return null; |
| + } |
| + |
| + public final boolean incrementToken() throws java.io.IOException { |
| + while (input.incrementToken()) { |
| + if (termAtt.term().equals("the")) { |
| + // stopword, do nothing |
| + } else if (termAtt.term().equals("quick")) { |
| + posIncrAtt.setPositionIncrement(2); |
| + return true; |
| + } else { |
| + posIncrAtt.setPositionIncrement(1); |
| + return true; |
| + } |
| + } |
| + return false; |
| + } |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestQueryParser.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestQueryParser.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestQueryParser.java (revision 0) |
| @@ -0,0 +1,1148 @@ |
| +package org.apache.lucene.queryParser.original; |
| + |
| +/** |
| + * 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 java.io.IOException; |
| +import java.io.Reader; |
| +import java.text.Collator; |
| +import java.text.DateFormat; |
| +import java.util.Calendar; |
| +import java.util.Date; |
| +import java.util.List; |
| +import java.util.Locale; |
| + |
| +import org.apache.lucene.analysis.Analyzer; |
| +import org.apache.lucene.analysis.KeywordAnalyzer; |
| +import org.apache.lucene.analysis.LowerCaseTokenizer; |
| +import org.apache.lucene.analysis.SimpleAnalyzer; |
| +import org.apache.lucene.analysis.StopAnalyzer; |
| +import org.apache.lucene.analysis.StopFilter; |
| +import org.apache.lucene.analysis.Token; |
| +import org.apache.lucene.analysis.TokenFilter; |
| +import org.apache.lucene.analysis.TokenStream; |
| +import org.apache.lucene.analysis.WhitespaceAnalyzer; |
| +import org.apache.lucene.analysis.standard.StandardAnalyzer; |
| +import org.apache.lucene.analysis.tokenattributes.OffsetAttribute; |
| +import org.apache.lucene.analysis.tokenattributes.TermAttribute; |
| +import org.apache.lucene.document.DateField; |
| +import org.apache.lucene.document.DateTools; |
| +import org.apache.lucene.document.Document; |
| +import org.apache.lucene.document.Field; |
| +import org.apache.lucene.index.IndexWriter; |
| +import org.apache.lucene.index.Term; |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.nodes.FieldQueryNode; |
| +import org.apache.lucene.queryParser.nodes.FuzzyQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.WildcardQueryNode; |
| +import org.apache.lucene.queryParser.original.builders.LuceneQueryTreeBuilder; |
| +import org.apache.lucene.queryParser.original.config.AnalyzerAttribute; |
| +import org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler; |
| +import org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler.Operator; |
| +import org.apache.lucene.queryParser.original.parser.EscapeQuerySyntaxImpl; |
| +import org.apache.lucene.queryParser.original.parser.TextParser; |
| +import org.apache.lucene.queryParser.original.processors.LuceneQueryNodeProcessorPipeline; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| +import org.apache.lucene.search.BooleanQuery; |
| +import org.apache.lucene.search.FuzzyQuery; |
| +import org.apache.lucene.search.IndexSearcher; |
| +import org.apache.lucene.search.MatchAllDocsQuery; |
| +import org.apache.lucene.search.PhraseQuery; |
| +import org.apache.lucene.search.PrefixQuery; |
| +import org.apache.lucene.search.Query; |
| +import org.apache.lucene.search.ScoreDoc; |
| +import org.apache.lucene.search.TermQuery; |
| +import org.apache.lucene.search.TermRangeQuery; |
| +import org.apache.lucene.search.WildcardQuery; |
| +import org.apache.lucene.store.RAMDirectory; |
| +import org.apache.lucene.util.LuceneTestCase; |
| + |
| +/** |
| + * This test case is a copy of the core Lucene query parser test, it was adapted |
| + * to use the new query parser instead of the old one. |
| + * |
| + * Tests QueryParser. |
| + */ |
| +public class TestQueryParser extends LuceneTestCase { |
| + |
| + public static Analyzer qpAnalyzer = new QPTestAnalyzer(); |
| + |
| + public static class QPTestFilter extends TokenFilter { |
| + TermAttribute termAtt; |
| + OffsetAttribute offsetAtt; |
| + |
| + /** |
| + * Filter which discards the token 'stop' and which expands the token |
| + * 'phrase' into 'phrase1 phrase2' |
| + */ |
| + public QPTestFilter(TokenStream in) { |
| + super(in); |
| + termAtt = (TermAttribute) addAttribute(TermAttribute.class); |
| + offsetAtt = (OffsetAttribute) addAttribute(OffsetAttribute.class); |
| + } |
| + |
| + boolean inPhrase = false; |
| + int savedStart = 0, savedEnd = 0; |
| + |
| + public Token next(Token reusableToken) throws IOException { |
| + Token token = reusableToken; |
| + |
| + if (inPhrase) { |
| + inPhrase = false; |
| + token.setTermBuffer("phrase2"); |
| + token.setStartOffset(savedStart); |
| + token.setEndOffset(savedEnd); |
| + return reusableToken; |
| + } else |
| + while ((token = this.input.next(reusableToken)) != null) { |
| + if (token.term().equals("phrase")) { |
| + inPhrase = true; |
| + savedStart = token.startOffset(); |
| + savedEnd = token.endOffset(); |
| + token.setTermBuffer("phrase1"); |
| + token.setStartOffset(savedStart); |
| + token.setEndOffset(savedEnd); |
| + return token; |
| + } else if (!token.term().equals("stop")) |
| + return token; |
| + } |
| + |
| + return null; |
| + |
| + } |
| + |
| + public boolean incrementToken() throws IOException { |
| + if (inPhrase) { |
| + inPhrase = false; |
| + termAtt.setTermBuffer("phrase2"); |
| + offsetAtt.setOffset(savedStart, savedEnd); |
| + return true; |
| + } else |
| + while (input.incrementToken()) { |
| + if (termAtt.term().equals("phrase")) { |
| + inPhrase = true; |
| + savedStart = offsetAtt.startOffset(); |
| + savedEnd = offsetAtt.endOffset(); |
| + termAtt.setTermBuffer("phrase1"); |
| + offsetAtt.setOffset(savedStart, savedEnd); |
| + return true; |
| + } else if (!termAtt.term().equals("stop")) |
| + return true; |
| + } |
| + return false; |
| + } |
| + } |
| + |
| + public static class QPTestAnalyzer extends Analyzer { |
| + |
| + /** Filters LowerCaseTokenizer with StopFilter. */ |
| + public final TokenStream tokenStream(String fieldName, Reader reader) { |
| + return new QPTestFilter(new LowerCaseTokenizer(reader)); |
| + } |
| + } |
| + |
| + private static class QPTestParserQueryNodeProcessor extends |
| + QueryNodeProcessorImpl { |
| + |
| + protected QueryNode postProcessNode(QueryNode node) |
| + throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected QueryNode preProcessNode(QueryNode node) |
| + throws QueryNodeException { |
| + |
| + if (node instanceof WildcardQueryNode || node instanceof FuzzyQueryNode) { |
| + |
| + throw new QueryNodeException(new MessageImpl( |
| + QueryParserMessages.EMPTY_MESSAGE)); |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| + } |
| + |
| + private int originalMaxClauses; |
| + |
| + public void setUp() throws Exception { |
| + super.setUp(); |
| + originalMaxClauses = BooleanQuery.getMaxClauseCount(); |
| + } |
| + |
| + public Query getQuery(String query, Analyzer a) throws Exception { |
| + |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + |
| + if (a == null) { |
| + a = new SimpleAnalyzer(); |
| + } |
| + |
| + config.setAnalyzer(a); |
| + |
| + return getQuery(config, query); |
| + |
| + } |
| + |
| + private Query getQuery(LuceneQueryConfigHandler config, String query) |
| + throws Exception { |
| + return getQuery(config, query, "field"); |
| + } |
| + |
| + private Query getQuery(LuceneQueryConfigHandler config, String query, |
| + CharSequence field) throws Exception { |
| + TextParser textParser = new TextParser(); |
| + |
| + if (((AnalyzerAttribute) config.getAttribute(AnalyzerAttribute.class)) |
| + .getAnalyzer() == null) { |
| + config.setAnalyzer(new SimpleAnalyzer()); |
| + } |
| + |
| + QueryNode queryTree = textParser.parse(query, field); |
| + |
| + LuceneQueryNodeProcessorPipeline processor = new LuceneQueryNodeProcessorPipeline( |
| + config); |
| + queryTree = processor.process(queryTree); |
| + |
| + LuceneQueryTreeBuilder builder = new LuceneQueryTreeBuilder(); |
| + |
| + return builder.build(queryTree); |
| + |
| + } |
| + |
| + public void assertQueryEquals(String query, Analyzer a, String result) |
| + throws Exception { |
| + Query q = getQuery(query, a); |
| + String s = q.toString("field"); |
| + if (!s.equals(result)) { |
| + fail("Query /" + query + "/ yielded /" + s + "/, expecting /" + result |
| + + "/"); |
| + } |
| + } |
| + |
| + public void assertQueryEquals(LuceneQueryConfigHandler config, String field, |
| + String query, String result) throws Exception { |
| + Query q = getQuery(config, query, field); |
| + String s = q.toString(field); |
| + if (!s.equals(result)) { |
| + fail("Query /" + query + "/ yielded /" + s + "/, expecting /" + result |
| + + "/"); |
| + } |
| + } |
| + |
| + public void assertEscapedQueryEquals(String query, Analyzer a, String result) |
| + throws Exception { |
| + QueryNode queryTree = new FieldQueryNode(null, query, 0, 0); |
| + CharSequence escapedQuery = queryTree |
| + .toQueryString(new EscapeQuerySyntaxImpl()); |
| + |
| + if (!escapedQuery.toString().equals(result)) { |
| + fail("Query /" + query + "/ yielded /" + escapedQuery + "/, expecting /" |
| + + result + "/"); |
| + } |
| + } |
| + |
| + public void assertWildcardQueryEquals(String query, boolean lowercase, |
| + String result, boolean allowLeadingWildcard) throws Exception { |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + |
| + config.setLowercaseExpandedTerms(lowercase); |
| + config.setAllowLeadingWildcard(allowLeadingWildcard); |
| + Query q = getQuery(config, query, "field"); |
| + String s = q.toString("field"); |
| + if (!s.equals(result)) { |
| + fail("WildcardQuery /" + query + "/ yielded /" + s + "/, expecting /" |
| + + result + "/"); |
| + } |
| + } |
| + |
| + public void assertWildcardQueryEquals(String query, boolean lowercase, |
| + String result) throws Exception { |
| + assertWildcardQueryEquals(query, lowercase, result, false); |
| + } |
| + |
| + public void assertWildcardQueryEquals(String query, String result) |
| + throws Exception { |
| + |
| + Query q = getQuery(query, null); |
| + String s = q.toString("field"); |
| + if (!s.equals(result)) { |
| + fail("WildcardQuery /" + query + "/ yielded /" + s + "/, expecting /" |
| + + result + "/"); |
| + } |
| + } |
| + |
| + public Query getQueryDOA(String query, Analyzer a) throws Exception { |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + config.setAnalyzer(new SimpleAnalyzer()); |
| + config.setDefaultOperator(Operator.AND); |
| + |
| + return getQuery(config, query); |
| + |
| + } |
| + |
| + public void assertQueryEqualsDOA(String query, Analyzer a, String result) |
| + throws Exception { |
| + Query q = getQueryDOA(query, a); |
| + String s = q.toString("field"); |
| + if (!s.equals(result)) { |
| + fail("Query /" + query + "/ yielded /" + s + "/, expecting /" + result |
| + + "/"); |
| + } |
| + } |
| + |
| + public void testCJK() throws Exception { |
| + // Test Ideographic Space - As wide as a CJK character cell (fullwidth) |
| + // used google to translate the word "term" to japanese -> 用語 |
| + assertQueryEquals("term\u3000term\u3000term", null, |
| + "term\u0020term\u0020term"); |
| + assertQueryEquals("用語\u3000用語\u3000用語", null, "用語\u0020用語\u0020用語"); |
| + } |
| + |
| + public void testSimple() throws Exception { |
| + assertQueryEquals("\"term germ\"~2", null, "\"term germ\"~2"); |
| + assertQueryEquals("term term term", null, "term term term"); |
| + assertQueryEquals("türm term term", new WhitespaceAnalyzer(), |
| + "türm term term"); |
| + assertQueryEquals("ümlaut", new WhitespaceAnalyzer(), "ümlaut"); |
| + |
| + assertQueryEquals("\"\"", new KeywordAnalyzer(), ""); |
| + assertQueryEquals("foo:\"\"", new KeywordAnalyzer(), "foo:"); |
| + |
| + assertQueryEquals("a AND b", null, "+a +b"); |
| + assertQueryEquals("(a AND b)", null, "+a +b"); |
| + assertQueryEquals("c OR (a AND b)", null, "c (+a +b)"); |
| + |
| + assertQueryEquals("a AND NOT b", null, "+a -b"); |
| + |
| + assertQueryEquals("a AND -b", null, "+a -b"); |
| + |
| + assertQueryEquals("a AND !b", null, "+a -b"); |
| + |
| + assertQueryEquals("a && b", null, "+a +b"); |
| + |
| + assertQueryEquals("a && ! b", null, "+a -b"); |
| + |
| + assertQueryEquals("a OR b", null, "a b"); |
| + assertQueryEquals("a || b", null, "a b"); |
| + |
| + assertQueryEquals("a OR !b", null, "a -b"); |
| + |
| + assertQueryEquals("a OR ! b", null, "a -b"); |
| + |
| + assertQueryEquals("a OR -b", null, "a -b"); |
| + |
| + assertQueryEquals("+term -term term", null, "+term -term term"); |
| + assertQueryEquals("foo:term AND field:anotherTerm", null, |
| + "+foo:term +anotherterm"); |
| + assertQueryEquals("term AND \"phrase phrase\"", null, |
| + "+term +\"phrase phrase\""); |
| + assertQueryEquals("\"hello there\"", null, "\"hello there\""); |
| + assertTrue(getQuery("a AND b", null) instanceof BooleanQuery); |
| + assertTrue(getQuery("hello", null) instanceof TermQuery); |
| + assertTrue(getQuery("\"hello there\"", null) instanceof PhraseQuery); |
| + |
| + assertQueryEquals("germ term^2.0", null, "germ term^2.0"); |
| + assertQueryEquals("(term)^2.0", null, "term^2.0"); |
| + assertQueryEquals("(germ term)^2.0", null, "(germ term)^2.0"); |
| + assertQueryEquals("term^2.0", null, "term^2.0"); |
| + assertQueryEquals("term^2", null, "term^2.0"); |
| + assertQueryEquals("\"germ term\"^2.0", null, "\"germ term\"^2.0"); |
| + assertQueryEquals("\"term germ\"^2", null, "\"term germ\"^2.0"); |
| + |
| + assertQueryEquals("(foo OR bar) AND (baz OR boo)", null, |
| + "+(foo bar) +(baz boo)"); |
| + assertQueryEquals("((a OR b) AND NOT c) OR d", null, "(+(a b) -c) d"); |
| + assertQueryEquals("+(apple \"steve jobs\") -(foo bar baz)", null, |
| + "+(apple \"steve jobs\") -(foo bar baz)"); |
| + assertQueryEquals("+title:(dog OR cat) -author:\"bob dole\"", null, |
| + "+(title:dog title:cat) -author:\"bob dole\""); |
| + |
| + } |
| + |
| + public void testPunct() throws Exception { |
| + Analyzer a = new WhitespaceAnalyzer(); |
| + assertQueryEquals("a&b", a, "a&b"); |
| + assertQueryEquals("a&&b", a, "a&&b"); |
| + assertQueryEquals(".NET", a, ".NET"); |
| + } |
| + |
| + public void testSlop() throws Exception { |
| + |
| + assertQueryEquals("\"term germ\"~2", null, "\"term germ\"~2"); |
| + assertQueryEquals("\"term germ\"~2 flork", null, "\"term germ\"~2 flork"); |
| + assertQueryEquals("\"term\"~2", null, "term"); |
| + assertQueryEquals("\" \"~2 germ", null, "germ"); |
| + assertQueryEquals("\"term germ\"~2^2", null, "\"term germ\"~2^2.0"); |
| + } |
| + |
| + public void testNumber() throws Exception { |
| + // The numbers go away because SimpleAnalzyer ignores them |
| + assertQueryEquals("3", null, ""); |
| + assertQueryEquals("term 1.0 1 2", null, "term"); |
| + assertQueryEquals("term term1 term2", null, "term term term"); |
| + |
| + Analyzer a = new StandardAnalyzer(); |
| + assertQueryEquals("3", a, "3"); |
| + assertQueryEquals("term 1.0 1 2", a, "term 1.0 1 2"); |
| + assertQueryEquals("term term1 term2", a, "term term1 term2"); |
| + } |
| + |
| + public void testWildcard() throws Exception { |
| + assertQueryEquals("term*", null, "term*"); |
| + assertQueryEquals("term*^2", null, "term*^2.0"); |
| + assertQueryEquals("term~", null, "term~0.5"); |
| + assertQueryEquals("term~0.7", null, "term~0.7"); |
| + |
| + assertQueryEquals("term~^2", null, "term~0.5^2.0"); |
| + |
| + assertQueryEquals("term^2~", null, "term~0.5^2.0"); |
| + assertQueryEquals("term*germ", null, "term*germ"); |
| + assertQueryEquals("term*germ^3", null, "term*germ^3.0"); |
| + |
| + assertTrue(getQuery("term*", null) instanceof PrefixQuery); |
| + assertTrue(getQuery("term*^2", null) instanceof PrefixQuery); |
| + assertTrue(getQuery("term~", null) instanceof FuzzyQuery); |
| + assertTrue(getQuery("term~0.7", null) instanceof FuzzyQuery); |
| + FuzzyQuery fq = (FuzzyQuery) getQuery("term~0.7", null); |
| + assertEquals(0.7f, fq.getMinSimilarity(), 0.1f); |
| + assertEquals(FuzzyQuery.defaultPrefixLength, fq.getPrefixLength()); |
| + fq = (FuzzyQuery) getQuery("term~", null); |
| + assertEquals(0.5f, fq.getMinSimilarity(), 0.1f); |
| + assertEquals(FuzzyQuery.defaultPrefixLength, fq.getPrefixLength()); |
| + |
| + assertQueryNodeException("term~1.1"); // value > 1, throws exception |
| + |
| + assertTrue(getQuery("term*germ", null) instanceof WildcardQuery); |
| + |
| + /* |
| + * Tests to see that wild card terms are (or are not) properly lower-cased |
| + * with propery parser configuration |
| + */ |
| + // First prefix queries: |
| + // by default, convert to lowercase: |
| + assertWildcardQueryEquals("Term*", true, "term*"); |
| + // explicitly set lowercase: |
| + assertWildcardQueryEquals("term*", true, "term*"); |
| + assertWildcardQueryEquals("Term*", true, "term*"); |
| + assertWildcardQueryEquals("TERM*", true, "term*"); |
| + // explicitly disable lowercase conversion: |
| + assertWildcardQueryEquals("term*", false, "term*"); |
| + assertWildcardQueryEquals("Term*", false, "Term*"); |
| + assertWildcardQueryEquals("TERM*", false, "TERM*"); |
| + // Then 'full' wildcard queries: |
| + // by default, convert to lowercase: |
| + assertWildcardQueryEquals("Te?m", "te?m"); |
| + // explicitly set lowercase: |
| + assertWildcardQueryEquals("te?m", true, "te?m"); |
| + assertWildcardQueryEquals("Te?m", true, "te?m"); |
| + assertWildcardQueryEquals("TE?M", true, "te?m"); |
| + assertWildcardQueryEquals("Te?m*gerM", true, "te?m*germ"); |
| + // explicitly disable lowercase conversion: |
| + assertWildcardQueryEquals("te?m", false, "te?m"); |
| + assertWildcardQueryEquals("Te?m", false, "Te?m"); |
| + assertWildcardQueryEquals("TE?M", false, "TE?M"); |
| + assertWildcardQueryEquals("Te?m*gerM", false, "Te?m*gerM"); |
| + // Fuzzy queries: |
| + assertWildcardQueryEquals("Term~", "term~0.5"); |
| + assertWildcardQueryEquals("Term~", true, "term~0.5"); |
| + assertWildcardQueryEquals("Term~", false, "Term~0.5"); |
| + // Range queries: |
| + |
| + // TODO: implement this on QueryParser |
| + // Q0002E_INVALID_SYNTAX_CANNOT_PARSE: Syntax Error, cannot parse '[A TO |
| + // C]': Lexical error at line 1, column 1. Encountered: "[" (91), after |
| + // : "" |
| + assertWildcardQueryEquals("[A TO C]", "[a TO c]"); |
| + assertWildcardQueryEquals("[A TO C]", true, "[a TO c]"); |
| + assertWildcardQueryEquals("[A TO C]", false, "[A TO C]"); |
| + // Test suffix queries: first disallow |
| + try { |
| + assertWildcardQueryEquals("*Term", true, "*term"); |
| + fail(); |
| + } catch (QueryNodeException pe) { |
| + // expected exception |
| + } |
| + try { |
| + assertWildcardQueryEquals("?Term", true, "?term"); |
| + fail(); |
| + } catch (QueryNodeException pe) { |
| + // expected exception |
| + } |
| + // Test suffix queries: then allow |
| + assertWildcardQueryEquals("*Term", true, "*term", true); |
| + assertWildcardQueryEquals("?Term", true, "?term", true); |
| + } |
| + |
| + public void testLeadingWildcardType() throws Exception { |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + config.setAllowLeadingWildcard(true); |
| + |
| + assertEquals(WildcardQuery.class, getQuery(config, "t*erm*").getClass()); |
| + assertEquals(WildcardQuery.class, getQuery(config, "?term*").getClass()); |
| + assertEquals(WildcardQuery.class, getQuery(config, "*term*").getClass()); |
| + } |
| + |
| + public void testQPA() throws Exception { |
| + assertQueryEquals("term term^3.0 term", qpAnalyzer, "term term^3.0 term"); |
| + assertQueryEquals("term stop^3.0 term", qpAnalyzer, "term term"); |
| + |
| + assertQueryEquals("term term term", qpAnalyzer, "term term term"); |
| + assertQueryEquals("term +stop term", qpAnalyzer, "term term"); |
| + assertQueryEquals("term -stop term", qpAnalyzer, "term term"); |
| + |
| + assertQueryEquals("drop AND (stop) AND roll", qpAnalyzer, "+drop +roll"); |
| + assertQueryEquals("term +(stop) term", qpAnalyzer, "term term"); |
| + assertQueryEquals("term -(stop) term", qpAnalyzer, "term term"); |
| + |
| + assertQueryEquals("drop AND stop AND roll", qpAnalyzer, "+drop +roll"); |
| + assertQueryEquals("term phrase term", qpAnalyzer, |
| + "term \"phrase1 phrase2\" term"); |
| + |
| + assertQueryEquals("term AND NOT phrase term", qpAnalyzer, |
| + "+term -\"phrase1 phrase2\" term"); |
| + |
| + assertQueryEquals("stop^3", qpAnalyzer, ""); |
| + assertQueryEquals("stop", qpAnalyzer, ""); |
| + assertQueryEquals("(stop)^3", qpAnalyzer, ""); |
| + assertQueryEquals("((stop))^3", qpAnalyzer, ""); |
| + assertQueryEquals("(stop^3)", qpAnalyzer, ""); |
| + assertQueryEquals("((stop)^3)", qpAnalyzer, ""); |
| + assertQueryEquals("(stop)", qpAnalyzer, ""); |
| + assertQueryEquals("((stop))", qpAnalyzer, ""); |
| + assertTrue(getQuery("term term term", qpAnalyzer) instanceof BooleanQuery); |
| + assertTrue(getQuery("term +stop", qpAnalyzer) instanceof TermQuery); |
| + } |
| + |
| + public void testRange() throws Exception { |
| + assertQueryEquals("[ a TO z]", null, "[a TO z]"); |
| + assertTrue(((TermRangeQuery) getQuery("[ a TO z]", null)) |
| + .getConstantScoreRewrite()); |
| + |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + |
| + config.setConstantScoreRewrite(false); |
| + assertFalse(((TermRangeQuery) getQuery(config, "[ a TO z]")) |
| + .getConstantScoreRewrite()); |
| + |
| + assertQueryEquals("[ a TO z ]", null, "[a TO z]"); |
| + assertQueryEquals("{ a TO z}", null, "{a TO z}"); |
| + assertQueryEquals("{ a TO z }", null, "{a TO z}"); |
| + assertQueryEquals("{ a TO z }^2.0", null, "{a TO z}^2.0"); |
| + assertQueryEquals("[ a TO z] OR bar", null, "[a TO z] bar"); |
| + assertQueryEquals("[ a TO z] AND bar", null, "+[a TO z] +bar"); |
| + assertQueryEquals("( bar blar { a TO z}) ", null, "bar blar {a TO z}"); |
| + assertQueryEquals("gack ( bar blar { a TO z}) ", null, |
| + "gack (bar blar {a TO z})"); |
| + } |
| + |
| + public void testFarsiRangeCollating() throws Exception { |
| + |
| + RAMDirectory ramDir = new RAMDirectory(); |
| + IndexWriter iw = new IndexWriter(ramDir, new WhitespaceAnalyzer(), true, |
| + IndexWriter.MaxFieldLength.LIMITED); |
| + Document doc = new Document(); |
| + doc.add(new Field("field", "\u0633\u0627\u0628", Field.Store.YES, |
| + Field.Index.UN_TOKENIZED)); |
| + iw.addDocument(doc); |
| + iw.close(); |
| + IndexSearcher is = new IndexSearcher(ramDir); |
| + |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + config.setAnalyzer(new WhitespaceAnalyzer()); |
| + |
| + // Neither Java 1.4.2 nor 1.5.0 has Farsi Locale collation available in |
| + // RuleBasedCollator. However, the Arabic Locale seems to order the |
| + // Farsi |
| + // characters properly. |
| + Collator c = Collator.getInstance(new Locale("ar")); |
| + config.setRangeCollator(c); |
| + |
| + // Unicode order would include U+0633 in [ U+062F - U+0698 ], but Farsi |
| + // orders the U+0698 character before the U+0633 character, so the |
| + // single |
| + // index Term below should NOT be returned by a ConstantScoreRangeQuery |
| + // with a Farsi Collator (or an Arabic one for the case when Farsi is |
| + // not |
| + // supported). |
| + |
| + // Test ConstantScoreRangeQuery |
| + config.setConstantScoreRewrite(true); |
| + ScoreDoc[] result = is.search(getQuery(config, "[ \u062F TO \u0698 ]", |
| + "field"), null, 1000).scoreDocs; |
| + assertEquals("The index Term should not be included.", 0, result.length); |
| + |
| + result = is.search(getQuery(config, "[ \u0633 TO \u0638 ]", "field"), null, |
| + 1000).scoreDocs; |
| + assertEquals("The index Term should be included.", 1, result.length); |
| + |
| + // Test RangeQuery |
| + config.setConstantScoreRewrite(false); |
| + result = is.search(getQuery(config, "[ \u062F TO \u0698 ]", "field"), null, |
| + 1000).scoreDocs; |
| + assertEquals("The index Term should not be included.", 0, result.length); |
| + |
| + result = is.search(getQuery(config, "[ \u0633 TO \u0638 ]", "field"), null, |
| + 1000).scoreDocs; |
| + assertEquals("The index Term should be included.", 1, result.length); |
| + |
| + is.close(); |
| + } |
| + |
| + /** for testing legacy DateField support */ |
| + private String getLegacyDate(String s) throws Exception { |
| + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); |
| + return DateField.dateToString(df.parse(s)); |
| + } |
| + |
| + /** for testing DateTools support */ |
| + private String getDate(String s, DateTools.Resolution resolution) |
| + throws Exception { |
| + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); |
| + return getDate(df.parse(s), resolution); |
| + } |
| + |
| + /** for testing DateTools support */ |
| + private String getDate(Date d, DateTools.Resolution resolution) |
| + throws Exception { |
| + if (resolution == null) { |
| + return DateField.dateToString(d); |
| + } else { |
| + return DateTools.dateToString(d, resolution); |
| + } |
| + } |
| + |
| + private String getLocalizedDate(int year, int month, int day, |
| + boolean extendLastDate) { |
| + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); |
| + Calendar calendar = Calendar.getInstance(); |
| + calendar.set(year, month, day); |
| + if (extendLastDate) { |
| + calendar.set(Calendar.HOUR_OF_DAY, 23); |
| + calendar.set(Calendar.MINUTE, 59); |
| + calendar.set(Calendar.SECOND, 59); |
| + calendar.set(Calendar.MILLISECOND, 999); |
| + } |
| + return df.format(calendar.getTime()); |
| + } |
| + |
| + /** for testing legacy DateField support */ |
| + public void testLegacyDateRange() throws Exception { |
| + String startDate = getLocalizedDate(2002, 1, 1, false); |
| + String endDate = getLocalizedDate(2002, 1, 4, false); |
| + Calendar endDateExpected = Calendar.getInstance(); |
| + endDateExpected.set(2002, 1, 4, 23, 59, 59); |
| + endDateExpected.set(Calendar.MILLISECOND, 999); |
| + assertQueryEquals("[ " + startDate + " TO " + endDate + "]", null, "[" |
| + + getLegacyDate(startDate) + " TO " |
| + + DateField.dateToString(endDateExpected.getTime()) + "]"); |
| + assertQueryEquals("{ " + startDate + " " + endDate + " }", null, "{" |
| + + getLegacyDate(startDate) + " TO " + getLegacyDate(endDate) + "}"); |
| + } |
| + |
| + public void testDateRange() throws Exception { |
| + String startDate = getLocalizedDate(2002, 1, 1, false); |
| + String endDate = getLocalizedDate(2002, 1, 4, false); |
| + Calendar endDateExpected = Calendar.getInstance(); |
| + endDateExpected.set(2002, 1, 4, 23, 59, 59); |
| + endDateExpected.set(Calendar.MILLISECOND, 999); |
| + final String defaultField = "default"; |
| + final String monthField = "month"; |
| + final String hourField = "hour"; |
| + |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + |
| + // Don't set any date resolution and verify if DateField is used |
| + assertDateRangeQueryEquals(config, defaultField, startDate, endDate, |
| + endDateExpected.getTime(), null); |
| + |
| + // set a field specific date resolution |
| + config.setDateResolution(monthField, DateTools.Resolution.MONTH); |
| + |
| + // DateField should still be used for defaultField |
| + assertDateRangeQueryEquals(config, defaultField, startDate, endDate, |
| + endDateExpected.getTime(), null); |
| + |
| + // set default date resolution to MILLISECOND |
| + config.setDateResolution(DateTools.Resolution.MILLISECOND); |
| + |
| + // set second field specific date resolution |
| + config.setDateResolution(hourField, DateTools.Resolution.HOUR); |
| + |
| + // for this field no field specific date resolution has been set, |
| + // so verify if the default resolution is used |
| + assertDateRangeQueryEquals(config, defaultField, startDate, endDate, |
| + endDateExpected.getTime(), DateTools.Resolution.MILLISECOND); |
| + |
| + // verify if field specific date resolutions are used for these two |
| + // fields |
| + assertDateRangeQueryEquals(config, monthField, startDate, endDate, |
| + endDateExpected.getTime(), DateTools.Resolution.MONTH); |
| + |
| + assertDateRangeQueryEquals(config, hourField, startDate, endDate, |
| + endDateExpected.getTime(), DateTools.Resolution.HOUR); |
| + } |
| + |
| + public void assertDateRangeQueryEquals(LuceneQueryConfigHandler config, |
| + String field, String startDate, String endDate, Date endDateInclusive, |
| + DateTools.Resolution resolution) throws Exception { |
| + assertQueryEquals(config, field, field + ":[" + startDate + " TO " |
| + + endDate + "]", "[" + getDate(startDate, resolution) + " TO " |
| + + getDate(endDateInclusive, resolution) + "]"); |
| + assertQueryEquals(config, field, field + ":{" + startDate + " TO " |
| + + endDate + "}", "{" + getDate(startDate, resolution) + " TO " |
| + + getDate(endDate, resolution) + "}"); |
| + } |
| + |
| + public void testEscaped() throws Exception { |
| + Analyzer a = new WhitespaceAnalyzer(); |
| + |
| + /* |
| + * assertQueryEquals("\\[brackets", a, "\\[brackets"); |
| + * assertQueryEquals("\\[brackets", null, "brackets"); |
| + * assertQueryEquals("\\\\", a, "\\\\"); assertQueryEquals("\\+blah", a, |
| + * "\\+blah"); assertQueryEquals("\\(blah", a, "\\(blah"); |
| + * |
| + * assertQueryEquals("\\-blah", a, "\\-blah"); assertQueryEquals("\\!blah", |
| + * a, "\\!blah"); assertQueryEquals("\\{blah", a, "\\{blah"); |
| + * assertQueryEquals("\\}blah", a, "\\}blah"); assertQueryEquals("\\:blah", |
| + * a, "\\:blah"); assertQueryEquals("\\^blah", a, "\\^blah"); |
| + * assertQueryEquals("\\[blah", a, "\\[blah"); assertQueryEquals("\\]blah", |
| + * a, "\\]blah"); assertQueryEquals("\\\"blah", a, "\\\"blah"); |
| + * assertQueryEquals("\\(blah", a, "\\(blah"); assertQueryEquals("\\)blah", |
| + * a, "\\)blah"); assertQueryEquals("\\~blah", a, "\\~blah"); |
| + * assertQueryEquals("\\*blah", a, "\\*blah"); assertQueryEquals("\\?blah", |
| + * a, "\\?blah"); //assertQueryEquals("foo \\&\\& bar", a, |
| + * "foo \\&\\& bar"); //assertQueryEquals("foo \\|| bar", a, |
| + * "foo \\|| bar"); //assertQueryEquals("foo \\AND bar", a, |
| + * "foo \\AND bar"); |
| + */ |
| + |
| + assertQueryEquals("\\a", a, "a"); |
| + |
| + assertQueryEquals("a\\-b:c", a, "a-b:c"); |
| + assertQueryEquals("a\\+b:c", a, "a+b:c"); |
| + assertQueryEquals("a\\:b:c", a, "a:b:c"); |
| + assertQueryEquals("a\\\\b:c", a, "a\\b:c"); |
| + |
| + assertQueryEquals("a:b\\-c", a, "a:b-c"); |
| + assertQueryEquals("a:b\\+c", a, "a:b+c"); |
| + assertQueryEquals("a:b\\:c", a, "a:b:c"); |
| + assertQueryEquals("a:b\\\\c", a, "a:b\\c"); |
| + |
| + assertQueryEquals("a:b\\-c*", a, "a:b-c*"); |
| + assertQueryEquals("a:b\\+c*", a, "a:b+c*"); |
| + assertQueryEquals("a:b\\:c*", a, "a:b:c*"); |
| + |
| + assertQueryEquals("a:b\\\\c*", a, "a:b\\c*"); |
| + |
| + assertQueryEquals("a:b\\-?c", a, "a:b-?c"); |
| + assertQueryEquals("a:b\\+?c", a, "a:b+?c"); |
| + assertQueryEquals("a:b\\:?c", a, "a:b:?c"); |
| + |
| + assertQueryEquals("a:b\\\\?c", a, "a:b\\?c"); |
| + |
| + assertQueryEquals("a:b\\-c~", a, "a:b-c~0.5"); |
| + assertQueryEquals("a:b\\+c~", a, "a:b+c~0.5"); |
| + assertQueryEquals("a:b\\:c~", a, "a:b:c~0.5"); |
| + assertQueryEquals("a:b\\\\c~", a, "a:b\\c~0.5"); |
| + |
| + // TODO: implement Range queries on TextParser |
| + assertQueryEquals("[ a\\- TO a\\+ ]", null, "[a- TO a+]"); |
| + assertQueryEquals("[ a\\: TO a\\~ ]", null, "[a: TO a~]"); |
| + assertQueryEquals("[ a\\\\ TO a\\* ]", null, "[a\\ TO a*]"); |
| + |
| + assertQueryEquals( |
| + "[\"c\\:\\\\temp\\\\\\~foo0.txt\" TO \"c\\:\\\\temp\\\\\\~foo9.txt\"]", |
| + a, "[c:\\temp\\~foo0.txt TO c:\\temp\\~foo9.txt]"); |
| + |
| + assertQueryEquals("a\\\\\\+b", a, "a\\+b"); |
| + |
| + assertQueryEquals("a \\\"b c\\\" d", a, "a \"b c\" d"); |
| + assertQueryEquals("\"a \\\"b c\\\" d\"", a, "\"a \"b c\" d\""); |
| + assertQueryEquals("\"a \\+b c d\"", a, "\"a +b c d\""); |
| + |
| + assertQueryEquals("c\\:\\\\temp\\\\\\~foo.txt", a, "c:\\temp\\~foo.txt"); |
| + |
| + assertQueryNodeException("XY\\"); // there must be a character after the |
| + // escape char |
| + |
| + // test unicode escaping |
| + assertQueryEquals("a\\u0062c", a, "abc"); |
| + assertQueryEquals("XY\\u005a", a, "XYZ"); |
| + assertQueryEquals("XY\\u005A", a, "XYZ"); |
| + assertQueryEquals("\"a \\\\\\u0028\\u0062\\\" c\"", a, "\"a \\(b\" c\""); |
| + |
| + assertQueryNodeException("XY\\u005G"); // test non-hex character in |
| + // escaped |
| + // unicode sequence |
| + assertQueryNodeException("XY\\u005"); // test incomplete escaped unicode |
| + // sequence |
| + |
| + // Tests bug LUCENE-800 |
| + assertQueryEquals("(item:\\\\ item:ABCD\\\\)", a, "item:\\ item:ABCD\\"); |
| + assertQueryNodeException("(item:\\\\ item:ABCD\\\\))"); // unmatched |
| + // closing |
| + // paranthesis |
| + assertQueryEquals("\\*", a, "*"); |
| + assertQueryEquals("\\\\", a, "\\"); // escaped backslash |
| + |
| + assertQueryNodeException("\\"); // a backslash must always be escaped |
| + |
| + // LUCENE-1189 |
| + assertQueryEquals("(\"a\\\\\") or (\"b\")", a, "a\\ or b"); |
| + } |
| + |
| + public void testQueryStringEscaping() throws Exception { |
| + Analyzer a = new WhitespaceAnalyzer(); |
| + |
| + assertEscapedQueryEquals("a-b:c", a, "a-b\\:c"); |
| + assertEscapedQueryEquals("a+b:c", a, "a+b\\:c"); |
| + assertEscapedQueryEquals("a:b:c", a, "a\\:b\\:c"); |
| + assertEscapedQueryEquals("a\\b:c", a, "a\\\\b\\:c"); |
| + |
| + assertEscapedQueryEquals("a:b-c", a, "a\\:b-c"); |
| + assertEscapedQueryEquals("a:b+c", a, "a\\:b+c"); |
| + assertEscapedQueryEquals("a:b:c", a, "a\\:b\\:c"); |
| + assertEscapedQueryEquals("a:b\\c", a, "a\\:b\\\\c"); |
| + |
| + assertEscapedQueryEquals("a:b-c*", a, "a\\:b-c*"); |
| + assertEscapedQueryEquals("a:b+c*", a, "a\\:b+c*"); |
| + assertEscapedQueryEquals("a:b:c*", a, "a\\:b\\:c*"); |
| + |
| + assertEscapedQueryEquals("a:b\\\\c*", a, "a\\:b\\\\\\\\c*"); |
| + |
| + assertEscapedQueryEquals("a:b-?c", a, "a\\:b-?c"); |
| + assertEscapedQueryEquals("a:b+?c", a, "a\\:b+?c"); |
| + assertEscapedQueryEquals("a:b:?c", a, "a\\:b\\:?c"); |
| + |
| + assertEscapedQueryEquals("a:b?c", a, "a\\:b?c"); |
| + |
| + assertEscapedQueryEquals("a:b-c~", a, "a\\:b-c\\~"); |
| + assertEscapedQueryEquals("a:b+c~", a, "a\\:b+c\\~"); |
| + assertEscapedQueryEquals("a:b:c~", a, "a\\:b\\:c\\~"); |
| + assertEscapedQueryEquals("a:b\\c~", a, "a\\:b\\\\c\\~"); |
| + |
| + assertEscapedQueryEquals("[ a - TO a+ ]", null, |
| + "\\[\\ a\\ -\\ TO\\ a+\\ \\]"); |
| + assertEscapedQueryEquals("[ a : TO a~ ]", null, |
| + "\\[\\ a\\ \\:\\ TO\\ a\\~\\ \\]"); |
| + assertEscapedQueryEquals("[ a\\ TO a* ]", null, |
| + "\\[\\ a\\\\\\ TO\\ a*\\ \\]"); |
| + |
| + // LUCENE-881 |
| + assertEscapedQueryEquals("|| abc ||", a, "||\\ abc\\ ||"); |
| + assertEscapedQueryEquals("&& abc &&", a, "&&\\ abc\\ &&"); |
| + } |
| + |
| + public void testTabNewlineCarriageReturn() throws Exception { |
| + assertQueryEqualsDOA("+weltbank +worlbank", null, "+weltbank +worlbank"); |
| + |
| + assertQueryEqualsDOA("+weltbank\n+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \n+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \n +worlbank", null, "+weltbank +worlbank"); |
| + |
| + assertQueryEqualsDOA("+weltbank\r+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \r+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \r +worlbank", null, "+weltbank +worlbank"); |
| + |
| + assertQueryEqualsDOA("+weltbank\r\n+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \r\n+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \r\n +worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \r \n +worlbank", null, |
| + "+weltbank +worlbank"); |
| + |
| + assertQueryEqualsDOA("+weltbank\t+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \t+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \t +worlbank", null, "+weltbank +worlbank"); |
| + } |
| + |
| + public void testSimpleDAO() throws Exception { |
| + assertQueryEqualsDOA("term term term", null, "+term +term +term"); |
| + assertQueryEqualsDOA("term +term term", null, "+term +term +term"); |
| + assertQueryEqualsDOA("term term +term", null, "+term +term +term"); |
| + assertQueryEqualsDOA("term +term +term", null, "+term +term +term"); |
| + assertQueryEqualsDOA("-term term term", null, "-term +term +term"); |
| + } |
| + |
| + public void testBoost() throws Exception { |
| + StandardAnalyzer oneStopAnalyzer = new StandardAnalyzer( |
| + new String[] { "on" }); |
| + |
| + Query q = getQuery("on^1.0", oneStopAnalyzer); |
| + assertNotNull(q); |
| + q = getQuery("\"hello\"^2.0", oneStopAnalyzer); |
| + assertNotNull(q); |
| + assertEquals(q.getBoost(), (float) 2.0, (float) 0.5); |
| + q = getQuery("hello^2.0", oneStopAnalyzer); |
| + assertNotNull(q); |
| + assertEquals(q.getBoost(), (float) 2.0, (float) 0.5); |
| + q = getQuery("\"on\"^1.0", oneStopAnalyzer); |
| + assertNotNull(q); |
| + |
| + StandardAnalyzer standardAnalyzer = new StandardAnalyzer(); |
| + |
| + q = getQuery("the^3", standardAnalyzer); |
| + // "the" is a stop word so the result is an empty query: |
| + assertNotNull(q); |
| + assertEquals("", q.toString()); |
| + assertEquals(1.0f, q.getBoost(), 0.01f); |
| + } |
| + |
| + public void assertQueryNodeException(String queryString) throws Exception { |
| + try { |
| + getQuery(queryString, null); |
| + } catch (QueryNodeException expected) { |
| + return; |
| + } |
| + fail("ParseException expected, not thrown"); |
| + } |
| + |
| + public void testException() throws Exception { |
| + assertQueryNodeException("\"some phrase"); |
| + assertQueryNodeException("(foo bar"); |
| + assertQueryNodeException("foo bar))"); |
| + assertQueryNodeException("field:term:with:colon some more terms"); |
| + assertQueryNodeException("(sub query)^5.0^2.0 plus more"); |
| + assertQueryNodeException("secret AND illegal) AND access:confidential"); |
| + } |
| + |
| + public void testCustomProcessor() { |
| + QPTestParserQueryNodeProcessor processor = new QPTestParserQueryNodeProcessor(); |
| + TextParser textParser = new TextParser(); |
| + |
| + try { |
| + QueryNode queryTree = textParser.parse("a?t", "contents"); |
| + processor.process(queryTree); |
| + |
| + fail("Wildcard queries should not be allowed"); |
| + } catch (QueryNodeException expected) { |
| + // expected exception |
| + } |
| + |
| + try { |
| + QueryNode queryTree = textParser.parse("xunit~", "contents"); |
| + processor.process(queryTree); |
| + |
| + fail("Fuzzy queries should not be allowed"); |
| + } catch (QueryNodeException expected) { |
| + // expected exception |
| + } |
| + |
| + } |
| + |
| + public void testCustomQueryParserFuzzy() throws Exception { |
| + |
| + } |
| + |
| + /** |
| + * This test differs from TestPrecedenceQueryParser |
| + */ |
| + public void testPrecedence() throws Exception { |
| + Analyzer wAnalyzer = new WhitespaceAnalyzer(); |
| + |
| + Query query1 = getQuery("A AND B OR C AND D", wAnalyzer); |
| + Query query2 = getQuery("+A +B +C +D", wAnalyzer); |
| + |
| + assertEquals(query1, query2); |
| + } |
| + |
| + public void testLocalDateFormat() throws Exception { |
| + |
| + RAMDirectory ramDir = new RAMDirectory(); |
| + IndexWriter iw = new IndexWriter(ramDir, new WhitespaceAnalyzer(), true, |
| + IndexWriter.MaxFieldLength.LIMITED); |
| + addDateDoc("a", 2005, 12, 2, 10, 15, 33, iw); |
| + addDateDoc("b", 2005, 12, 4, 22, 15, 00, iw); |
| + iw.close(); |
| + IndexSearcher is = new IndexSearcher(ramDir); |
| + assertHits(1, "[12/1/2005 TO 12/3/2005]", is); |
| + assertHits(2, "[12/1/2005 TO 12/4/2005]", is); |
| + assertHits(1, "[12/3/2005 TO 12/4/2005]", is); |
| + assertHits(1, "{12/1/2005 TO 12/3/2005}", is); |
| + assertHits(1, "{12/1/2005 TO 12/4/2005}", is); |
| + assertHits(0, "{12/3/2005 TO 12/4/2005}", is); |
| + is.close(); |
| + } |
| + |
| + // TODO: fix this test |
| + // public void testStarParsing() throws Exception { |
| + // final int[] type = new int[1]; |
| + // TextParser qp = new QueryParserWrapper("field", new |
| + // WhitespaceAnalyzer()) { |
| + // protected Query getWildcardQuery(String field, String termStr) throws |
| + // ParseException { |
| + // // override error checking of superclass |
| + // type[0]=1; |
| + // return new TermQuery(new Term(field,termStr)); |
| + // } |
| + // protected Query getPrefixQuery(String field, String termStr) throws |
| + // ParseException { |
| + // // override error checking of superclass |
| + // type[0]=2; |
| + // return new TermQuery(new Term(field,termStr)); |
| + // } |
| + // |
| + // protected Query getFieldQuery(String field, String queryText) throws |
| + // ParseException { |
| + // type[0]=3; |
| + // return super.getFieldQuery(field, queryText); |
| + // } |
| + // }; |
| + // |
| + // TermQuery tq; |
| + // |
| + // tq = (TermQuery)qp.parse("foo:zoo*"); |
| + // assertEquals("zoo",tq.getTerm().text()); |
| + // assertEquals(2,type[0]); |
| + // |
| + // tq = (TermQuery)qp.parse("foo:zoo*^2"); |
| + // assertEquals("zoo",tq.getTerm().text()); |
| + // assertEquals(2,type[0]); |
| + // assertEquals(tq.getBoost(),2,0); |
| + // |
| + // tq = (TermQuery)qp.parse("foo:*"); |
| + // assertEquals("*",tq.getTerm().text()); |
| + // assertEquals(1,type[0]); // could be a valid prefix query in the |
| + // future too |
| + // |
| + // tq = (TermQuery)qp.parse("foo:*^2"); |
| + // assertEquals("*",tq.getTerm().text()); |
| + // assertEquals(1,type[0]); |
| + // assertEquals(tq.getBoost(),2,0); |
| + // |
| + // tq = (TermQuery)qp.parse("*:foo"); |
| + // assertEquals("*",tq.getTerm().field()); |
| + // assertEquals("foo",tq.getTerm().text()); |
| + // assertEquals(3,type[0]); |
| + // |
| + // tq = (TermQuery)qp.parse("*:*"); |
| + // assertEquals("*",tq.getTerm().field()); |
| + // assertEquals("*",tq.getTerm().text()); |
| + // assertEquals(1,type[0]); // could be handled as a prefix query in the |
| + // future |
| + // |
| + // tq = (TermQuery)qp.parse("(*:*)"); |
| + // assertEquals("*",tq.getTerm().field()); |
| + // assertEquals("*",tq.getTerm().text()); |
| + // assertEquals(1,type[0]); |
| + |
| + // } |
| + |
| + public void testStopwords() throws Exception { |
| + Analyzer analyzer = new StopAnalyzer(new String[] { "the", "foo" }); |
| + |
| + Query result = getQuery("field:the OR field:foo", analyzer); |
| + assertNotNull("result is null and it shouldn't be", result); |
| + assertTrue("result is not a BooleanQuery", result instanceof BooleanQuery); |
| + assertTrue(((BooleanQuery) result).clauses().size() + " does not equal: " |
| + + 0, ((BooleanQuery) result).clauses().size() == 0); |
| + result = getQuery("field:woo OR field:the", analyzer); |
| + assertNotNull("result is null and it shouldn't be", result); |
| + assertTrue("result is not a TermQuery", result instanceof TermQuery); |
| + result = getQuery( |
| + "(fieldX:xxxxx OR fieldy:xxxxxxxx)^2 AND (fieldx:the OR fieldy:foo)", |
| + analyzer); |
| + assertNotNull("result is null and it shouldn't be", result); |
| + assertTrue("result is not a BooleanQuery", result instanceof BooleanQuery); |
| + System.out.println("Result: " + result); |
| + assertTrue(((BooleanQuery) result).clauses().size() + " does not equal: " |
| + + 2, ((BooleanQuery) result).clauses().size() == 2); |
| + } |
| + |
| + public void testPositionIncrement() throws Exception { |
| + boolean dflt = StopFilter.getEnablePositionIncrementsDefault(); |
| + StopFilter.setEnablePositionIncrementsDefault(true); |
| + |
| + try { |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + Analyzer analyzer = new StopAnalyzer(new String[] { "the", "in", "are", |
| + "this" }); |
| + config.setAnalyzer(analyzer); |
| + config.setEnablePositionIncrements(true); |
| + |
| + String qtxt = "\"the words in poisitions pos02578 are stopped in this phrasequery\""; |
| + // 0 2 5 7 8 |
| + int expectedPositions[] = { 1, 3, 4, 6, 9 }; |
| + PhraseQuery pq = (PhraseQuery) getQuery(config, qtxt); |
| + // System.out.println("Query text: "+qtxt); |
| + // System.out.println("Result: "+pq); |
| + Term t[] = pq.getTerms(); |
| + int pos[] = pq.getPositions(); |
| + for (int i = 0; i < t.length; i++) { |
| + // System.out.println(i+". "+t[i]+" pos: "+pos[i]); |
| + assertEquals("term " + i + " = " + t[i] + " has wrong term-position!", |
| + expectedPositions[i], pos[i]); |
| + } |
| + |
| + } finally { |
| + StopFilter.setEnablePositionIncrementsDefault(dflt); |
| + } |
| + } |
| + |
| + public void testMatchAllDocs() throws Exception { |
| + Analyzer wAnalyzer = new WhitespaceAnalyzer(); |
| + |
| + assertEquals(new MatchAllDocsQuery(), getQuery("*:*", wAnalyzer)); |
| + assertEquals(new MatchAllDocsQuery(), getQuery("(*:*)", wAnalyzer)); |
| + BooleanQuery bq = (BooleanQuery) getQuery("+*:* -*:*", wAnalyzer); |
| + assertTrue(bq.getClauses()[0].getQuery() instanceof MatchAllDocsQuery); |
| + assertTrue(bq.getClauses()[1].getQuery() instanceof MatchAllDocsQuery); |
| + } |
| + |
| + private void assertHits(int expected, String query, IndexSearcher is) |
| + throws Exception { |
| + |
| + LuceneQueryConfigHandler config = new LuceneQueryConfigHandler(); |
| + config.setAnalyzer(new WhitespaceAnalyzer()); |
| + config.setLocale(Locale.ENGLISH); |
| + Query q = getQuery(config, query, "date"); |
| + ScoreDoc[] hits = is.search(q, null, 1000).scoreDocs; |
| + assertEquals(expected, hits.length); |
| + } |
| + |
| + private static void addDateDoc(String content, int year, int month, int day, |
| + int hour, int minute, int second, IndexWriter iw) throws IOException { |
| + Document d = new Document(); |
| + d.add(new Field("f", content, Field.Store.YES, Field.Index.ANALYZED)); |
| + Calendar cal = Calendar.getInstance(); |
| + cal.set(year, month - 1, day, hour, minute, second); |
| + d.add(new Field("date", DateField.dateToString(cal.getTime()), |
| + Field.Store.YES, Field.Index.NOT_ANALYZED)); |
| + iw.addDocument(d); |
| + } |
| + |
| + public void tearDown() throws Exception { |
| + super.tearDown(); |
| + BooleanQuery.setMaxClauseCount(originalMaxClauses); |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestQueryParserWrapper.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestQueryParserWrapper.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestQueryParserWrapper.java (revision 0) |
| @@ -0,0 +1,1123 @@ |
| +package org.apache.lucene.queryParser.original; |
| + |
| +/** |
| + * 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 java.io.IOException; |
| +import java.io.Reader; |
| +import java.text.Collator; |
| +import java.text.DateFormat; |
| +import java.util.Calendar; |
| +import java.util.Date; |
| +import java.util.List; |
| +import java.util.Locale; |
| + |
| +import org.apache.lucene.analysis.Analyzer; |
| +import org.apache.lucene.analysis.KeywordAnalyzer; |
| +import org.apache.lucene.analysis.LowerCaseTokenizer; |
| +import org.apache.lucene.analysis.SimpleAnalyzer; |
| +import org.apache.lucene.analysis.StopAnalyzer; |
| +import org.apache.lucene.analysis.StopFilter; |
| +import org.apache.lucene.analysis.Token; |
| +import org.apache.lucene.analysis.TokenFilter; |
| +import org.apache.lucene.analysis.TokenStream; |
| +import org.apache.lucene.analysis.WhitespaceAnalyzer; |
| +import org.apache.lucene.analysis.standard.StandardAnalyzer; |
| +import org.apache.lucene.analysis.tokenattributes.OffsetAttribute; |
| +import org.apache.lucene.analysis.tokenattributes.TermAttribute; |
| +import org.apache.lucene.document.DateField; |
| +import org.apache.lucene.document.DateTools; |
| +import org.apache.lucene.document.Document; |
| +import org.apache.lucene.document.Field; |
| +import org.apache.lucene.index.IndexWriter; |
| +import org.apache.lucene.index.Term; |
| +import org.apache.lucene.messages.MessageImpl; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.messages.QueryParserMessages; |
| +import org.apache.lucene.queryParser.nodes.FuzzyQueryNode; |
| +import org.apache.lucene.queryParser.nodes.QueryNode; |
| +import org.apache.lucene.queryParser.nodes.WildcardQueryNode; |
| +import org.apache.lucene.queryParser.original.QueryParserWrapper; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl; |
| +import org.apache.lucene.queryParser.processors.QueryNodeProcessorPipeline; |
| +import org.apache.lucene.queryParser.ParseException; |
| +import org.apache.lucene.search.BooleanQuery; |
| +import org.apache.lucene.search.FuzzyQuery; |
| +import org.apache.lucene.search.IndexSearcher; |
| +import org.apache.lucene.search.MatchAllDocsQuery; |
| +import org.apache.lucene.search.PhraseQuery; |
| +import org.apache.lucene.search.PrefixQuery; |
| +import org.apache.lucene.search.Query; |
| +import org.apache.lucene.search.ScoreDoc; |
| +import org.apache.lucene.search.TermQuery; |
| +import org.apache.lucene.search.TermRangeQuery; |
| +import org.apache.lucene.search.WildcardQuery; |
| +import org.apache.lucene.store.RAMDirectory; |
| +import org.apache.lucene.util.LuceneTestCase; |
| + |
| +/** |
| + * This test case is a copy of the core Lucene query parser test, it was adapted |
| + * to use new QueryParserWrapper instead of the old query parser. |
| + * |
| + * Tests QueryParser. |
| + */ |
| +public class TestQueryParserWrapper extends LuceneTestCase { |
| + |
| + public static Analyzer qpAnalyzer = new QPTestAnalyzer(); |
| + |
| + public static class QPTestFilter extends TokenFilter { |
| + TermAttribute termAtt; |
| + OffsetAttribute offsetAtt; |
| + |
| + /** |
| + * Filter which discards the token 'stop' and which expands the token |
| + * 'phrase' into 'phrase1 phrase2' |
| + */ |
| + public QPTestFilter(TokenStream in) { |
| + super(in); |
| + termAtt = (TermAttribute) addAttribute(TermAttribute.class); |
| + offsetAtt = (OffsetAttribute) addAttribute(OffsetAttribute.class); |
| + } |
| + |
| + boolean inPhrase = false; |
| + int savedStart = 0, savedEnd = 0; |
| + |
| + public Token next(Token reusableToken) throws IOException { |
| + Token token = reusableToken; |
| + |
| + if (inPhrase) { |
| + inPhrase = false; |
| + token.setTermBuffer("phrase2"); |
| + token.setStartOffset(savedStart); |
| + token.setEndOffset(savedEnd); |
| + return reusableToken; |
| + } else |
| + while ((token = this.input.next(reusableToken)) != null) { |
| + if (token.term().equals("phrase")) { |
| + inPhrase = true; |
| + savedStart = token.startOffset(); |
| + savedEnd = token.endOffset(); |
| + token.setTermBuffer("phrase1"); |
| + token.setStartOffset(savedStart); |
| + token.setEndOffset(savedEnd); |
| + return token; |
| + } else if (!token.term().equals("stop")) |
| + return token; |
| + } |
| + |
| + return null; |
| + |
| + } |
| + |
| + public boolean incrementToken() throws IOException { |
| + if (inPhrase) { |
| + inPhrase = false; |
| + termAtt.setTermBuffer("phrase2"); |
| + offsetAtt.setOffset(savedStart, savedEnd); |
| + return true; |
| + } else |
| + while (input.incrementToken()) { |
| + if (termAtt.term().equals("phrase")) { |
| + inPhrase = true; |
| + savedStart = offsetAtt.startOffset(); |
| + savedEnd = offsetAtt.endOffset(); |
| + termAtt.setTermBuffer("phrase1"); |
| + offsetAtt.setOffset(savedStart, savedEnd); |
| + return true; |
| + } else if (!termAtt.term().equals("stop")) |
| + return true; |
| + } |
| + return false; |
| + } |
| + } |
| + |
| + public static class QPTestAnalyzer extends Analyzer { |
| + |
| + /** Filters LowerCaseTokenizer with StopFilter. */ |
| + public final TokenStream tokenStream(String fieldName, Reader reader) { |
| + return new QPTestFilter(new LowerCaseTokenizer(reader)); |
| + } |
| + } |
| + |
| + public static class QPTestParser extends QueryParserWrapper { |
| + public QPTestParser(String f, Analyzer a) { |
| + super(f, a); |
| + |
| + QueryNodeProcessorPipeline newProcessorPipeline = new QueryNodeProcessorPipeline( |
| + getQueryProcessor().getQueryConfigHandler()); |
| + newProcessorPipeline.addProcessor(new QPTestParserQueryNodeProcessor()); |
| + newProcessorPipeline.addProcessor(getQueryProcessor()); |
| + |
| + setQueryProcessor(newProcessorPipeline); |
| + |
| + } |
| + |
| + protected Query getFuzzyQuery(String field, String termStr, |
| + float minSimilarity) throws ParseException { |
| + throw new ParseException("Fuzzy queries not allowed"); |
| + } |
| + |
| + protected Query getWildcardQuery(String field, String termStr) |
| + throws ParseException { |
| + throw new ParseException("Wildcard queries not allowed"); |
| + } |
| + |
| + private static class QPTestParserQueryNodeProcessor extends |
| + QueryNodeProcessorImpl { |
| + |
| + protected QueryNode postProcessNode(QueryNode node) |
| + throws QueryNodeException { |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected QueryNode preProcessNode(QueryNode node) |
| + throws QueryNodeException { |
| + |
| + if (node instanceof WildcardQueryNode || node instanceof FuzzyQueryNode) { |
| + |
| + throw new QueryNodeException(new MessageImpl( |
| + QueryParserMessages.EMPTY_MESSAGE)); |
| + |
| + } |
| + |
| + return node; |
| + |
| + } |
| + |
| + protected List<QueryNode> setChildrenOrder(List<QueryNode> children) |
| + throws QueryNodeException { |
| + |
| + return children; |
| + |
| + } |
| + |
| + } |
| + |
| + } |
| + |
| + private int originalMaxClauses; |
| + |
| + public void setUp() throws Exception { |
| + super.setUp(); |
| + originalMaxClauses = BooleanQuery.getMaxClauseCount(); |
| + } |
| + |
| + public QueryParserWrapper getParser(Analyzer a) throws Exception { |
| + if (a == null) |
| + a = new SimpleAnalyzer(); |
| + QueryParserWrapper qp = new QueryParserWrapper("field", a); |
| + qp.setDefaultOperator(QueryParserWrapper.OR_OPERATOR); |
| + return qp; |
| + } |
| + |
| + public Query getQuery(String query, Analyzer a) throws Exception { |
| + return getParser(a).parse(query); |
| + } |
| + |
| + public void assertQueryEquals(String query, Analyzer a, String result) |
| + throws Exception { |
| + Query q = getQuery(query, a); |
| + String s = q.toString("field"); |
| + if (!s.equals(result)) { |
| + fail("Query /" + query + "/ yielded /" + s + "/, expecting /" + result |
| + + "/"); |
| + } |
| + } |
| + |
| + public void assertQueryEquals(QueryParserWrapper qp, String field, |
| + String query, String result) throws Exception { |
| + Query q = qp.parse(query); |
| + String s = q.toString(field); |
| + if (!s.equals(result)) { |
| + fail("Query /" + query + "/ yielded /" + s + "/, expecting /" + result |
| + + "/"); |
| + } |
| + } |
| + |
| + public void assertEscapedQueryEquals(String query, Analyzer a, String result) |
| + throws Exception { |
| + String escapedQuery = QueryParserWrapper.escape(query); |
| + if (!escapedQuery.equals(result)) { |
| + fail("Query /" + query + "/ yielded /" + escapedQuery + "/, expecting /" |
| + + result + "/"); |
| + } |
| + } |
| + |
| + public void assertWildcardQueryEquals(String query, boolean lowercase, |
| + String result, boolean allowLeadingWildcard) throws Exception { |
| + QueryParserWrapper qp = getParser(null); |
| + qp.setLowercaseExpandedTerms(lowercase); |
| + qp.setAllowLeadingWildcard(allowLeadingWildcard); |
| + Query q = qp.parse(query); |
| + String s = q.toString("field"); |
| + if (!s.equals(result)) { |
| + fail("WildcardQuery /" + query + "/ yielded /" + s + "/, expecting /" |
| + + result + "/"); |
| + } |
| + } |
| + |
| + public void assertWildcardQueryEquals(String query, boolean lowercase, |
| + String result) throws Exception { |
| + assertWildcardQueryEquals(query, lowercase, result, false); |
| + } |
| + |
| + public void assertWildcardQueryEquals(String query, String result) |
| + throws Exception { |
| + QueryParserWrapper qp = getParser(null); |
| + Query q = qp.parse(query); |
| + String s = q.toString("field"); |
| + if (!s.equals(result)) { |
| + fail("WildcardQuery /" + query + "/ yielded /" + s + "/, expecting /" |
| + + result + "/"); |
| + } |
| + } |
| + |
| + public Query getQueryDOA(String query, Analyzer a) throws Exception { |
| + if (a == null) |
| + a = new SimpleAnalyzer(); |
| + QueryParserWrapper qp = new QueryParserWrapper("field", a); |
| + qp.setDefaultOperator(QueryParserWrapper.AND_OPERATOR); |
| + return qp.parse(query); |
| + } |
| + |
| + public void assertQueryEqualsDOA(String query, Analyzer a, String result) |
| + throws Exception { |
| + Query q = getQueryDOA(query, a); |
| + String s = q.toString("field"); |
| + if (!s.equals(result)) { |
| + fail("Query /" + query + "/ yielded /" + s + "/, expecting /" + result |
| + + "/"); |
| + } |
| + } |
| + |
| + public void testCJK() throws Exception { |
| + // Test Ideographic Space - As wide as a CJK character cell (fullwidth) |
| + // used google to translate the word "term" to japanese -> 用語 |
| + assertQueryEquals("term\u3000term\u3000term", null, |
| + "term\u0020term\u0020term"); |
| + assertQueryEquals("用語\u3000用語\u3000用語", null, "用語\u0020用語\u0020用語"); |
| + } |
| + |
| + public void testSimple() throws Exception { |
| + assertQueryEquals("\"term germ\"~2", null, "\"term germ\"~2"); |
| + assertQueryEquals("term term term", null, "term term term"); |
| + assertQueryEquals("türm term term", new WhitespaceAnalyzer(), |
| + "türm term term"); |
| + assertQueryEquals("ümlaut", new WhitespaceAnalyzer(), "ümlaut"); |
| + |
| + assertQueryEquals("\"\"", new KeywordAnalyzer(), ""); |
| + assertQueryEquals("foo:\"\"", new KeywordAnalyzer(), "foo:"); |
| + |
| + assertQueryEquals("a AND b", null, "+a +b"); |
| + assertQueryEquals("(a AND b)", null, "+a +b"); |
| + assertQueryEquals("c OR (a AND b)", null, "c (+a +b)"); |
| + |
| + assertQueryEquals("a AND NOT b", null, "+a -b"); |
| + |
| + assertQueryEquals("a AND -b", null, "+a -b"); |
| + |
| + assertQueryEquals("a AND !b", null, "+a -b"); |
| + |
| + assertQueryEquals("a && b", null, "+a +b"); |
| + |
| + assertQueryEquals("a && ! b", null, "+a -b"); |
| + |
| + assertQueryEquals("a OR b", null, "a b"); |
| + assertQueryEquals("a || b", null, "a b"); |
| + |
| + assertQueryEquals("a OR !b", null, "a -b"); |
| + |
| + assertQueryEquals("a OR ! b", null, "a -b"); |
| + |
| + assertQueryEquals("a OR -b", null, "a -b"); |
| + |
| + assertQueryEquals("+term -term term", null, "+term -term term"); |
| + assertQueryEquals("foo:term AND field:anotherTerm", null, |
| + "+foo:term +anotherterm"); |
| + assertQueryEquals("term AND \"phrase phrase\"", null, |
| + "+term +\"phrase phrase\""); |
| + assertQueryEquals("\"hello there\"", null, "\"hello there\""); |
| + assertTrue(getQuery("a AND b", null) instanceof BooleanQuery); |
| + assertTrue(getQuery("hello", null) instanceof TermQuery); |
| + assertTrue(getQuery("\"hello there\"", null) instanceof PhraseQuery); |
| + |
| + assertQueryEquals("germ term^2.0", null, "germ term^2.0"); |
| + assertQueryEquals("(term)^2.0", null, "term^2.0"); |
| + assertQueryEquals("(germ term)^2.0", null, "(germ term)^2.0"); |
| + assertQueryEquals("term^2.0", null, "term^2.0"); |
| + assertQueryEquals("term^2", null, "term^2.0"); |
| + assertQueryEquals("\"germ term\"^2.0", null, "\"germ term\"^2.0"); |
| + assertQueryEquals("\"term germ\"^2", null, "\"term germ\"^2.0"); |
| + |
| + assertQueryEquals("(foo OR bar) AND (baz OR boo)", null, |
| + "+(foo bar) +(baz boo)"); |
| + assertQueryEquals("((a OR b) AND NOT c) OR d", null, "(+(a b) -c) d"); |
| + assertQueryEquals("+(apple \"steve jobs\") -(foo bar baz)", null, |
| + "+(apple \"steve jobs\") -(foo bar baz)"); |
| + assertQueryEquals("+title:(dog OR cat) -author:\"bob dole\"", null, |
| + "+(title:dog title:cat) -author:\"bob dole\""); |
| + |
| + QueryParserWrapper qp = new QueryParserWrapper("field", |
| + new StandardAnalyzer()); |
| + // make sure OR is the default: |
| + assertEquals(QueryParserWrapper.OR_OPERATOR, qp.getDefaultOperator()); |
| + qp.setDefaultOperator(QueryParserWrapper.AND_OPERATOR); |
| + assertEquals(QueryParserWrapper.AND_OPERATOR, qp.getDefaultOperator()); |
| + qp.setDefaultOperator(QueryParserWrapper.OR_OPERATOR); |
| + assertEquals(QueryParserWrapper.OR_OPERATOR, qp.getDefaultOperator()); |
| + } |
| + |
| + public void testPunct() throws Exception { |
| + Analyzer a = new WhitespaceAnalyzer(); |
| + assertQueryEquals("a&b", a, "a&b"); |
| + assertQueryEquals("a&&b", a, "a&&b"); |
| + assertQueryEquals(".NET", a, ".NET"); |
| + } |
| + |
| + public void testSlop() throws Exception { |
| + |
| + assertQueryEquals("\"term germ\"~2", null, "\"term germ\"~2"); |
| + assertQueryEquals("\"term germ\"~2 flork", null, "\"term germ\"~2 flork"); |
| + assertQueryEquals("\"term\"~2", null, "term"); |
| + assertQueryEquals("\" \"~2 germ", null, "germ"); |
| + assertQueryEquals("\"term germ\"~2^2", null, "\"term germ\"~2^2.0"); |
| + } |
| + |
| + public void testNumber() throws Exception { |
| + // The numbers go away because SimpleAnalzyer ignores them |
| + assertQueryEquals("3", null, ""); |
| + assertQueryEquals("term 1.0 1 2", null, "term"); |
| + assertQueryEquals("term term1 term2", null, "term term term"); |
| + |
| + Analyzer a = new StandardAnalyzer(); |
| + assertQueryEquals("3", a, "3"); |
| + assertQueryEquals("term 1.0 1 2", a, "term 1.0 1 2"); |
| + assertQueryEquals("term term1 term2", a, "term term1 term2"); |
| + } |
| + |
| + public void testWildcard() throws Exception { |
| + assertQueryEquals("term*", null, "term*"); |
| + assertQueryEquals("term*^2", null, "term*^2.0"); |
| + assertQueryEquals("term~", null, "term~0.5"); |
| + assertQueryEquals("term~0.7", null, "term~0.7"); |
| + |
| + assertQueryEquals("term~^2", null, "term~0.5^2.0"); |
| + |
| + assertQueryEquals("term^2~", null, "term~0.5^2.0"); |
| + assertQueryEquals("term*germ", null, "term*germ"); |
| + assertQueryEquals("term*germ^3", null, "term*germ^3.0"); |
| + |
| + assertTrue(getQuery("term*", null) instanceof PrefixQuery); |
| + assertTrue(getQuery("term*^2", null) instanceof PrefixQuery); |
| + assertTrue(getQuery("term~", null) instanceof FuzzyQuery); |
| + assertTrue(getQuery("term~0.7", null) instanceof FuzzyQuery); |
| + FuzzyQuery fq = (FuzzyQuery) getQuery("term~0.7", null); |
| + assertEquals(0.7f, fq.getMinSimilarity(), 0.1f); |
| + assertEquals(FuzzyQuery.defaultPrefixLength, fq.getPrefixLength()); |
| + fq = (FuzzyQuery) getQuery("term~", null); |
| + assertEquals(0.5f, fq.getMinSimilarity(), 0.1f); |
| + assertEquals(FuzzyQuery.defaultPrefixLength, fq.getPrefixLength()); |
| + |
| + assertParseException("term~1.1"); // value > 1, throws exception |
| + |
| + assertTrue(getQuery("term*germ", null) instanceof WildcardQuery); |
| + |
| + /* |
| + * Tests to see that wild card terms are (or are not) properly lower-cased |
| + * with propery parser configuration |
| + */ |
| + // First prefix queries: |
| + // by default, convert to lowercase: |
| + assertWildcardQueryEquals("Term*", true, "term*"); |
| + // explicitly set lowercase: |
| + assertWildcardQueryEquals("term*", true, "term*"); |
| + assertWildcardQueryEquals("Term*", true, "term*"); |
| + assertWildcardQueryEquals("TERM*", true, "term*"); |
| + // explicitly disable lowercase conversion: |
| + assertWildcardQueryEquals("term*", false, "term*"); |
| + assertWildcardQueryEquals("Term*", false, "Term*"); |
| + assertWildcardQueryEquals("TERM*", false, "TERM*"); |
| + // Then 'full' wildcard queries: |
| + // by default, convert to lowercase: |
| + assertWildcardQueryEquals("Te?m", "te?m"); |
| + // explicitly set lowercase: |
| + assertWildcardQueryEquals("te?m", true, "te?m"); |
| + assertWildcardQueryEquals("Te?m", true, "te?m"); |
| + assertWildcardQueryEquals("TE?M", true, "te?m"); |
| + assertWildcardQueryEquals("Te?m*gerM", true, "te?m*germ"); |
| + // explicitly disable lowercase conversion: |
| + assertWildcardQueryEquals("te?m", false, "te?m"); |
| + assertWildcardQueryEquals("Te?m", false, "Te?m"); |
| + assertWildcardQueryEquals("TE?M", false, "TE?M"); |
| + assertWildcardQueryEquals("Te?m*gerM", false, "Te?m*gerM"); |
| + // Fuzzy queries: |
| + assertWildcardQueryEquals("Term~", "term~0.5"); |
| + assertWildcardQueryEquals("Term~", true, "term~0.5"); |
| + assertWildcardQueryEquals("Term~", false, "Term~0.5"); |
| + // Range queries: |
| + |
| + // TODO: implement this on QueryParser |
| + // Q0002E_INVALID_SYNTAX_CANNOT_PARSE: Syntax Error, cannot parse '[A TO |
| + // C]': Lexical error at line 1, column 1. Encountered: "[" (91), after : "" |
| + assertWildcardQueryEquals("[A TO C]", "[a TO c]"); |
| + assertWildcardQueryEquals("[A TO C]", true, "[a TO c]"); |
| + assertWildcardQueryEquals("[A TO C]", false, "[A TO C]"); |
| + // Test suffix queries: first disallow |
| + try { |
| + assertWildcardQueryEquals("*Term", true, "*term"); |
| + fail(); |
| + } catch (ParseException pe) { |
| + // expected exception |
| + } |
| + try { |
| + assertWildcardQueryEquals("?Term", true, "?term"); |
| + fail(); |
| + } catch (ParseException pe) { |
| + // expected exception |
| + } |
| + // Test suffix queries: then allow |
| + assertWildcardQueryEquals("*Term", true, "*term", true); |
| + assertWildcardQueryEquals("?Term", true, "?term", true); |
| + } |
| + |
| + public void testLeadingWildcardType() throws Exception { |
| + QueryParserWrapper qp = getParser(null); |
| + qp.setAllowLeadingWildcard(true); |
| + assertEquals(WildcardQuery.class, qp.parse("t*erm*").getClass()); |
| + assertEquals(WildcardQuery.class, qp.parse("?term*").getClass()); |
| + assertEquals(WildcardQuery.class, qp.parse("*term*").getClass()); |
| + } |
| + |
| + public void testQPA() throws Exception { |
| + assertQueryEquals("term term^3.0 term", qpAnalyzer, "term term^3.0 term"); |
| + assertQueryEquals("term stop^3.0 term", qpAnalyzer, "term term"); |
| + |
| + assertQueryEquals("term term term", qpAnalyzer, "term term term"); |
| + assertQueryEquals("term +stop term", qpAnalyzer, "term term"); |
| + assertQueryEquals("term -stop term", qpAnalyzer, "term term"); |
| + |
| + assertQueryEquals("drop AND (stop) AND roll", qpAnalyzer, "+drop +roll"); |
| + assertQueryEquals("term +(stop) term", qpAnalyzer, "term term"); |
| + assertQueryEquals("term -(stop) term", qpAnalyzer, "term term"); |
| + |
| + assertQueryEquals("drop AND stop AND roll", qpAnalyzer, "+drop +roll"); |
| + assertQueryEquals("term phrase term", qpAnalyzer, |
| + "term \"phrase1 phrase2\" term"); |
| + |
| + assertQueryEquals("term AND NOT phrase term", qpAnalyzer, |
| + "+term -\"phrase1 phrase2\" term"); |
| + |
| + assertQueryEquals("stop^3", qpAnalyzer, ""); |
| + assertQueryEquals("stop", qpAnalyzer, ""); |
| + assertQueryEquals("(stop)^3", qpAnalyzer, ""); |
| + assertQueryEquals("((stop))^3", qpAnalyzer, ""); |
| + assertQueryEquals("(stop^3)", qpAnalyzer, ""); |
| + assertQueryEquals("((stop)^3)", qpAnalyzer, ""); |
| + assertQueryEquals("(stop)", qpAnalyzer, ""); |
| + assertQueryEquals("((stop))", qpAnalyzer, ""); |
| + assertTrue(getQuery("term term term", qpAnalyzer) instanceof BooleanQuery); |
| + assertTrue(getQuery("term +stop", qpAnalyzer) instanceof TermQuery); |
| + } |
| + |
| + public void testRange() throws Exception { |
| + assertQueryEquals("[ a TO z]", null, "[a TO z]"); |
| + assertTrue(((TermRangeQuery) getQuery("[ a TO z]", null)) |
| + .getConstantScoreRewrite()); |
| + |
| + QueryParserWrapper qp = new QueryParserWrapper("field", |
| + new SimpleAnalyzer()); |
| + qp.setConstantScoreRewrite(false); |
| + assertFalse(((TermRangeQuery) qp.parse("[ a TO z]")) |
| + .getConstantScoreRewrite()); |
| + |
| + assertQueryEquals("[ a TO z ]", null, "[a TO z]"); |
| + assertQueryEquals("{ a TO z}", null, "{a TO z}"); |
| + assertQueryEquals("{ a TO z }", null, "{a TO z}"); |
| + assertQueryEquals("{ a TO z }^2.0", null, "{a TO z}^2.0"); |
| + assertQueryEquals("[ a TO z] OR bar", null, "[a TO z] bar"); |
| + assertQueryEquals("[ a TO z] AND bar", null, "+[a TO z] +bar"); |
| + assertQueryEquals("( bar blar { a TO z}) ", null, "bar blar {a TO z}"); |
| + assertQueryEquals("gack ( bar blar { a TO z}) ", null, |
| + "gack (bar blar {a TO z})"); |
| + } |
| + |
| + public void testFarsiRangeCollating() throws Exception { |
| + |
| + RAMDirectory ramDir = new RAMDirectory(); |
| + IndexWriter iw = new IndexWriter(ramDir, new WhitespaceAnalyzer(), true, |
| + IndexWriter.MaxFieldLength.LIMITED); |
| + Document doc = new Document(); |
| + doc.add(new Field("content", "\u0633\u0627\u0628", Field.Store.YES, |
| + Field.Index.UN_TOKENIZED)); |
| + iw.addDocument(doc); |
| + iw.close(); |
| + IndexSearcher is = new IndexSearcher(ramDir); |
| + |
| + QueryParserWrapper qp = new QueryParserWrapper("content", |
| + new WhitespaceAnalyzer()); |
| + |
| + // Neither Java 1.4.2 nor 1.5.0 has Farsi Locale collation available in |
| + // RuleBasedCollator. However, the Arabic Locale seems to order the Farsi |
| + // characters properly. |
| + Collator c = Collator.getInstance(new Locale("ar")); |
| + qp.setRangeCollator(c); |
| + |
| + // Unicode order would include U+0633 in [ U+062F - U+0698 ], but Farsi |
| + // orders the U+0698 character before the U+0633 character, so the single |
| + // index Term below should NOT be returned by a ConstantScoreRangeQuery |
| + // with a Farsi Collator (or an Arabic one for the case when Farsi is not |
| + // supported). |
| + |
| + // Test ConstantScoreRangeQuery |
| + qp.setConstantScoreRewrite(true); |
| + ScoreDoc[] result = is.search(qp.parse("[ \u062F TO \u0698 ]"), null, 1000).scoreDocs; |
| + assertEquals("The index Term should not be included.", 0, result.length); |
| + |
| + result = is.search(qp.parse("[ \u0633 TO \u0638 ]"), null, 1000).scoreDocs; |
| + assertEquals("The index Term should be included.", 1, result.length); |
| + |
| + // Test RangeQuery |
| + qp.setConstantScoreRewrite(false); |
| + result = is.search(qp.parse("[ \u062F TO \u0698 ]"), null, 1000).scoreDocs; |
| + assertEquals("The index Term should not be included.", 0, result.length); |
| + |
| + result = is.search(qp.parse("[ \u0633 TO \u0638 ]"), null, 1000).scoreDocs; |
| + assertEquals("The index Term should be included.", 1, result.length); |
| + |
| + is.close(); |
| + } |
| + |
| + /** for testing legacy DateField support */ |
| + private String getLegacyDate(String s) throws Exception { |
| + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); |
| + return DateField.dateToString(df.parse(s)); |
| + } |
| + |
| + /** for testing DateTools support */ |
| + private String getDate(String s, DateTools.Resolution resolution) |
| + throws Exception { |
| + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); |
| + return getDate(df.parse(s), resolution); |
| + } |
| + |
| + /** for testing DateTools support */ |
| + private String getDate(Date d, DateTools.Resolution resolution) |
| + throws Exception { |
| + if (resolution == null) { |
| + return DateField.dateToString(d); |
| + } else { |
| + return DateTools.dateToString(d, resolution); |
| + } |
| + } |
| + |
| + private String getLocalizedDate(int year, int month, int day, |
| + boolean extendLastDate) { |
| + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); |
| + Calendar calendar = Calendar.getInstance(); |
| + calendar.set(year, month, day); |
| + if (extendLastDate) { |
| + calendar.set(Calendar.HOUR_OF_DAY, 23); |
| + calendar.set(Calendar.MINUTE, 59); |
| + calendar.set(Calendar.SECOND, 59); |
| + calendar.set(Calendar.MILLISECOND, 999); |
| + } |
| + return df.format(calendar.getTime()); |
| + } |
| + |
| + /** for testing legacy DateField support */ |
| + public void testLegacyDateRange() throws Exception { |
| + String startDate = getLocalizedDate(2002, 1, 1, false); |
| + String endDate = getLocalizedDate(2002, 1, 4, false); |
| + Calendar endDateExpected = Calendar.getInstance(); |
| + endDateExpected.set(2002, 1, 4, 23, 59, 59); |
| + endDateExpected.set(Calendar.MILLISECOND, 999); |
| + assertQueryEquals("[ " + startDate + " TO " + endDate + "]", null, "[" |
| + + getLegacyDate(startDate) + " TO " |
| + + DateField.dateToString(endDateExpected.getTime()) + "]"); |
| + assertQueryEquals("{ " + startDate + " " + endDate + " }", null, "{" |
| + + getLegacyDate(startDate) + " TO " + getLegacyDate(endDate) + "}"); |
| + } |
| + |
| + public void testDateRange() throws Exception { |
| + String startDate = getLocalizedDate(2002, 1, 1, false); |
| + String endDate = getLocalizedDate(2002, 1, 4, false); |
| + Calendar endDateExpected = Calendar.getInstance(); |
| + endDateExpected.set(2002, 1, 4, 23, 59, 59); |
| + endDateExpected.set(Calendar.MILLISECOND, 999); |
| + final String defaultField = "default"; |
| + final String monthField = "month"; |
| + final String hourField = "hour"; |
| + QueryParserWrapper qp = new QueryParserWrapper("field", |
| + new SimpleAnalyzer()); |
| + |
| + // Don't set any date resolution and verify if DateField is used |
| + assertDateRangeQueryEquals(qp, defaultField, startDate, endDate, |
| + endDateExpected.getTime(), null); |
| + |
| + // set a field specific date resolution |
| + qp.setDateResolution(monthField, DateTools.Resolution.MONTH); |
| + |
| + // DateField should still be used for defaultField |
| + assertDateRangeQueryEquals(qp, defaultField, startDate, endDate, |
| + endDateExpected.getTime(), null); |
| + |
| + // set default date resolution to MILLISECOND |
| + qp.setDateResolution(DateTools.Resolution.MILLISECOND); |
| + |
| + // set second field specific date resolution |
| + qp.setDateResolution(hourField, DateTools.Resolution.HOUR); |
| + |
| + // for this field no field specific date resolution has been set, |
| + // so verify if the default resolution is used |
| + assertDateRangeQueryEquals(qp, defaultField, startDate, endDate, |
| + endDateExpected.getTime(), DateTools.Resolution.MILLISECOND); |
| + |
| + // verify if field specific date resolutions are used for these two fields |
| + assertDateRangeQueryEquals(qp, monthField, startDate, endDate, |
| + endDateExpected.getTime(), DateTools.Resolution.MONTH); |
| + |
| + assertDateRangeQueryEquals(qp, hourField, startDate, endDate, |
| + endDateExpected.getTime(), DateTools.Resolution.HOUR); |
| + } |
| + |
| + public void assertDateRangeQueryEquals(QueryParserWrapper qp, String field, |
| + String startDate, String endDate, Date endDateInclusive, |
| + DateTools.Resolution resolution) throws Exception { |
| + assertQueryEquals(qp, field, field + ":[" + startDate + " TO " + endDate |
| + + "]", "[" + getDate(startDate, resolution) + " TO " |
| + + getDate(endDateInclusive, resolution) + "]"); |
| + assertQueryEquals(qp, field, field + ":{" + startDate + " TO " + endDate |
| + + "}", "{" + getDate(startDate, resolution) + " TO " |
| + + getDate(endDate, resolution) + "}"); |
| + } |
| + |
| + public void testEscaped() throws Exception { |
| + Analyzer a = new WhitespaceAnalyzer(); |
| + |
| + /* |
| + * assertQueryEquals("\\[brackets", a, "\\[brackets"); |
| + * assertQueryEquals("\\[brackets", null, "brackets"); |
| + * assertQueryEquals("\\\\", a, "\\\\"); assertQueryEquals("\\+blah", a, |
| + * "\\+blah"); assertQueryEquals("\\(blah", a, "\\(blah"); |
| + * |
| + * assertQueryEquals("\\-blah", a, "\\-blah"); assertQueryEquals("\\!blah", |
| + * a, "\\!blah"); assertQueryEquals("\\{blah", a, "\\{blah"); |
| + * assertQueryEquals("\\}blah", a, "\\}blah"); assertQueryEquals("\\:blah", |
| + * a, "\\:blah"); assertQueryEquals("\\^blah", a, "\\^blah"); |
| + * assertQueryEquals("\\[blah", a, "\\[blah"); assertQueryEquals("\\]blah", |
| + * a, "\\]blah"); assertQueryEquals("\\\"blah", a, "\\\"blah"); |
| + * assertQueryEquals("\\(blah", a, "\\(blah"); assertQueryEquals("\\)blah", |
| + * a, "\\)blah"); assertQueryEquals("\\~blah", a, "\\~blah"); |
| + * assertQueryEquals("\\*blah", a, "\\*blah"); assertQueryEquals("\\?blah", |
| + * a, "\\?blah"); //assertQueryEquals("foo \\&\\& bar", a, |
| + * "foo \\&\\& bar"); //assertQueryEquals("foo \\|| bar", a, |
| + * "foo \\|| bar"); //assertQueryEquals("foo \\AND bar", a, |
| + * "foo \\AND bar"); |
| + */ |
| + |
| + assertQueryEquals("\\a", a, "a"); |
| + |
| + assertQueryEquals("a\\-b:c", a, "a-b:c"); |
| + assertQueryEquals("a\\+b:c", a, "a+b:c"); |
| + assertQueryEquals("a\\:b:c", a, "a:b:c"); |
| + assertQueryEquals("a\\\\b:c", a, "a\\b:c"); |
| + |
| + assertQueryEquals("a:b\\-c", a, "a:b-c"); |
| + assertQueryEquals("a:b\\+c", a, "a:b+c"); |
| + assertQueryEquals("a:b\\:c", a, "a:b:c"); |
| + assertQueryEquals("a:b\\\\c", a, "a:b\\c"); |
| + |
| + assertQueryEquals("a:b\\-c*", a, "a:b-c*"); |
| + assertQueryEquals("a:b\\+c*", a, "a:b+c*"); |
| + assertQueryEquals("a:b\\:c*", a, "a:b:c*"); |
| + |
| + assertQueryEquals("a:b\\\\c*", a, "a:b\\c*"); |
| + |
| + assertQueryEquals("a:b\\-?c", a, "a:b-?c"); |
| + assertQueryEquals("a:b\\+?c", a, "a:b+?c"); |
| + assertQueryEquals("a:b\\:?c", a, "a:b:?c"); |
| + |
| + assertQueryEquals("a:b\\\\?c", a, "a:b\\?c"); |
| + |
| + assertQueryEquals("a:b\\-c~", a, "a:b-c~0.5"); |
| + assertQueryEquals("a:b\\+c~", a, "a:b+c~0.5"); |
| + assertQueryEquals("a:b\\:c~", a, "a:b:c~0.5"); |
| + assertQueryEquals("a:b\\\\c~", a, "a:b\\c~0.5"); |
| + |
| + // TODO: implement Range queries on QueryParser |
| + assertQueryEquals("[ a\\- TO a\\+ ]", null, "[a- TO a+]"); |
| + assertQueryEquals("[ a\\: TO a\\~ ]", null, "[a: TO a~]"); |
| + assertQueryEquals("[ a\\\\ TO a\\* ]", null, "[a\\ TO a*]"); |
| + |
| + assertQueryEquals( |
| + "[\"c\\:\\\\temp\\\\\\~foo0.txt\" TO \"c\\:\\\\temp\\\\\\~foo9.txt\"]", |
| + a, "[c:\\temp\\~foo0.txt TO c:\\temp\\~foo9.txt]"); |
| + |
| + assertQueryEquals("a\\\\\\+b", a, "a\\+b"); |
| + |
| + assertQueryEquals("a \\\"b c\\\" d", a, "a \"b c\" d"); |
| + assertQueryEquals("\"a \\\"b c\\\" d\"", a, "\"a \"b c\" d\""); |
| + assertQueryEquals("\"a \\+b c d\"", a, "\"a +b c d\""); |
| + |
| + assertQueryEquals("c\\:\\\\temp\\\\\\~foo.txt", a, "c:\\temp\\~foo.txt"); |
| + |
| + assertParseException("XY\\"); // there must be a character after the escape |
| + // char |
| + |
| + // test unicode escaping |
| + assertQueryEquals("a\\u0062c", a, "abc"); |
| + assertQueryEquals("XY\\u005a", a, "XYZ"); |
| + assertQueryEquals("XY\\u005A", a, "XYZ"); |
| + assertQueryEquals("\"a \\\\\\u0028\\u0062\\\" c\"", a, "\"a \\(b\" c\""); |
| + |
| + assertParseException("XY\\u005G"); // test non-hex character in escaped |
| + // unicode sequence |
| + assertParseException("XY\\u005"); // test incomplete escaped unicode |
| + // sequence |
| + |
| + // Tests bug LUCENE-800 |
| + assertQueryEquals("(item:\\\\ item:ABCD\\\\)", a, "item:\\ item:ABCD\\"); |
| + assertParseException("(item:\\\\ item:ABCD\\\\))"); // unmatched closing |
| + // paranthesis |
| + assertQueryEquals("\\*", a, "*"); |
| + assertQueryEquals("\\\\", a, "\\"); // escaped backslash |
| + |
| + assertParseException("\\"); // a backslash must always be escaped |
| + |
| + // LUCENE-1189 |
| + assertQueryEquals("(\"a\\\\\") or (\"b\")", a, "a\\ or b"); |
| + } |
| + |
| + public void testQueryStringEscaping() throws Exception { |
| + Analyzer a = new WhitespaceAnalyzer(); |
| + |
| + assertEscapedQueryEquals("a-b:c", a, "a\\-b\\:c"); |
| + assertEscapedQueryEquals("a+b:c", a, "a\\+b\\:c"); |
| + assertEscapedQueryEquals("a:b:c", a, "a\\:b\\:c"); |
| + assertEscapedQueryEquals("a\\b:c", a, "a\\\\b\\:c"); |
| + |
| + assertEscapedQueryEquals("a:b-c", a, "a\\:b\\-c"); |
| + assertEscapedQueryEquals("a:b+c", a, "a\\:b\\+c"); |
| + assertEscapedQueryEquals("a:b:c", a, "a\\:b\\:c"); |
| + assertEscapedQueryEquals("a:b\\c", a, "a\\:b\\\\c"); |
| + |
| + assertEscapedQueryEquals("a:b-c*", a, "a\\:b\\-c\\*"); |
| + assertEscapedQueryEquals("a:b+c*", a, "a\\:b\\+c\\*"); |
| + assertEscapedQueryEquals("a:b:c*", a, "a\\:b\\:c\\*"); |
| + |
| + assertEscapedQueryEquals("a:b\\\\c*", a, "a\\:b\\\\\\\\c\\*"); |
| + |
| + assertEscapedQueryEquals("a:b-?c", a, "a\\:b\\-\\?c"); |
| + assertEscapedQueryEquals("a:b+?c", a, "a\\:b\\+\\?c"); |
| + assertEscapedQueryEquals("a:b:?c", a, "a\\:b\\:\\?c"); |
| + |
| + assertEscapedQueryEquals("a:b?c", a, "a\\:b\\?c"); |
| + |
| + assertEscapedQueryEquals("a:b-c~", a, "a\\:b\\-c\\~"); |
| + assertEscapedQueryEquals("a:b+c~", a, "a\\:b\\+c\\~"); |
| + assertEscapedQueryEquals("a:b:c~", a, "a\\:b\\:c\\~"); |
| + assertEscapedQueryEquals("a:b\\c~", a, "a\\:b\\\\c\\~"); |
| + |
| + assertEscapedQueryEquals("[ a - TO a+ ]", null, "\\[ a \\- TO a\\+ \\]"); |
| + assertEscapedQueryEquals("[ a : TO a~ ]", null, "\\[ a \\: TO a\\~ \\]"); |
| + assertEscapedQueryEquals("[ a\\ TO a* ]", null, "\\[ a\\\\ TO a\\* \\]"); |
| + |
| + // LUCENE-881 |
| + assertEscapedQueryEquals("|| abc ||", a, "\\|\\| abc \\|\\|"); |
| + assertEscapedQueryEquals("&& abc &&", a, "\\&\\& abc \\&\\&"); |
| + } |
| + |
| + public void testTabNewlineCarriageReturn() throws Exception { |
| + assertQueryEqualsDOA("+weltbank +worlbank", null, "+weltbank +worlbank"); |
| + |
| + assertQueryEqualsDOA("+weltbank\n+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \n+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \n +worlbank", null, "+weltbank +worlbank"); |
| + |
| + assertQueryEqualsDOA("+weltbank\r+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \r+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \r +worlbank", null, "+weltbank +worlbank"); |
| + |
| + assertQueryEqualsDOA("+weltbank\r\n+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \r\n+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \r\n +worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \r \n +worlbank", null, |
| + "+weltbank +worlbank"); |
| + |
| + assertQueryEqualsDOA("+weltbank\t+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \t+worlbank", null, "+weltbank +worlbank"); |
| + assertQueryEqualsDOA("weltbank \t +worlbank", null, "+weltbank +worlbank"); |
| + } |
| + |
| + public void testSimpleDAO() throws Exception { |
| + assertQueryEqualsDOA("term term term", null, "+term +term +term"); |
| + assertQueryEqualsDOA("term +term term", null, "+term +term +term"); |
| + assertQueryEqualsDOA("term term +term", null, "+term +term +term"); |
| + assertQueryEqualsDOA("term +term +term", null, "+term +term +term"); |
| + assertQueryEqualsDOA("-term term term", null, "-term +term +term"); |
| + } |
| + |
| + public void testBoost() throws Exception { |
| + StandardAnalyzer oneStopAnalyzer = new StandardAnalyzer( |
| + new String[] { "on" }); |
| + QueryParserWrapper qp = new QueryParserWrapper("field", oneStopAnalyzer); |
| + Query q = qp.parse("on^1.0"); |
| + assertNotNull(q); |
| + q = qp.parse("\"hello\"^2.0"); |
| + assertNotNull(q); |
| + assertEquals(q.getBoost(), (float) 2.0, (float) 0.5); |
| + q = qp.parse("hello^2.0"); |
| + assertNotNull(q); |
| + assertEquals(q.getBoost(), (float) 2.0, (float) 0.5); |
| + q = qp.parse("\"on\"^1.0"); |
| + assertNotNull(q); |
| + |
| + QueryParserWrapper qp2 = new QueryParserWrapper("field", |
| + new StandardAnalyzer()); |
| + q = qp2.parse("the^3"); |
| + // "the" is a stop word so the result is an empty query: |
| + assertNotNull(q); |
| + assertEquals("", q.toString()); |
| + assertEquals(1.0f, q.getBoost(), 0.01f); |
| + } |
| + |
| + public void assertParseException(String queryString) throws Exception { |
| + try { |
| + getQuery(queryString, null); |
| + } catch (ParseException expected) { |
| + return; |
| + } |
| + fail("ParseException expected, not thrown"); |
| + } |
| + |
| + public void testException() throws Exception { |
| + assertParseException("\"some phrase"); |
| + assertParseException("(foo bar"); |
| + assertParseException("foo bar))"); |
| + assertParseException("field:term:with:colon some more terms"); |
| + assertParseException("(sub query)^5.0^2.0 plus more"); |
| + assertParseException("secret AND illegal) AND access:confidential"); |
| + } |
| + |
| + public void testCustomQueryParserWildcard() { |
| + try { |
| + new QPTestParser("contents", new WhitespaceAnalyzer()).parse("a?t"); |
| + fail("Wildcard queries should not be allowed"); |
| + } catch (ParseException expected) { |
| + // expected exception |
| + } |
| + } |
| + |
| + public void testCustomQueryParserFuzzy() throws Exception { |
| + try { |
| + new QPTestParser("contents", new WhitespaceAnalyzer()).parse("xunit~"); |
| + fail("Fuzzy queries should not be allowed"); |
| + } catch (ParseException expected) { |
| + // expected exception |
| + } |
| + } |
| + |
| + public void testBooleanQuery() throws Exception { |
| + BooleanQuery.setMaxClauseCount(2); |
| + try { |
| + QueryParserWrapper qp = new QueryParserWrapper("field", |
| + new WhitespaceAnalyzer()); |
| + qp.parse("one two three"); |
| + fail("ParseException expected due to too many boolean clauses"); |
| + } catch (ParseException expected) { |
| + // too many boolean clauses, so ParseException is expected |
| + } |
| + } |
| + |
| + /** |
| + * This test differs from TestPrecedenceQueryParser |
| + */ |
| + public void testPrecedence() throws Exception { |
| + QueryParserWrapper qp = new QueryParserWrapper("field", |
| + new WhitespaceAnalyzer()); |
| + Query query1 = qp.parse("A AND B OR C AND D"); |
| + Query query2 = qp.parse("+A +B +C +D"); |
| + |
| + assertEquals(query1, query2); |
| + } |
| + |
| + public void testLocalDateFormat() throws IOException, ParseException { |
| + |
| + RAMDirectory ramDir = new RAMDirectory(); |
| + IndexWriter iw = new IndexWriter(ramDir, new WhitespaceAnalyzer(), true, |
| + IndexWriter.MaxFieldLength.LIMITED); |
| + addDateDoc("a", 2005, 12, 2, 10, 15, 33, iw); |
| + addDateDoc("b", 2005, 12, 4, 22, 15, 00, iw); |
| + iw.close(); |
| + IndexSearcher is = new IndexSearcher(ramDir); |
| + assertHits(1, "[12/1/2005 TO 12/3/2005]", is); |
| + assertHits(2, "[12/1/2005 TO 12/4/2005]", is); |
| + assertHits(1, "[12/3/2005 TO 12/4/2005]", is); |
| + assertHits(1, "{12/1/2005 TO 12/3/2005}", is); |
| + assertHits(1, "{12/1/2005 TO 12/4/2005}", is); |
| + assertHits(0, "{12/3/2005 TO 12/4/2005}", is); |
| + is.close(); |
| + } |
| + |
| + public void testStarParsing() throws Exception { |
| + // final int[] type = new int[1]; |
| + // QueryParser qp = new QueryParserWrapper("field", new |
| + // WhitespaceAnalyzer()) { |
| + // protected Query getWildcardQuery(String field, String termStr) throws |
| + // ParseException { |
| + // // override error checking of superclass |
| + // type[0]=1; |
| + // return new TermQuery(new Term(field,termStr)); |
| + // } |
| + // protected Query getPrefixQuery(String field, String termStr) throws |
| + // ParseException { |
| + // // override error checking of superclass |
| + // type[0]=2; |
| + // return new TermQuery(new Term(field,termStr)); |
| + // } |
| + // |
| + // protected Query getFieldQuery(String field, String queryText) throws |
| + // ParseException { |
| + // type[0]=3; |
| + // return super.getFieldQuery(field, queryText); |
| + // } |
| + // }; |
| + // |
| + // TermQuery tq; |
| + // |
| + // tq = (TermQuery)qp.parse("foo:zoo*"); |
| + // assertEquals("zoo",tq.getTerm().text()); |
| + // assertEquals(2,type[0]); |
| + // |
| + // tq = (TermQuery)qp.parse("foo:zoo*^2"); |
| + // assertEquals("zoo",tq.getTerm().text()); |
| + // assertEquals(2,type[0]); |
| + // assertEquals(tq.getBoost(),2,0); |
| + // |
| + // tq = (TermQuery)qp.parse("foo:*"); |
| + // assertEquals("*",tq.getTerm().text()); |
| + // assertEquals(1,type[0]); // could be a valid prefix query in the future |
| + // too |
| + // |
| + // tq = (TermQuery)qp.parse("foo:*^2"); |
| + // assertEquals("*",tq.getTerm().text()); |
| + // assertEquals(1,type[0]); |
| + // assertEquals(tq.getBoost(),2,0); |
| + // |
| + // tq = (TermQuery)qp.parse("*:foo"); |
| + // assertEquals("*",tq.getTerm().field()); |
| + // assertEquals("foo",tq.getTerm().text()); |
| + // assertEquals(3,type[0]); |
| + // |
| + // tq = (TermQuery)qp.parse("*:*"); |
| + // assertEquals("*",tq.getTerm().field()); |
| + // assertEquals("*",tq.getTerm().text()); |
| + // assertEquals(1,type[0]); // could be handled as a prefix query in the |
| + // future |
| + // |
| + // tq = (TermQuery)qp.parse("(*:*)"); |
| + // assertEquals("*",tq.getTerm().field()); |
| + // assertEquals("*",tq.getTerm().text()); |
| + // assertEquals(1,type[0]); |
| + |
| + } |
| + |
| + public void testStopwords() throws Exception { |
| + QueryParserWrapper qp = new QueryParserWrapper("a", new StopAnalyzer( |
| + new String[] { "the", "foo" })); |
| + Query result = qp.parse("a:the OR a:foo"); |
| + assertNotNull("result is null and it shouldn't be", result); |
| + assertTrue("result is not a BooleanQuery", result instanceof BooleanQuery); |
| + assertTrue(((BooleanQuery) result).clauses().size() + " does not equal: " |
| + + 0, ((BooleanQuery) result).clauses().size() == 0); |
| + result = qp.parse("a:woo OR a:the"); |
| + assertNotNull("result is null and it shouldn't be", result); |
| + assertTrue("result is not a TermQuery", result instanceof TermQuery); |
| + result = qp |
| + .parse("(fieldX:xxxxx OR fieldy:xxxxxxxx)^2 AND (fieldx:the OR fieldy:foo)"); |
| + assertNotNull("result is null and it shouldn't be", result); |
| + assertTrue("result is not a BooleanQuery", result instanceof BooleanQuery); |
| + System.out.println("Result: " + result); |
| + assertTrue(((BooleanQuery) result).clauses().size() + " does not equal: " |
| + + 2, ((BooleanQuery) result).clauses().size() == 2); |
| + } |
| + |
| + public void testPositionIncrement() throws Exception { |
| + boolean dflt = StopFilter.getEnablePositionIncrementsDefault(); |
| + StopFilter.setEnablePositionIncrementsDefault(true); |
| + try { |
| + QueryParserWrapper qp = new QueryParserWrapper("a", new StopAnalyzer( |
| + new String[] { "the", "in", "are", "this" })); |
| + qp.setEnablePositionIncrements(true); |
| + String qtxt = "\"the words in poisitions pos02578 are stopped in this phrasequery\""; |
| + // 0 2 5 7 8 |
| + int expectedPositions[] = { 1, 3, 4, 6, 9 }; |
| + PhraseQuery pq = (PhraseQuery) qp.parse(qtxt); |
| + // System.out.println("Query text: "+qtxt); |
| + // System.out.println("Result: "+pq); |
| + Term t[] = pq.getTerms(); |
| + int pos[] = pq.getPositions(); |
| + for (int i = 0; i < t.length; i++) { |
| + // System.out.println(i+". "+t[i]+" pos: "+pos[i]); |
| + assertEquals("term " + i + " = " + t[i] + " has wrong term-position!", |
| + expectedPositions[i], pos[i]); |
| + } |
| + |
| + } finally { |
| + StopFilter.setEnablePositionIncrementsDefault(dflt); |
| + } |
| + } |
| + |
| + public void testMatchAllDocs() throws Exception { |
| + QueryParserWrapper qp = new QueryParserWrapper("field", |
| + new WhitespaceAnalyzer()); |
| + assertEquals(new MatchAllDocsQuery(), qp.parse("*:*")); |
| + assertEquals(new MatchAllDocsQuery(), qp.parse("(*:*)")); |
| + BooleanQuery bq = (BooleanQuery) qp.parse("+*:* -*:*"); |
| + assertTrue(bq.getClauses()[0].getQuery() instanceof MatchAllDocsQuery); |
| + assertTrue(bq.getClauses()[1].getQuery() instanceof MatchAllDocsQuery); |
| + } |
| + |
| + private void assertHits(int expected, String query, IndexSearcher is) |
| + throws ParseException, IOException { |
| + QueryParserWrapper qp = new QueryParserWrapper("date", |
| + new WhitespaceAnalyzer()); |
| + qp.setLocale(Locale.ENGLISH); |
| + Query q = qp.parse(query); |
| + ScoreDoc[] hits = is.search(q, null, 1000).scoreDocs; |
| + assertEquals(expected, hits.length); |
| + } |
| + |
| + private static void addDateDoc(String content, int year, int month, int day, |
| + int hour, int minute, int second, IndexWriter iw) throws IOException { |
| + Document d = new Document(); |
| + d.add(new Field("f", content, Field.Store.YES, Field.Index.ANALYZED)); |
| + Calendar cal = Calendar.getInstance(); |
| + cal.set(year, month - 1, day, hour, minute, second); |
| + d.add(new Field("date", DateField.dateToString(cal.getTime()), |
| + Field.Store.YES, Field.Index.NOT_ANALYZED)); |
| + iw.addDocument(d); |
| + } |
| + |
| + public void tearDown() throws Exception { |
| + super.tearDown(); |
| + BooleanQuery.setMaxClauseCount(originalMaxClauses); |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiAnalyzerQPHelper.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiAnalyzerQPHelper.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiAnalyzerQPHelper.java (revision 0) |
| @@ -0,0 +1,326 @@ |
| +package org.apache.lucene.queryParser.original; |
| + |
| +/** |
| + * 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 java.io.IOException; |
| +import java.io.Reader; |
| + |
| +import org.apache.lucene.analysis.Analyzer; |
| +import org.apache.lucene.analysis.LowerCaseFilter; |
| +import org.apache.lucene.analysis.Token; |
| +import org.apache.lucene.analysis.TokenFilter; |
| +import org.apache.lucene.analysis.TokenStream; |
| +import org.apache.lucene.analysis.standard.StandardTokenizer; |
| +import org.apache.lucene.analysis.tokenattributes.OffsetAttribute; |
| +import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute; |
| +import org.apache.lucene.analysis.tokenattributes.TermAttribute; |
| +import org.apache.lucene.analysis.tokenattributes.TypeAttribute; |
| +import org.apache.lucene.queryParser.QueryNodeException; |
| +import org.apache.lucene.queryParser.original.LuceneQueryParserHelper; |
| +import org.apache.lucene.queryParser.original.config.LuceneQueryConfigHandler.Operator; |
| +import org.apache.lucene.util.LuceneTestCase; |
| + |
| +/** |
| + * This test case is a copy of the core Lucene query parser test, it was adapted |
| + * to use new QueryParserHelper instead of the old query parser. |
| + * |
| + * Test QueryParser's ability to deal with Analyzers that return more than one |
| + * token per position or that return tokens with a position increment > 1. |
| + */ |
| +public class TestMultiAnalyzerQPHelper extends LuceneTestCase { |
| + |
| + private static int multiToken = 0; |
| + |
| + public void testMultiAnalyzer() throws QueryNodeException { |
| + |
| + LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + qp.getQueryConfigHandler().setAnalyzer(new MultiAnalyzer()); |
| + |
| + // trivial, no multiple tokens: |
| + assertEquals("foo", qp.parse("foo", "").toString()); |
| + assertEquals("foo", qp.parse("\"foo\"", "").toString()); |
| + assertEquals("foo foobar", qp.parse("foo foobar", "").toString()); |
| + assertEquals("\"foo foobar\"", qp.parse("\"foo foobar\"", "").toString()); |
| + assertEquals("\"foo foobar blah\"", qp.parse("\"foo foobar blah\"", "") |
| + .toString()); |
| + |
| + // two tokens at the same position: |
| + assertEquals("(multi multi2) foo", qp.parse("multi foo", "").toString()); |
| + assertEquals("foo (multi multi2)", qp.parse("foo multi", "").toString()); |
| + assertEquals("(multi multi2) (multi multi2)", qp.parse("multi multi", "") |
| + .toString()); |
| + assertEquals("+(foo (multi multi2)) +(bar (multi multi2))", qp.parse( |
| + "+(foo multi) +(bar multi)", "").toString()); |
| + assertEquals("+(foo (multi multi2)) field:\"bar (multi multi2)\"", qp |
| + .parse("+(foo multi) field:\"bar multi\"", "").toString()); |
| + |
| + // phrases: |
| + assertEquals("\"(multi multi2) foo\"", qp.parse("\"multi foo\"", "") |
| + .toString()); |
| + assertEquals("\"foo (multi multi2)\"", qp.parse("\"foo multi\"", "") |
| + .toString()); |
| + assertEquals("\"foo (multi multi2) foobar (multi multi2)\"", qp.parse( |
| + "\"foo multi foobar multi\"", "").toString()); |
| + |
| + // fields: |
| + assertEquals("(field:multi field:multi2) field:foo", qp.parse( |
| + "field:multi field:foo", "").toString()); |
| + assertEquals("field:\"(multi multi2) foo\"", qp.parse( |
| + "field:\"multi foo\"", "").toString()); |
| + |
| + // three tokens at one position: |
| + assertEquals("triplemulti multi3 multi2", qp.parse("triplemulti", "") |
| + .toString()); |
| + assertEquals("foo (triplemulti multi3 multi2) foobar", qp.parse( |
| + "foo triplemulti foobar", "").toString()); |
| + |
| + // phrase with non-default slop: |
| + assertEquals("\"(multi multi2) foo\"~10", qp.parse("\"multi foo\"~10", "") |
| + .toString()); |
| + |
| + // phrase with non-default boost: |
| + assertEquals("\"(multi multi2) foo\"^2.0", qp.parse("\"multi foo\"^2", "") |
| + .toString()); |
| + |
| + // phrase after changing default slop |
| + qp.getQueryConfigHandler().setDefaultPhraseSlop(99); |
| + assertEquals("\"(multi multi2) foo\"~99 bar", qp.parse("\"multi foo\" bar", |
| + "").toString()); |
| + assertEquals("\"(multi multi2) foo\"~99 \"foo bar\"~2", qp.parse( |
| + "\"multi foo\" \"foo bar\"~2", "").toString()); |
| + qp.getQueryConfigHandler().setDefaultPhraseSlop(0); |
| + |
| + // non-default operator: |
| + qp.getQueryConfigHandler().setDefaultOperator(Operator.AND); |
| + assertEquals("+(multi multi2) +foo", qp.parse("multi foo", "").toString()); |
| + |
| + } |
| + |
| + // public void testMultiAnalyzerWithSubclassOfQueryParser() throws |
| + // ParseException { |
| + // this test doesn't make sense when using the new QueryParser API |
| + // DumbQueryParser qp = new DumbQueryParser("", new MultiAnalyzer()); |
| + // qp.setPhraseSlop(99); // modified default slop |
| + // |
| + // // direct call to (super's) getFieldQuery to demonstrate differnce |
| + // // between phrase and multiphrase with modified default slop |
| + // assertEquals("\"foo bar\"~99", |
| + // qp.getSuperFieldQuery("","foo bar").toString()); |
| + // assertEquals("\"(multi multi2) bar\"~99", |
| + // qp.getSuperFieldQuery("","multi bar").toString()); |
| + // |
| + // |
| + // // ask sublcass to parse phrase with modified default slop |
| + // assertEquals("\"(multi multi2) foo\"~99 bar", |
| + // qp.parse("\"multi foo\" bar").toString()); |
| + // |
| + // } |
| + |
| + public void testPosIncrementAnalyzer() throws QueryNodeException { |
| + LuceneQueryParserHelper qp = new LuceneQueryParserHelper(); |
| + qp.getQueryConfigHandler().setAnalyzer(new PosIncrementAnalyzer()); |
| + |
| + assertEquals("quick brown", qp.parse("the quick brown", "").toString()); |
| + assertEquals("\"quick brown\"", qp.parse("\"the quick brown\"", "") |
| + .toString()); |
| + assertEquals("quick brown fox", qp.parse("the quick brown fox", "") |
| + .toString()); |
| + assertEquals("\"quick brown fox\"", qp.parse("\"the quick brown fox\"", "") |
| + .toString()); |
| + } |
| + |
| + /** |
| + * Expands "multi" to "multi" and "multi2", both at the same position, and |
| + * expands "triplemulti" to "triplemulti", "multi3", and "multi2". |
| + */ |
| + private class MultiAnalyzer extends Analyzer { |
| + |
| + public MultiAnalyzer() { |
| + } |
| + |
| + public TokenStream tokenStream(String fieldName, Reader reader) { |
| + TokenStream result = new StandardTokenizer(reader); |
| + result = new TestFilter(result); |
| + result = new LowerCaseFilter(result); |
| + return result; |
| + } |
| + } |
| + |
| + private final class TestFilter extends TokenFilter { |
| + |
| + private String prevType; |
| + private int prevStartOffset; |
| + private int prevEndOffset; |
| + |
| + TermAttribute termAtt; |
| + PositionIncrementAttribute posIncrAtt; |
| + OffsetAttribute offsetAtt; |
| + TypeAttribute typeAtt; |
| + |
| + public TestFilter(TokenStream in) { |
| + super(in); |
| + termAtt = (TermAttribute) addAttribute(TermAttribute.class); |
| + posIncrAtt = (PositionIncrementAttribute) addAttribute(PositionIncrementAttribute.class); |
| + offsetAtt = (OffsetAttribute) addAttribute(OffsetAttribute.class); |
| + typeAtt = (TypeAttribute) addAttribute(TypeAttribute.class); |
| + |
| + } |
| + |
| + /* |
| + * (non-Javadoc) |
| + * |
| + * @see |
| + * org.apache.lucene.analysis.TokenStream#next(org.apache.lucene.analysis |
| + * .Token) |
| + */ |
| + @Override |
| + public Token next(Token reusableToken) throws IOException { |
| + |
| + if (multiToken > 0) { |
| + reusableToken.setTermBuffer("multi" + (multiToken + 1)); |
| + reusableToken.setStartOffset(prevStartOffset); |
| + reusableToken.setEndOffset(prevEndOffset); |
| + reusableToken.setType(prevType); |
| + reusableToken.setPositionIncrement(0); |
| + multiToken--; |
| + return reusableToken; |
| + } else { |
| + boolean next = (reusableToken = input.next(token)) != null; |
| + if (next == false) { |
| + return null; |
| + } |
| + prevType = reusableToken.type(); |
| + prevStartOffset = reusableToken.startOffset(); |
| + prevEndOffset = reusableToken.endOffset(); |
| + String text = reusableToken.term(); |
| + if (text.equals("triplemulti")) { |
| + multiToken = 2; |
| + return reusableToken; |
| + } else if (text.equals("multi")) { |
| + multiToken = 1; |
| + return reusableToken; |
| + } else { |
| + return reusableToken; |
| + } |
| + } |
| + |
| + } |
| + |
| + private Token token = new Token(); |
| + |
| + public final boolean incrementToken() throws java.io.IOException { |
| + if (multiToken > 0) { |
| + termAtt.setTermBuffer("multi" + (multiToken + 1)); |
| + offsetAtt.setOffset(prevStartOffset, prevEndOffset); |
| + typeAtt.setType(prevType); |
| + posIncrAtt.setPositionIncrement(0); |
| + multiToken--; |
| + return true; |
| + } else { |
| + boolean next = input.incrementToken(); |
| + if (next == false) { |
| + return false; |
| + } |
| + prevType = typeAtt.type(); |
| + prevStartOffset = offsetAtt.startOffset(); |
| + prevEndOffset = offsetAtt.endOffset(); |
| + String text = termAtt.term(); |
| + if (text.equals("triplemulti")) { |
| + multiToken = 2; |
| + return true; |
| + } else if (text.equals("multi")) { |
| + multiToken = 1; |
| + return true; |
| + } else { |
| + return true; |
| + } |
| + } |
| + } |
| + |
| + } |
| + |
| + /** |
| + * Analyzes "the quick brown" as: quick(incr=2) brown(incr=1). Does not work |
| + * correctly for input other than "the quick brown ...". |
| + */ |
| + private class PosIncrementAnalyzer extends Analyzer { |
| + |
| + public PosIncrementAnalyzer() { |
| + } |
| + |
| + public TokenStream tokenStream(String fieldName, Reader reader) { |
| + TokenStream result = new StandardTokenizer(reader); |
| + result = new TestPosIncrementFilter(result); |
| + result = new LowerCaseFilter(result); |
| + return result; |
| + } |
| + } |
| + |
| + private class TestPosIncrementFilter extends TokenFilter { |
| + |
| + TermAttribute termAtt; |
| + PositionIncrementAttribute posIncrAtt; |
| + |
| + public TestPosIncrementFilter(TokenStream in) { |
| + super(in); |
| + termAtt = (TermAttribute) addAttribute(TermAttribute.class); |
| + posIncrAtt = (PositionIncrementAttribute) addAttribute(PositionIncrementAttribute.class); |
| + } |
| + |
| + private Token token = new Token(); |
| + |
| + /* |
| + * (non-Javadoc) |
| + * |
| + * @see org.apache.lucene.analysis.TokenStream#next() |
| + */ |
| + @Override |
| + public Token next(Token reusableToken) throws IOException { |
| + while (null != (reusableToken = input.next(token))) { |
| + String term = reusableToken.term(); |
| + if (term.equals("the")) { |
| + // stopword, do nothing |
| + } else if (term.equals("quick")) { |
| + reusableToken.setPositionIncrement(2); |
| + return reusableToken; |
| + } else { |
| + reusableToken.setPositionIncrement(1); |
| + return reusableToken; |
| + } |
| + } |
| + return null; |
| + } |
| + |
| + public final boolean incrementToken() throws java.io.IOException { |
| + while (input.incrementToken()) { |
| + if (termAtt.term().equals("the")) { |
| + // stopword, do nothing |
| + } else if (termAtt.term().equals("quick")) { |
| + posIncrAtt.setPositionIncrement(2); |
| + return true; |
| + } else { |
| + posIncrAtt.setPositionIncrement(1); |
| + return true; |
| + } |
| + } |
| + return false; |
| + } |
| + |
| + } |
| + |
| +} |
| Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiFieldQueryParserWrapper.java |
| =================================================================== |
| --- contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiFieldQueryParserWrapper.java (revision 0) |
| +++ contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiFieldQueryParserWrapper.java (revision 0) |
| @@ -0,0 +1,366 @@ |
| +package org.apache.lucene.queryParser.original; |
| + |
| +/** |
| + * 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 java.io.Reader; |
| +import java.util.HashMap; |
| +import java.util.Map; |
| + |
| +import org.apache.lucene.analysis.Analyzer; |
| +import org.apache.lucene.analysis.Token; |
| +import org.apache.lucene.analysis.TokenStream; |
| +import org.apache.lucene.analysis.standard.StandardAnalyzer; |
| +import org.apache.lucene.document.Document; |
| +import org.apache.lucene.document.Field; |
| +import org.apache.lucene.index.IndexWriter; |
| +import org.apache.lucene.queryParser.ParseException; |
| +import org.apache.lucene.queryParser.original.MultiFieldQueryParserWrapper; |
| +import org.apache.lucene.queryParser.original.QueryParserWrapper; |
| +import org.apache.lucene.search.BooleanClause; |
| +import org.apache.lucene.search.IndexSearcher; |
| +import org.apache.lucene.search.Query; |
| +import org.apache.lucene.search.ScoreDoc; |
| +import org.apache.lucene.search.BooleanClause.Occur; |
| +import org.apache.lucene.store.Directory; |
| +import org.apache.lucene.store.RAMDirectory; |
| +import org.apache.lucene.util.LuceneTestCase; |
| + |
| +/** |
| + * Tests QueryParser. |
| + */ |
| +public class TestMultiFieldQueryParserWrapper extends LuceneTestCase { |
| + |
| + /** |
| + * test stop words arsing for both the non static form, and for the |
| + * corresponding static form (qtxt, fields[]). |
| + */ |
| + public void tesStopwordsParsing() throws Exception { |
| + assertStopQueryEquals("one", "b:one t:one"); |
| + assertStopQueryEquals("one stop", "b:one t:one"); |
| + assertStopQueryEquals("one (stop)", "b:one t:one"); |
| + assertStopQueryEquals("one ((stop))", "b:one t:one"); |
| + assertStopQueryEquals("stop", ""); |
| + assertStopQueryEquals("(stop)", ""); |
| + assertStopQueryEquals("((stop))", ""); |
| + } |
| + |
| + // verify parsing of query using a stopping analyzer |
| + private void assertStopQueryEquals(String qtxt, String expectedRes) |
| + throws Exception { |
| + String[] fields = { "b", "t" }; |
| + Occur occur[] = { Occur.SHOULD, Occur.SHOULD }; |
| + TestQueryParser.QPTestAnalyzer a = new TestQueryParser.QPTestAnalyzer(); |
| + MultiFieldQueryParserWrapper mfqp = new MultiFieldQueryParserWrapper( |
| + fields, a); |
| + |
| + Query q = mfqp.parse(qtxt); |
| + assertEquals(expectedRes, q.toString()); |
| + |
| + q = MultiFieldQueryParserWrapper.parse(qtxt, fields, occur, a); |
| + assertEquals(expectedRes, q.toString()); |
| + } |
| + |
| + public void testSimple() throws Exception { |
| + String[] fields = { "b", "t" }; |
| + MultiFieldQueryParserWrapper mfqp = new MultiFieldQueryParserWrapper( |
| + fields, new StandardAnalyzer()); |
| + |
| + Query q = mfqp.parse("one"); |
| + assertEquals("b:one t:one", q.toString()); |
| + |
| + q = mfqp.parse("one two"); |
| + assertEquals("(b:one t:one) (b:two t:two)", q.toString()); |
| + |
| + q = mfqp.parse("+one +two"); |
| + assertEquals("+(b:one t:one) +(b:two t:two)", q.toString()); |
| + |
| + q = mfqp.parse("+one -two -three"); |
| + assertEquals("+(b:one t:one) -(b:two t:two) -(b:three t:three)", q |
| + .toString()); |
| + |
| + q = mfqp.parse("one^2 two"); |
| + assertEquals("((b:one t:one)^2.0) (b:two t:two)", q.toString()); |
| + |
| + q = mfqp.parse("one~ two"); |
| + assertEquals("(b:one~0.5 t:one~0.5) (b:two t:two)", q.toString()); |
| + |
| + q = mfqp.parse("one~0.8 two^2"); |
| + assertEquals("(b:one~0.8 t:one~0.8) ((b:two t:two)^2.0)", q.toString()); |
| + |
| + q = mfqp.parse("one* two*"); |
| + assertEquals("(b:one* t:one*) (b:two* t:two*)", q.toString()); |
| + |
| + q = mfqp.parse("[a TO c] two"); |
| + assertEquals("(b:[a TO c] t:[a TO c]) (b:two t:two)", q.toString()); |
| + |
| + q = mfqp.parse("w?ldcard"); |
| + assertEquals("b:w?ldcard t:w?ldcard", q.toString()); |
| + |
| + q = mfqp.parse("\"foo bar\""); |
| + assertEquals("b:\"foo bar\" t:\"foo bar\"", q.toString()); |
| + |
| + q = mfqp.parse("\"aa bb cc\" \"dd ee\""); |
| + assertEquals("(b:\"aa bb cc\" t:\"aa bb cc\") (b:\"dd ee\" t:\"dd ee\")", q |
| + .toString()); |
| + |
| + q = mfqp.parse("\"foo bar\"~4"); |
| + assertEquals("b:\"foo bar\"~4 t:\"foo bar\"~4", q.toString()); |
| + |
| + // LUCENE-1213: MultiFieldQueryParserWrapper was ignoring slop when phrase |
| + // had a field. |
| + q = mfqp.parse("b:\"foo bar\"~4"); |
| + assertEquals("b:\"foo bar\"~4", q.toString()); |
| + |
| + // make sure that terms which have a field are not touched: |
| + q = mfqp.parse("one f:two"); |
| + assertEquals("(b:one t:one) f:two", q.toString()); |
| + |
| + // AND mode: |
| + mfqp.setDefaultOperator(QueryParserWrapper.AND_OPERATOR); |
| + q = mfqp.parse("one two"); |
| + assertEquals("+(b:one t:one) +(b:two t:two)", q.toString()); |
| + q = mfqp.parse("\"aa bb cc\" \"dd ee\""); |
| + assertEquals("+(b:\"aa bb cc\" t:\"aa bb cc\") +(b:\"dd ee\" t:\"dd ee\")", |
| + q.toString()); |
| + |
| + } |
| + |
| + public void testBoostsSimple() throws Exception { |
| + Map boosts = new HashMap(); |
| + boosts.put("b", new Float(5)); |
| + boosts.put("t", new Float(10)); |
| + String[] fields = { "b", "t" }; |
| + MultiFieldQueryParserWrapper mfqp = new MultiFieldQueryParserWrapper( |
| + fields, new StandardAnalyzer(), boosts); |
| + |
| + // Check for simple |
| + Query q = mfqp.parse("one"); |
| + assertEquals("b:one^5.0 t:one^10.0", q.toString()); |
| + |
| + // Check for AND |
| + q = mfqp.parse("one AND two"); |
| + assertEquals("+(b:one^5.0 t:one^10.0) +(b:two^5.0 t:two^10.0)", q |
| + .toString()); |
| + |
| + // Check for OR |
| + q = mfqp.parse("one OR two"); |
| + assertEquals("(b:one^5.0 t:one^10.0) (b:two^5.0 t:two^10.0)", q.toString()); |
| + |
| + // Check for AND and a field |
| + q = mfqp.parse("one AND two AND foo:test"); |
| + assertEquals("+(b:one^5.0 t:one^10.0) +(b:two^5.0 t:two^10.0) +foo:test", q |
| + .toString()); |
| + |
| + q = mfqp.parse("one^3 AND two^4"); |
| + assertEquals("+((b:one^5.0 t:one^10.0)^3.0) +((b:two^5.0 t:two^10.0)^4.0)", |
| + q.toString()); |
| + } |
| + |
| + public void testStaticMethod1() throws ParseException { |
| + String[] fields = { "b", "t" }; |
| + String[] queries = { "one", "two" }; |
| + Query q = MultiFieldQueryParserWrapper.parse(queries, fields, |
| + new StandardAnalyzer()); |
| + assertEquals("b:one t:two", q.toString()); |
| + |
| + String[] queries2 = { "+one", "+two" }; |
| + q = MultiFieldQueryParserWrapper.parse(queries2, fields, |
| + new StandardAnalyzer()); |
| + assertEquals("(+b:one) (+t:two)", q.toString()); |
| + |
| + String[] queries3 = { "one", "+two" }; |
| + q = MultiFieldQueryParserWrapper.parse(queries3, fields, |
| + new StandardAnalyzer()); |
| + assertEquals("b:one (+t:two)", q.toString()); |
| + |
| + String[] queries4 = { "one +more", "+two" }; |
| + q = MultiFieldQueryParserWrapper.parse(queries4, fields, |
| + new StandardAnalyzer()); |
| + assertEquals("(b:one +b:more) (+t:two)", q.toString()); |
| + |
| + String[] queries5 = { "blah" }; |
| + try { |
| + q = MultiFieldQueryParserWrapper.parse(queries5, fields, |
| + new StandardAnalyzer()); |
| + fail(); |
| + } catch (IllegalArgumentException e) { |
| + // expected exception, array length differs |
| + } |
| + |
| + // check also with stop words for this static form (qtxts[], fields[]). |
| + TestQueryParser.QPTestAnalyzer stopA = new TestQueryParser.QPTestAnalyzer(); |
| + |
| + String[] queries6 = { "((+stop))", "+((stop))" }; |
| + q = MultiFieldQueryParserWrapper.parse(queries6, fields, stopA); |
| + assertEquals("", q.toString()); |
| + |
| + String[] queries7 = { "one ((+stop)) +more", "+((stop)) +two" }; |
| + q = MultiFieldQueryParserWrapper.parse(queries7, fields, stopA); |
| + assertEquals("(b:one +b:more) (+t:two)", q.toString()); |
| + |
| + } |
| + |
| + public void testStaticMethod2() throws ParseException { |
| + String[] fields = { "b", "t" }; |
| + BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST, |
| + BooleanClause.Occur.MUST_NOT }; |
| + Query q = MultiFieldQueryParserWrapper.parse("one", fields, flags, |
| + new StandardAnalyzer()); |
| + assertEquals("+b:one -t:one", q.toString()); |
| + |
| + q = MultiFieldQueryParserWrapper.parse("one two", fields, flags, |
| + new StandardAnalyzer()); |
| + assertEquals("+(b:one b:two) -(t:one t:two)", q.toString()); |
| + |
| + try { |
| + BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST }; |
| + q = MultiFieldQueryParserWrapper.parse("blah", fields, flags2, |
| + new StandardAnalyzer()); |
| + fail(); |
| + } catch (IllegalArgumentException e) { |
| + // expected exception, array length differs |
| + } |
| + } |
| + |
| + public void testStaticMethod2Old() throws ParseException { |
| + String[] fields = { "b", "t" }; |
| + // int[] flags = {MultiFieldQueryParserWrapper.REQUIRED_FIELD, |
| + // MultiFieldQueryParserWrapper.PROHIBITED_FIELD}; |
| + BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST, |
| + BooleanClause.Occur.MUST_NOT }; |
| + MultiFieldQueryParserWrapper parser = new MultiFieldQueryParserWrapper( |
| + fields, new StandardAnalyzer()); |
| + |
| + Query q = MultiFieldQueryParserWrapper.parse("one", fields, flags, |
| + new StandardAnalyzer());// , fields, flags, new StandardAnalyzer()); |
| + assertEquals("+b:one -t:one", q.toString()); |
| + |
| + q = MultiFieldQueryParserWrapper.parse("one two", fields, flags, |
| + new StandardAnalyzer()); |
| + assertEquals("+(b:one b:two) -(t:one t:two)", q.toString()); |
| + |
| + try { |
| + BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST }; |
| + q = MultiFieldQueryParserWrapper.parse("blah", fields, flags2, |
| + new StandardAnalyzer()); |
| + fail(); |
| + } catch (IllegalArgumentException e) { |
| + // expected exception, array length differs |
| + } |
| + } |
| + |
| + public void testStaticMethod3() throws ParseException { |
| + String[] queries = { "one", "two", "three" }; |
| + String[] fields = { "f1", "f2", "f3" }; |
| + BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST, |
| + BooleanClause.Occur.MUST_NOT, BooleanClause.Occur.SHOULD }; |
| + Query q = MultiFieldQueryParserWrapper.parse(queries, fields, flags, |
| + new StandardAnalyzer()); |
| + assertEquals("+f1:one -f2:two f3:three", q.toString()); |
| + |
| + try { |
| + BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST }; |
| + q = MultiFieldQueryParserWrapper.parse(queries, fields, flags2, |
| + new StandardAnalyzer()); |
| + fail(); |
| + } catch (IllegalArgumentException e) { |
| + // expected exception, array length differs |
| + } |
| + } |
| + |
| + public void testStaticMethod3Old() throws ParseException { |
| + String[] queries = { "one", "two" }; |
| + String[] fields = { "b", "t" }; |
| + BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST, |
| + BooleanClause.Occur.MUST_NOT }; |
| + Query q = MultiFieldQueryParserWrapper.parse(queries, fields, flags, |
| + new StandardAnalyzer()); |
| + assertEquals("+b:one -t:two", q.toString()); |
| + |
| + try { |
| + BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST }; |
| + q = MultiFieldQueryParserWrapper.parse(queries, fields, flags2, |
| + new StandardAnalyzer()); |
| + fail(); |
| + } catch (IllegalArgumentException e) { |
| + // expected exception, array length differs |
| + } |
| + } |
| + |
| + public void testAnalyzerReturningNull() throws ParseException { |
| + String[] fields = new String[] { "f1", "f2", "f3" }; |
| + MultiFieldQueryParserWrapper parser = new MultiFieldQueryParserWrapper( |
| + fields, new AnalyzerReturningNull()); |
| + Query q = parser.parse("bla AND blo"); |
| + assertEquals("+(f2:bla f3:bla) +(f2:blo f3:blo)", q.toString()); |
| + // the following queries are not affected as their terms are not analyzed |
| + // anyway: |
| + q = parser.parse("bla*"); |
| + assertEquals("f1:bla* f2:bla* f3:bla*", q.toString()); |
| + q = parser.parse("bla~"); |
| + assertEquals("f1:bla~0.5 f2:bla~0.5 f3:bla~0.5", q.toString()); |
| + q = parser.parse("[a TO c]"); |
| + assertEquals("f1:[a TO c] f2:[a TO c] f3:[a TO c]", q.toString()); |
| + } |
| + |
| + public void testStopWordSearching() throws Exception { |
| + Analyzer analyzer = new StandardAnalyzer(); |
| + Directory ramDir = new RAMDirectory(); |
| + IndexWriter iw = new IndexWriter(ramDir, analyzer, true, |
| + IndexWriter.MaxFieldLength.LIMITED); |
| + Document doc = new Document(); |
| + doc.add(new Field("body", "blah the footest blah", Field.Store.NO, |
| + Field.Index.ANALYZED)); |
| + iw.addDocument(doc); |
| + iw.close(); |
| + |
| + MultiFieldQueryParserWrapper mfqp = new MultiFieldQueryParserWrapper( |
| + new String[] { "body" }, analyzer); |
| + mfqp.setDefaultOperator(QueryParserWrapper.Operator.AND); |
| + Query q = mfqp.parse("the footest"); |
| + IndexSearcher is = new IndexSearcher(ramDir); |
| + ScoreDoc[] hits = is.search(q, null, 1000).scoreDocs; |
| + assertEquals(1, hits.length); |
| + is.close(); |
| + } |
| + |
| + /** |
| + * Return empty tokens for field "f1". |
| + */ |
| + private static class AnalyzerReturningNull extends Analyzer { |
| + StandardAnalyzer stdAnalyzer = new StandardAnalyzer(); |
| + |
| + public AnalyzerReturningNull() { |
| + } |
| + |
| + public TokenStream tokenStream(String fieldName, Reader reader) { |
| + if ("f1".equals(fieldName)) { |
| + return new EmptyTokenStream(); |
| + } else { |
| + return stdAnalyzer.tokenStream(fieldName, reader); |
| + } |
| + } |
| + |
| + private static class EmptyTokenStream extends TokenStream { |
| + public Token next(final Token reusableToken) { |
| + return null; |
| + } |
| + } |
| + } |
| + |
| +} |