blob: bba3cf15de9937825babca06f8edb74f14bd3c76 [file] [log] [blame]
Index: src/java/org/apache/lucene/queryParser/QueryParser.jj
===================================================================
--- src/java/org/apache/lucene/queryParser/QueryParser.jj (revision 793146)
+++ 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/Token.java
===================================================================
--- src/java/org/apache/lucene/queryParser/Token.java (revision 793146)
+++ 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
+ *
*/
public class Token {
Index: src/java/org/apache/lucene/queryParser/TokenMgrError.java
===================================================================
--- src/java/org/apache/lucene/queryParser/TokenMgrError.java (revision 793146)
+++ 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
+ *
+ */
public class TokenMgrError extends Error
{
Index: src/java/org/apache/lucene/queryParser/package.html
===================================================================
--- src/java/org/apache/lucene/queryParser/package.html (revision 793146)
+++ 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.&nbsp; These clutter the documentation.&nbsp;
Index: src/java/org/apache/lucene/queryParser/ParseException.java
===================================================================
--- src/java/org/apache/lucene/queryParser/ParseException.java (revision 793146)
+++ 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
+ *
*/
public class ParseException extends Exception {
Index: src/java/org/apache/lucene/queryParser/QueryParserConstants.java
===================================================================
--- src/java/org/apache/lucene/queryParser/QueryParserConstants.java (revision 793146)
+++ 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
+ *
*/
public interface QueryParserConstants {
Index: src/java/org/apache/lucene/queryParser/QueryParser.java
===================================================================
--- src/java/org/apache/lucene/queryParser/QueryParser.java (revision 793146)
+++ 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 use new the flexible query parser instead
+ *
*/
public class QueryParser implements QueryParserConstants {
Index: src/java/org/apache/lucene/queryParser/QueryParserTokenManager.java
===================================================================
--- src/java/org/apache/lucene/queryParser/QueryParserTokenManager.java (revision 793146)
+++ 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/CharStream.java
===================================================================
--- src/java/org/apache/lucene/queryParser/CharStream.java (revision 793146)
+++ src/java/org/apache/lucene/queryParser/CharStream.java (working copy)
@@ -15,6 +15,12 @@
* 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 use new the flexible query parser instead
+ *
*/
public interface CharStream {
Index: src/java/org/apache/lucene/queryParser/ComplexPhraseQueryParser.java
===================================================================
--- src/java/org/apache/lucene/queryParser/ComplexPhraseQueryParser.java (revision 793146)
+++ src/java/org/apache/lucene/queryParser/ComplexPhraseQueryParser.java (working copy)
@@ -54,6 +54,10 @@
* 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 {
Index: src/java/org/apache/lucene/queryParser/FastCharStream.java
===================================================================
--- src/java/org/apache/lucene/queryParser/FastCharStream.java (revision 793146)
+++ 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 use new the flexible query parser instead
+ *
+ * */
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 793146)
+++ src/java/org/apache/lucene/queryParser/MultiFieldQueryParser.java (working copy)
@@ -30,6 +30,10 @@
import org.apache.lucene.search.Query;
/**
+ * @deprecated use new the flexible query parser instead
+ */
+
+/**
* A QueryParser which constructs queries to search multiple fields.
*
*
Index: build.xml
===================================================================
--- build.xml (revision 793146)
+++ build.xml (working copy)
@@ -614,9 +614,10 @@
<attribute name="failonerror" default="true"/>
<sequential>
<subant target="@{target}" failonerror="@{failonerror}">
- <fileset dir="."
- includes="contrib/*/build.xml"
- />
+ <fileset dir="." >
+ <include name="contrib/*/build.xml"/>
+ <include name="contrib/*/build15.xml" if="build-1-5-contrib"/>
+ </fileset>
</subant>
</sequential>
</macrodef>
Index: contrib/queryparser/build15.xml
===================================================================
--- contrib/queryparser/build15.xml (revision 0)
+++ contrib/queryparser/build15.xml (revision 0)
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<project name="queryparser" default="default">
+
+ <description>
+ Flexible Query Parser
+ </description>
+
+ <property name="javac.source" value="1.5" />
+ <property name="javac.target" value="1.5" />
+
+ <import file="../contrib-build.xml"/>
+
+</project>
Index: contrib/queryparser/pom.xml.template
===================================================================
--- contrib/queryparser/pom.xml.template (revision 0)
+++ contrib/queryparser/pom.xml.template (revision 0)
@@ -0,0 +1,40 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <!--
+ 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.
+ -->
+
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.lucene</groupId>
+ <artifactId>lucene-contrib</artifactId>
+ <version>@version@</version>
+ </parent>
+ <groupId>org.apache.lucene</groupId>
+ <artifactId>lucene-queryparser</artifactId>
+ <name>Lucene Highlighter</name>
+ <version>@version@</version>
+ <description>
+ This is the Flexible Query Parser for apache lucene java
+ </description>
+ <packaging>jar</packaging>
+ <dependencies>
+ </dependencies>
+</project>
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);
+
+}
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,71 @@
+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;
+ }
+
+}
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,199 @@
+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;
+ }
+ });
+ }
+ }
+}
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,30 @@
+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();
+}
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,69 @@
+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;
+ }
+
+}
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,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 java.util.Locale;
+
+import org.apache.lucene.messages.Message;
+import org.apache.lucene.messages.MessageImpl;
+import org.apache.lucene.messages.NLSException;
+import org.apache.lucene.queryParser.messages.QueryParserMessages;
+
+
+/**
+ *
+ */
+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();
+ }
+
+}
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,106 @@
+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;
+
+/**
+ * TODO: document this class
+ */
+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;
+ }
+}
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,41 @@
+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;
+
+}
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,221 @@
+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;
+
+/**
+ * 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 interface and classes this class
+ * implements 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) {
+ // TODO: node should be converted to a readable query instead of
+ // just invoking node.toString()
+ throw new QueryNodeException(new MessageImpl(
+ QueryParserMessages.LUCENE_QUERY_CONVERSION_ERROR, node
+ .toString(), 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);
+
+ }
+
+}
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,36 @@
+<!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 <tt>QueryTreeBuilder</tt> walks the tree
+and call the Builder for each node in the tree.
+
+These builders expect that the query node tree was already processed by a processor pipeline.
+
+</p>
+<p>
+</p>
+</body>
+</html>
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,59 @@
+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;
+ }
+
+}
+
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,52 @@
+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
+ */
+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);
+
+}
+
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,47 @@
+<!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.
+
+See <tt>org.apache.lucene.queryParser.lucene2.config.LuceneQueryConfigHandler</tt> for a reference
+implementation
+
+FieldConfig and Queryconfig should use <tt>org.apache.lucene.util.Attribute</tt> to store all attributes
+required by the config implementation. See <tt>org.apache.lucene.queryParser.lucene2.config.*Attribute</tt>
+for reference implementation.
+
+The QueryConfigHandler, FieldConfig, and Attributes are used in the Processors to access config
+information in a flexible and independent way.
+See <tt>org.apache.lucene.queryParser.lucene2.processors.ParametricRangeQueryNodeProcessor</tt> for a
+reference implementation.
+
+</p>
+<p>
+
+</p>
+</body>
+</html
+
Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/MultiFieldQueryParserWrapper.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/MultiFieldQueryParserWrapper.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/MultiFieldQueryParserWrapper.java (revision 0)
@@ -0,0 +1,249 @@
+package org.apache.lucene.queryParser.lucene2;
+
+/**
+ * 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.lucene2.config.LuceneMultiFieldQueryConfigHandler;
+import org.apache.lucene.queryParser.lucene2.processors.MultiFieldQueryNodeProcessor;
+import org.apache.lucene.queryParser.processors.QueryNodeProcessorPipeline;
+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 {
+ protected String[] fields;
+
+ protected Map boosts;
+
+ /**
+ * 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);
+ this.boosts = boosts;
+ this.fields = fields;
+
+ setQueryConfig(new LuceneMultiFieldQueryConfigHandler(fields, 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);
+
+ this.fields = fields;
+ LuceneMultiFieldQueryConfigHandler config = new LuceneMultiFieldQueryConfigHandler(fields, null);
+ config.setAnalyzer(analyzer);
+ setQueryConfig(config);
+
+ QueryNodeProcessorPipeline newProcessorPipeline = new QueryNodeProcessorPipeline();
+ newProcessorPipeline.addProcessor(new MultiFieldQueryNodeProcessor());
+ newProcessorPipeline.addProcessor(getQueryProcessor());
+
+ setQueryProcessor(newProcessorPipeline);
+
+ }
+
+ /**
+ * 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;
+ }
+
+}
+
Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/QueryParserWrapper.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/QueryParserWrapper.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/QueryParserWrapper.java (revision 0)
@@ -0,0 +1,422 @@
+package org.apache.lucene.queryParser.lucene2;
+
+/**
+ * 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.lucene2.builders.LuceneQueryBuilder;
+import org.apache.lucene.queryParser.lucene2.builders.LuceneQueryTreeBuilder;
+import org.apache.lucene.queryParser.lucene2.config.AllowLeadingWildcardAttribute;
+import org.apache.lucene.queryParser.lucene2.config.AnalyzerAttribute;
+import org.apache.lucene.queryParser.lucene2.config.ConstantScoreRewriteAttribute;
+import org.apache.lucene.queryParser.lucene2.config.DateResolutionAttribute;
+import org.apache.lucene.queryParser.lucene2.config.DefaultOperatorAttribute;
+import org.apache.lucene.queryParser.lucene2.config.DefaultPhraseSlopAttribute;
+import org.apache.lucene.queryParser.lucene2.config.LocaleAttribute;
+import org.apache.lucene.queryParser.lucene2.config.LowercaseExpandedTermsAttribute;
+import org.apache.lucene.queryParser.lucene2.config.LuceneQueryConfigHandler;
+import org.apache.lucene.queryParser.lucene2.config.PositionIncrementsAttribute;
+import org.apache.lucene.queryParser.lucene2.config.RangeCollatorAttribute;
+import org.apache.lucene.queryParser.lucene2.processors.LuceneQueryNodeProcessorPipeline;
+import org.apache.lucene.queryParser.nodes.QueryNode;
+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.lucene2.parser.QueryParser luceneQueryParser = new org.apache.lucene.queryParser.lucene2.parser.QueryParser();
+
+ 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.lucene2.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 {@link QueryNodeProcessor} used to process the query
+ * node tree generated by the {@link org.apache.lucene.queryParser.lucene2.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.setAndAsDefaultOperator(OR_OPERATOR.equals(op) ? false : true);
+ }
+
+ public Operator getDefaultOperator() {
+
+ if (this.config != null && this.config.hasAttribute(DefaultOperatorAttribute.class)) {
+ return (((DefaultOperatorAttribute) this.config.getAttribute(DefaultOperatorAttribute.class)).isDefaultAND()) ?
+ AND_OPERATOR : OR_OPERATOR;
+ }
+
+ return OR_OPERATOR;
+
+ }
+
+ public void setEnablePositionIncrements(boolean enable) {
+ this.config.setPositionIncrementsEnabled(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();
+ }
+
+}
+
Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/AnyQueryNodeBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/AnyQueryNodeBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/AnyQueryNodeBuilder.java (revision 0)
@@ -0,0 +1,78 @@
+package org.apache.lucene.queryParser.lucene2.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
+ }
+
+ /* (non-Javadoc)
+ * @see com.ibm.ilel.query.builders.lucene.LuceneQueryBuilder#build(com.ibm.ilel.query.nodes.QueryNode)
+ */
+ 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/lucene2/builders/BooleanQueryNodeBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/BooleanQueryNodeBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/BooleanQueryNodeBuilder.java (revision 0)
@@ -0,0 +1,107 @@
+package org.apache.lucene.queryParser.lucene2.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.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) {
+
+ // TODO: create a good message for this exception
+ throw new QueryNodeException(new MessageImpl(
+ QueryParserMessages.EMPTY_MESSAGE), 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;
+
+ // TODO: what should be the best way to get the default modifier
+ case MOD_NONE:
+ return BooleanClause.Occur.SHOULD;
+
+ }
+
+ }
+
+ return BooleanClause.Occur.SHOULD;
+
+ }
+
+}
Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/BoostQueryNodeBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/BoostQueryNodeBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/BoostQueryNodeBuilder.java (revision 0)
@@ -0,0 +1,52 @@
+package org.apache.lucene.queryParser.lucene2.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/lucene2/builders/FieldQueryNodeBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/FieldQueryNodeBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/FieldQueryNodeBuilder.java (revision 0)
@@ -0,0 +1,43 @@
+package org.apache.lucene.queryParser.lucene2.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/lucene2/builders/FuzzyQueryNodeBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/FuzzyQueryNodeBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/FuzzyQueryNodeBuilder.java (revision 0)
@@ -0,0 +1,45 @@
+package org.apache.lucene.queryParser.lucene2.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;
+
+ // TODO: the prefix length should be extracted from the FuzzyQueryNode instead of using the default one
+ return new FuzzyQuery(new Term(fuzzyNode.getFieldAsString(), fuzzyNode.getTextAsString()),
+ fuzzyNode.getSimilarity(), FuzzyQuery.defaultPrefixLength);
+
+ }
+
+}
Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/GroupQueryNodeBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/GroupQueryNodeBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/GroupQueryNodeBuilder.java (revision 0)
@@ -0,0 +1,45 @@
+package org.apache.lucene.queryParser.lucene2.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/lucene2/builders/LuceneBooleanQueryNodeBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/LuceneBooleanQueryNodeBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/LuceneBooleanQueryNodeBuilder.java (revision 0)
@@ -0,0 +1,108 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.nodes.LuceneBooleanQueryNode;
+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.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) {
+
+ // TODO: create a good message for this exception
+ throw new QueryNodeException(new MessageImpl(
+ QueryParserMessages.EMPTY_MESSAGE), 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/lucene2/builders/LuceneQueryBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/LuceneQueryBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/LuceneQueryBuilder.java (revision 0)
@@ -0,0 +1,38 @@
+package org.apache.lucene.queryParser.lucene2.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 a {@link QueryNode} object.
+ * <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/lucene2/builders/LuceneQueryTreeBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/LuceneQueryTreeBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/LuceneQueryTreeBuilder.java (revision 0)
@@ -0,0 +1,75 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.nodes.LuceneBooleanQueryNode;
+import org.apache.lucene.queryParser.lucene2.nodes.MultiPhraseQueryNode;
+import org.apache.lucene.queryParser.lucene2.nodes.RangeQueryNode;
+import org.apache.lucene.queryParser.lucene2.processors.LuceneQueryNodeProcessorPipeline;
+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.search.Query;
+
+
+/**
+ * This query tree builder only defines the necessary map to build a {@link Query} object.
+ * It should be used to generate a {@link Query} 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/lucene2/builders/MatchAllDocsQueryNodeBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/MatchAllDocsQueryNodeBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/MatchAllDocsQueryNodeBuilder.java (revision 0)
@@ -0,0 +1,50 @@
+package org.apache.lucene.queryParser.lucene2.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.nodes.MatchAllDocsQueryNode;
+import org.apache.lucene.queryParser.nodes.QueryNode;
+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)) {
+
+ // TODO: node should be converted to a readable query instead of just invoking node.toString()
+ throw new QueryNodeException(new MessageImpl("Q0019E.LUCENE_QUERY_CONVERSION_ERROR", queryNode.toString(), queryNode.getClass().getName()));
+
+ }
+
+ return new MatchAllDocsQuery();
+
+ }
+
+}
Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/MatchNoDocsQueryNodeBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/MatchNoDocsQueryNodeBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/MatchNoDocsQueryNodeBuilder.java (revision 0)
@@ -0,0 +1,50 @@
+package org.apache.lucene.queryParser.lucene2.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.nodes.MatchNoDocsQueryNode;
+import org.apache.lucene.queryParser.nodes.QueryNode;
+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)) {
+
+ // TODO: node should be converted to a readable query instead of just invoking node.toString()
+ throw new QueryNodeException(new MessageImpl("Q0019E.LUCENE_QUERY_CONVERSION_ERROR", queryNode.toString(), queryNode.getClass().getName()));
+
+ }
+
+ return new BooleanQuery();
+
+ }
+
+}
Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/ModifierQueryNodeBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/ModifierQueryNodeBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/ModifierQueryNodeBuilder.java (revision 0)
@@ -0,0 +1,45 @@
+package org.apache.lucene.queryParser.lucene2.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/lucene2/builders/MultiPhraseQueryNodeBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/MultiPhraseQueryNodeBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/MultiPhraseQueryNodeBuilder.java (revision 0)
@@ -0,0 +1,81 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.nodes.MultiPhraseQueryNode;
+import org.apache.lucene.queryParser.nodes.FieldQueryNode;
+import org.apache.lucene.queryParser.nodes.QueryNode;
+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/lucene2/builders/PhraseQueryNodeBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/PhraseQueryNodeBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/PhraseQueryNodeBuilder.java (revision 0)
@@ -0,0 +1,64 @@
+package org.apache.lucene.queryParser.lucene2.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/lucene2/builders/PrefixWildcardQueryNodeBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/PrefixWildcardQueryNodeBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/PrefixWildcardQueryNodeBuilder.java (revision 0)
@@ -0,0 +1,43 @@
+package org.apache.lucene.queryParser.lucene2.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/lucene2/builders/RangeQueryNodeBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/RangeQueryNodeBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/RangeQueryNodeBuilder.java (revision 0)
@@ -0,0 +1,61 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.nodes.RangeQueryNode;
+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.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/lucene2/builders/SlopQueryNodeBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/SlopQueryNodeBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/SlopQueryNodeBuilder.java (revision 0)
@@ -0,0 +1,56 @@
+package org.apache.lucene.queryParser.lucene2.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/lucene2/builders/WildcardQueryNodeBuilder.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/WildcardQueryNodeBuilder.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/WildcardQueryNodeBuilder.java (revision 0)
@@ -0,0 +1,43 @@
+package org.apache.lucene.queryParser.lucene2.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/lucene2/builders/package.html
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/builders/package.html (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/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>Lucene 2 Query Node Builders</h2>
+<p>
+The package org.apache.lucene.queryParser.lucene2.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 LuceneQueryNodeProcessorPipeline.
+</p>
+<p>
+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/lucene2/config/AllowLeadingWildcardAttribute.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/AllowLeadingWildcardAttribute.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/AllowLeadingWildcardAttribute.java (revision 0)
@@ -0,0 +1,78 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.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.lucene2.QueryParserWrapper#setAllowLeadingWildcard(boolean)
+ */
+public class AllowLeadingWildcardAttribute extends Attribute {
+
+ private static final long serialVersionUID = -2804763012723049527L;
+
+ private boolean allowLeadingWildcard = true;
+
+ public AllowLeadingWildcardAttribute() {
+ // empty constructor
+ }
+
+ 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/lucene2/config/AnalyzerAttribute.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/AnalyzerAttribute.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/AnalyzerAttribute.java (revision 0)
@@ -0,0 +1,85 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.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.lucene2.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/lucene2/config/BoostAttribute.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/BoostAttribute.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/BoostAttribute.java (revision 0)
@@ -0,0 +1,79 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.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.lucene2.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/lucene2/config/ConstantScoreRewriteAttribute.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/ConstantScoreRewriteAttribute.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/ConstantScoreRewriteAttribute.java (revision 0)
@@ -0,0 +1,79 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.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.lucene2.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/lucene2/config/DateResolutionAttribute.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/DateResolutionAttribute.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/DateResolutionAttribute.java (revision 0)
@@ -0,0 +1,87 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.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.lucene2.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/lucene2/config/DefaultOperatorAttribute.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/DefaultOperatorAttribute.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/DefaultOperatorAttribute.java (revision 0)
@@ -0,0 +1,85 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.QueryParserWrapper;
+import org.apache.lucene.queryParser.lucene2.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 boolean usingAND = false;
+
+ public DefaultOperatorAttribute() {
+ // empty constructor
+ }
+
+ public void setDefaultAND(boolean bool) {
+ this.usingAND = bool;
+ }
+
+ public boolean isDefaultAND() {
+ return this.usingAND;
+ }
+
+ 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.isDefaultAND() == this.isDefaultAND()) {
+ return true;
+
+ }
+
+ }
+
+ return false;
+
+ }
+
+ public int hashCode() {
+ return Boolean.valueOf(this.isDefaultAND()).hashCode();
+ }
+
+ public String toString() {
+ return "<defaultOperatorAttribute defaultOperator=" + this.isDefaultAND() + "/>";
+ }
+
+}
+
Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/DefaultPhraseSlopAttribute.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/DefaultPhraseSlopAttribute.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/DefaultPhraseSlopAttribute.java (revision 0)
@@ -0,0 +1,79 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.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.lucene2.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/lucene2/config/LocaleAttribute.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/LocaleAttribute.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/LocaleAttribute.java (revision 0)
@@ -0,0 +1,86 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.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.lucene2.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/lucene2/config/LowercaseExpandedTermsAttribute.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/LowercaseExpandedTermsAttribute.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/LowercaseExpandedTermsAttribute.java (revision 0)
@@ -0,0 +1,81 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.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.lucene2.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/lucene2/config/LuceneMultiFieldQueryConfigHandler.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/LuceneMultiFieldQueryConfigHandler.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/LuceneMultiFieldQueryConfigHandler.java (revision 0)
@@ -0,0 +1,60 @@
+package org.apache.lucene.queryParser.lucene2.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.Map;
+
+import org.apache.lucene.queryParser.config.FieldConfig;
+
+
+/**
+ * This configuration handler holds every configuration supported by {@link LuceneQueryConfigHandler}
+ * plus a field boost mapping and the list of fields that should be used to expand each term.
+ * <br/>
+ * @see org.apache.lucene.queryParser.lucene2.MultiFieldQueryParserWrapper
+ */
+public class LuceneMultiFieldQueryConfigHandler extends LuceneQueryConfigHandler {
+
+ private Map<CharSequence, Float> boosts;
+
+ public LuceneMultiFieldQueryConfigHandler(CharSequence[] fields, Map<CharSequence, Float> boosts) {
+ MultiFieldAttribute multiFieldAttr = (MultiFieldAttribute) addAttribute(MultiFieldAttribute.class);
+ multiFieldAttr.setFields(fields);
+
+ this.boosts = boosts;
+
+ }
+
+ public FieldConfig getFieldConfig(CharSequence fieldName) {
+ FieldConfig fc = super.getFieldConfig(fieldName);
+
+ if (this.boosts != null) {
+ BoostAttribute boostAttr = (BoostAttribute) fc.addAttribute(BoostAttribute.class);
+ Float boost = this.boosts.get(fieldName);
+
+ if (boost != null) {
+ boostAttr.setBoost(boost.floatValue());
+ }
+
+ }
+
+ return fc;
+
+ }
+
+}
Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/LuceneQueryConfigHandler.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/LuceneQueryConfigHandler.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/LuceneQueryConfigHandler.java (revision 0)
@@ -0,0 +1,260 @@
+package org.apache.lucene.queryParser.lucene2.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 org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.document.DateTools;
+import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.queryParser.config.FieldConfig;
+import org.apache.lucene.queryParser.config.QueryConfigHandler;
+import org.apache.lucene.queryParser.lucene2.nodes.RangeQueryNode;
+import org.apache.lucene.queryParser.lucene2.processors.LuceneQueryNodeProcessorPipeline;
+import org.apache.lucene.queryParser.nodes.PrefixWildcardQueryNode;
+import org.apache.lucene.queryParser.nodes.WildcardQueryNode;
+
+
+/**
+ * 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.lucene2.QueryParserWrapper
+ */
+public class LuceneQueryConfigHandler extends QueryConfigHandler {
+
+ 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 HashMap<CharSequence, DateTools.Resolution> dateResolutions;
+
+ public LuceneQueryConfigHandler() {
+ // 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.defaultOperatorAttribute.setDefaultAND(false);
+
+ this.analyzerAttr = ((AnalyzerAttribute) addAttribute(AnalyzerAttribute.class));
+ this.analyzerAttr.setAnalyzer(null);
+
+ 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);
+
+ }
+
+ public FieldConfig getFieldConfig(CharSequence fieldName) {
+ // TODO: cache a field config when it's constructed for the first time,
+ // consecutive calls could return the cached object
+
+ if (fieldName != null) {
+ FieldConfig fieldConfig = new FieldConfig(fieldName);
+
+ DateResolutionAttribute dateResolutionAttr = (DateResolutionAttribute) fieldConfig.addAttribute(DateResolutionAttribute.class);
+ DateTools.Resolution dateRes = null;
+
+ if (this.dateResolutions != null) {
+ dateRes = this.dateResolutions.get(fieldName.toString());
+ }
+
+ if (dateRes == null) {
+ dateRes = this.defaultDateResolution;
+ }
+
+ dateResolutionAttr.setDateResolution(dateRes);
+
+ return fieldConfig;
+
+ }
+
+ return null;
+
+ }
+
+ /**
+ * 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 RangeQuerys
+ */
+ public void setRangeCollator(Collator collator) {
+ this.rangeCollatorAttribute.setDateResolution(collator);
+ }
+
+ public void setAndAsDefaultOperator(boolean defaultAnd) {
+ this.defaultOperatorAttribute.setDefaultAND(defaultAnd);
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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 setPositionIncrementsEnabled(boolean enabled) {
+ this.positionIncrementsAttribute.setPositionIncrementsEnabled(enabled);
+ }
+
+ /**
+ * By default QueryParser uses constant-score rewriting
+ * when creating a {@link PrefixWildcardQueryNode}, {@link WildcardQueryNode} or {@link RangeQueryNode}. This implementation is generally preferable because it
+ * a) Runs faster b) Does not have the scarcity of terms unduly influence score
+ * c) avoids any "TooManyBooleanClauses" exception.
+ * However, if your application really needs to use the
+ * old-fashioned BooleanQuery 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);
+ }
+
+ /**
+ * Sets the default date resolution used by RangeQueries 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 locale used by date range parsing.
+ */
+ public void setLocale(Locale locale) {
+ this.localeAttribute.setLocale(locale);
+ }
+
+ /**
+ * 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} 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);
+ }
+
+ }
+}
Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/MultiFieldAttribute.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/MultiFieldAttribute.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/MultiFieldAttribute.java (revision 0)
@@ -0,0 +1,82 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.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.lucene2.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/lucene2/config/PositionIncrementsAttribute.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/PositionIncrementsAttribute.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/PositionIncrementsAttribute.java (revision 0)
@@ -0,0 +1,79 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.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.lucene2.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/lucene2/config/RangeCollatorAttribute.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/RangeCollatorAttribute.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/RangeCollatorAttribute.java (revision 0)
@@ -0,0 +1,89 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.processors.ParametricRangeQueryNodeProcessor;
+import org.apache.lucene.search.RangeQuery;
+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 RangeQuery}
+ * <br/>
+ * @see org.apache.lucene.queryParser.lucene2.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/lucene2/config/package.html
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/config/package.html (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/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>Lucene 2 Query Configuration</h2>
+<p>
+The package org.apache.lucene.queryParser.lucene2.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/lucene2/nodes/BooleanModifierNode.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/nodes/BooleanModifierNode.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/nodes/BooleanModifierNode.java (revision 0)
@@ -0,0 +1,39 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.processors.GroupQueryNodeProcessor;
+import org.apache.lucene.queryParser.nodes.ModifierQueryNode;
+import org.apache.lucene.queryParser.nodes.QueryNode;
+
+/**
+ * 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/lucene2/nodes/LuceneBooleanQueryNode.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/nodes/LuceneBooleanQueryNode.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/nodes/LuceneBooleanQueryNode.java (revision 0)
@@ -0,0 +1,56 @@
+package org.apache.lucene.queryParser.lucene2.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/lucene2/nodes/MultiPhraseQueryNode.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/nodes/MultiPhraseQueryNode.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/nodes/MultiPhraseQueryNode.java (revision 0)
@@ -0,0 +1,109 @@
+package org.apache.lucene.queryParser.lucene2.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/lucene2/nodes/RangeQueryNode.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/nodes/RangeQueryNode.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/nodes/RangeQueryNode.java (revision 0)
@@ -0,0 +1,78 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.QueryParserWrapper#setConstantScoreRewrite(boolean)
+ * @see org.apache.lucene.queryParser.lucene2.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/lucene2/nodes/package.html
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/nodes/package.html (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/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>Lucene 2 Query Nodes</h2>
+<p>
+The package org.apache.lucene.queryParser.lucene2.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/lucene2/package.html
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/package.html (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/package.html (revision 0)
@@ -0,0 +1,44 @@
+<!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.lucene2
+are used to reproduce the same behaviour as the old 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>
Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/EscapeQuerySyntaxImpl.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/EscapeQuerySyntaxImpl.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/EscapeQuerySyntaxImpl.java (revision 0)
@@ -0,0 +1,283 @@
+package org.apache.lucene.queryParser.lucene2.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/lucene2/parser/JavaCharStream.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/JavaCharStream.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/JavaCharStream.java (revision 0)
@@ -0,0 +1,634 @@
+/* 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.lucene2.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/lucene2/parser/ParseException.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/ParseException.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/ParseException.java (revision 0)
@@ -0,0 +1,200 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 4.1 */
+/* JavaCCOptions:KEEP_LINE_COL=null */
+package org.apache.lucene.queryParser.lucene2.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/lucene2/parser/QueryParser.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/QueryParser.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/QueryParser.java (revision 0)
@@ -0,0 +1,950 @@
+/* Generated By:JavaCC: Do not edit this line. QueryParser.java */
+package org.apache.lucene.queryParser.lucene2.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 QueryParser 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 QueryParser() {
+ 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 QueryParser(java.io.InputStream stream) {
+ this(stream, null);
+ }
+ /** Constructor with InputStream and supplied encoding */
+ public QueryParser(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 QueryParser(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 QueryParser(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/lucene2/parser/QueryParser.jj
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/QueryParser.jj (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/QueryParser.jj (revision 0)
@@ -0,0 +1,484 @@
+/**
+ * Original file is based on the QueryParser.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(QueryParser)
+package org.apache.lucene.queryParser.lucene2.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 QueryParser 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 QueryParser() {
+ this(new StringReader(""));
+ }
+ /** Parses a query string, returning a {@link com.ibm.es.nuvo.search.query.tree.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(QueryParser)
+
+/* ***************** */
+/* 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;
+ }
+}\ No newline at end of file
Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/QueryParserConstants.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/QueryParserConstants.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/QueryParserConstants.java (revision 0)
@@ -0,0 +1,141 @@
+/* Generated By:JavaCC: Do not edit this line. QueryParserConstants.java */
+package org.apache.lucene.queryParser.lucene2.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/lucene2/parser/QueryParserTokenManager.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/QueryParserTokenManager.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/QueryParserTokenManager.java (revision 0)
@@ -0,0 +1,1249 @@
+/* Generated By:JavaCC: Do not edit this line. QueryParserTokenManager.java */
+package org.apache.lucene.queryParser.lucene2.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/lucene2/parser/Token.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/Token.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/Token.java (revision 0)
@@ -0,0 +1,148 @@
+/* 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.lucene2.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/lucene2/parser/TokenMgrError.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/TokenMgrError.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/TokenMgrError.java (revision 0)
@@ -0,0 +1,164 @@
+/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 4.1 */
+/* JavaCCOptions: */
+package org.apache.lucene.queryParser.lucene2.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/lucene2/parser/package.html
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/parser/package.html (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/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.lucene2.parser contains the query parser.
+</p>
+<p>
+This new query parser only performs the syntax validation and create an QueryNode tree
+from a string of text.
+</p>
+</body>
+</html>
Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/AllowLeadingWildcardProcessor.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/AllowLeadingWildcardProcessor.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/AllowLeadingWildcardProcessor.java (revision 0)
@@ -0,0 +1,98 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.QueryParserWrapper;
+import org.apache.lucene.queryParser.lucene2.config.AllowLeadingWildcardAttribute;
+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.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 '?' :
+ // TODO: create a message for this exception: "'*' not allowed as first character in PrefixQuery"
+ throw new QueryNodeException(new MessageImpl(QueryParserMessages.EMPTY_MESSAGE));
+
+ }
+
+ }
+
+ 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/lucene2/processors/AnalyzerQueryNodeProcessor.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/AnalyzerQueryNodeProcessor.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/AnalyzerQueryNodeProcessor.java (revision 0)
@@ -0,0 +1,393 @@
+package org.apache.lucene.queryParser.lucene2.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.queryParser.QueryNodeException;
+import org.apache.lucene.queryParser.config.QueryConfigHandler;
+import org.apache.lucene.queryParser.lucene2.config.AnalyzerAttribute;
+import org.apache.lucene.queryParser.lucene2.config.PositionIncrementsAttribute;
+import org.apache.lucene.queryParser.lucene2.nodes.LuceneBooleanQueryNode;
+import org.apache.lucene.queryParser.lucene2.nodes.MultiPhraseQueryNode;
+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.TokenizedPhraseQueryNode;
+import org.apache.lucene.queryParser.nodes.WildcardQueryNode;
+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
+ }
+
+ /* (non-Javadoc)
+ * @see com.ibm.ilel.query.processors.QueryNodeProcessorImpl#process(com.ibm.ilel.query.nodes.QueryNode)
+ */
+ 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;
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.ibm.ilel.query.processors.QueryNodeProcessorImpl#postProcessNode(com.ibm.ilel.query.nodes.QueryNode)
+ */
+ @Override
+ protected QueryNode postProcessNode(QueryNode node)
+ throws QueryNodeException {
+
+ // TODO: it should check if it's an instance of "TextableNode" interface instead of FieldQueryNode
+ if (node instanceof FieldQueryNode
+ && !(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);
+// }
+
+ org.apache.lucene.analysis.Token reusableToken = null;
+ org.apache.lucene.analysis.Token nextToken = null;
+
+ // TODO: use this block when Lucene releases the new TokenStream API
+ /*try {
+
+ while (buffer.incrementToken()) {
+ numTokens++;
+ int positionIncrement = (posIncrAtt != null) ? posIncrAtt.getPositionIncrement()
+ : 1;
+ if (positionIncrement != 0) {
+ positionCount += positionIncrement;
+
+ } else {
+ severalTokensAtSamePosition = true;
+ }
+
+ }
+
+ } catch (IOException e) {
+ // ignore
+ }*/
+
+ // TODO: this block should be removed when Lucene releases the new TokenStream API
+ reusableToken = new org.apache.lucene.analysis.Token();
+ while (true) {
+ try {
+ nextToken = buffer.next(reusableToken);
+ } catch (IOException e) {
+ nextToken = null;
+ }
+ if (nextToken == null)
+ break;
+ numTokens++;
+ if (nextToken.getPositionIncrement() != 0)
+ positionCount += nextToken.getPositionIncrement();
+ else
+ severalTokensAtSamePosition = true;
+ }
+
+ 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 {
+ //// TODO: use this block when Lucene releases the new TokenStream API
+ /*boolean hasNext;
+ hasNext = buffer.incrementToken();
+ assert hasNext == true;
+ term = termAtt.term();*/
+
+ // TODO: this block should be removed when Lucene releases the new TokenStream API
+ nextToken = buffer.next(reusableToken);
+ assert nextToken != null;
+ term = nextToken.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 {
+ // TODO: use this block when Lucene releases the new TokenStream API
+ /*boolean hasNext = buffer.incrementToken();
+ assert hasNext == true;
+ term = termAtt.term();*/
+
+ // TODO: this block should be removed when Lucene releases the new TokenStream API
+ nextToken = buffer.next(reusableToken);
+ assert nextToken != null;
+ term = nextToken.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 {
+ // TODO: use this block when Lucene releases the new TokenStream API
+ /*boolean hasNext = buffer.incrementToken();
+ assert hasNext == true;
+ term = termAtt.term();
+ if (posIncrAtt != null) {
+ positionIncrement = posIncrAtt.getPositionIncrement();
+ }*/
+
+ // TODO: this block should be removed when Lucene releases the new TokenStream API
+ nextToken = buffer.next(reusableToken);
+ assert nextToken != null;
+ term = nextToken.term();
+ positionIncrement = nextToken.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 {
+ // TODO: use this block when Lucene releases the new TokenStream API
+ /*boolean hasNext = buffer.incrementToken();
+ assert hasNext == true;
+ term = termAtt.term();
+
+ if (posIncrAtt != null) {
+ positionIncrement = posIncrAtt.getPositionIncrement();
+ }*/
+
+ // TODO: this block should be removed when Lucene releases the new TokenStream API
+ nextToken = buffer.next(reusableToken);
+ assert nextToken != null;
+ term = nextToken.term();
+ positionIncrement = nextToken.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;
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.ibm.ilel.query.processors.QueryNodeProcessorImpl#preProcessNode(com.ibm.ilel.query.nodes.QueryNode)
+ */
+ protected QueryNode preProcessNode(QueryNode node)
+ throws QueryNodeException {
+
+ return node;
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.ibm.ilel.query.processors.QueryNodeProcessorImpl#setChildrenOrder(java.util.List)
+ */
+ protected List<QueryNode> setChildrenOrder(List<QueryNode> children)
+ throws QueryNodeException {
+
+ return children;
+
+ }
+
+}
Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/BooleanSingleChildOptimizationQueryNodeProcessor.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/BooleanSingleChildOptimizationQueryNodeProcessor.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/BooleanSingleChildOptimizationQueryNodeProcessor.java (revision 0)
@@ -0,0 +1,90 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.nodes.BooleanModifierNode;
+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.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/lucene2/processors/DefaultPhraseSlopQueryNodeProcessor.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/DefaultPhraseSlopQueryNodeProcessor.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/DefaultPhraseSlopQueryNodeProcessor.java (revision 0)
@@ -0,0 +1,119 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.QueryParserWrapper;
+import org.apache.lucene.queryParser.lucene2.config.DefaultPhraseSlopAttribute;
+import org.apache.lucene.queryParser.lucene2.nodes.MultiPhraseQueryNode;
+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.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/lucene2/processors/GroupQueryNodeProcessor.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/GroupQueryNodeProcessor.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/GroupQueryNodeProcessor.java (revision 0)
@@ -0,0 +1,219 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.QueryParserWrapper;
+import org.apache.lucene.queryParser.lucene2.config.DefaultOperatorAttribute;
+import org.apache.lucene.queryParser.lucene2.nodes.BooleanModifierNode;
+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.processors.QueryNodeProcessor;
+
+
+/**
+ * The {@link org.apache.lucene.queryParser.lucene2.parser.QueryParser} 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 = ((DefaultOperatorAttribute) getQueryConfigHandler().getAttribute(DefaultOperatorAttribute.class)).isDefaultAND();
+
+ 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/lucene2/processors/LowercaseExpandedTermsQueryNodeProcessor.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/LowercaseExpandedTermsQueryNodeProcessor.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/LowercaseExpandedTermsQueryNodeProcessor.java (revision 0)
@@ -0,0 +1,94 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.QueryParserWrapper;
+import org.apache.lucene.queryParser.lucene2.config.LowercaseExpandedTermsAttribute;
+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.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/lucene2/processors/LuceneQueryNodeProcessorPipeline.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/LuceneQueryNodeProcessorPipeline.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/LuceneQueryNodeProcessorPipeline.java (revision 0)
@@ -0,0 +1,65 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.builders.LuceneQueryTreeBuilder;
+import org.apache.lucene.queryParser.lucene2.config.LuceneQueryConfigHandler;
+import org.apache.lucene.queryParser.lucene2.parser.QueryParser;
+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 QueryParser} 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 QueryParser
+ */
+public class LuceneQueryNodeProcessorPipeline extends QueryNodeProcessorPipeline {
+
+ public LuceneQueryNodeProcessorPipeline(QueryConfigHandler queryConfig) {
+ super(queryConfig);
+
+ 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());
+
+ }
+
+}
Index: contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/MatchAllDocsQueryNodeProcessor.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/MatchAllDocsQueryNodeProcessor.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/MatchAllDocsQueryNodeProcessor.java (revision 0)
@@ -0,0 +1,76 @@
+package org.apache.lucene.queryParser.lucene2.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/lucene2/processors/MultiFieldQueryNodeProcessor.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/MultiFieldQueryNodeProcessor.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/MultiFieldQueryNodeProcessor.java (revision 0)
@@ -0,0 +1,169 @@
+package org.apache.lucene.queryParser.lucene2.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.FieldConfig;
+import org.apache.lucene.queryParser.config.QueryConfigHandler;
+import org.apache.lucene.queryParser.lucene2.MultiFieldQueryParserWrapper;
+import org.apache.lucene.queryParser.lucene2.config.BoostAttribute;
+import org.apache.lucene.queryParser.lucene2.config.MultiFieldAttribute;
+import org.apache.lucene.queryParser.nodes.BooleanQueryNode;
+import org.apache.lucene.queryParser.nodes.BoostQueryNode;
+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.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/><br/>
+ * This processor also looks a {@link BoostAttribute} for each field in the {@link QueryConfigHandler}.
+ * If there is a {@link BoostAttribute} in a specific field, this boost is applied to the {@link FieldableNode}.
+ * <br/>
+ * @see BoostAttribute
+ * @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;
+
+ }
+
+ private QueryNode addBoost(FieldableNode node) throws QueryNodeException {
+ FieldConfig fieldConfig = getQueryConfigHandler().getFieldConfig(
+ node.getField());
+
+ if (fieldConfig != null) {
+
+ if (fieldConfig.hasAttribute(BoostAttribute.class)) {
+ float boost = ((BoostAttribute) fieldConfig.getAttribute(BoostAttribute.class)).getBoost();
+
+ return new BoostQueryNode(node, boost);
+
+ }
+
+ }
+
+ 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]);
+ QueryNode boostedNode = addBoost(fieldNode);
+
+ if (fields.length == 1) {
+ return boostedNode;
+
+ } else {
+ LinkedList<QueryNode> children = new LinkedList<QueryNode>();
+ children.add(boostedNode);
+
+ for (int i = 1; i < fields.length; i++) {
+ try {
+ fieldNode = (FieldableNode) fieldNode.cloneTree();
+ fieldNode.setField(fields[i]);
+ boostedNode = addBoost(fieldNode);
+
+ children.add(boostedNode);
+
+ } 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/lucene2/processors/ParametricRangeQueryNodeProcessor.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/ParametricRangeQueryNodeProcessor.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/ParametricRangeQueryNodeProcessor.java (revision 0)
@@ -0,0 +1,178 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.config.ConstantScoreRewriteAttribute;
+import org.apache.lucene.queryParser.lucene2.config.DateResolutionAttribute;
+import org.apache.lucene.queryParser.lucene2.config.LocaleAttribute;
+import org.apache.lucene.queryParser.lucene2.config.RangeCollatorAttribute;
+import org.apache.lucene.queryParser.lucene2.nodes.RangeQueryNode;
+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.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/lucene2/processors/PhraseSlopQueryNodeProcessor.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/PhraseSlopQueryNodeProcessor.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/PhraseSlopQueryNodeProcessor.java (revision 0)
@@ -0,0 +1,74 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.nodes.MultiPhraseQueryNode;
+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.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/lucene2/processors/PrefixWildcardQueryNodeProcessor.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/PrefixWildcardQueryNodeProcessor.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/PrefixWildcardQueryNodeProcessor.java (revision 0)
@@ -0,0 +1,74 @@
+package org.apache.lucene.queryParser.lucene2.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.lucene2.parser.QueryParser;
+import org.apache.lucene.queryParser.nodes.PrefixWildcardQueryNode;
+import org.apache.lucene.queryParser.nodes.QueryNode;
+import org.apache.lucene.queryParser.processors.QueryNodeProcessorImpl;
+import org.apache.lucene.search.PrefixQuery;
+
+
+/**
+ * The {@link QueryParser} 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/lucene2/processors/RemoveEmptyNonLeafQueryNodeProcessor.java
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/RemoveEmptyNonLeafQueryNodeProcessor.java (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/RemoveEmptyNonLeafQueryNodeProcessor.java (revision 0)
@@ -0,0 +1,113 @@
+package org.apache.lucene.queryParser.lucene2.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/lucene2/processors/package.html
===================================================================
--- contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/processors/package.html (revision 0)
+++ contrib/queryparser/src/java/org/apache/lucene/queryParser/lucene2/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 2 Query Node Processors</h2>
+<p>
+The package org.apache.lucene.queryParser.lucene2.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/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,51 @@
+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;
+
+}
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,39 @@
+# 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}
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, using <tt>org.apache.lucene.messages.NLS</tt> API.
+</body>
+</html>
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,75 @@
+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() + " )";
+ }
+
+}
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,144 @@
+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 + ")";
+ }
+ }
+
+}
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,85 @@
+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;
+ }
+
+}
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,119 @@
+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;
+ }
+
+}
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;
+
+ }
+
+}
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,177 @@
+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;
+
+ }
+
+}
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,44 @@
+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);
+
+}
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,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 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;
+
+ /**
+ * @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 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 FuzzyQueryNode cloneTree() throws CloneNotSupportedException {
+ FuzzyQueryNode clone=(FuzzyQueryNode)super.cloneTree();
+
+ clone.similarity = this.similarity;
+
+ return clone;
+ }
+
+ /**
+ * @return the similarity
+ */
+ public float getSimilarity() {
+ return this.similarity;
+ }
+}
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,86 @@
+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);
+ }
+
+}
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;
+ }
+}
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/>";
+ }
+
+}
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,152 @@
+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);
+ }
+
+}
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;
+ }
+}
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;
+ }
+
+}
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,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.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() + " )";
+ }
+}
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,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 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;
+ }
+}
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,113 @@
+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);
+ }
+
+ }
+
+ }
+
+ }
+
+}
+
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,210 @@
+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
+ * @return QueryText List size
+ */
+ 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
+ */
+ 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;
+ }
+
+}
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,114 @@
+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;
+
+/**
+ * @author Luis Alves
+ */
+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;
+ }
+
+ /* (non-Javadoc)
+ * @see com.ibm.ilel.query.nodes.FieldableNode#getField()
+ */
+ public CharSequence getField() {
+ QueryNode child = getChild();
+
+ if (child instanceof FieldableNode) {
+ return ((FieldableNode) child).getField();
+ }
+
+ return null;
+
+ }
+
+ /* (non-Javadoc)
+ * @see com.ibm.ilel.query.nodes.FieldableNode#setField(java.lang.CharSequence)
+ */
+ public void setField(CharSequence fieldName) {
+ QueryNode child = getChild();
+
+ if (child instanceof FieldableNode) {
+ ((FieldableNode) child).setField(fieldName);
+ }
+
+ }
+
+}
+
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,54 @@
+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;
+ }
+}
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,232 @@
+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 lucene2 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;
+ }
+
+}
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,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 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();
+
+}
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,216 @@
+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
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,60 @@
+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;
+ }
+
+}
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,113 @@
+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 QueryParser 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);
+ }
+
+ }
+
+}
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);
+
+}
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
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,60 @@
+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;
+ }
+}
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,76 @@
+<!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 QueryNodes.
+QueryNodes are serializable.
+These basic QueryNodes are used by the text parser to create a syntax tree.
+These nodes are designed to be used by UI or other parsers.
+A current reference implementation is <tt>org.apache.lucene.queryParser.lucene2.parser.QueryParser</tt>,
+this parser implements lucene 2.4 syntax.
+
+QueryNode interface is implement by all QueryNodes, the class QueryNodeImpl implements QueryNode and is extended
+by all QueryNode implementations.
+
+A QueryNode tree can be printed to the a stream, and it generates a seudo XML representation
+with all the nodes.
+
+A QueryNode tree can also generate a query String that can be parsed back by the original text parser,
+at this point only the lucene2 syntax is supported.
+
+Grouping nodes:
+AndQueryNode - used for AND operator
+AnyQueryNode - used for ANY operator
+OrQueryNode - used for OR operator
+BooleanQueryNode - used when no operator is specified
+ModifierQueryNode - used for modifier operator
+GroupQueryNode - used for parenthesis
+BoostQueryNode - used for Boost operator
+
+Final Nodes:
+FieldQueryNode - field/value node
+FuzzyQueryNode - fuzzy node
+MultiLevelFieldQueryNode - QueryNode object used with hierarchical multi-values
+OpaqueQueryNode - Used as for part of the query that can be parsed by other parsers. schema/value
+ParametricQueryNode - used for parametric field [>=|<=|=|<|>] value
+ParametricRangeQueryNode - used for parametric field:[low_value TO high_value]
+SlopQueryNode - phrase slop
+PrefixWildcardQueryNode - non-phrase wildcard query
+ProximityQueryNode - used for proximity search
+QuotedFieldQUeryNode - regular phrase node
+TokenizedPhraseQueryNode - used by tokenizers/lemmatizers/analizers for phrases/autophrases
+WildcardQueryNode - non-phrase wildcard query
+
+Final Utility Nodes:
+DeletedQueryNode - used by Processors on optimizations
+MatchAllDocsQueryNode - used by Processors on optimizations
+MatchNoDocsQueryNode - used by Processors on optimizations
+NoTokenFoundQueryNode - used by tokenizers/lemmatizers/analizers
+
+
+</p>
+<p>
+
+</p>
+</body>
+</html>
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,125 @@
+<!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>Lucene 2.4 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 parsing layer which simply transforms the
+query text string into a QueryNode tree. Currently our implementations of
+this layer use javacc.
+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.
+3. The third layer is also a configurable chain of builders, which
+transform the QueryNode tree into Lucene Query objects.
+</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.lucene2.
+<p>
+To make it simpler to use the new query parser, specially for people that does not
+want to extend it, the class QueryParser2 can be used. It uses the default Lucene
+query processors, text parser and builders, and you still have the option to
+set your own processor, text parser and builder.
+
+QueryParser2 usage:
+
+QueryParser2 qp2 = new QueryParser2();
+
+// it does not always return a LuceneQueryConfigHandler Object, but as we just created it, it will
+LuceneQueryConfigHandler config = (LuceneQueryConfigHandler) qp2.getQueryConfigHandler();
+
+config.setAllowLeadingWildcard(true);
+config.setAnalyzer(new WhitespaceAnalyzer());
+
+Query query = qp2.parse("defaultField", "apache AND lucene");
+
+
+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.lucene2
+that keeps the old query parser interface, but uses the new query parser features.
+</p>
+</p>
+</tt>
+</body>
+</html>
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,39 @@
+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);
+}
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,33 @@
+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;
+}
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>
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,89 @@
+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;
+
+
+/**
+ * A {@link NoChildOptimizationQueryNodeProcessor} removes every BooleanQueryNode,
+ * BoostQueryNode, TokenizedPhraseQueryNode or ModifierQueryNode that do not have
+ * a valid children
+ * Example: When the children of these nodes are removed for any reason then the
+ * nodes may become invalid.
+ */
+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;
+
+ }
+
+}
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,71 @@
+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;
+
+/**
+ * A {@link QueryNodeProcessor} is a interface for classes that process a
+ * query node tree.
+ *
+ * The implementor of this class should perform some operation on a query node tree
+ * and return the same or another query node tree.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ */
+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();
+
+}
+
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,149 @@
+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;
+
+
+/**
+ * @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;
+
+ }
+
+ 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;
+
+ }
+
+ public void setQueryConfigHandler(QueryConfigHandler queryConfigHandler) {
+ this.queryConfig = queryConfigHandler;
+ }
+
+ public QueryConfigHandler getQueryConfigHandler() {
+ return this.queryConfig;
+ }
+
+ abstract protected QueryNode preProcessNode(QueryNode node)
+ throws QueryNodeException;
+
+ abstract protected QueryNode postProcessNode(QueryNode node)
+ throws QueryNodeException;
+
+ 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;
+
+ }
+
+}
+
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,99 @@
+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;
+ }
+
+ public QueryConfigHandler getQueryConfigHandler() {
+ return this.queryConfig;
+ }
+
+ 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);
+
+ }
+
+ public void setQueryConfigHandler(QueryConfigHandler queryConfigHandler) {
+ this.queryConfig = queryConfigHandler;
+
+ for (QueryNodeProcessor processor : this.processors) {
+ processor.setQueryConfigHandler(this.queryConfig);
+ }
+
+ }
+
+}
+
+
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,113 @@
+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;
+
+ }
+
+}
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,93 @@
+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;
+
+ }
+
+}
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,136 @@
+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();
+ }
+}
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>
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,39 @@
+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;
+}
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.
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
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,68 @@
+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);
+ }
+}
Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/lucene2/TestMultiAnalyzer.java
===================================================================
--- contrib/queryparser/src/test/org/apache/lucene/queryParser/lucene2/TestMultiAnalyzer.java (revision 0)
+++ contrib/queryparser/src/test/org/apache/lucene/queryParser/lucene2/TestMultiAnalyzer.java (revision 0)
@@ -0,0 +1,352 @@
+package org.apache.lucene.queryParser.lucene2;
+
+/**
+ * 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.lucene2.builders.LuceneQueryTreeBuilder;
+import org.apache.lucene.queryParser.lucene2.config.LuceneQueryConfigHandler;
+import org.apache.lucene.queryParser.lucene2.parser.QueryParser;
+import org.apache.lucene.queryParser.lucene2.processors.LuceneQueryNodeProcessorPipeline;
+import org.apache.lucene.queryParser.nodes.QueryNode;
+import org.apache.lucene.util.LuceneTestCase;
+
+/**
+ * Test QueryParser's ability to deal with Analyzers that return more than one
+ * token per position or that return tokens with a position increment &gt; 1.
+ *
+ */
+public class TestMultiAnalyzer extends LuceneTestCase {
+
+ private static int multiToken = 0;
+
+ private String parse(LuceneQueryConfigHandler config, String queryString)
+ throws QueryNodeException {
+
+ QueryParser textParser = new QueryParser();
+ 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.setAndAsDefaultOperator(true);
+ 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/lucene2/TestMultiAnalyzerWrapper.java
===================================================================
--- contrib/queryparser/src/test/org/apache/lucene/queryParser/lucene2/TestMultiAnalyzerWrapper.java (revision 0)
+++ contrib/queryparser/src/test/org/apache/lucene/queryParser/lucene2/TestMultiAnalyzerWrapper.java (revision 0)
@@ -0,0 +1,304 @@
+package org.apache.lucene.queryParser.lucene2;
+
+/**
+ * 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.util.LuceneTestCase;
+
+/**
+ * Test QueryParser's ability to deal with Analyzers that return more
+ * than one token per position or that return tokens with a position
+ * increment &gt; 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/lucene2/TestMultiFieldQueryParser.java
===================================================================
--- contrib/queryparser/src/test/org/apache/lucene/queryParser/lucene2/TestMultiFieldQueryParser.java (revision 0)
+++ contrib/queryparser/src/test/org/apache/lucene/queryParser/lucene2/TestMultiFieldQueryParser.java (revision 0)
@@ -0,0 +1,511 @@
+package org.apache.lucene.queryParser.lucene2;
+
+/**
+ * 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.lucene2.builders.LuceneQueryTreeBuilder;
+import org.apache.lucene.queryParser.lucene2.config.AnalyzerAttribute;
+import org.apache.lucene.queryParser.lucene2.config.LuceneMultiFieldQueryConfigHandler;
+import org.apache.lucene.queryParser.lucene2.config.LuceneQueryConfigHandler;
+import org.apache.lucene.queryParser.lucene2.parser.QueryParser;
+import org.apache.lucene.queryParser.lucene2.processors.LuceneQueryNodeProcessorPipeline;
+import org.apache.lucene.queryParser.lucene2.processors.MultiFieldQueryNodeProcessor;
+import org.apache.lucene.queryParser.nodes.QueryNode;
+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;
+
+/**
+ * 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();
+
+ LuceneMultiFieldQueryConfigHandler config = new LuceneMultiFieldQueryConfigHandler(fields, null);
+ 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 {
+
+ QueryParser textParser = new QueryParser();
+
+ if (((AnalyzerAttribute) config.getAttribute(AnalyzerAttribute.class))
+ .getAnalyzer() == null) {
+ config.setAnalyzer(new SimpleAnalyzer());
+ }
+
+ QueryNode queryTree = textParser.parse(query, null);
+
+ QueryNodeProcessorPipeline processor = new QueryNodeProcessorPipeline(config);
+ processor.addProcessor(new MultiFieldQueryNodeProcessor());
+ processor.addProcessor(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" };
+
+ LuceneMultiFieldQueryConfigHandler config = new LuceneMultiFieldQueryConfigHandler(
+ fields, null);
+ 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.setAndAsDefaultOperator(true);
+ 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" };
+
+ LuceneMultiFieldQueryConfigHandler config = new LuceneMultiFieldQueryConfigHandler(
+ fields, 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" };
+
+ LuceneMultiFieldQueryConfigHandler config = new LuceneMultiFieldQueryConfigHandler(fields, null);
+ 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();
+
+ LuceneMultiFieldQueryConfigHandler config = new LuceneMultiFieldQueryConfigHandler(new String[] { "body" }, null);
+ config.setAnalyzer(analyzer);
+ config.setAndAsDefaultOperator(true);
+
+ 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 {
+
+ QueryParser textParser = new QueryParser();
+ 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 {
+
+ QueryParser textParser = new QueryParser();
+ 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 {
+
+ QueryParser textParser = new QueryParser();
+ 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/lucene2/TestMultiFieldQueryParserWrapper.java
===================================================================
--- contrib/queryparser/src/test/org/apache/lucene/queryParser/lucene2/TestMultiFieldQueryParserWrapper.java (revision 0)
+++ contrib/queryparser/src/test/org/apache/lucene/queryParser/lucene2/TestMultiFieldQueryParserWrapper.java (revision 0)
@@ -0,0 +1,328 @@
+package org.apache.lucene.queryParser.lucene2;
+
+/**
+ * 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.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;
+ }
+ }
+ }
+
+}
Index: contrib/queryparser/src/test/org/apache/lucene/queryParser/lucene2/TestQueryParser.java
===================================================================
--- contrib/queryparser/src/test/org/apache/lucene/queryParser/lucene2/TestQueryParser.java (revision 0)
+++ contrib/queryparser/src/test/org/apache/lucene/queryParser/lucene2/TestQueryParser.java (revision 0)
@@ -0,0 +1,1168 @@
+package org.apache.lucene.queryParser.lucene2;
+
+/**
+ * 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.lucene2.builders.LuceneQueryTreeBuilder;
+import org.apache.lucene.queryParser.lucene2.config.AnalyzerAttribute;
+import org.apache.lucene.queryParser.lucene2.config.LuceneQueryConfigHandler;
+import org.apache.lucene.queryParser.lucene2.parser.EscapeQuerySyntaxImpl;
+import org.apache.lucene.queryParser.lucene2.parser.ParseException;
+import org.apache.lucene.queryParser.lucene2.parser.QueryParser;
+import org.apache.lucene.queryParser.lucene2.processors.LuceneQueryNodeProcessorPipeline;
+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.parser.EscapeQuerySyntax;
+import org.apache.lucene.queryParser.parser.Parser;
+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;
+
+/**
+ * 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 {
+ QueryParser textParser = new QueryParser();
+
+ 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.setAndAsDefaultOperator(true);
+
+ 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 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" });
+
+ 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();
+ QueryParser textParser = new QueryParser();
+
+ 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];
+ // 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 {
+ 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.setPositionIncrementsEnabled(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/lucene2/TestQueryParserWrapper.java
===================================================================
--- contrib/queryparser/src/test/org/apache/lucene/queryParser/lucene2/TestQueryParserWrapper.java (revision 0)
+++ contrib/queryparser/src/test/org/apache/lucene/queryParser/lucene2/TestQueryParserWrapper.java (revision 0)
@@ -0,0 +1,1097 @@
+package org.apache.lucene.queryParser.lucene2;
+
+/**
+ * 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.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;
+
+
+/**
+ * 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/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,54 @@
+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.lucene2.builders.LuceneQueryBuilder;
+import org.apache.lucene.queryParser.nodes.BooleanQueryNode;
+import org.apache.lucene.queryParser.nodes.QueryNode;
+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);
+
+ }
+
+}
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,39 @@
+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.lucene2.builders.LuceneQueryBuilder;
+import org.apache.lucene.queryParser.nodes.FieldQueryNode;
+import org.apache.lucene.queryParser.nodes.QueryNode;
+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()));
+
+ }
+
+}
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;
+
+ }
+
+}
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,48 @@
+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.lucene2.builders.LuceneQueryBuilder;
+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.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);
+ }
+
+}
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,70 @@
+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;
+
+ }
+
+}
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,214 @@
+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.lucene2.parser.QueryParser;
+import org.apache.lucene.queryParser.nodes.OrQueryNode;
+import org.apache.lucene.queryParser.nodes.QueryNode;
+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 QueryParser}).<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 QueryParser}.<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 QueryParser
+ * @see UniqueFieldQueryNodeProcessor
+ * @see UniqueFieldAttribute
+ *
+ */
+public class TestSpanQueryParser extends TestCase {
+
+ private QueryNodeProcessorPipeline spanProcessorPipeline;
+
+ private SpansQueryConfigHandler spanQueryConfigHandler;
+
+ private SpansQueryTreeBuilder spansQueryTreeBuilder;
+
+ private QueryParser queryParser = new QueryParser();
+
+ 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
+ }
+
+ }
+
+}
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,141 @@
+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.lucene2.parser.QueryParser;
+import org.apache.lucene.queryParser.nodes.OrQueryNode;
+import org.apache.lucene.queryParser.nodes.QueryNode;
+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 QueryParser}).<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 QueryParser}.<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 QueryParser
+ * @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 QueryParser();
+
+ // 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 QueryTree before being processed
+ System.out.println(queryTree);
+
+ // Process the QueryTree using our new Processors
+ queryTree = spanProcessorPipeline.process(queryTree);
+
+ // print to show out the QueryTree 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");
+
+ }
+
+}
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,88 @@
+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 + "'/>";
+ }
+
+}
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,81 @@
+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;
+
+ }
+
+}
Index: contrib/queryparser/src/util/org/apache/lucene/queryParser/MultiFieldQueryParser.java
===================================================================
--- contrib/queryparser/src/util/org/apache/lucene/queryParser/MultiFieldQueryParser.java (revision 0)
+++ contrib/queryparser/src/util/org/apache/lucene/queryParser/MultiFieldQueryParser.java (revision 0)
@@ -0,0 +1,41 @@
+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.Map;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.queryParser.lucene2.MultiFieldQueryParserWrapper;
+
+/**
+ * This class is a Wrapper for the old lucene 2.4 MultiFieldQueryParser
+ * @deprecated this class will be removed soon, it's a temporary class to be used
+ */
+@SuppressWarnings("deprecation")
+public class MultiFieldQueryParser extends MultiFieldQueryParserWrapper {
+
+ @SuppressWarnings("unchecked")
+ public MultiFieldQueryParser(String[] fields, Analyzer analyzer, Map boosts) {
+ super(fields, analyzer, boosts);
+ }
+
+ public MultiFieldQueryParser(String[] fields, Analyzer analyzer) {
+ super(fields, analyzer);
+ }
+
+}
Index: contrib/queryparser/src/util/org/apache/lucene/queryParser/ParseException.java
===================================================================
--- contrib/queryparser/src/util/org/apache/lucene/queryParser/ParseException.java (revision 0)
+++ contrib/queryparser/src/util/org/apache/lucene/queryParser/ParseException.java (revision 0)
@@ -0,0 +1,38 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 4.1 */
+/* JavaCCOptions:KEEP_LINE_COL=null */
+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.
+ */
+
+/**
+ * This class is a Wrapper for the old lucene 2.4 ParseException
+ * @deprecated this class will be removed soon, it's a temporary class to be used
+ */
+public class ParseException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public ParseException() {
+ super();
+ }
+
+ public ParseException(String message) {
+ super(message);
+ }
+
+}
Index: contrib/queryparser/src/util/org/apache/lucene/queryParser/QueryParser.java
===================================================================
--- contrib/queryparser/src/util/org/apache/lucene/queryParser/QueryParser.java (revision 0)
+++ contrib/queryparser/src/util/org/apache/lucene/queryParser/QueryParser.java (revision 0)
@@ -0,0 +1,36 @@
+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.analysis.Analyzer;
+import org.apache.lucene.queryParser.lucene2.QueryParserWrapper;
+
+@SuppressWarnings("deprecation")
+/**
+ * This class is a Wrapper for the old lucene 2.4 QueryParser
+ *
+ * @deprecated this class will be removed soon, it's a temporary class to be
+ * used
+ */
+public class QueryParser extends QueryParserWrapper {
+
+ public QueryParser(String defaultField, Analyzer analizer) {
+ super(defaultField, analizer);
+ }
+
+}