From 343992fcbb4b31249f07354014723f18d0508d8a Mon Sep 17 00:00:00 2001 From: Michael Busch Date: Mon, 3 Aug 2009 03:38:44 +0000 Subject: [PATCH] LUCENE-1567: New flexible QueryParser framework. git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@800191 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES.txt | 14 +- build.xml | 4 +- contrib/CHANGES.txt | 7 + contrib/queryparser/build.xml | 31 + contrib/queryparser/pom.xml.template | 40 + .../org/apache/lucene/messages/Message.java | 37 + .../apache/lucene/messages/MessageImpl.java | 71 + .../java/org/apache/lucene/messages/NLS.java | 209 +++ .../apache/lucene/messages/NLSException.java | 34 + .../org/apache/lucene/messages/package.html | 99 ++ .../queryParser/core/QueryNodeError.java | 75 + .../queryParser/core/QueryNodeException.java | 87 ++ .../core/QueryNodeParseException.java | 121 ++ .../queryParser/core/QueryParserHelper.java | 261 ++++ .../core/builders/QueryBuilder.java | 43 + .../core/builders/QueryTreeBuilder.java | 222 +++ .../queryParser/core/builders/package.html | 39 + .../queryParser/core/config/FieldConfig.java | 64 + .../core/config/FieldConfigListener.java | 21 + .../core/config/QueryConfigHandler.java | 85 ++ .../queryParser/core/config/package.html | 50 + .../core/messages/QueryParserMessages.java | 54 + .../messages/QueryParserMessages.properties | 45 + .../queryParser/core/messages/package.html | 31 + .../queryParser/core/nodes/AndQueryNode.java | 77 + .../queryParser/core/nodes/AnyQueryNode.java | 143 ++ .../core/nodes/BooleanQueryNode.java | 83 ++ .../core/nodes/BoostQueryNode.java | 122 ++ .../core/nodes/DeletedQueryNode.java | 51 + .../core/nodes/FieldQueryNode.java | 184 +++ .../queryParser/core/nodes/FieldableNode.java | 45 + .../core/nodes/FuzzyQueryNode.java | 98 ++ .../core/nodes/GroupQueryNode.java | 83 ++ .../core/nodes/MatchAllDocsQueryNode.java | 49 + .../core/nodes/MatchNoDocsQueryNode.java | 37 + .../core/nodes/ModifierQueryNode.java | 156 +++ .../core/nodes/NoTokenFoundQueryNode.java | 49 + .../core/nodes/OpaqueQueryNode.java | 80 ++ .../queryParser/core/nodes/OrQueryNode.java | 78 ++ .../core/nodes/ParametricQueryNode.java | 100 ++ .../core/nodes/ParametricRangeQueryNode.java | 120 ++ .../queryParser/core/nodes/PathQueryNode.java | 214 +++ .../core/nodes/PhraseSlopQueryNode.java | 109 ++ .../core/nodes/PrefixWildcardQueryNode.java | 57 + .../core/nodes/ProximityQueryNode.java | 251 ++++ .../queryParser/core/nodes/QueryNode.java | 95 ++ .../queryParser/core/nodes/QueryNodeImpl.java | 225 +++ .../core/nodes/QuotedFieldQueryNode.java | 64 + .../queryParser/core/nodes/SlopQueryNode.java | 116 ++ .../core/nodes/TextableQueryNode.java | 26 + .../core/nodes/TokenizedPhraseQueryNode.java | 104 ++ .../core/nodes/WildcardQueryNode.java | 63 + .../queryParser/core/nodes/package.html | 89 ++ .../lucene/queryParser/core/package.html | 59 + .../core/parser/EscapeQuerySyntax.java | 41 + .../queryParser/core/parser/SyntaxParser.java | 36 + .../queryParser/core/parser/package.html | 44 + ...NoChildOptimizationQueryNodeProcessor.java | 90 ++ .../core/processors/QueryNodeProcessor.java | 79 ++ .../processors/QueryNodeProcessorImpl.java | 253 ++++ .../QueryNodeProcessorPipeline.java | 128 ++ .../RemoveDeletedQueryNodesProcessor.java | 109 ++ .../queryParser/core/processors/package.html | 57 + .../core/util/QueryNodeOperation.java | 94 ++ .../core/util/UnescapedCharSequence.java | 141 ++ .../lucene/queryParser/core/util/package.html | 29 + .../MultiFieldQueryParserWrapper.java | 269 ++++ .../original/OriginalQueryParserHelper.java | 430 ++++++ .../queryParser/original/QueryParserUtil.java | 189 +++ .../original/QueryParserWrapper.java | 488 +++++++ .../builders/AnyQueryNodeBuilder.java | 77 + .../builders/BooleanQueryNodeBuilder.java | 110 ++ .../builders/BoostQueryNodeBuilder.java | 54 + .../builders/FieldQueryNodeBuilder.java | 43 + .../builders/FuzzyQueryNodeBuilder.java | 44 + .../builders/GroupQueryNodeBuilder.java | 45 + .../MatchAllDocsQueryNodeBuilder.java | 52 + .../builders/MatchNoDocsQueryNodeBuilder.java | 52 + .../builders/ModifierQueryNodeBuilder.java | 45 + .../builders/MultiPhraseQueryNodeBuilder.java | 84 ++ .../OriginalBooleanQueryNodeBuilder.java | 109 ++ .../builders/OriginalQueryBuilder.java | 37 + .../builders/OriginalQueryTreeBuilder.java | 78 ++ .../builders/PhraseQueryNodeBuilder.java | 64 + .../PrefixWildcardQueryNodeBuilder.java | 44 + .../builders/RangeQueryNodeBuilder.java | 63 + .../builders/SlopQueryNodeBuilder.java | 57 + .../builders/WildcardQueryNodeBuilder.java | 44 + .../original/builders/package.html | 35 + .../config/AllowLeadingWildcardAttribute.java | 33 + .../AllowLeadingWildcardAttributeImpl.java | 80 ++ .../original/config/AnalyzerAttribute.java | 35 + .../config/AnalyzerAttributeImpl.java | 87 ++ .../original/config/BoostAttribute.java | 35 + .../original/config/BoostAttributeImpl.java | 81 ++ .../config/DateResolutionAttribute.java | 43 + .../config/DateResolutionAttributeImpl.java | 87 ++ .../config/DefaultOperatorAttribute.java | 39 + .../config/DefaultOperatorAttributeImpl.java | 89 ++ .../config/DefaultPhraseSlopAttribute.java | 34 + .../DefaultPhraseSlopAttributeImpl.java | 82 ++ .../config/FieldBoostMapAttribute.java | 35 + .../config/FieldBoostMapAttributeImpl.java | 89 ++ .../config/FieldBoostMapFCListener.java | 59 + .../config/FieldDateResolutionFCListener.java | 73 + .../FieldDateResolutionMapAttribute.java | 35 + .../FieldDateResolutionMapAttributeImpl.java | 86 ++ .../original/config/FuzzyAttribute.java | 36 + .../original/config/FuzzyAttributeImpl.java | 91 ++ .../original/config/LocaleAttribute.java | 35 + .../original/config/LocaleAttributeImpl.java | 87 ++ .../LowercaseExpandedTermsAttribute.java | 35 + .../LowercaseExpandedTermsAttributeImpl.java | 82 ++ .../original/config/MultiFieldAttribute.java | 33 + .../config/MultiFieldAttributeImpl.java | 81 ++ .../MultiTermRewriteMethodAttribute.java | 37 + .../MultiTermRewriteMethodAttributeImpl.java | 83 ++ .../config/OriginalQueryConfigHandler.java | 55 + .../config/PositionIncrementsAttribute.java | 33 + .../PositionIncrementsAttributeImpl.java | 81 ++ .../config/RangeCollatorAttribute.java | 37 + .../config/RangeCollatorAttributeImpl.java | 89 ++ .../queryParser/original/config/package.html | 34 + .../original/nodes/BooleanModifierNode.java | 39 + .../original/nodes/MultiPhraseQueryNode.java | 108 ++ .../nodes/OriginalBooleanQueryNode.java | 55 + .../original/nodes/RangeQueryNode.java | 80 ++ .../queryParser/original/nodes/package.html | 31 + .../lucene/queryParser/original/package.html | 50 + .../parser/EscapeQuerySyntaxImpl.java | 296 ++++ .../original/parser/JavaCharStream.java | 617 ++++++++ .../original/parser/OriginalSyntaxParser.java | 955 +++++++++++++ .../original/parser/OriginalSyntaxParser.jj | 484 +++++++ .../parser/OriginalSyntaxParserConstants.java | 125 ++ .../OriginalSyntaxParserTokenManager.java | 1247 +++++++++++++++++ .../original/parser/ParseException.java | 197 +++ .../queryParser/original/parser/Token.java | 131 ++ .../original/parser/TokenMgrError.java | 147 ++ .../queryParser/original/parser/package.html | 33 + .../AllowLeadingWildcardProcessor.java | 98 ++ .../AnalyzerQueryNodeProcessor.java | 337 +++++ ...leChildOptimizationQueryNodeProcessor.java | 88 ++ .../processors/BoostQueryNodeProcessor.java | 84 ++ .../DefaultPhraseSlopQueryNodeProcessor.java | 115 ++ .../processors/FuzzyQueryNodeProcessor.java | 86 ++ .../processors/GroupQueryNodeProcessor.java | 219 +++ ...ercaseExpandedTermsQueryNodeProcessor.java | 93 ++ .../MatchAllDocsQueryNodeProcessor.java | 73 + .../MultiFieldQueryNodeProcessor.java | 131 ++ .../OriginalQueryNodeProcessorPipeline.java | 70 + .../ParametricRangeQueryNodeProcessor.java | 188 +++ .../PhraseSlopQueryNodeProcessor.java | 71 + .../PrefixWildcardQueryNodeProcessor.java | 72 + .../RemoveEmptyNonLeafQueryNodeProcessor.java | 112 ++ .../original/processors/package.html | 33 + .../apache/lucene/queryParser/package.html | 131 ++ contrib/queryparser/src/java/overview.html | 39 + .../lucene/messages/MessagesTestBundle.java | 40 + .../messages/MessagesTestBundle.properties | 3 + .../messages/MessagesTestBundle_ja.properties | 3 + .../org/apache/lucene/messages/TestNLS.java | 81 ++ .../original/TestMultiAnalyzerQPHelper.java | 326 +++++ .../original/TestMultiAnalyzerWrapper.java | 320 +++++ .../original/TestMultiFieldQPHelper.java | 368 +++++ .../TestMultiFieldQueryParserWrapper.java | 366 +++++ .../queryParser/original/TestQPHelper.java | 1130 +++++++++++++++ .../original/TestQueryParserWrapper.java | 1122 +++++++++++++++ .../spans/SpanOrQueryNodeBuilder.java | 56 + .../spans/SpanTermQueryNodeBuilder.java | 41 + .../spans/SpansQueryConfigHandler.java | 43 + .../spans/SpansQueryTreeBuilder.java | 51 + .../SpansValidatorQueryNodeProcessor.java | 72 + .../spans/TestSpanQueryParser.java | 233 +++ .../TestSpanQueryParserSimpleSample.java | 155 ++ .../spans/UniqueFieldAttribute.java | 35 + .../spans/UniqueFieldAttributeImpl.java | 93 ++ .../spans/UniqueFieldQueryNodeProcessor.java | 84 ++ .../apache/lucene/queryParser/CharStream.java | 2 + .../queryParser/ComplexPhraseQueryParser.java | 4 +- .../lucene/queryParser/FastCharStream.java | 7 +- .../queryParser/MultiFieldQueryParser.java | 3 +- .../lucene/queryParser/ParseException.java | 3 + .../lucene/queryParser/QueryParser.java | 3 + .../apache/lucene/queryParser/QueryParser.jj | 6 +- .../queryParser/QueryParserConstants.java | 4 + .../queryParser/QueryParserTokenManager.java | 6 +- .../org/apache/lucene/queryParser/Token.java | 4 + .../lucene/queryParser/TokenMgrError.java | 7 +- .../apache/lucene/queryParser/package.html | 2 + 189 files changed, 21715 insertions(+), 9 deletions(-) create mode 100644 contrib/queryparser/build.xml create mode 100644 contrib/queryparser/pom.xml.template create mode 100644 contrib/queryparser/src/java/org/apache/lucene/messages/Message.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/messages/MessageImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/messages/NLS.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/messages/NLSException.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/messages/package.html create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/QueryNodeError.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/QueryNodeException.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/QueryNodeParseException.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/QueryParserHelper.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/builders/QueryBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/builders/QueryTreeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/builders/package.html create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/config/FieldConfig.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/config/FieldConfigListener.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/config/QueryConfigHandler.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/config/package.html create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/messages/QueryParserMessages.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/messages/QueryParserMessages.properties create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/messages/package.html create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/AndQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/AnyQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/BooleanQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/BoostQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/DeletedQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/FieldQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/FieldableNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/FuzzyQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/GroupQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/MatchAllDocsQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/MatchNoDocsQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/ModifierQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/NoTokenFoundQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/OpaqueQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/OrQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/ParametricQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/ParametricRangeQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/PathQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/PhraseSlopQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/PrefixWildcardQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/ProximityQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/QueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/QueryNodeImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/QuotedFieldQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/SlopQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/TextableQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/TokenizedPhraseQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/WildcardQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/package.html create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/package.html create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/parser/EscapeQuerySyntax.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/parser/SyntaxParser.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/parser/package.html create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/NoChildOptimizationQueryNodeProcessor.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/QueryNodeProcessor.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/QueryNodeProcessorImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/QueryNodeProcessorPipeline.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/RemoveDeletedQueryNodesProcessor.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/package.html create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/util/QueryNodeOperation.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/util/UnescapedCharSequence.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/core/util/package.html create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/MultiFieldQueryParserWrapper.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/OriginalQueryParserHelper.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/QueryParserUtil.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/QueryParserWrapper.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/AnyQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/BooleanQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/BoostQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/FieldQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/FuzzyQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/GroupQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MatchAllDocsQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MatchNoDocsQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/ModifierQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MultiPhraseQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/OriginalBooleanQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/OriginalQueryBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/OriginalQueryTreeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/PhraseQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/PrefixWildcardQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/RangeQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/SlopQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/WildcardQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/package.html create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AllowLeadingWildcardAttribute.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AllowLeadingWildcardAttributeImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AnalyzerAttribute.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AnalyzerAttributeImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/BoostAttribute.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/BoostAttributeImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DateResolutionAttribute.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DateResolutionAttributeImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultOperatorAttribute.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultOperatorAttributeImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultPhraseSlopAttribute.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultPhraseSlopAttributeImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldBoostMapAttribute.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldBoostMapAttributeImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldBoostMapFCListener.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldDateResolutionFCListener.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldDateResolutionMapAttribute.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldDateResolutionMapAttributeImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FuzzyAttribute.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FuzzyAttributeImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LocaleAttribute.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LocaleAttributeImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LowercaseExpandedTermsAttribute.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LowercaseExpandedTermsAttributeImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiFieldAttribute.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiFieldAttributeImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiTermRewriteMethodAttribute.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiTermRewriteMethodAttributeImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/OriginalQueryConfigHandler.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/PositionIncrementsAttribute.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/PositionIncrementsAttributeImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/RangeCollatorAttribute.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/RangeCollatorAttributeImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/package.html create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/BooleanModifierNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/MultiPhraseQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/OriginalBooleanQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/RangeQueryNode.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/package.html create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/package.html create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/EscapeQuerySyntaxImpl.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/JavaCharStream.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/OriginalSyntaxParser.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/OriginalSyntaxParser.jj create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/OriginalSyntaxParserConstants.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/OriginalSyntaxParserTokenManager.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/ParseException.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/Token.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/TokenMgrError.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/package.html create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/AllowLeadingWildcardProcessor.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/AnalyzerQueryNodeProcessor.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/BooleanSingleChildOptimizationQueryNodeProcessor.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/BoostQueryNodeProcessor.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/DefaultPhraseSlopQueryNodeProcessor.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/FuzzyQueryNodeProcessor.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/GroupQueryNodeProcessor.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/LowercaseExpandedTermsQueryNodeProcessor.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/MatchAllDocsQueryNodeProcessor.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/MultiFieldQueryNodeProcessor.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/OriginalQueryNodeProcessorPipeline.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/ParametricRangeQueryNodeProcessor.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/PhraseSlopQueryNodeProcessor.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/PrefixWildcardQueryNodeProcessor.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/RemoveEmptyNonLeafQueryNodeProcessor.java create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/package.html create mode 100644 contrib/queryparser/src/java/org/apache/lucene/queryParser/package.html create mode 100644 contrib/queryparser/src/java/overview.html create mode 100644 contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle.java create mode 100644 contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle.properties create mode 100644 contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle_ja.properties create mode 100644 contrib/queryparser/src/test/org/apache/lucene/messages/TestNLS.java create mode 100644 contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiAnalyzerQPHelper.java create mode 100644 contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiAnalyzerWrapper.java create mode 100644 contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiFieldQPHelper.java create mode 100644 contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiFieldQueryParserWrapper.java create mode 100644 contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestQPHelper.java create mode 100644 contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestQueryParserWrapper.java create mode 100644 contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpanOrQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpanTermQueryNodeBuilder.java create mode 100644 contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansQueryConfigHandler.java create mode 100644 contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansQueryTreeBuilder.java create mode 100644 contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansValidatorQueryNodeProcessor.java create mode 100644 contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/TestSpanQueryParser.java create mode 100644 contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/TestSpanQueryParserSimpleSample.java create mode 100644 contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldAttribute.java create mode 100644 contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldAttributeImpl.java create mode 100644 contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldQueryNodeProcessor.java diff --git a/CHANGES.txt b/CHANGES.txt index b5202a6486a..a48bd03ff51 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -359,6 +359,11 @@ API Changes 34. LUCENE-1460: Changed TokenStreams/TokenFilters in contrib to use the new TokenStream API. (Robert Muir, Michael Busch) +35. LUCENE-1567: Deprecated Queryparser, which will be replaced by a + new QueryParser framework in Lucene 3.0, that is currently located + in contrib. (see New Features 35.) + (Luis Alves and Adriano Campos via Michael Busch) + Bug fixes 1. LUCENE-1415: MultiPhraseQuery has incorrect hashCode() and equals() @@ -641,7 +646,14 @@ New features operations. This is currently used to fix offset problems when multiple fields with the same name are added to a document. (Mike McCandless, Mark Miller, Michael Busch) - + +35. LUCENE-1567: Added a new QueryParser framework to contrib, that + allows implementing a new query syntax in a flexible and efficient + way. This new QueryParser will be moved to Lucene's core in release + 3.0 and will then replace the current core QueryParser, which + has been deprecated with this patch. + (Luis Alves and Adriano Campos via Michael Busch) + Optimizations 1. LUCENE-1427: Fixed QueryWrapperFilter to not waste time computing diff --git a/build.xml b/build.xml index 29ed91ea1eb..39256bf2da4 100644 --- a/build.xml +++ b/build.xml @@ -330,6 +330,7 @@ + @@ -352,6 +353,7 @@ + @@ -361,7 +363,7 @@ - + diff --git a/contrib/CHANGES.txt b/contrib/CHANGES.txt index 84be15381bb..f8a1ec780f6 100644 --- a/contrib/CHANGES.txt +++ b/contrib/CHANGES.txt @@ -100,6 +100,13 @@ New features and fine tune how regular expressions are compiled and matched. (Marc Zampetti zampettim@aim.com via Mike McCandless) +12. LUCENE-1567: Added a new QueryParser framework, that allows + implementing a new query syntax in a flexible and efficient way. + This new QueryParser will be moved to Lucene's core in release + 3.0 and will then replace the current core QueryParser, which + has been deprecated with this patch. + (Luis Alves and Adriano Campos via Michael Busch) + Optimizations 1. LUCENE-1643: Re-use the collation key (RawCollationKey) for diff --git a/contrib/queryparser/build.xml b/contrib/queryparser/build.xml new file mode 100644 index 00000000000..daba9af24b2 --- /dev/null +++ b/contrib/queryparser/build.xml @@ -0,0 +1,31 @@ + + + + + + + + Flexible Query Parser + + + + + + + + diff --git a/contrib/queryparser/pom.xml.template b/contrib/queryparser/pom.xml.template new file mode 100644 index 00000000000..96b5c23bfb2 --- /dev/null +++ b/contrib/queryparser/pom.xml.template @@ -0,0 +1,40 @@ + + + + + 4.0.0 + + org.apache.lucene + lucene-contrib + @version@ + + org.apache.lucene + lucene-queryparser + Lucene Query Parser + @version@ + + This is the Flexible Query Parser for apache lucene java + + jar + + + diff --git a/contrib/queryparser/src/java/org/apache/lucene/messages/Message.java b/contrib/queryparser/src/java/org/apache/lucene/messages/Message.java new file mode 100644 index 00000000000..f56f57999bd --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/messages/Message.java @@ -0,0 +1,37 @@ +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; + +/** + * Message Interface for a lazy loading. + * 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); + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/messages/MessageImpl.java b/contrib/queryparser/src/java/org/apache/lucene/messages/MessageImpl.java new file mode 100644 index 00000000000..cf9e520862f --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/messages/MessageImpl.java @@ -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; + +/** + * Default implementation of Message interface. + * 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; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/messages/NLS.java b/contrib/queryparser/src/java/org/apache/lucene/messages/NLS.java new file mode 100644 index 00000000000..4c7dda5d9b4 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/messages/NLS.java @@ -0,0 +1,209 @@ +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; + +/** + * MessageBundles classes extend this class, to implement a bundle. + * + * 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 + * + * MessageBundle classes may subclass this type. + */ +public class NLS { + + private static Map> bundles = new HashMap>( + 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 it = bundles.keySet().iterator(); it.hasNext();) { + Class 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 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 fields = new HashMap(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 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 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; + } + }); + } + } +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/messages/NLSException.java b/contrib/queryparser/src/java/org/apache/lucene/messages/NLSException.java new file mode 100644 index 00000000000..0c6b904c2fe --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/messages/NLSException.java @@ -0,0 +1,34 @@ +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. + */ + +/** + * Interface that exceptions should implement to support lazy loading of messages. + * + * 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(); +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/messages/package.html b/contrib/queryparser/src/java/org/apache/lucene/messages/package.html new file mode 100644 index 00000000000..14219e895d1 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/messages/package.html @@ -0,0 +1,99 @@ + + + + + + + + +For Native Language Support (NLS), system of software internationalization. + +

NLS message API

+

+This utility API, adds support for NLS messages in the apache code. +It is currently used by the lucene "New Flexible Query PArser". +

+

+Features: +

    +
  1. Message reference in the code, using static Strings
  2. +
  3. Message resource validation at class load time, for easier debugging
  4. +
  5. Allows for message IDs to be re-factored using eclipse or other code re-factor tools
  6. +
  7. Allows for reference count on messages, just like code
  8. +
  9. Lazy loading of Message Strings
  10. +
  11. Normal loading Message Strings
  12. +
+

+ +
+
+

+Lazy loading of Message Strings + +

+	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;
+	}
+
+    // Create a message reference
+    Message invalidSyntax = new MessageImpl(MessagesTestBundle.Q0001E_INVALID_SYNTAX, "XXX");
+    
+    // Do other stuff in the code...
+    // when is time to display the message to the user or log the message on a file
+    // the message is loaded from the correct bundle
+    
+    String message1 = invalidSyntax.getLocalizedMessage();
+    String message2 = invalidSyntax.getLocalizedMessage(Locale.JAPANESE);
+
+

+ +
+
+

+Normal loading of Message Strings + +

+	String message1 = NLS.getLocalizedMessage(MessagesTestBundle.Q0004E_INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION);
+	String message2 = NLS.getLocalizedMessage(MessagesTestBundle.Q0004E_INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION, Locale.JAPANESE);
+
+

+ +

+The org.apache.lucene.messages.TestNLS junit contains several other examples. +The TestNLS java code is available from the Apache Lucene code repository. +

+ + diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/QueryNodeError.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/QueryNodeError.java new file mode 100644 index 00000000000..95b25722d1f --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/QueryNodeError.java @@ -0,0 +1,75 @@ +package org.apache.lucene.queryParser.core; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/QueryNodeException.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/QueryNodeException.java new file mode 100644 index 00000000000..907df6ec8cd --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/QueryNodeException.java @@ -0,0 +1,87 @@ +package org.apache.lucene.queryParser.core; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Locale; + +import org.apache.lucene.messages.Message; +import org.apache.lucene.messages.MessageImpl; +import org.apache.lucene.messages.NLS; +import org.apache.lucene.messages.NLSException; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.nodes.QueryNode; + +/** + *

+ * This exception should be thrown if something wrong happens when dealing with + * {@link QueryNode}s. + *

+ *

+ * It also supports NLS messages. + *

+ * + * @see Message + * @see NLS + * @see NLSException + * @see QueryNode + */ +public class QueryNodeException extends Exception implements NLSException { + + private static final long serialVersionUID = -5962648855261624214L; + + protected Message message = new MessageImpl(QueryParserMessages.EMPTY_MESSAGE); + + public QueryNodeException(Message message) { + super(message.getKey()); + + this.message = message; + + } + + public QueryNodeException(Throwable throwable) { + super(throwable); + } + + public QueryNodeException(Message message, Throwable throwable) { + super(message.getKey(), throwable); + + this.message = message; + + } + + public Message getMessageObject() { + return this.message; + } + + public String getMessage() { + return getLocalizedMessage(); + } + + public String getLocalizedMessage() { + return getLocalizedMessage(Locale.getDefault()); + } + + public String getLocalizedMessage(Locale locale) { + return this.message.getLocalizedMessage(locale); + } + + public String toString() { + return this.message.getKey() + ": " + getLocalizedMessage(); + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/QueryNodeParseException.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/QueryNodeParseException.java new file mode 100644 index 00000000000..c60f657b140 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/QueryNodeParseException.java @@ -0,0 +1,121 @@ +package org.apache.lucene.queryParser.core; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.parser.SyntaxParser; + +/** + * This should be thrown when an exception happens during the query parsing from + * string to the query node tree. + * + * @see QueryNodeException + * @see SyntaxParser + * @see QueryNode + */ +public class QueryNodeParseException extends QueryNodeException { + + private static final long serialVersionUID = 8197535103538766773L; + + private CharSequence query; + + private int beginColumn = -1; + + private int beginLine = -1; + + private String errorToken = ""; + + public QueryNodeParseException(Message message) { + super(message); + } + + public QueryNodeParseException(Throwable throwable) { + super(throwable); + } + + public QueryNodeParseException(Message message, Throwable throwable) { + super(message, throwable); + } + + public void setQuery(CharSequence query) { + this.query = query; + this.message = new MessageImpl( + QueryParserMessages.INVALID_SYNTAX_CANNOT_PARSE, query, ""); + } + + public CharSequence getQuery() { + return this.query; + } + + /** + * @param errorToken + * the errorToken in the query + */ + protected void setErrorToken(String errorToken) { + this.errorToken = errorToken; + } + + public String getErrorToken() { + return this.errorToken; + } + + public void setNonLocalizedMessage(Message message) { + this.message = message; + } + + /** + * For EndOfLine and EndOfFile ("") 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 ("") 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; + } +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/QueryParserHelper.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/QueryParserHelper.java new file mode 100644 index 00000000000..b7d05b0bddc --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/QueryParserHelper.java @@ -0,0 +1,261 @@ +package org.apache.lucene.queryParser.core; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.core.builders.QueryBuilder; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.parser.SyntaxParser; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessor; + +/** + *

+ * This class is a helper for the query parser framework, it does all the three + * query parser phrases at once: text parsing, query processing and query + * building. + *

+ *

+ * It contains methods that allows the user to change the implementation used on + * the three phases. + *

+ * + * @see QueryNodeProcessor + * @see SyntaxParser + * @see QueryBuilder + * @see QueryConfigHandler + */ +public class QueryParserHelper { + + private QueryNodeProcessor processor; + + private SyntaxParser syntaxParser; + + private QueryBuilder builder; + + private QueryConfigHandler config; + + /** + * Creates a query parser helper object using the specified configuration, + * text parser, processor and builder. + * + * @param queryConfigHandler + * the query configuration handler that will be initially set to this + * helper + * @param syntaxParser + * the text parser that will be initially set to this helper + * @param processor + * the query processor that will be initially set to this helper + * @param builder + * the query builder that will be initially set to this helper + * + * @see QueryNodeProcessor + * @see SyntaxParser + * @see QueryBuilder + * @see QueryConfigHandler + */ + public QueryParserHelper(QueryConfigHandler queryConfigHandler, SyntaxParser syntaxParser, QueryNodeProcessor processor, + QueryBuilder builder) { + this.syntaxParser = syntaxParser; + this.config = queryConfigHandler; + this.processor = processor; + this.builder = builder; + + if (processor != null) { + processor.setQueryConfigHandler(queryConfigHandler); + } + + } + + /** + * Returns the processor object used to process the query node tree, it + * returns null if no processor is used. + * + * @return the actual processor used to process the query node tree, + * null if no processor is used + * + * @see QueryNodeProcessor + * @see #setQueryNodeProcessor(QueryNodeProcessor) + */ + public QueryNodeProcessor getQueryNodeProcessor() { + return processor; + } + + /** + * Sets the processor that will be used to process the query node tree. If + * there is any {@link QueryConfigHandler} returned by + * {@link #getQueryConfigHandler()}, it will be set on the processor. The + * argument can be null, which means that no processor will be + * used to process the query node tree. + * + * @param processor + * the processor that will be used to process the query node tree, + * this argument can be null + * + * @see #getQueryNodeProcessor() + * @see QueryNodeProcessor + */ + public void setQueryNodeProcessor(QueryNodeProcessor processor) { + this.processor = processor; + this.processor.setQueryConfigHandler(getQueryConfigHandler()); + + } + + /** + * Sets the text parser that will be used to parse the query string, it cannot + * be null. + * + * @param syntaxParser + * the text parser that will be used to parse the query string + * + * @see #getTextParser() + * @see SyntaxParser + */ + public void setSyntaxParser(SyntaxParser syntaxParser) { + + if (syntaxParser == null) { + throw new IllegalArgumentException("textParser should not be null!"); + } + + this.syntaxParser = syntaxParser; + + } + + /** + * The query builder that will be used to build an object from the query node + * tree. It cannot be null. + * + * @param queryBuilder + * the query builder used to build something from the query node tree + * + * @see #getQueryBuilder() + * @see QueryBuilder + */ + public void setQueryBuilder(QueryBuilder queryBuilder) { + + if (queryBuilder == null) { + throw new IllegalArgumentException("queryBuilder should not be null!"); + } + + this.builder = queryBuilder; + + } + + /** + * Returns the query configuration handler, which is used during the query + * node tree processing. It can be null. + * + * @return the query configuration handler used on the query processing, + * null if not query configuration handler is defined + * + * @see QueryConfigHandler + * @see #setQueryConfigHandler(QueryConfigHandler) + */ + public QueryConfigHandler getQueryConfigHandler() { + return config; + } + + /** + * Returns the query builder used to build a object from the query node tree. + * The object produced by this builder is returned by + * {@link #parse(String, String)}. + * + * @return the query builder + * + * @see #setQueryBuilder(QueryBuilder) + * @see QueryBuilder + */ + public QueryBuilder getQueryBuilder() { + return this.builder; + } + + /** + * Returns the text parser used to build a query node tree from a query + * string. The default text parser instance returned by this method is a + * {@link SyntaxParser}. + * + * @return the text parse used to build query node trees. + * + * @see SyntaxParser + * @see #setSyntaxParser(SyntaxParser) + */ + public SyntaxParser getTextParser() { + return this.syntaxParser; + } + + /** + * Sets the query configuration handler that will be used during query + * processing. It can be null. It's also set to the processor + * returned by {@link #getQueryNodeProcessor()}. + * + * @param config + * the query configuration handler used during query processing, it + * can be null + * + * @see #getQueryConfigHandler() + * @see QueryConfigHandler + */ + public void setQueryConfigHandler(QueryConfigHandler config) { + this.config = config; + QueryNodeProcessor processor = getQueryNodeProcessor(); + + if (processor != null) { + processor.setQueryConfigHandler(config); + } + + } + + /** + * Parses a query string to an object, usually some query object.
+ *
+ * In this method the three phases are executed:
+ *
+ *      1st - the query string is parsed using the + * text parser returned by {@link #getTextParser()}, the result is a query + * node tree
+ *
+ *      2nd - the query node tree is processed by the + * processor returned by {@link #getQueryNodeProcessor()}
+ *
+ *      3th - a object is built from the query node + * tree using the builder returned by {@link #getQueryBuilder()} + * + * @param query + * the query string + * @param defaultField + * the default field used by the text parser + * + * @return the object built from the query + * + * @throws QueryNodeException + * if something wrong happens along the three phases + */ + public Object parse(String query, String defaultField) + throws QueryNodeException { + QueryNode queryTree = getTextParser().parse(query, defaultField); + + QueryNodeProcessor processor = getQueryNodeProcessor(); + + if (processor != null) { + queryTree = processor.process(queryTree); + } + + return getQueryBuilder().build(queryTree); + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/builders/QueryBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/builders/QueryBuilder.java new file mode 100644 index 00000000000..509833f4076 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/builders/QueryBuilder.java @@ -0,0 +1,43 @@ +package org.apache.lucene.queryParser.core.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.core.QueryNodeException; +import org.apache.lucene.queryParser.core.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; + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/builders/QueryTreeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/builders/QueryTreeBuilder.java new file mode 100644 index 00000000000..6b3d31ae326 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/builders/QueryTreeBuilder.java @@ -0,0 +1,222 @@ +package org.apache.lucene.queryParser.core.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.core.QueryNodeException; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.nodes.FieldableNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.original.parser.EscapeQuerySyntaxImpl; + +/** + * This class should be used when there is a builder for each type of node. + * + * The type of node may be defined in 2 different ways: - by the field name, + * when the node implements the {@link FieldableNode} interface - by its class, + * it keeps checking the class and all the interfaces and classes this class + * implements/extends until it finds a builder for that class/interface + * + * This class always check if there is a builder for the field name before it + * checks for the node class. So, field name builders have precedence over class + * builders. + * + * When a builder is found for a node, it's called and the node is passed to the + * builder. If the returned built object is not null, 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, QueryBuilder> queryNodeBuilders; + + private HashMap 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(); + } + + 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 queryNodeClass, + QueryBuilder builder) { + + if (this.queryNodeBuilders == null) { + this.queryNodeBuilders = new HashMap, 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 children = node.getChildren(); + + if (children != null) { + + for (QueryNode child : children) { + process(child); + } + + } + + } + + processNode(node, builder); + + } + + } + + private QueryBuilder getBuilder(QueryNode node) { + QueryBuilder builder = null; + + if (this.fieldNameBuilders != null && node instanceof FieldableNode) { + + builder = this.fieldNameBuilders.get(((FieldableNode) node).getField()); + + } + + if (builder == null && this.queryNodeBuilders != null) { + + Class clazz = node.getClass(); + + do { + builder = getQueryBuilder(clazz); + + if (builder == null) { + Class[] classes = node.getClass().getInterfaces(); + + for (Class actualClass : classes) { + builder = getQueryBuilder(actualClass); + + if (builder != null) { + break; + } + + } + + } + + } while (builder == null && (clazz = clazz.getSuperclass()) != null); + + } + + return builder; + + } + + private void processNode(QueryNode node, QueryBuilder builder) + throws QueryNodeException { + + if (builder == null) { + + throw new QueryNodeException(new MessageImpl( + QueryParserMessages.LUCENE_QUERY_CONVERSION_ERROR, node + .toQueryString(new EscapeQuerySyntaxImpl()), node.getClass() + .getName())); + + } + + Object obj = builder.build(node); + + if (obj != null) { + node.setTag(QUERY_TREE_BUILDER_TAGID, obj); + } + + } + + private QueryBuilder getQueryBuilder(Class clazz) { + + if (QueryNode.class.isAssignableFrom(clazz)) { + return this.queryNodeBuilders.get(clazz); + } + + return null; + + } + + /** + * Builds some kind of object from a query tree. Each node in the query tree + * is built using an specific builder associated to it. + * + * @param queryNode + * the query tree root node + * + * @return the built object + * + * @throws QueryNodeException + * if some node builder throws a {@link QueryNodeException} or if + * there is a node which had no builder associated to it + */ + public Object build(QueryNode queryNode) throws QueryNodeException { + process(queryNode); + + return queryNode.getTag(QUERY_TREE_BUILDER_TAGID); + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/builders/package.html b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/builders/package.html new file mode 100644 index 00000000000..d85cebbe9cb --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/builders/package.html @@ -0,0 +1,39 @@ + + + + + + + + +Contains the necessary classes to implement query builders + +

Query Parser Builders

+

+The package org.apache.lucene.queryParser.builders contains the interface that +builders must implement, it also contain a utility {@link org.apache.lucene.queryParser.core.builders.QueryTreeBuilder}, which walks the tree +and call the Builder for each node in the tree. +Builder normally convert QueryNode Object into a Lucene Query Object, +and normally it's a one-to-one mapping class. + +But other builders implementations can by written to convert QueryNode objects to other non lucene objects. +

+

+

+ + diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/config/FieldConfig.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/config/FieldConfig.java new file mode 100644 index 00000000000..d715d36b198 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/config/FieldConfig.java @@ -0,0 +1,64 @@ +package org.apache.lucene.queryParser.core.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; + } + + public String toString(){ + return ""; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/config/FieldConfigListener.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/config/FieldConfigListener.java new file mode 100644 index 00000000000..0f9f6c1163d --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/config/FieldConfigListener.java @@ -0,0 +1,21 @@ +package org.apache.lucene.queryParser.core.config; + +/** + * This interface should be implemented by classes that wants to listen for + * field configuration requests. The implementation receives a + * {@link FieldConfig} object and may add/change its attributes. + * + * @see FieldConfig + * @see QueryConfigHandler + */ +public interface FieldConfigListener { + + /** + * This method is called ever time a field configuration is requested. + * + * @param fieldConfig + * the field configuration requested, should never be null + */ + void buildFieldConfig(FieldConfig fieldConfig); + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/config/QueryConfigHandler.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/config/QueryConfigHandler.java new file mode 100644 index 00000000000..be44c7c7a96 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/config/QueryConfigHandler.java @@ -0,0 +1,85 @@ +package org.apache.lucene.queryParser.core.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.LinkedList; + +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessor; +import org.apache.lucene.util.Attribute; +import org.apache.lucene.util.AttributeSource; + +/** + * This class can be used to hold any query configuration and no field + * configuration. For field configuration, it creates a empty + * {@link FieldConfig} object and delegate it to field config listeners, + * these are responsible for setting up all the field configuration. + * + * {@link QueryConfigHandler} should be extended 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 extends {@link QueryConfigHandler} should also provide + * {@link FieldConfig} objects for each collection field. + * + * @see Attribute + * @see FieldConfig + * @see FieldConfigListener + * @see QueryConfigHandler + */ +public abstract class QueryConfigHandler extends AttributeSource { + + private LinkedList listeners = new LinkedList();; + + /** + * Returns 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 null, indicating there is no configuration for that + * field. + * + * @param fieldName + * the field name + * @return a {@link FieldConfig} object containing the field name + * configuration or null, if the implemented + * {@link QueryConfigHandler} has no configuration for that field + */ + public FieldConfig getFieldConfig(CharSequence fieldName) { + FieldConfig fieldConfig = new FieldConfig(fieldName); + + for (FieldConfigListener listener : this.listeners) { + listener.buildFieldConfig(fieldConfig); + } + + return fieldConfig; + + } + + /** + * Adds a listener. The added listeners are called in the order they are + * added. + * + * @param listener + * the listener to be added + */ + public void addFieldConfigListener(FieldConfigListener listener) { + this.listeners.add(listener); + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/config/package.html b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/config/package.html new file mode 100644 index 00000000000..65d7c3c75e5 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/config/package.html @@ -0,0 +1,50 @@ + + + + + + + + +Contains the base classes used to configure the query processing + +

Query Configuration Interfaces

+

+The package org.apache.lucene.queryParser.config contains query configuration handler +abstract class that all config handlers should extend. +

+

+See {@link org.apache.lucene.queryParser.original.config.OriginalQueryConfigHandler} for a reference +implementation. +

+

+{@link org.apache.lucene.queryParser.core.config.FieldConfig} and {@link org.apache.lucene.queryParser.core.config.QueryConfigHandler} + should use {@link org.apache.lucene.util.Attribute} to store all attributes +required by the config implementation. See org.apache.lucene.queryParser.original.config.*Attribute +for reference implementation. +

+

+The {@link org.apache.lucene.queryParser.core.config.QueryConfigHandler}, {@link org.apache.lucene.queryParser.core.config.FieldConfig}, + and {@link org.apache.lucene.util.Attribute}s are used in the processors to access config +information in a flexible and independent way. +See {@link org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor} for a +reference implementation. +

+ +Apache Lucene Community +# +INVALID_SYNTAX = Syntax Error: {0} + +#Apache Lucene Community +# +# +INVALID_SYNTAX_CANNOT_PARSE = Syntax Error, cannot parse {0}: {1} + +#Apache Lucene Community +INVALID_SYNTAX_FUZZY_LIMITS = The similarity value for a fuzzy search must be between 0.0 and 1.0. + +#Apache Lucene Community +INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION = Truncated unicode escape sequence. + +#Apache Lucene Community +INVALID_SYNTAX_ESCAPE_CHARACTER = Term can not end with escape character. + +#Apache Lucene Community +INVALID_SYNTAX_ESCAPE_NONE_HEX_UNICODE = None-hex character in unicode escape sequence: {0} + +#Apache Lucene Community +NODE_ACTION_NOT_SUPPORTED = This node does not support this action. + +#Apache Lucene Community +PARAMETER_VALUE_NOT_SUPPORTED = Parameter {1} with value {0} not supported. + +#Apache Lucene Community +# +# +LUCENE_QUERY_CONVERSION_ERROR = Cannot convert query to lucene syntax: {0} error: {1} + +#Apache Lucene Community +EMPTY_MESSAGE = + +#Apache Lucene Community +WILDCARD_NOT_SUPPORTED = Wildcard is not supported for query: {0} + +#Apache Lucene Community +TOO_MANY_BOOLEAN_CLAUSES = Too many boolean clauses, the maximum supported is {0}: {1} + +#Apache Lucene Community +LEADING_WILDCARD_NOT_ALLOWED = Leading wildcard is not allowed: {0} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/messages/package.html b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/messages/package.html new file mode 100644 index 00000000000..c05fa7e6b5c --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/messages/package.html @@ -0,0 +1,31 @@ + + + + + + + + +Contains messages usually used by query parser implementations + +

Query Parser Messages

+ +Messages for the Flexible Query Parser, they use org.apache.lucene.messages.NLS API. + + + diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/AndQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/AndQueryNode.java new file mode 100644 index 00000000000..a94e79e5324 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/AndQueryNode.java @@ -0,0 +1,77 @@ +package org.apache.lucene.queryParser.core.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.core.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 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 ""; + StringBuilder sb = new StringBuilder(); + sb.append(""); + for (QueryNode child : getChildren()) { + sb.append("\n"); + sb.append(child.toString()); + + } + sb.append("\n"); + 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() + " )"; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/AnyQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/AnyQueryNode.java new file mode 100644 index 00000000000..1571c3b74fa --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/AnyQueryNode.java @@ -0,0 +1,143 @@ +package org.apache.lucene.queryParser.core.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.core.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 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 ""; + StringBuilder sb = new StringBuilder(); + sb.append(""); + for (QueryNode clause : getChildren()) { + sb.append("\n"); + sb.append(clause.toString()); + } + sb.append("\n"); + 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 + ")"; + } + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/BooleanQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/BooleanQueryNode.java new file mode 100644 index 00000000000..3750a236c5a --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/BooleanQueryNode.java @@ -0,0 +1,83 @@ +package org.apache.lucene.queryParser.core.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.core.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 clauses) { + setLeaf(false); + allocate(); + set(clauses); + } + + public String toString() { + if (getChildren() == null || getChildren().size() == 0) + return ""; + StringBuilder sb = new StringBuilder(); + sb.append(""); + for (QueryNode child : getChildren()) { + sb.append("\n"); + sb.append(child.toString()); + } + sb.append("\n"); + 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; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/BoostQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/BoostQueryNode.java new file mode 100644 index 00000000000..125d25359e3 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/BoostQueryNode.java @@ -0,0 +1,122 @@ +package org.apache.lucene.queryParser.core.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.core.QueryNodeError; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.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 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 "" + "\n" + + getChild().toString() + "\n"; + } + + 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; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/DeletedQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/DeletedQueryNode.java new file mode 100644 index 00000000000..8e52e405e48 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/DeletedQueryNode.java @@ -0,0 +1,51 @@ +package org.apache.lucene.queryParser.core.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.core.parser.EscapeQuerySyntax; +import org.apache.lucene.queryParser.core.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 ""; + } + + public QueryNode cloneTree() throws CloneNotSupportedException { + DeletedQueryNode clone = (DeletedQueryNode) super.cloneTree(); + + return clone; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/FieldQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/FieldQueryNode.java new file mode 100644 index 00000000000..82b38b1a8db --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/FieldQueryNode.java @@ -0,0 +1,184 @@ +package org.apache.lucene.queryParser.core.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.core.parser.EscapeQuerySyntax; +import org.apache.lucene.queryParser.core.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 ""; + } + + /** + * @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; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/FieldableNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/FieldableNode.java new file mode 100644 index 00000000000..ca666263a9d --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/FieldableNode.java @@ -0,0 +1,45 @@ +package org.apache.lucene.queryParser.core.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); + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/FuzzyQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/FuzzyQueryNode.java new file mode 100644 index 00000000000..30a0dc88aee --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/FuzzyQueryNode.java @@ -0,0 +1,98 @@ +package org.apache.lucene.queryParser.core.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.core.parser.EscapeQuerySyntax; + +/** + * A {@link FuzzyQueryNode} represents a element that contains + * field/text/similarity tuple + */ +public class FuzzyQueryNode extends FieldQueryNode { + + private static final long serialVersionUID = -1794537213032589441L; + + private float similarity; + + private int prefixLength; + + /** + * @param field + * Name of the field query will use. + * @param termStr + * Term token to use for building term for the query + */ + /** + * @param field + * - Field name + * @param term + * - Value + * @param minSimilarity + * - similarity value + * @param begin + * - position in the query string + * @param end + * - position in the query string + */ + public FuzzyQueryNode(CharSequence field, CharSequence term, + float minSimilarity, int begin, int end) { + super(field, term, begin, end); + this.similarity = minSimilarity; + setLeaf(true); + } + + public void setPrefixLength(int prefixLength) { + this.prefixLength = prefixLength; + } + + public int getPrefixLength() { + return this.prefixLength; + } + + public CharSequence toQueryString(EscapeQuerySyntax escaper) { + if (isDefaultField(this.field)) { + return getTermEscaped(escaper) + "~" + this.similarity; + } else { + return this.field + ":" + getTermEscaped(escaper) + "~" + this.similarity; + } + } + + public String toString() { + return ""; + } + + public void setSimilarity(float similarity) { + this.similarity = similarity; + } + + public FuzzyQueryNode cloneTree() throws CloneNotSupportedException { + FuzzyQueryNode clone = (FuzzyQueryNode) super.cloneTree(); + + clone.similarity = this.similarity; + + return clone; + } + + /** + * @return the similarity + */ + public float getSimilarity() { + return this.similarity; + } +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/GroupQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/GroupQueryNode.java new file mode 100644 index 00000000000..14ae263d1ce --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/GroupQueryNode.java @@ -0,0 +1,83 @@ +package org.apache.lucene.queryParser.core.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.core.QueryNodeError; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.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 "" + "\n" + getChild().toString() + "\n"; + } + + 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 list = new ArrayList(); + list.add(child); + this.set(list); + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/MatchAllDocsQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/MatchAllDocsQueryNode.java new file mode 100644 index 00000000000..58575d98ea4 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/MatchAllDocsQueryNode.java @@ -0,0 +1,49 @@ +package org.apache.lucene.queryParser.core.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.core.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 ""; + } + + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { + return "*:*"; + } + + public MatchAllDocsQueryNode cloneTree() throws CloneNotSupportedException { + MatchAllDocsQueryNode clone = (MatchAllDocsQueryNode) super.cloneTree(); + + // nothing to clone + + return clone; + } +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/MatchNoDocsQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/MatchNoDocsQueryNode.java new file mode 100644 index 00000000000..582ba8ae950 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/MatchNoDocsQueryNode.java @@ -0,0 +1,37 @@ +package org.apache.lucene.queryParser.core.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 ""; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/ModifierQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/ModifierQueryNode.java new file mode 100644 index 00000000000..8b8529f2a1d --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/ModifierQueryNode.java @@ -0,0 +1,156 @@ +package org.apache.lucene.queryParser.core.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.core.QueryNodeError; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.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 + * + * + * + * + */ +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 "" + "\n" + + getChild().toString() + "\n"; + } + + 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 list = new ArrayList(); + list.add(child); + this.set(list); + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/NoTokenFoundQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/NoTokenFoundQueryNode.java new file mode 100644 index 00000000000..3554c64afb6 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/NoTokenFoundQueryNode.java @@ -0,0 +1,49 @@ +package org.apache.lucene.queryParser.core.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.core.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 ""; + } + + public QueryNode cloneTree() throws CloneNotSupportedException { + NoTokenFoundQueryNode clone = (NoTokenFoundQueryNode) super.cloneTree(); + + // nothing to do here + + return clone; + } +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/OpaqueQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/OpaqueQueryNode.java new file mode 100644 index 00000000000..293ec6b3ae5 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/OpaqueQueryNode.java @@ -0,0 +1,80 @@ +package org.apache.lucene.queryParser.core.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.core.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 ""; + } + + 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; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/OrQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/OrQueryNode.java new file mode 100644 index 00000000000..e88d37b16be --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/OrQueryNode.java @@ -0,0 +1,78 @@ +package org.apache.lucene.queryParser.core.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.core.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 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 ""; + StringBuilder sb = new StringBuilder(); + sb.append(""); + for (QueryNode child : getChildren()) { + sb.append("\n"); + sb.append(child.toString()); + + } + sb.append("\n"); + return sb.toString(); + } + + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { + if (getChildren() == null || getChildren().size() == 0) + return ""; + + StringBuilder sb = new StringBuilder(); + String filler = ""; + for (Iterator 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() + " )"; + } +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/ParametricQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/ParametricQueryNode.java new file mode 100644 index 00000000000..0f81525c857 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/ParametricQueryNode.java @@ -0,0 +1,100 @@ +package org.apache.lucene.queryParser.core.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.core.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 ""; + } + + 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; + } +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/ParametricRangeQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/ParametricRangeQueryNode.java new file mode 100644 index 00000000000..2405c3a68e0 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/ParametricRangeQueryNode.java @@ -0,0 +1,120 @@ +package org.apache.lucene.queryParser.core.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.core.nodes.ParametricQueryNode.CompareOperator; +import org.apache.lucene.queryParser.core.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("\n\t"); + sb.append(getUpperBound()).append("\n\t"); + sb.append(getLowerBound()).append("\n"); + sb.append("\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 children = getChildren(); + + if (children != null) { + + for (QueryNode child : getChildren()) { + + if (child instanceof FieldableNode) { + ((FieldableNode) child).setField(fieldName); + } + + } + + } + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/PathQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/PathQueryNode.java new file mode 100644 index 00000000000..859095fc4b5 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/PathQueryNode.java @@ -0,0 +1,214 @@ +package org.apache.lucene.queryParser.core.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.core.parser.EscapeQuerySyntax; +import org.apache.lucene.queryParser.core.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 values = null; + + /** + * @param pathElements + * - List of QueryText objects + */ + public PathQueryNode(List 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 getPathElements() { + return values; + } + + /** + * Returns the a List with all QueryText elements + */ + public void setPathElements(List elements) { + this.values = elements; + } + + /** + * Returns the a specific QueryText element + * + * @return QueryText List size + */ + public QueryText getPathElement(int index) { + return values.get(index); + } + + /** + * Returns the CharSequence value of a specific QueryText element + * + * @return the CharSequence for a specific QueryText element + */ + public CharSequence getFirstPathElement() { + return values.get(0).value; + } + + /** + * Returns a List QueryText element from position startIndex + * + * @return a List QueryText element from position startIndex + */ + public List getPathElements(int startIndex) { + List rValues = new ArrayList(); + 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 ""; + } + + public QueryNode cloneTree() throws CloneNotSupportedException { + PathQueryNode clone = (PathQueryNode) super.cloneTree(); + + // copy children + if (this.values != null) { + List localValues = new ArrayList(); + for (QueryText value : this.values) { + localValues.add(value.clone()); + } + clone.values = localValues; + } + + return clone; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/PhraseSlopQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/PhraseSlopQueryNode.java new file mode 100644 index 00000000000..e68f90a49e5 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/PhraseSlopQueryNode.java @@ -0,0 +1,109 @@ +package org.apache.lucene.queryParser.core.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.core.QueryNodeError; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.QueryNodeParseException; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.parser.EscapeQuerySyntax; + +public class PhraseSlopQueryNode extends QueryNodeImpl implements FieldableNode { + + private static final long serialVersionUID = 0L; + + private int value = 0; + + /** + * @throws QueryNodeException + * @throws QueryNodeParseException + * @exception QueryNodeParseException + * throw in overridden method to disallow + */ + public PhraseSlopQueryNode(QueryNode query, int value) + throws QueryNodeException { + if (query == null) { + throw new QueryNodeError(new MessageImpl( + QueryParserMessages.NODE_ACTION_NOT_SUPPORTED, "query", "null")); + } + + this.value = value; + setLeaf(false); + allocate(); + add(query); + } + + public QueryNode getChild() { + return getChildren().get(0); + } + + public int getValue() { + return this.value; + } + + private CharSequence getValueString() { + Float f = new Float(this.value); + if (f == f.longValue()) + return "" + f.longValue(); + else + return "" + f; + + } + + public String toString() { + return "" + "\n" + + getChild().toString() + "\n"; + } + + public CharSequence toQueryString(EscapeQuerySyntax escapeSyntaxParser) { + if (getChild() == null) + return ""; + return getChild().toQueryString(escapeSyntaxParser) + "~" + + getValueString(); + } + + public QueryNode cloneTree() throws CloneNotSupportedException { + PhraseSlopQueryNode clone = (PhraseSlopQueryNode) super.cloneTree(); + + clone.value = this.value; + + return clone; + } + + public CharSequence getField() { + QueryNode child = getChild(); + + if (child instanceof FieldableNode) { + return ((FieldableNode) child).getField(); + } + + return null; + + } + + public void setField(CharSequence fieldName) { + QueryNode child = getChild(); + + if (child instanceof FieldableNode) { + ((FieldableNode) child).setField(fieldName); + } + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/PrefixWildcardQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/PrefixWildcardQueryNode.java new file mode 100644 index 00000000000..d905e463ae3 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/PrefixWildcardQueryNode.java @@ -0,0 +1,57 @@ +package org.apache.lucene.queryParser.core.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 ""; + } + + public PrefixWildcardQueryNode cloneTree() throws CloneNotSupportedException { + PrefixWildcardQueryNode clone = (PrefixWildcardQueryNode) super.cloneTree(); + + // nothing to do here + + return clone; + } +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/ProximityQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/ProximityQueryNode.java new file mode 100644 index 00000000000..eba8c4813d7 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/ProximityQueryNode.java @@ -0,0 +1,251 @@ +package org.apache.lucene.queryParser.core.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.core.QueryNodeError; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.parser.EscapeQuerySyntax; + +/** + * A {@link ProximityQueryNode} represents a query where the terms should meet + * specific distance conditions. (a b c) WITHIN [SENTENCE|PARAGRAPH|NUMBER] + * [INORDER] ("a" "b" "c") WITHIN [SENTENCE|PARAGRAPH|NUMBER] [INORDER] + * + * TODO: Add this to the future original Lucene parser/processor/builder + */ +public class ProximityQueryNode extends BooleanQueryNode { + + private static final long serialVersionUID = 9018220596680832916L; + + public enum Type { + PARAGRAPH, SENTENCE, NUMBER; + + CharSequence toQueryString() { + switch (this) { + case PARAGRAPH: + return "WITHIN PARAGRAPH"; + case SENTENCE: + return "WITHIN SENTENCE"; + case NUMBER: + return "WITHIN"; + default: + return "WITHIN SENTENCE"; + } + } + + public String toString() { + switch (this) { + case PARAGRAPH: + return "PARAGRAPH"; + case SENTENCE: + return "SENTENCE"; + case NUMBER: + return "NUMBER"; + default: + return "NUMBER"; + } + } + } + + // utility class + static public class ProximityType { + int pDistance = 0; + + Type pType = null; + + public ProximityType(Type type) { + this(type, 0); + } + + public ProximityType(Type type, int distance) { + this.pType = type; + this.pDistance = distance; + } + } + + private Type proximityType = Type.SENTENCE; + private int distance = -1; + private boolean inorder = false; + private CharSequence field = null; + + /** + * @param clauses + * - QueryNode children + * @param field + * - field name + * @param type + * - type of proximity query + * @param distance + * - positive integer that specifies the distance + * @param inorder + * - true, if the tokens should be matched in the order of the + * clauses + */ + public ProximityQueryNode(List 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 clauses, CharSequence field, + Type type, boolean inorder) { + this(clauses, field, type, -1, inorder); + } + + static private void clearFields(List 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 ""; + StringBuilder sb = new StringBuilder(); + sb.append(""); + for (QueryNode child : getChildren()) { + sb.append("\n"); + sb.append(child.toString()); + } + sb.append("\n"); + 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; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/QueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/QueryNode.java new file mode 100644 index 00000000000..f1afdaec59b --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/QueryNode.java @@ -0,0 +1,95 @@ +package org.apache.lucene.queryParser.core.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.core.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 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 children); + + // reset the children of a node + public void set(List 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 getTags(); + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/QueryNodeImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/QueryNodeImpl.java new file mode 100644 index 00000000000..bf5525b4bd2 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/QueryNodeImpl.java @@ -0,0 +1,225 @@ +package org.apache.lucene.queryParser.core.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.core.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 tags = new Hashtable(); + + private List clauses = null; + + protected void allocate() { + + if (this.clauses == null) { + this.clauses = new ArrayList(); + + } 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 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 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(); + + // copy children + if (this.clauses != null) { + List localClauses = new ArrayList(); + 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 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: + * + * @see org.apache.lucene.queryParser.core.nodes.QueryNode#toString() + */ + public String toString() { + return super.toString(); + } + + /** + * @see org.apache.lucene.queryParser.core.nodes.QueryNode#getTag(CharSequence) + * @return a Map with all tags for this QueryNode + */ + @SuppressWarnings( { "unchecked" }) + public Map getTags() { + return (Map) this.tags.clone(); + } + +} // end class QueryNodeImpl diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/QuotedFieldQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/QuotedFieldQueryNode.java new file mode 100644 index 00000000000..08d88a38363 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/QuotedFieldQueryNode.java @@ -0,0 +1,64 @@ +package org.apache.lucene.queryParser.core.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.core.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 ""; + } + + public QuotedFieldQueryNode cloneTree() throws CloneNotSupportedException { + QuotedFieldQueryNode clone = (QuotedFieldQueryNode) super.cloneTree(); + // nothing to do here + return clone; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/SlopQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/SlopQueryNode.java new file mode 100644 index 00000000000..516925c4f66 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/SlopQueryNode.java @@ -0,0 +1,116 @@ +package org.apache.lucene.queryParser.core.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.core.QueryNodeError; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.parser.EscapeQuerySyntax; + +/** + * A {@link SlopQueryNode} represents phrase query with a slop. + * + * From Lucene FAQ: Is there a way to use a proximity operator (like near or + * within) with Lucene? There is a variable called slop that allows you to + * perform NEAR/WITHIN-like queries. By default, slop is set to 0 so that only + * exact phrases will match. When using TextParser you can use this syntax to + * specify the slop: "doug cutting"~2 will find documents that contain + * "doug cutting" as well as ones that contain "cutting doug". + */ +public class SlopQueryNode extends QueryNodeImpl implements FieldableNode { + + private static final long serialVersionUID = 0L; + + private int value = 0; + + /** + * @param query + * - QueryNode Tree with the phrase + * @param value + * - slop value + */ + public SlopQueryNode(QueryNode query, int value) { + if (query == null) { + throw new QueryNodeError(new MessageImpl( + QueryParserMessages.NODE_ACTION_NOT_SUPPORTED, "query", "null")); + } + + this.value = value; + setLeaf(false); + allocate(); + add(query); + } + + public QueryNode getChild() { + return getChildren().get(0); + } + + public int getValue() { + return this.value; + } + + private CharSequence getValueString() { + Float f = new Float(this.value); + if (f == f.longValue()) + return "" + f.longValue(); + else + return "" + f; + + } + + public String toString() { + return "" + "\n" + + getChild().toString() + "\n"; + } + + 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); + } + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/TextableQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/TextableQueryNode.java new file mode 100644 index 00000000000..7bf9c55845a --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/TextableQueryNode.java @@ -0,0 +1,26 @@ +package org.apache.lucene.queryParser.core.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); + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/TokenizedPhraseQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/TokenizedPhraseQueryNode.java new file mode 100644 index 00000000000..cf652ce3199 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/TokenizedPhraseQueryNode.java @@ -0,0 +1,104 @@ +package org.apache.lucene.queryParser.core.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.core.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 ""; + StringBuilder sb = new StringBuilder(); + sb.append(""); + for (QueryNode child : getChildren()) { + sb.append("\n"); + sb.append(child.toString()); + } + sb.append("\n"); + 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 children = getChildren(); + + if (children == null || children.size() == 0) { + return null; + + } else { + return ((FieldableNode) children.get(0)).getField(); + } + + } + + public void setField(CharSequence fieldName) { + List children = getChildren(); + + if (children != null) { + + for (QueryNode child : getChildren()) { + + if (child instanceof FieldableNode) { + ((FieldableNode) child).setField(fieldName); + } + + } + + } + + } + +} // end class MultitermQueryNode diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/WildcardQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/WildcardQueryNode.java new file mode 100644 index 00000000000..9458e69c61a --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/WildcardQueryNode.java @@ -0,0 +1,63 @@ +package org.apache.lucene.queryParser.core.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.core.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 ""; + } + + public WildcardQueryNode cloneTree() throws CloneNotSupportedException { + WildcardQueryNode clone = (WildcardQueryNode) super.cloneTree(); + + // nothing to do here + + return clone; + } +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/package.html b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/package.html new file mode 100644 index 00000000000..20255ee78d1 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/nodes/package.html @@ -0,0 +1,89 @@ + + + + + + + + +Contains query nodes that are commonly used by query parser implementations + +

Query Nodes

+

+The package org.apache.lucene.queryParser.nodes contains all the basic query nodes. The interface +that represents a query node is {@link org.apache.lucene.queryParser.core.nodes.QueryNode}. Every query node must be serializable. +

+

+{@link org.apache.lucene.queryParser.core.nodes.QueryNode}s are used by the text parser to create a syntax tree. +These nodes are designed to be used by UI or other text parsers. +The default Lucene text parser is {@link org.apache.lucene.queryParser.original.parser.OriginalSyntaxParser}, +it implements original syntax. +

+

+{@link org.apache.lucene.queryParser.core.nodes.QueryNode} interface should be implemented by all query nodes, +the class {@link org.apache.lucene.queryParser.core.nodes.QueryNodeImpl} implements {@link org.apache.lucene.queryParser.core.nodes.QueryNode} and is extended +by all current query node implementations. +

+

+A query node tree can be printed to the a stream, and it generates a pseudo XML representation +with all the nodes. +

+

+A query node tree can also generate a query string that can be parsed back by the original text parser, +at this point only the original lucene syntax is supported. +

+

+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
  • +
  • SlopQueryNode - phrase slop
  • +
  • FuzzyQueryNode - fuzzy node
  • +
  • ParametricRangeQueryNode - used for parametric field:[low_value TO high_value]
  • +
  • ProximityQueryNode - used for proximity search
  • +
  • TokenizedPhraseQueryNode - used by tokenizers/lemmatizers/analizers for phrases/autophrases
  • +
+

+

+Leaf Nodes: +

    +
  • FieldQueryNode - field/value node
  • +
  • PathQueryNode - {@link org.apache.lucene.queryParser.core.nodes.QueryNode} object used with path-like queries
  • +
  • OpaqueQueryNode - Used as for part of the query that can be parsed by other parsers. schema/value
  • +
  • ParametricQueryNode - used for parametric field [>=|<=|=|<|>] value
  • +
  • PrefixWildcardQueryNode - non-phrase wildcard query
  • +
  • QuotedFieldQUeryNode - regular phrase node
  • +
  • WildcardQueryNode - non-phrase wildcard query
  • +
+

+

+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
  • +
+

+ + diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/package.html b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/package.html new file mode 100644 index 00000000000..ff80c35a504 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/package.html @@ -0,0 +1,59 @@ + + + + + + + + +Contains the core classes of the flexible query parser framework + +

Flexible Query Parser

+ +

+This package contains the necessary classes to implement a query parser. +

+ +

+A query parser is divided in at least 2 phases, text parsing and query building, and one optional phase called query processing. +

+ +

First Phase: Text Parsing

+

+The text parsing phase is performed by a text parser, which implements {@link org.apache.lucene.queryParser.core.parser.SyntaxParser} interface. +A text parser is responsible to get a query string and convert it to a {@link org.apache.lucene.queryParser.core.nodes.QueryNode} tree, +which is an object structure that represents the elements defined in the query string. +

+ +

Second (optional) Phase: Query Processing

+

+The query processing phase is performed by a query processor, which implements {@link org.apache.lucene.queryParser.core.processors.QueryNodeProcessor}. +A query processor is responsible to perform any processing on a {@link org.apache.lucene.queryParser.core.nodes.QueryNode} tree. This phase +is optional and is used only if an extra processing, validation, query expansion, etc needs to be perfomed in a {@link org.apache.lucene.queryParser.core.nodes.QueryNode} tree. +The {@link org.apache.lucene.queryParser.core.nodes.QueryNode} tree can be either be generated by a text parser or programmatically created. +

+ +

Third Phase: Query Building

+

+The query building phase is performed by a query builder, which implements {@link org.apache.lucene.queryParser.core.builders.QueryBuilder}. +A query builder is responsible to convert a {@link org.apache.lucene.queryParser.core.nodes.QueryNode} tree into an arbitrary object, which +is usually used to be executed against a search index. +

+ + + diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/parser/EscapeQuerySyntax.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/parser/EscapeQuerySyntax.java new file mode 100644 index 00000000000..be03a6af66c --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/parser/EscapeQuerySyntax.java @@ -0,0 +1,41 @@ +package org.apache.lucene.queryParser.core.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); +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/parser/SyntaxParser.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/parser/SyntaxParser.java new file mode 100644 index 00000000000..fde61a1a7b6 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/parser/SyntaxParser.java @@ -0,0 +1,36 @@ +package org.apache.lucene.queryParser.core.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.core.QueryNodeParseException; +import org.apache.lucene.queryParser.core.nodes.QueryNode; + +/** + * A parser needs to implement {@link SyntaxParser} interface + */ +public interface SyntaxParser { + /** + * @param query + * - query data to be parsed + * @param field + * - default field name + * @return QueryNode tree + */ + public QueryNode parse(CharSequence query, CharSequence field) + throws QueryNodeParseException; +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/parser/package.html b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/parser/package.html new file mode 100644 index 00000000000..3202d8dfc76 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/parser/package.html @@ -0,0 +1,44 @@ + + + + + + + + +Contains the necessary interfaces to implement text parsers + +

Parser

+

+The package org.apache.lucene.queryParser.parser 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. + +

+

+ +

+ + diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/NoChildOptimizationQueryNodeProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/NoChildOptimizationQueryNodeProcessor.java new file mode 100644 index 00000000000..a34b9abb079 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/NoChildOptimizationQueryNodeProcessor.java @@ -0,0 +1,90 @@ +package org.apache.lucene.queryParser.core.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.core.QueryNodeException; +import org.apache.lucene.queryParser.core.nodes.BooleanQueryNode; +import org.apache.lucene.queryParser.core.nodes.BoostQueryNode; +import org.apache.lucene.queryParser.core.nodes.DeletedQueryNode; +import org.apache.lucene.queryParser.core.nodes.MatchNoDocsQueryNode; +import org.apache.lucene.queryParser.core.nodes.ModifierQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.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 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 setChildrenOrder(List children) + throws QueryNodeException { + + return children; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/QueryNodeProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/QueryNodeProcessor.java new file mode 100644 index 00000000000..b58fbcdbed6 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/QueryNodeProcessor.java @@ -0,0 +1,79 @@ +package org.apache.lucene.queryParser.core.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.core.QueryNodeException; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.core.nodes.QueryNode; + +/** + *

+ * A {@link QueryNodeProcessor} is an interface for classes that process a + * {@link QueryNode} 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. + * + * @see QueryNode + * @see QueryNodeProcessor + * @see QueryConfigHandler + */ +public interface QueryNodeProcessor { + + /** + * Processes a query node tree. It may return the same or another query tree. + * I should never return null. + * + * @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 null + * + * @return the {@link QueryConfigHandler} associated to the query tree if any, + * otherwise it returns null + */ + public QueryConfigHandler getQueryConfigHandler(); + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/QueryNodeProcessorImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/QueryNodeProcessorImpl.java new file mode 100644 index 00000000000..97bedd043e5 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/QueryNodeProcessorImpl.java @@ -0,0 +1,253 @@ +package org.apache.lucene.queryParser.core.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.core.QueryNodeException; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.core.nodes.QueryNode; + +/** + *

+ * This is a default implementation for the {@link QueryNodeProcessor} + * interface, it's an abstract class, so it should be extended by classes that + * want to process a {@link QueryNode} tree. + *

+ *

+ * This class process {@link QueryNode}s from left to right in the tree. While + * it's walking down the tree, for every node, + * {@link #preProcessNode(QueryNode)} is invoked. After a node's children are + * processed, {@link #postProcessNode(QueryNode)} is invoked for that node. + * {@link #setChildrenOrder(List)} is invoked before + * {@link #postProcessNode(QueryNode)} only if the node has at least one child, + * in {@link #setChildrenOrder(List)} the implementor might redefine the + * children order or remove any children from the children list. + *

+ *

+ * Here is an example about how it process the nodes: + *

+ * + *
+ *      a
+ *     / \
+ *    b   e
+ *   / \
+ *  c   d
+ * 
+ * + * Here is the order the methods would be invoked for the tree described above: + * + *
+ *      preProcessNode( a );
+ *      preProcessNode( b );
+ *      preProcessNode( c );
+ *      postProcessNode( c );
+ *      preProcessNode( d );
+ *      postProcessNode( d );
+ *      setChildrenOrder( bChildrenList );
+ *      postProcessNode( b );
+ *      preProcessNode( e );
+ *      postProcessNode( e );
+ *      setChildrenOrder( aChildrenList );
+ *      postProcessNode( a )
+ * 
+ * + * @see org.apache.lucene.queryParser.core.processors.QueryNodeProcessor + */ +public abstract class QueryNodeProcessorImpl implements QueryNodeProcessor { + + private ArrayList childrenListPool = new ArrayList(); + + private QueryConfigHandler queryConfig; + + public QueryNodeProcessorImpl() { + // empty constructor + } + + public QueryNodeProcessorImpl(QueryConfigHandler queryConfigHandler) { + this.queryConfig = queryConfigHandler; + } + + public QueryNode process(QueryNode queryTree) throws QueryNodeException { + return processIteration(queryTree); + } + + private QueryNode processIteration(QueryNode queryTree) + throws QueryNodeException { + queryTree = preProcessNode(queryTree); + + processChildren(queryTree); + + queryTree = postProcessNode(queryTree); + + return queryTree; + + } + + /** + * This method is called every time a child is processed. + * + * @param queryTree + * the query node child to be processed + * @throws QueryNodeException + * if something goes wrong during the query node processing + */ + protected void processChildren(QueryNode queryTree) throws QueryNodeException { + + List 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 orderedChildrenList = setChildrenOrder(newChildren); + + queryTree.set(orderedChildrenList); + + } finally { + newChildren.beingUsed = false; + } + + } + + } + + private ChildrenList allocateChildrenList() { + ChildrenList list = null; + + for (ChildrenList auxList : this.childrenListPool) { + + if (!auxList.beingUsed) { + list = auxList; + list.clear(); + + break; + + } + + } + + if (list == null) { + list = new ChildrenList(); + this.childrenListPool.add(list); + + } + + list.beingUsed = true; + + return list; + + } + + /** + * For reference about this method check: + * {@link QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler)}. + * + * @param queryConfigHandler + * the query configuration handler to be set. + * + * @see QueryNodeProcessor#getQueryConfigHandler() + * @see QueryConfigHandler + */ + public void setQueryConfigHandler(QueryConfigHandler queryConfigHandler) { + this.queryConfig = queryConfigHandler; + } + + /** + * For reference about this method check: + * {@link QueryNodeProcessor#getQueryConfigHandler()}. + * + * @return QueryConfigHandler the query configuration handler to be set. + * + * @see QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler) + * @see QueryConfigHandler + */ + public QueryConfigHandler getQueryConfigHandler() { + return this.queryConfig; + } + + /** + * This method is invoked for every node when walking down the tree. + * + * @param node + * the query node to be pre-processed + * + * @return a query node + * + * @throws QueryNodeException + * if something goes wrong during the query node processing + */ + abstract protected QueryNode preProcessNode(QueryNode node) + throws QueryNodeException; + + /** + * This method is invoked for every node when walking up the tree. + * + * @param node + * node the query node to be post-processed + * + * @return a query node + * + * @throws QueryNodeException + * if something goes wrong during the query node processing + */ + abstract protected QueryNode postProcessNode(QueryNode node) + throws QueryNodeException; + + /** + * This method is invoked for every node that has at least on child. It's + * invoked right before {@link #postProcessNode(QueryNode)} is invoked. + * + * @param children + * the list containing all current node's children + * + * @return a new list containing all children that should be set to the + * current node + * + * @throws QueryNodeException + * if something goes wrong during the query node processing + */ + abstract protected List setChildrenOrder(List children) + throws QueryNodeException; + + private static class ChildrenList extends ArrayList { + + private static final long serialVersionUID = -2613518456949297135L; + + boolean beingUsed; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/QueryNodeProcessorPipeline.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/QueryNodeProcessorPipeline.java new file mode 100644 index 00000000000..d9e591cb528 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/QueryNodeProcessorPipeline.java @@ -0,0 +1,128 @@ +package org.apache.lucene.queryParser.core.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.core.QueryNodeException; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.core.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 processors = new LinkedList(); + + private QueryConfigHandler queryConfig; + + /** + * Constructs an empty query node processor pipeline. + */ + public QueryNodeProcessorPipeline() { + // empty constructor + } + + /** + * Constructs with a {@link QueryConfigHandler} object. + */ + public QueryNodeProcessorPipeline(QueryConfigHandler queryConfigHandler) { + this.queryConfig = queryConfigHandler; + } + + /** + * For reference about this method check: + * {@link QueryNodeProcessor#getQueryConfigHandler()}. + * + * @return QueryConfigHandler the query configuration handler to be set. + * + * @see QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler) + * @see QueryConfigHandler + */ + public QueryConfigHandler getQueryConfigHandler() { + return this.queryConfig; + } + + /** + * For reference about this method check: + * {@link QueryNodeProcessor#process(QueryNode)}. + * + * @param queryTree + * the query node tree to be processed + * + * @throws QueryNodeException + * if something goes wrong during the query node processing + * + * @see QueryNode + */ + public QueryNode process(QueryNode queryTree) throws QueryNodeException { + + for (QueryNodeProcessor processor : this.processors) { + queryTree = processor.process(queryTree); + } + + return queryTree; + + } + + /** + * Adds a processor to the pipeline, it's always added to the end of the + * pipeline. + * + * @param processor + * the processor to be added + */ + public void addProcessor(QueryNodeProcessor processor) { + this.processors.add(processor); + + processor.setQueryConfigHandler(this.queryConfig); + + } + + /** + * For reference about this method check: + * {@link QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler)}. + * + * @param queryConfigHandler + * the query configuration handler to be set. + * + * @see QueryNodeProcessor#getQueryConfigHandler() + * @see QueryConfigHandler + */ + public void setQueryConfigHandler(QueryConfigHandler queryConfigHandler) { + this.queryConfig = queryConfigHandler; + + for (QueryNodeProcessor processor : this.processors) { + processor.setQueryConfigHandler(this.queryConfig); + } + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/RemoveDeletedQueryNodesProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/RemoveDeletedQueryNodesProcessor.java new file mode 100644 index 00000000000..e19df6b4ae7 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/RemoveDeletedQueryNodesProcessor.java @@ -0,0 +1,109 @@ +package org.apache.lucene.queryParser.core.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.core.QueryNodeException; +import org.apache.lucene.queryParser.core.nodes.DeletedQueryNode; +import org.apache.lucene.queryParser.core.nodes.MatchNoDocsQueryNode; +import org.apache.lucene.queryParser.core.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 children = node.getChildren(); + boolean removeBoolean = false; + + if (children == null || children.size() == 0) { + removeBoolean = true; + + } else { + removeBoolean = true; + + for (Iterator it = children.iterator(); it.hasNext();) { + + if (!(it.next() instanceof DeletedQueryNode)) { + removeBoolean = false; + break; + + } + + } + + } + + if (removeBoolean) { + return new DeletedQueryNode(); + } + + } + + return node; + + } + + protected List setChildrenOrder(List 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; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/package.html b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/package.html new file mode 100644 index 00000000000..ae599fd6026 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/processors/package.html @@ -0,0 +1,57 @@ + + + + + + + + +Interfaces and implementations used by query node processors + +

Query Node Processors

+

+The package org.apache.lucene.queryParser.processors contains interfaces +that should be implemented by every query node processor. +

+

+The interface that every query node processor should implement is {@link org.apache.lucene.queryParser.core.processors.QueryNodeProcessor}. +

+

+A query node processor should be used to process a {@link org.apache.lucene.queryParser.core.nodes.QueryNode} tree. +{@link org.apache.lucene.queryParser.core.nodes.QueryNode} trees can be programmatically created or generated by a +text parser. See {@link org.apache.lucene.queryParser.core.parser} for more details about text parsers. +

+ +

+A query node processor should be used to process a {@link org.apache.lucene.queryParser.core.nodes.QueryNode} tree. +{@link org.apache.lucene.queryParser.core.nodes.QueryNode} trees can be programmatically created or generated by a +text parser. See {@link org.apache.lucene.queryParser.core.parser} for more details about text parsers. +

+ +

+A pipeline of processors can be assembled using {@link org.apache.lucene.queryParser.core.processors.QueryNodeProcessorPipeline}. +

+ +

+Implementors may want to extend {@link org.apache.lucene.queryParser.core.processors.QueryNodeProcessorImpl}, which simplifies +the implementation, because it walks automatically the {@link org.apache.lucene.queryParser.core.nodes.QueryNode}. See +{@link org.apache.lucene.queryParser.core.processors.QueryNodeProcessorImpl} for more details. +

+ + + diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/util/QueryNodeOperation.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/util/QueryNodeOperation.java new file mode 100644 index 00000000000..e43ac73f4c9 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/util/QueryNodeOperation.java @@ -0,0 +1,94 @@ +package org.apache.lucene.queryParser.core.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.core.QueryNodeError; +import org.apache.lucene.queryParser.core.nodes.AndQueryNode; +import org.apache.lucene.queryParser.core.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 children = new ArrayList(); + 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; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/util/UnescapedCharSequence.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/util/UnescapedCharSequence.java new file mode 100644 index 00000000000..c00904eac84 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/util/UnescapedCharSequence.java @@ -0,0 +1,141 @@ +package org.apache.lucene.queryParser.core.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(); + } +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/util/package.html b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/util/package.html new file mode 100644 index 00000000000..dc76a02d0e3 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/core/util/package.html @@ -0,0 +1,29 @@ + + + + + + + +Utility classes to used with the Query Parser +

Utility classes to used with the Query Parser

+

+This package contains utility classes used with the query parsers. +

+ + diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/MultiFieldQueryParserWrapper.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/MultiFieldQueryParserWrapper.java new file mode 100644 index 00000000000..e05c91feb6c --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/MultiFieldQueryParserWrapper.java @@ -0,0 +1,269 @@ +package org.apache.lucene.queryParser.original; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Map; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.queryParser.ParseException; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.Query; + +/** + * This class behaves as the as the lucene 2.4 MultiFieldQueryParser class, but uses the new + * query parser interface instead of the old one.
+ *
+ * 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.
+ * + * @deprecated this class will be removed soon, it's a temporary class to be + * used along the transition from the old query parser to the new + * one + */ +public class MultiFieldQueryParserWrapper extends QueryParserWrapper { + + /** + * Creates a MultiFieldQueryParser. Allows passing of a map with term to + * Boost, and the boost to apply to each term. + * + *

+ * 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 + * title and body): + *

+ * + * + * (title:term1 body:term1) (title:term2 body:term2) + * + * + *

+ * When setDefaultOperator(AND_OPERATOR) is set, the result will be: + *

+ * + * + * +(title:term1 body:term1) +(title:term2 body:term2) + * + * + *

+ * When you pass a boost (title=>5 body=>10) you can get + *

+ * + * + * +(title:term1^5.0 body:term1^10.0) +(title:term2^5.0 body:term2^10.0) + * + * + *

+ * In other words, all the query's terms must appear, but it doesn't matter in + * what fields they appear. + *

+ */ + @SuppressWarnings("unchecked") +public MultiFieldQueryParserWrapper(String[] fields, Analyzer analyzer, Map boosts) { + this(fields, analyzer); + OriginalQueryParserHelper qpHelper = (OriginalQueryParserHelper) getQueryParserHelper(); + + qpHelper.setMultiFields(fields); + qpHelper.setFieldsBoost(boosts); + + } + + /** + * Creates a MultiFieldQueryParser. + * + *

+ * 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 + * title and body): + *

+ * + * + * (title:term1 body:term1) (title:term2 body:term2) + * + * + *

+ * When setDefaultOperator(AND_OPERATOR) is set, the result will be: + *

+ * + * + * +(title:term1 body:term1) +(title:term2 body:term2) + * + * + *

+ * In other words, all the query's terms must appear, but it doesn't matter in + * what fields they appear. + *

+ */ + public MultiFieldQueryParserWrapper(String[] fields, Analyzer analyzer) { + super(null, analyzer); + + OriginalQueryParserHelper qpHelper = (OriginalQueryParserHelper) getQueryParserHelper(); + qpHelper.setAnalyzer(analyzer); + + qpHelper.setMultiFields(fields); + } + + /** + * Parses a query which searches on the fields specified. + *

+ * If x fields are specified, this effectively constructs: + * + *

+   * <code>
+   * (field1:query1) (field2:query2) (field3:query3)...(fieldx:queryx)
+   * </code>
+   * 
+ * + * @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. + *

+ * + *

+   * 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>
+   * 
+ *

+ * The code above would construct a query: + * + *

+   * <code>
+   * (filename:query) +(contents:query) -(description:query)
+   * </code>
+   * 
+ * + * @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. + *

+ * + *

+   * 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>
+   * 
+ *

+ * The code above would construct a query: + * + *

+   * <code>
+   * (filename:query1) +(contents:query2) -(description:query3)
+   * </code>
+   * 
+ * + * @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; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/OriginalQueryParserHelper.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/OriginalQueryParserHelper.java new file mode 100644 index 00000000000..ee5538d4134 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/OriginalQueryParserHelper.java @@ -0,0 +1,430 @@ +package org.apache.lucene.queryParser.original; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.text.Collator; +import java.util.Locale; +import java.util.Map; +import java.util.TooManyListenersException; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.document.DateTools; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.QueryParserHelper; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.builders.OriginalQueryTreeBuilder; +import org.apache.lucene.queryParser.original.config.AllowLeadingWildcardAttribute; +import org.apache.lucene.queryParser.original.config.AnalyzerAttribute; +import org.apache.lucene.queryParser.original.config.DateResolutionAttribute; +import org.apache.lucene.queryParser.original.config.FieldDateResolutionMapAttribute; +import org.apache.lucene.queryParser.original.config.DefaultOperatorAttribute; +import org.apache.lucene.queryParser.original.config.DefaultPhraseSlopAttribute; +import org.apache.lucene.queryParser.original.config.FieldBoostMapAttribute; +import org.apache.lucene.queryParser.original.config.FuzzyAttribute; +import org.apache.lucene.queryParser.original.config.LocaleAttribute; +import org.apache.lucene.queryParser.original.config.LowercaseExpandedTermsAttribute; +import org.apache.lucene.queryParser.original.config.MultiFieldAttribute; +import org.apache.lucene.queryParser.original.config.MultiTermRewriteMethodAttribute; +import org.apache.lucene.queryParser.original.config.OriginalQueryConfigHandler; +import org.apache.lucene.queryParser.original.config.PositionIncrementsAttribute; +import org.apache.lucene.queryParser.original.config.RangeCollatorAttribute; +import org.apache.lucene.queryParser.original.config.DefaultOperatorAttribute.Operator; +import org.apache.lucene.queryParser.original.nodes.RangeQueryNode; +import org.apache.lucene.queryParser.original.parser.OriginalSyntaxParser; +import org.apache.lucene.queryParser.original.processors.OriginalQueryNodeProcessorPipeline; +import org.apache.lucene.search.FuzzyQuery; +import org.apache.lucene.search.MultiTermQuery; +import org.apache.lucene.search.Query; + +/** + *

+ * This class is a helper that enables users to easily use the Lucene query + * parser. + *

+ *

+ * To construct a Query object from a query string, use the + * {@link #parse(String, String)} method: + *

    + * OriginalQueryParserHelper queryParserHelper = new OriginalQueryParserHelper();
    + * Query query = queryParserHelper.parse("a AND b", "defaultField"); + *
+ *

+ * To change any configuration before parsing the query string do, for example: + *

+ *

    + * // the query config handler returned by {@link OriginalQueryParserHelper} is a + * {@link OriginalQueryConfigHandler}
    + * queryParserHelper.getQueryConfigHandler().setAnalyzer(new + * WhitespaceAnalyzer()); + *
+ *

+ * The syntax for query strings is as follows (copied from the old QueryParser + * javadoc): + *

    + * A Query is a series of clauses. A clause may be prefixed by: + *
      + *
    • a plus (+) or a minus (-) sign, indicating that + * the clause is required or prohibited respectively; or + *
    • a term followed by a colon, indicating the field to be searched. This + * enables one to construct queries which search multiple fields. + *
    + * + * A clause may be either: + *
      + *
    • a term, indicating all the documents that contain this term; or + *
    • a nested query, enclosed in parentheses. Note that this may be used with + * a +/- prefix to require any of a set of terms. + *
    + * + * Thus, in BNF, the query grammar is: + * + *
    + *   Query  ::= ( Clause )*
    + *   Clause ::= ["+", "-"] [<TERM> ":"] ( <TERM> | "(" Query ")" )
    + * 
    + * + *

    + * Examples of appropriately formatted queries can be found in the query syntax + * documentation. + *

    + *
+ *

+ * The text parser used by this helper is a {@link OriginalSyntaxParser}. + *

+ *

+ * The query node processor used by this helper is a + * {@link OriginalQueryNodeProcessorPipeline}. + *

+ *

+ * The builder used by this helper is a {@link OriginalQueryTreeBuilder}. + *

+ * + * @see OriginalQueryParserHelper + * @see OriginalQueryConfigHandler + * @see OriginalSyntaxParser + * @see OriginalQueryNodeProcessorPipeline + * @see OriginalQueryTreeBuilder + */ +public class OriginalQueryParserHelper extends QueryParserHelper { + + /** + * Constructs a {@link OriginalQueryParserHelper} object. + */ + public OriginalQueryParserHelper() { + super(new OriginalQueryConfigHandler(), new OriginalSyntaxParser(), + new OriginalQueryNodeProcessorPipeline(null), + new OriginalQueryTreeBuilder()); + } + + /** + * Constructs a {@link OriginalQueryParserHelper} object and sets an + * {@link Analyzer} to it. The same as: + * + *

    + * OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + * qp.getQueryConfigHandler().setAnalyzer(analyzer); + *
+ * + * @param analyzer + * the analyzer to be used by this query parser helper + */ + public OriginalQueryParserHelper(Analyzer analyzer) { + this(); + + this.setAnalyzer(analyzer); + } + + public String toString(){ + return ""; + } + + /** + * Overrides {@link QueryParserHelper#parse(String, String)} so it casts the + * return object to {@link Query}. For more reference about this method, check + * {@link QueryParserHelper#parse(String, String)}. + * + * @param query + * the query string + * @param defaultField + * the default field used by the text parser + * + * @return the object built from the query + * + * @throws QueryNodeException + * if something wrong happens along the three phases + */ + @Override + public Query parse(String query, String defaultField) + throws QueryNodeException { + + return (Query) super.parse(query, defaultField); + + } + + /** + * Gets implicit operator setting, which will be either {@link Operator#AND} + * or {@link Operator#OR}. + */ + public Operator getDefaultOperator() { + DefaultOperatorAttribute attr = (DefaultOperatorAttribute) getQueryConfigHandler().getAttribute(DefaultOperatorAttribute.class); + return attr.getOperator(); + } + + /** + * Sets the collator used to determine index term inclusion in ranges for + * RangeQuerys. + *

+ * WARNING: Setting the rangeCollator to a non-null collator + * using this method will cause every single index Term in the Field + * referenced by lowerTerm and/or upperTerm to be examined. Depending on the + * number of index Terms in this Field, the operation could be very slow. + * + * @param collator + * the collator to use when constructing {@link RangeQueryNode}s + */ + public void setRangeCollator(Collator collator) { + RangeCollatorAttribute attr = (RangeCollatorAttribute) getQueryConfigHandler().getAttribute(RangeCollatorAttribute.class); + attr.setDateResolution(collator); + } + + /** + * @return the collator used to determine index term inclusion in ranges for + * RangeQuerys. + */ + public Collator getRangeCollator() { + RangeCollatorAttribute attr = (RangeCollatorAttribute) getQueryConfigHandler().getAttribute(RangeCollatorAttribute.class); + return attr.getRangeCollator(); + } + + /** + * Sets the boolean operator of the QueryParser. In default mode ( + * {@link Operator#OR}) terms without any modifiers are considered optional: + * for example capital of Hungary is equal to + * capital OR of OR Hungary.
+ * In {@link Operator#AND} mode terms are considered to be in conjunction: the + * above mentioned query is parsed as capital AND of AND Hungary + */ + public void setDefaultOperator(Operator operator) { + DefaultOperatorAttribute attr = (DefaultOperatorAttribute) getQueryConfigHandler().getAttribute(DefaultOperatorAttribute.class); + attr.setOperator(operator); + } + + /** + * Set to true to allow leading wildcard characters. + *

+ * When set, * or ? are allowed as the first + * character of a PrefixQuery and WildcardQuery. Note that this can produce + * very slow queries on big indexes. + *

+ * Default: false. + */ + public void setLowercaseExpandedTerms(boolean lowercaseExpandedTerms) { + LowercaseExpandedTermsAttribute attr= (LowercaseExpandedTermsAttribute) getQueryConfigHandler().getAttribute(LowercaseExpandedTermsAttribute.class); + attr.setLowercaseExpandedTerms(lowercaseExpandedTerms); + } + + /** + * @see #setLowercaseExpandedTerms(boolean) + */ + public boolean getLowercaseExpandedTerms() { + LowercaseExpandedTermsAttribute attr = (LowercaseExpandedTermsAttribute) getQueryConfigHandler().getAttribute(LowercaseExpandedTermsAttribute.class); + return attr.isLowercaseExpandedTerms(); + } + + /** + * Set to true to allow leading wildcard characters. + *

+ * When set, * or ? are allowed as the first + * character of a PrefixQuery and WildcardQuery. Note that this can produce + * very slow queries on big indexes. + *

+ * Default: false. + */ + public void setAllowLeadingWildcard(boolean allowLeadingWildcard) { + AllowLeadingWildcardAttribute attr = (AllowLeadingWildcardAttribute) getQueryConfigHandler().getAttribute(AllowLeadingWildcardAttribute.class); + attr.setAllowLeadingWildcard(allowLeadingWildcard); + } + + /** + * Set to true to enable position increments in result query. + *

+ * 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. + *

+ * Default: false. + */ + public void setEnablePositionIncrements(boolean enabled) { + PositionIncrementsAttribute attr = (PositionIncrementsAttribute) getQueryConfigHandler().getAttribute(PositionIncrementsAttribute.class); + attr.setPositionIncrementsEnabled(enabled); + } + + /** + * @see #setEnablePositionIncrements(boolean) + */ + public boolean getEnablePositionIncrements() { + PositionIncrementsAttribute attr = (PositionIncrementsAttribute) getQueryConfigHandler().getAttribute(PositionIncrementsAttribute.class); + return attr.isPositionIncrementsEnabled(); + } + + /** + * By default, it uses + * {@link MultiTermQuery#CONSTANT_SCORE_AUTO_REWRITE_DEFAULT} when creating a + * prefix, wildcard and range queries. This implementation is generally + * preferable because it a) Runs faster b) Does not have the scarcity of terms + * unduly influence score c) avoids any {@link TooManyListenersException} + * exception. However, if your application really needs to use the + * old-fashioned boolean queries expansion rewriting and the above points are + * not relevant then use this change the rewrite method. + */ + public void setMultiTermRewriteMethod(MultiTermQuery.RewriteMethod method) { + MultiTermRewriteMethodAttribute attr = (MultiTermRewriteMethodAttribute) getQueryConfigHandler().getAttribute(MultiTermRewriteMethodAttribute.class); + attr.setMultiTermRewriteMethod(method); + } + + /** + * @see #setMultiTermRewriteMethod(org.apache.lucene.search.MultiTermQuery.RewriteMethod) + */ + public MultiTermQuery.RewriteMethod getMultiTermRewriteMethod() { + MultiTermRewriteMethodAttribute attr =(MultiTermRewriteMethodAttribute) getQueryConfigHandler().getAttribute(MultiTermRewriteMethodAttribute.class); + return attr.getMultiTermRewriteMethod(); + } + + public void setMultiFields(CharSequence[] fields) { + + if (fields == null) { + fields = new CharSequence[0]; + } + + MultiFieldAttribute attr = (MultiFieldAttribute) getQueryConfigHandler().addAttribute(MultiFieldAttribute.class); + attr.setFields(fields); + + } + + /** + * Set the prefix length for fuzzy queries. Default is 0. + * + * @param fuzzyPrefixLength + * The fuzzyPrefixLength to set. + */ + public void setFuzzyPrefixLength(int fuzzyPrefixLength) { + FuzzyAttribute attr = (FuzzyAttribute) getQueryConfigHandler().addAttribute(FuzzyAttribute.class); + attr.setPrefixLength(fuzzyPrefixLength); + } + + /** + * Set locale used by date range parsing. + */ + public void setLocale(Locale locale) { + LocaleAttribute attr = (LocaleAttribute) getQueryConfigHandler().addAttribute(LocaleAttribute.class); + attr.setLocale(locale); + } + + /** + * Returns current locale, allowing access by subclasses. + */ + public Locale getLocale() { + LocaleAttribute attr = (LocaleAttribute) getQueryConfigHandler().addAttribute(LocaleAttribute.class); + return attr.getLocale(); + } + + /** + * Sets the default slop for phrases. If zero, then exact phrase matches are + * required. Default value is zero. + */ + public void setDefaultPhraseSlop(int defaultPhraseSlop) { + DefaultPhraseSlopAttribute attr = (DefaultPhraseSlopAttribute) getQueryConfigHandler().addAttribute(DefaultPhraseSlopAttribute.class); + attr.setDefaultPhraseSlop(defaultPhraseSlop); + } + + public void setAnalyzer(Analyzer analyzer) { + AnalyzerAttribute attr= (AnalyzerAttribute) getQueryConfigHandler().getAttribute(AnalyzerAttribute.class); + attr.setAnalyzer(analyzer); + } + + public Analyzer getAnalyzer() { + QueryConfigHandler config = this.getQueryConfigHandler(); + + if ( config.hasAttribute(AnalyzerAttribute.class)) { + AnalyzerAttribute attr= (AnalyzerAttribute) config.getAttribute(AnalyzerAttribute.class); + return attr.getAnalyzer(); + } + + return null; + } + + /** + * @see #setAllowLeadingWildcard(boolean) + */ + public boolean getAllowLeadingWildcard() { + AllowLeadingWildcardAttribute attr = (AllowLeadingWildcardAttribute) getQueryConfigHandler().addAttribute(AllowLeadingWildcardAttribute.class); + return attr.isAllowLeadingWildcard(); + } + + /** + * Get the minimal similarity for fuzzy queries. + */ + public float getFuzzyMinSim() { + FuzzyAttribute attr = (FuzzyAttribute) getQueryConfigHandler().addAttribute(FuzzyAttribute.class); + return attr.getFuzzyMinSimilarity(); + } + + /** + * Get the prefix length for fuzzy queries. + * + * @return Returns the fuzzyPrefixLength. + */ + public int getFuzzyPrefixLength() { + FuzzyAttribute attr = (FuzzyAttribute) getQueryConfigHandler().addAttribute(FuzzyAttribute.class); + return attr.getPrefixLength(); + } + + /** + * Gets the default slop for phrases. + */ + public int getPhraseSlop() { + DefaultPhraseSlopAttribute attr = (DefaultPhraseSlopAttribute) getQueryConfigHandler().addAttribute(DefaultPhraseSlopAttribute.class); + return attr.getDefaultPhraseSlop(); + } + + /** + * Set the minimum similarity for fuzzy queries. Default is defined on + * {@link FuzzyQuery#defaultMinSimilarity}. + */ + public void setFuzzyMinSim(float fuzzyMinSim) { + FuzzyAttribute attr = (FuzzyAttribute) getQueryConfigHandler().addAttribute(FuzzyAttribute.class); + attr.setFuzzyMinSimilarity(fuzzyMinSim); + } + + public void setFieldsBoost(Map boosts) { + FieldBoostMapAttribute attr = (FieldBoostMapAttribute) getQueryConfigHandler().addAttribute(FieldBoostMapAttribute.class); + attr.setFieldBoostMap(boosts); + } + + public void setDateResolution(DateTools.Resolution dateResolution) { + DateResolutionAttribute attr = (DateResolutionAttribute) getQueryConfigHandler().addAttribute(DateResolutionAttribute.class); + attr.setDateResolution(dateResolution); + } + + public void setDateResolution(Map dateRes) { + FieldDateResolutionMapAttribute attr = (FieldDateResolutionMapAttribute) getQueryConfigHandler().addAttribute(FieldDateResolutionMapAttribute.class); + attr.setFieldDateResolutionMap(dateRes); + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/QueryParserUtil.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/QueryParserUtil.java new file mode 100644 index 00000000000..a7e1304def9 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/QueryParserUtil.java @@ -0,0 +1,189 @@ +package org.apache.lucene.queryParser.original; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.Query; + +/** + * This class defines utility methods to (help) parse query strings into + * {@link Query} objects. + */ +final public class QueryParserUtil { + + /** + * Parses a query which searches on the fields specified. + *

+ * If x fields are specified, this effectively constructs: + * + *

+   * <code>
+   * (field1:query1) (field2:query2) (field3:query3)...(fieldx:queryx)
+   * </code>
+   * 
+ * + * @param queries + * Queries strings to parse + * @param fields + * Fields to search on + * @param analyzer + * Analyzer to use + * @throws IllegalArgumentException + * if the length of the queries array differs from the length of the + * fields array + */ + public static Query parse(String[] queries, String[] fields, Analyzer analyzer) + throws QueryNodeException { + if (queries.length != fields.length) + throw new IllegalArgumentException("queries.length != fields.length"); + BooleanQuery bQuery = new BooleanQuery(); + + OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + qp.setAnalyzer(analyzer); + + for (int i = 0; i < fields.length; i++) { + Query q = qp.parse(queries[i], fields[i]); + + if (q != null && // q never null, just being defensive + (!(q instanceof BooleanQuery) || ((BooleanQuery) q).getClauses().length > 0)) { + bQuery.add(q, BooleanClause.Occur.SHOULD); + } + } + return bQuery; + } + + /** + * Parses a query, searching on the fields specified. Use this if you need to + * specify certain fields as required, and others as prohibited. + *

+ * + *

+   * 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>
+   * 
+ *

+ * The code above would construct a query: + * + *

+   * <code>
+   * (filename:query) +(contents:query) -(description:query)
+   * </code>
+   * 
+ * + * @param query + * Query string to parse + * @param fields + * Fields to search on + * @param flags + * Flags describing the fields + * @param analyzer + * Analyzer to use + * @throws IllegalArgumentException + * if the length of the fields array differs from the length of the + * flags array + */ + public static Query parse(String query, String[] fields, + BooleanClause.Occur[] flags, Analyzer analyzer) throws QueryNodeException { + if (fields.length != flags.length) + throw new IllegalArgumentException("fields.length != flags.length"); + BooleanQuery bQuery = new BooleanQuery(); + + OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + qp.setAnalyzer(analyzer); + + for (int i = 0; i < fields.length; i++) { + Query q = qp.parse(query, fields[i]); + + if (q != null && // q never null, just being defensive + (!(q instanceof BooleanQuery) || ((BooleanQuery) q).getClauses().length > 0)) { + bQuery.add(q, flags[i]); + } + } + return bQuery; + } + + /** + * Parses a query, searching on the fields specified. Use this if you need to + * specify certain fields as required, and others as prohibited. + *

+ * + *

+   * 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>
+   * 
+ *

+ * The code above would construct a query: + * + *

+   * <code>
+   * (filename:query1) +(contents:query2) -(description:query3)
+   * </code>
+   * 
+ * + * @param queries + * Queries string to parse + * @param fields + * Fields to search on + * @param flags + * Flags describing the fields + * @param analyzer + * Analyzer to use + * @throws IllegalArgumentException + * if the length of the queries, fields, and flags array differ + */ + public static Query parse(String[] queries, String[] fields, + BooleanClause.Occur[] flags, Analyzer analyzer) throws QueryNodeException { + if (!(queries.length == fields.length && queries.length == flags.length)) + throw new IllegalArgumentException( + "queries, fields, and flags array have have different length"); + BooleanQuery bQuery = new BooleanQuery(); + + OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + qp.setAnalyzer(analyzer); + + for (int i = 0; i < fields.length; i++) { + Query q = qp.parse(queries[i], fields[i]); + + if (q != null && // q never null, just being defensive + (!(q instanceof BooleanQuery) || ((BooleanQuery) q).getClauses().length > 0)) { + bQuery.add(q, flags[i]); + } + } + return bQuery; + } + + /** + * Returns a String where those characters that TextParser expects to be + * escaped are escaped by a preceding \. + */ + 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(); + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/QueryParserWrapper.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/QueryParserWrapper.java new file mode 100644 index 00000000000..850d46cc2dc --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/QueryParserWrapper.java @@ -0,0 +1,488 @@ +package org.apache.lucene.queryParser.original; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.text.Collator; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.document.DateTools; +import org.apache.lucene.document.DateTools.Resolution; +import org.apache.lucene.queryParser.ParseException; +import org.apache.lucene.queryParser.QueryParser; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.config.FieldConfig; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.parser.SyntaxParser; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessor; +import org.apache.lucene.queryParser.original.builders.OriginalQueryBuilder; +import org.apache.lucene.queryParser.original.builders.OriginalQueryTreeBuilder; +import org.apache.lucene.queryParser.original.config.AllowLeadingWildcardAttribute; +import org.apache.lucene.queryParser.original.config.AnalyzerAttribute; +import org.apache.lucene.queryParser.original.config.MultiTermRewriteMethodAttribute; +import org.apache.lucene.queryParser.original.config.DateResolutionAttribute; +import org.apache.lucene.queryParser.original.config.DefaultOperatorAttribute; +import org.apache.lucene.queryParser.original.config.DefaultPhraseSlopAttribute; +import org.apache.lucene.queryParser.original.config.LocaleAttribute; +import org.apache.lucene.queryParser.original.config.LowercaseExpandedTermsAttribute; +import org.apache.lucene.queryParser.original.config.OriginalQueryConfigHandler; +import org.apache.lucene.queryParser.original.config.PositionIncrementsAttribute; +import org.apache.lucene.queryParser.original.config.RangeCollatorAttribute; +import org.apache.lucene.queryParser.original.parser.OriginalSyntaxParser; +import org.apache.lucene.queryParser.original.processors.OriginalQueryNodeProcessorPipeline; +import org.apache.lucene.search.FuzzyQuery; +import org.apache.lucene.search.MultiTermQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.util.Parameter; + +/** + * This class performs the query parsing using the new query parser implementation, but + * keeps the old {@link QueryParser} API.
+ *
+ * This class should be used when the new query parser features are and + * the old {@link QueryParser} API are needed at the same time.
+ * + * @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 QueryParserWrapper#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 \. + */ + 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 SyntaxParser syntaxParser = new OriginalSyntaxParser(); + + private OriginalQueryConfigHandler config; + private OriginalQueryParserHelper qpHelper; + + private QueryNodeProcessor processorPipeline; + + private OriginalQueryBuilder builder = new OriginalQueryTreeBuilder(); + + private String defaultField; + + public QueryParserWrapper(String defaultField, Analyzer analyzer) { + this.defaultField = defaultField; + + this.qpHelper = new OriginalQueryParserHelper(); + + this.config = (OriginalQueryConfigHandler) qpHelper.getQueryConfigHandler(); + + this.qpHelper.setAnalyzer(analyzer); + + this.processorPipeline = new OriginalQueryNodeProcessorPipeline(this.config); + + } + + OriginalQueryParserHelper getQueryParserHelper() { + return qpHelper; + } + + 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 OriginalQueryBuilder} used to generate a {@link Query} object + * from the parsed and processed query node tree. + * + * @param builder + * the builder + */ + public void setQueryBuilder(OriginalQueryBuilder builder) { + this.builder = builder; + } + + /** + * Sets the {@link QueryNodeProcessor} used to process the query node tree + * generated by the + * {@link org.apache.lucene.queryParser.original.parser.OriginalSyntaxParser}. + * + * @param processor + * the processor + */ + 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 + */ + public void setQueryConfig(OriginalQueryConfigHandler queryConfig) { + this.config = queryConfig; + + if (this.processorPipeline != null) { + this.processorPipeline.setQueryConfigHandler(this.config); + } + + } + + /** + * Returns the query config handler used by this query parser + * + * @return the query config handler + */ + public QueryConfigHandler getQueryConfigHandler() { + return this.config; + } + + /** + * Returns {@link QueryNodeProcessor} used to process the query node tree + * generated by the + * {@link org.apache.lucene.queryParser.original.parser.OriginalSyntaxParser}. + * + * @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 MultiTermQuery.RewriteMethod getMultiTermRewriteMethod() { + if (this.config != null + && this.config.hasAttribute(MultiTermRewriteMethodAttribute.class)) { + return ((MultiTermRewriteMethodAttribute) this.config + .getAttribute(MultiTermRewriteMethodAttribute.class)) + .getMultiTermRewriteMethod(); + } + + return MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT; + + } + + 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() { + if (getMultiTermRewriteMethod() == MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE) { + return true; + } else { + return false; + } + } + + public Query parse(String query) throws ParseException { + + try { + QueryNode queryTree = this.syntaxParser.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.qpHelper.setAllowLeadingWildcard(allowLeadingWildcard); + } + + public void setMultiTermRewriteMethod(MultiTermQuery.RewriteMethod method) { + this.qpHelper.setMultiTermRewriteMethod(method); + } + + public void setDateResolution(Resolution dateResolution) { + this.qpHelper.setDateResolution(dateResolution); + } + + private Map dateRes = new HashMap(); + + public void setDateResolution(String fieldName, Resolution dateResolution) { + dateRes.put(fieldName, dateResolution); + this.qpHelper.setDateResolution(dateRes); + } + + public void setDefaultOperator(Operator op) { + + this.qpHelper + .setDefaultOperator(OR_OPERATOR.equals(op) ? org.apache.lucene.queryParser.original.config.DefaultOperatorAttribute.Operator.OR + : org.apache.lucene.queryParser.original.config.DefaultOperatorAttribute.Operator.AND); + + } + + public Operator getDefaultOperator() { + + if (this.config != null + && this.config.hasAttribute(DefaultOperatorAttribute.class)) { + + return (((DefaultOperatorAttribute) this.config + .getAttribute(DefaultOperatorAttribute.class)).getOperator() == org.apache.lucene.queryParser.original.config.DefaultOperatorAttribute.Operator.AND) ? AND_OPERATOR + : OR_OPERATOR; + + } + + return OR_OPERATOR; + + } + + public void setEnablePositionIncrements(boolean enable) { + this.qpHelper.setEnablePositionIncrements(enable); + } + + public void setFuzzyMinSim(float fuzzyMinSim) { + // TODO Auto-generated method stub + + } + + public void setFuzzyPrefixLength(int fuzzyPrefixLength) { + // TODO Auto-generated method stub + + } + + public void setLocale(Locale locale) { + this.qpHelper.setLocale(locale); + } + + public void setLowercaseExpandedTerms(boolean lowercaseExpandedTerms) { + this.qpHelper.setLowercaseExpandedTerms(lowercaseExpandedTerms); + } + + public void setPhraseSlop(int phraseSlop) { + this.qpHelper.setDefaultPhraseSlop(phraseSlop); + } + + public void setRangeCollator(Collator rc) { + this.qpHelper.setRangeCollator(rc); + } + + public void setUseOldRangeQuery(boolean useOldRangeQuery) { + if (useOldRangeQuery) { + setMultiTermRewriteMethod(MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE); + } else { + setMultiTermRewriteMethod(MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT); + } + } + + 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(); + } + + @SuppressWarnings("unchecked") +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(); + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/AnyQueryNodeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/AnyQueryNodeBuilder.java new file mode 100644 index 00000000000..27c7ba0121d --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/AnyQueryNodeBuilder.java @@ -0,0 +1,77 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.messages.MessageImpl; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.builders.QueryTreeBuilder; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.nodes.AnyQueryNode; +import org.apache.lucene.queryParser.core.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 OriginalQueryBuilder { + + public AnyQueryNodeBuilder() { + // empty constructor + } + + public BooleanQuery build(QueryNode queryNode) throws QueryNodeException { + AnyQueryNode andNode = (AnyQueryNode) queryNode; + + BooleanQuery bQuery = new BooleanQuery(); + List 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; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/BooleanQueryNodeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/BooleanQueryNodeBuilder.java new file mode 100644 index 00000000000..98577c5d413 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/BooleanQueryNodeBuilder.java @@ -0,0 +1,110 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.messages.MessageImpl; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.builders.QueryTreeBuilder; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.nodes.BooleanQueryNode; +import org.apache.lucene.queryParser.core.nodes.ModifierQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.original.parser.EscapeQuerySyntaxImpl; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.BooleanQuery.TooManyClauses; + +/** + * Builds a {@link BooleanQuery} object from a {@link BooleanQueryNode} object. + * Every children in the {@link BooleanQueryNode} object must be already tagged + * using {@link QueryTreeBuilder#QUERY_TREE_BUILDER_TAGID} with a {@link Query} + * object.
+ *
+ * It takes in consideration if the children is a {@link ModifierQueryNode} to + * define the {@link BooleanClause}. + */ +public class BooleanQueryNodeBuilder implements OriginalQueryBuilder { + + public BooleanQueryNodeBuilder() { + // empty constructor + } + + public BooleanQuery build(QueryNode queryNode) throws QueryNodeException { + BooleanQueryNode booleanNode = (BooleanQueryNode) queryNode; + + BooleanQuery bQuery = new BooleanQuery(); + List children = booleanNode.getChildren(); + + if (children != null) { + + for (QueryNode child : children) { + Object obj = child.getTag(QueryTreeBuilder.QUERY_TREE_BUILDER_TAGID); + + if (obj != null) { + Query query = (Query) obj; + + try { + bQuery.add(query, getModifierValue(child)); + + } catch (TooManyClauses ex) { + + throw new QueryNodeException(new MessageImpl( + QueryParserMessages.TOO_MANY_BOOLEAN_CLAUSES, BooleanQuery + .getMaxClauseCount(), queryNode + .toQueryString(new EscapeQuerySyntaxImpl())), ex); + + } + + } + + } + + } + + return bQuery; + + } + + private static BooleanClause.Occur getModifierValue(QueryNode node) + throws QueryNodeException { + + if (node instanceof ModifierQueryNode) { + ModifierQueryNode mNode = ((ModifierQueryNode) node); + switch (mNode.getModifier()) { + + case MOD_REQ: + return BooleanClause.Occur.MUST; + + case MOD_NOT: + return BooleanClause.Occur.MUST_NOT; + + case MOD_NONE: + return BooleanClause.Occur.SHOULD; + + } + + } + + return BooleanClause.Occur.SHOULD; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/BoostQueryNodeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/BoostQueryNodeBuilder.java new file mode 100644 index 00000000000..a4d449d7ada --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/BoostQueryNodeBuilder.java @@ -0,0 +1,54 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.builders.QueryTreeBuilder; +import org.apache.lucene.queryParser.core.nodes.BoostQueryNode; +import org.apache.lucene.queryParser.core.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 OriginalQueryBuilder { + + 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; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/FieldQueryNodeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/FieldQueryNodeBuilder.java new file mode 100644 index 00000000000..6fffc6789d5 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/FieldQueryNodeBuilder.java @@ -0,0 +1,43 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.index.Term; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.nodes.FieldQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.search.TermQuery; + +/** + * Builds a {@link TermQuery} object from a {@link FieldQueryNode} object. + */ +public class FieldQueryNodeBuilder implements OriginalQueryBuilder { + + public FieldQueryNodeBuilder() { + // empty constructor + } + + public TermQuery build(QueryNode queryNode) throws QueryNodeException { + FieldQueryNode fieldNode = (FieldQueryNode) queryNode; + + return new TermQuery(new Term(fieldNode.getFieldAsString(), fieldNode + .getTextAsString())); + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/FuzzyQueryNodeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/FuzzyQueryNodeBuilder.java new file mode 100644 index 00000000000..16e205f5d06 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/FuzzyQueryNodeBuilder.java @@ -0,0 +1,44 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.index.Term; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.nodes.FuzzyQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.search.FuzzyQuery; + +/** + * Builds a {@link FuzzyQuery} object from a {@link FuzzyQueryNode} object. + */ +public class FuzzyQueryNodeBuilder implements OriginalQueryBuilder { + + public FuzzyQueryNodeBuilder() { + // empty constructor + } + + public FuzzyQuery build(QueryNode queryNode) throws QueryNodeException { + FuzzyQueryNode fuzzyNode = (FuzzyQueryNode) queryNode; + + return new FuzzyQuery(new Term(fuzzyNode.getFieldAsString(), fuzzyNode + .getTextAsString()), fuzzyNode.getSimilarity(), fuzzyNode + .getPrefixLength()); + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/GroupQueryNodeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/GroupQueryNodeBuilder.java new file mode 100644 index 00000000000..9dd39254093 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/GroupQueryNodeBuilder.java @@ -0,0 +1,45 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.builders.QueryTreeBuilder; +import org.apache.lucene.queryParser.core.nodes.GroupQueryNode; +import org.apache.lucene.queryParser.core.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 OriginalQueryBuilder { + + 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); + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MatchAllDocsQueryNodeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MatchAllDocsQueryNodeBuilder.java new file mode 100644 index 00000000000..a6c3de33856 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MatchAllDocsQueryNodeBuilder.java @@ -0,0 +1,52 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.messages.MessageImpl; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.nodes.MatchAllDocsQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.original.parser.EscapeQuerySyntaxImpl; +import org.apache.lucene.search.MatchAllDocsQuery; + +/** + * Builds a {@link MatchAllDocsQuery} object from a + * {@link MatchAllDocsQueryNode} object. + */ +public class MatchAllDocsQueryNodeBuilder implements OriginalQueryBuilder { + + public MatchAllDocsQueryNodeBuilder() { + // empty constructor + } + + public MatchAllDocsQuery build(QueryNode queryNode) throws QueryNodeException { + + // validates node + if (!(queryNode instanceof MatchAllDocsQueryNode)) { + throw new QueryNodeException(new MessageImpl( + QueryParserMessages.LUCENE_QUERY_CONVERSION_ERROR, queryNode + .toQueryString(new EscapeQuerySyntaxImpl()), queryNode.getClass() + .getName())); + } + + return new MatchAllDocsQuery(); + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MatchNoDocsQueryNodeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MatchNoDocsQueryNodeBuilder.java new file mode 100644 index 00000000000..6234019520d --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MatchNoDocsQueryNodeBuilder.java @@ -0,0 +1,52 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.messages.MessageImpl; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.nodes.MatchNoDocsQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.original.parser.EscapeQuerySyntaxImpl; +import org.apache.lucene.search.BooleanQuery; + +/** + * Builds an empty {@link BooleanQuery} object from a + * {@link MatchNoDocsQueryNode} object. + */ +public class MatchNoDocsQueryNodeBuilder implements OriginalQueryBuilder { + + public MatchNoDocsQueryNodeBuilder() { + // empty constructor + } + + public BooleanQuery build(QueryNode queryNode) throws QueryNodeException { + + // validates node + if (!(queryNode instanceof MatchNoDocsQueryNode)) { + throw new QueryNodeException(new MessageImpl( + QueryParserMessages.LUCENE_QUERY_CONVERSION_ERROR, queryNode + .toQueryString(new EscapeQuerySyntaxImpl()), queryNode.getClass() + .getName())); + } + + return new BooleanQuery(); + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/ModifierQueryNodeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/ModifierQueryNodeBuilder.java new file mode 100644 index 00000000000..f4b6767f0be --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/ModifierQueryNodeBuilder.java @@ -0,0 +1,45 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.builders.QueryTreeBuilder; +import org.apache.lucene.queryParser.core.nodes.ModifierQueryNode; +import org.apache.lucene.queryParser.core.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 OriginalQueryBuilder { + + 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); + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MultiPhraseQueryNodeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MultiPhraseQueryNodeBuilder.java new file mode 100644 index 00000000000..986b65c97bd --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/MultiPhraseQueryNodeBuilder.java @@ -0,0 +1,84 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.LinkedList; +import java.util.List; +import java.util.TreeMap; + +import org.apache.lucene.index.Term; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.builders.QueryTreeBuilder; +import org.apache.lucene.queryParser.core.nodes.FieldQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.original.nodes.MultiPhraseQueryNode; +import org.apache.lucene.search.MultiPhraseQuery; +import org.apache.lucene.search.TermQuery; + +/** + * Builds a {@link MultiPhraseQuery} object from a {@link MultiPhraseQueryNode} + * object. + */ +public class MultiPhraseQueryNodeBuilder implements OriginalQueryBuilder { + + public MultiPhraseQueryNodeBuilder() { + // empty constructor + } + + public MultiPhraseQuery build(QueryNode queryNode) throws QueryNodeException { + MultiPhraseQueryNode phraseNode = (MultiPhraseQueryNode) queryNode; + + MultiPhraseQuery phraseQuery = new MultiPhraseQuery(); + + List children = phraseNode.getChildren(); + + if (children != null) { + TreeMap> positionTermMap = new TreeMap>(); + + for (QueryNode child : children) { + FieldQueryNode termNode = (FieldQueryNode) child; + TermQuery termQuery = (TermQuery) termNode + .getTag(QueryTreeBuilder.QUERY_TREE_BUILDER_TAGID); + List termList = positionTermMap.get(termNode + .getPositionIncrement()); + + if (termList == null) { + termList = new LinkedList(); + positionTermMap.put(termNode.getPositionIncrement(), termList); + + } + + termList.add(termQuery.getTerm()); + + } + + for (int positionIncrement : positionTermMap.keySet()) { + List termList = positionTermMap.get(positionIncrement); + + phraseQuery.add(termList.toArray(new Term[termList.size()]), + positionIncrement); + + } + + } + + return phraseQuery; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/OriginalBooleanQueryNodeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/OriginalBooleanQueryNodeBuilder.java new file mode 100644 index 00000000000..dc3c2f6f1c8 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/OriginalBooleanQueryNodeBuilder.java @@ -0,0 +1,109 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.messages.MessageImpl; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.builders.QueryTreeBuilder; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.nodes.ModifierQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.ModifierQueryNode.Modifier; +import org.apache.lucene.queryParser.original.nodes.OriginalBooleanQueryNode; +import org.apache.lucene.queryParser.original.parser.EscapeQuerySyntaxImpl; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.Similarity; +import org.apache.lucene.search.BooleanQuery.TooManyClauses; + +/** + * This builder does the same as the {@link BooleanQueryNodeBuilder}, but this + * considers if the built {@link BooleanQuery} should have its coord disabled or + * not.
+ * + * @see BooleanQueryNodeBuilder + * @see BooleanQuery + * @see Similarity#coord(int, int) + */ +public class OriginalBooleanQueryNodeBuilder implements OriginalQueryBuilder { + + public OriginalBooleanQueryNodeBuilder() { + // empty constructor + } + + public BooleanQuery build(QueryNode queryNode) throws QueryNodeException { + OriginalBooleanQueryNode booleanNode = (OriginalBooleanQueryNode) queryNode; + + BooleanQuery bQuery = new BooleanQuery(booleanNode.isDisableCoord()); + List children = booleanNode.getChildren(); + + if (children != null) { + + for (QueryNode child : children) { + Object obj = child.getTag(QueryTreeBuilder.QUERY_TREE_BUILDER_TAGID); + + if (obj != null) { + Query query = (Query) obj; + + try { + bQuery.add(query, getModifierValue(child)); + } catch (TooManyClauses ex) { + + throw new QueryNodeException(new MessageImpl( + QueryParserMessages.TOO_MANY_BOOLEAN_CLAUSES, BooleanQuery + .getMaxClauseCount(), queryNode + .toQueryString(new EscapeQuerySyntaxImpl())), ex); + + } + + } + + } + + } + + return bQuery; + + } + + private static BooleanClause.Occur getModifierValue(QueryNode node) + throws QueryNodeException { + + if (node instanceof ModifierQueryNode) { + ModifierQueryNode mNode = ((ModifierQueryNode) node); + Modifier modifier = mNode.getModifier(); + + if (Modifier.MOD_NONE.equals(modifier)) { + return BooleanClause.Occur.SHOULD; + + } else if (Modifier.MOD_NOT.equals(modifier)) { + return BooleanClause.Occur.MUST_NOT; + + } else { + return BooleanClause.Occur.MUST; + } + } + + return BooleanClause.Occur.SHOULD; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/OriginalQueryBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/OriginalQueryBuilder.java new file mode 100644 index 00000000000..06dba9cea7a --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/OriginalQueryBuilder.java @@ -0,0 +1,37 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.builders.QueryBuilder; +import org.apache.lucene.queryParser.core.builders.QueryTreeBuilder; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.search.Query; + +/** + * This interface should be implemented by every class that wants to build + * {@link Query} objects from {@link QueryNode} objects.
+ * + * @see QueryBuilder + * @see QueryTreeBuilder + */ +public interface OriginalQueryBuilder extends QueryBuilder { + + public Query build(QueryNode queryNode) throws QueryNodeException; + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/OriginalQueryTreeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/OriginalQueryTreeBuilder.java new file mode 100644 index 00000000000..e5d83a65e9c --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/OriginalQueryTreeBuilder.java @@ -0,0 +1,78 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.builders.QueryTreeBuilder; +import org.apache.lucene.queryParser.core.nodes.BooleanQueryNode; +import org.apache.lucene.queryParser.core.nodes.BoostQueryNode; +import org.apache.lucene.queryParser.core.nodes.FieldQueryNode; +import org.apache.lucene.queryParser.core.nodes.FuzzyQueryNode; +import org.apache.lucene.queryParser.core.nodes.GroupQueryNode; +import org.apache.lucene.queryParser.core.nodes.MatchAllDocsQueryNode; +import org.apache.lucene.queryParser.core.nodes.MatchNoDocsQueryNode; +import org.apache.lucene.queryParser.core.nodes.ModifierQueryNode; +import org.apache.lucene.queryParser.core.nodes.PrefixWildcardQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.SlopQueryNode; +import org.apache.lucene.queryParser.core.nodes.TokenizedPhraseQueryNode; +import org.apache.lucene.queryParser.core.nodes.WildcardQueryNode; +import org.apache.lucene.queryParser.original.nodes.OriginalBooleanQueryNode; +import org.apache.lucene.queryParser.original.nodes.MultiPhraseQueryNode; +import org.apache.lucene.queryParser.original.nodes.RangeQueryNode; +import org.apache.lucene.queryParser.original.processors.OriginalQueryNodeProcessorPipeline; +import org.apache.lucene.search.Query; + +/** + * This query tree builder only defines the necessary map to build a + * {@link Query} tree object. It should be used to generate a {@link Query} tree + * object from a query node tree processed by a + * {@link OriginalQueryNodeProcessorPipeline}.
+ * + * @see QueryTreeBuilder + * @see OriginalQueryNodeProcessorPipeline + */ +public class OriginalQueryTreeBuilder extends QueryTreeBuilder implements + OriginalQueryBuilder { + + public OriginalQueryTreeBuilder() { + 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(OriginalBooleanQueryNode.class, + new OriginalBooleanQueryNodeBuilder()); + setBuilder(MultiPhraseQueryNode.class, new MultiPhraseQueryNodeBuilder()); + setBuilder(MatchAllDocsQueryNode.class, new MatchAllDocsQueryNodeBuilder()); + + } + + public Query build(QueryNode queryNode) throws QueryNodeException { + return (Query) super.build(queryNode); + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/PhraseQueryNodeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/PhraseQueryNodeBuilder.java new file mode 100644 index 00000000000..3622ac16743 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/PhraseQueryNodeBuilder.java @@ -0,0 +1,64 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.builders.QueryTreeBuilder; +import org.apache.lucene.queryParser.core.nodes.FieldQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.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 OriginalQueryBuilder { + + public PhraseQueryNodeBuilder() { + // empty constructor + } + + public PhraseQuery build(QueryNode queryNode) throws QueryNodeException { + TokenizedPhraseQueryNode phraseNode = (TokenizedPhraseQueryNode) queryNode; + + PhraseQuery phraseQuery = new PhraseQuery(); + + List 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; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/PrefixWildcardQueryNodeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/PrefixWildcardQueryNodeBuilder.java new file mode 100644 index 00000000000..653c9334331 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/PrefixWildcardQueryNodeBuilder.java @@ -0,0 +1,44 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.index.Term; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.nodes.PrefixWildcardQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.search.PrefixQuery; + +/** + * Builds a {@link PrefixQuery} object from a {@link PrefixWildcardQueryNode} + * object. + */ +public class PrefixWildcardQueryNodeBuilder implements OriginalQueryBuilder { + + public PrefixWildcardQueryNodeBuilder() { + // empty constructor + } + + public PrefixQuery build(QueryNode queryNode) throws QueryNodeException { + PrefixWildcardQueryNode wildcardNode = (PrefixWildcardQueryNode) queryNode; + + return new PrefixQuery(new Term(wildcardNode.getFieldAsString(), + wildcardNode.getTextAsString())); + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/RangeQueryNodeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/RangeQueryNodeBuilder.java new file mode 100644 index 00000000000..7876e6e6c3f --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/RangeQueryNodeBuilder.java @@ -0,0 +1,63 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.nodes.ParametricQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.ParametricQueryNode.CompareOperator; +import org.apache.lucene.queryParser.original.nodes.RangeQueryNode; +import org.apache.lucene.search.TermRangeQuery; + +/** + * Builds a {@link TermRangeQuery} object from a {@link RangeQueryNode} object. + */ +public class RangeQueryNodeBuilder implements OriginalQueryBuilder { + + 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.setRewriteMethod(rangeNode.getMultiTermRewriteMethod()); + + return rangeQuery; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/SlopQueryNodeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/SlopQueryNodeBuilder.java new file mode 100644 index 00000000000..80f8e6744d1 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/SlopQueryNodeBuilder.java @@ -0,0 +1,57 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.builders.QueryTreeBuilder; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.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 OriginalQueryBuilder { + + 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; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/WildcardQueryNodeBuilder.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/WildcardQueryNodeBuilder.java new file mode 100644 index 00000000000..389d8439cbc --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/WildcardQueryNodeBuilder.java @@ -0,0 +1,44 @@ +package org.apache.lucene.queryParser.original.builders; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.index.Term; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.WildcardQueryNode; +import org.apache.lucene.search.WildcardQuery; + +/** + * Builds a {@link WildcardQuery} object from a {@link WildcardQueryNode} + * object. + */ +public class WildcardQueryNodeBuilder implements OriginalQueryBuilder { + + public WildcardQueryNodeBuilder() { + // empty constructor + } + + public WildcardQuery build(QueryNode queryNode) throws QueryNodeException { + WildcardQueryNode wildcardNode = (WildcardQueryNode) queryNode; + + return new WildcardQuery(new Term(wildcardNode.getFieldAsString(), + wildcardNode.getTextAsString())); + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/package.html b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/package.html new file mode 100644 index 00000000000..dbd4559a27b --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/builders/package.html @@ -0,0 +1,35 @@ + + + + + + + + +

Original Lucene Query Node Builders

+

+The package org.apache.lucene.queryParser.original.builders contains all the builders needed +to build a Lucene Query object from a query node tree. These builders expect the query node tree was +already processed by the {@link org.apache.lucene.queryParser.original.processors.OriginalQueryNodeProcessorPipeline}. +

+

+{@link org.apache.lucene.queryParser.original.builders.OriginalQueryTreeBuilder} is a builder that already contains a defined map that maps each QueryNode object +with its respective builder. +

+ + diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AllowLeadingWildcardAttribute.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AllowLeadingWildcardAttribute.java new file mode 100644 index 00000000000..da3b01a6efb --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AllowLeadingWildcardAttribute.java @@ -0,0 +1,33 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.AllowLeadingWildcardProcessor; +import org.apache.lucene.util.Attribute; + +/** + * This attribute is used by {@link AllowLeadingWildcardProcessor} processor and + * must be defined in the {@link QueryConfigHandler}. It basically tells the + * processor if it should allow leading wildcard.
+ * + */ +public interface AllowLeadingWildcardAttribute extends Attribute { + public void setAllowLeadingWildcard(boolean allowLeadingWildcard); + public boolean isAllowLeadingWildcard(); +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AllowLeadingWildcardAttributeImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AllowLeadingWildcardAttributeImpl.java new file mode 100644 index 00000000000..44acdc88ebf --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AllowLeadingWildcardAttributeImpl.java @@ -0,0 +1,80 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.AllowLeadingWildcardProcessor; +import org.apache.lucene.util.AttributeImpl; + +/** + * 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.
+ * + * @see org.apache.lucene.queryParser.original.config.AllowLeadingWildcardAttribute + */ +public class AllowLeadingWildcardAttributeImpl extends AttributeImpl + implements AllowLeadingWildcardAttribute { + + private static final long serialVersionUID = -2804763012723049527L; + + private boolean allowLeadingWildcard = true; + + public AllowLeadingWildcardAttributeImpl() { + allowLeadingWildcard = true; // default in 2.4 + } + + public void setAllowLeadingWildcard(boolean allowLeadingWildcard) { + this.allowLeadingWildcard = allowLeadingWildcard; + } + + public boolean isAllowLeadingWildcard() { + return this.allowLeadingWildcard; + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public void copyTo(AttributeImpl target) { + throw new UnsupportedOperationException(); + } + + public boolean equals(Object other) { + + if (other instanceof AllowLeadingWildcardAttributeImpl + && ((AllowLeadingWildcardAttributeImpl) other).allowLeadingWildcard == this.allowLeadingWildcard) { + + return true; + + } + + return false; + + } + + public int hashCode() { + return this.allowLeadingWildcard ? -1 : Integer.MAX_VALUE; + } + + public String toString() { + return ""; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AnalyzerAttribute.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AnalyzerAttribute.java new file mode 100644 index 00000000000..99c1bae7511 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AnalyzerAttribute.java @@ -0,0 +1,35 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.AnalyzerQueryNodeProcessor; +import org.apache.lucene.util.Attribute; + +/** + * This attribute is used by {@link AnalyzerQueryNodeProcessor} processor and + * must be defined in the {@link QueryConfigHandler}. It provides to this + * processor the {@link Analyzer}, if there is one, which will be used to + * analyze the query terms.
+ * + */ +public interface AnalyzerAttribute extends Attribute { + public void setAnalyzer(Analyzer analyzer); + public Analyzer getAnalyzer(); +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AnalyzerAttributeImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AnalyzerAttributeImpl.java new file mode 100644 index 00000000000..0cba759a8c7 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/AnalyzerAttributeImpl.java @@ -0,0 +1,87 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.AnalyzerQueryNodeProcessor; +import org.apache.lucene.util.AttributeImpl; + +/** + * 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.
+ * + * @see org.apache.lucene.queryParser.original.config.AnalyzerAttribute + */ +public class AnalyzerAttributeImpl extends AttributeImpl + implements AnalyzerAttribute { + + private static final long serialVersionUID = -6804760312723049526L; + + private Analyzer analyzer; + + public AnalyzerAttributeImpl() { + analyzer = null; //default value 2.4 + } + + public void setAnalyzer(Analyzer analyzer) { + this.analyzer = analyzer; + } + + public Analyzer getAnalyzer() { + return this.analyzer; + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public void copyTo(AttributeImpl target) { + throw new UnsupportedOperationException(); + } + + public boolean equals(Object other) { + + if (other instanceof AnalyzerAttributeImpl) { + AnalyzerAttributeImpl analyzerAttr = (AnalyzerAttributeImpl) 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 ""; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/BoostAttribute.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/BoostAttribute.java new file mode 100644 index 00000000000..881a6c86c83 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/BoostAttribute.java @@ -0,0 +1,35 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.FieldConfig; +import org.apache.lucene.queryParser.original.processors.MultiFieldQueryNodeProcessor; +import org.apache.lucene.util.Attribute; + +/** + * This attribute is used by {@link MultiFieldQueryNodeProcessor} processor and + * it should be defined in a {@link FieldConfig}. This processor uses this + * attribute to define which boost a specific field should have when none is + * defined to it.
+ *
+ * + */ +public interface BoostAttribute extends Attribute { + public void setBoost(float boost); + public float getBoost(); +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/BoostAttributeImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/BoostAttributeImpl.java new file mode 100644 index 00000000000..e86e3b15e79 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/BoostAttributeImpl.java @@ -0,0 +1,81 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.FieldConfig; +import org.apache.lucene.queryParser.original.processors.MultiFieldQueryNodeProcessor; +import org.apache.lucene.util.AttributeImpl; + +/** + * 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.
+ *
+ * + * @see org.apache.lucene.queryParser.original.config.BoostAttribute + */ +public class BoostAttributeImpl extends AttributeImpl + implements BoostAttribute { + + private static final long serialVersionUID = -2104763012523049527L; + + private float boost = 1.0f; + + public BoostAttributeImpl() { + // empty constructor + } + + public void setBoost(float boost) { + this.boost = boost; + } + + public float getBoost() { + return this.boost; + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public void copyTo(AttributeImpl target) { + throw new UnsupportedOperationException(); + } + + public boolean equals(Object other) { + + if (other instanceof BoostAttributeImpl && other != null + && ((BoostAttributeImpl) other).boost == this.boost) { + + return true; + + } + + return false; + + } + + public int hashCode() { + return Float.valueOf(this.boost).hashCode(); + } + + public String toString() { + return ""; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DateResolutionAttribute.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DateResolutionAttribute.java new file mode 100644 index 00000000000..f5e66dc0e57 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DateResolutionAttribute.java @@ -0,0 +1,43 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.document.DateTools; +import org.apache.lucene.document.DateTools.Resolution; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.nodes.RangeQueryNode; +import org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor; +import org.apache.lucene.util.Attribute; + +/** + * This attribute is used by {@link ParametricRangeQueryNodeProcessor} processor + * and must be defined in the {@link QueryConfigHandler}. This attribute tells + * the processor which {@link Resolution} to use when parsing the date.
+ * + */ +public interface DateResolutionAttribute extends Attribute { + /** + * Sets the default date resolution used by {@link RangeQueryNode}s for + * fields for which no specific date resolutions has been set. Field + * specific resolutions can be set with + * + * @param dateResolution the default date resolution to set + */ + public void setDateResolution(DateTools.Resolution dateResolution); + public DateTools.Resolution getDateResolution(); +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DateResolutionAttributeImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DateResolutionAttributeImpl.java new file mode 100644 index 00000000000..4c9de6e0d49 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DateResolutionAttributeImpl.java @@ -0,0 +1,87 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.document.DateTools; +import org.apache.lucene.document.DateTools.Resolution; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor; +import org.apache.lucene.util.AttributeImpl; + +/** + * 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.
+ * + * @see org.apache.lucene.queryParser.original.config.DateResolutionAttribute + */ +public class DateResolutionAttributeImpl extends AttributeImpl + implements DateResolutionAttribute { + + private static final long serialVersionUID = -6804360312723049526L; + + private DateTools.Resolution dateResolution = null; + + public DateResolutionAttributeImpl() { + dateResolution = null; //default in 2.4 + } + + public void setDateResolution(DateTools.Resolution dateResolution) { + this.dateResolution = dateResolution; + } + + public DateTools.Resolution getDateResolution() { + return this.dateResolution; + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public void copyTo(AttributeImpl target) { + throw new UnsupportedOperationException(); + } + + public boolean equals(Object other) { + + if (other instanceof DateResolutionAttributeImpl) { + DateResolutionAttributeImpl dateResAttr = (DateResolutionAttributeImpl) 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 ""; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultOperatorAttribute.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultOperatorAttribute.java new file mode 100644 index 00000000000..7ad2ae5ba81 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultOperatorAttribute.java @@ -0,0 +1,39 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.GroupQueryNodeProcessor; +import org.apache.lucene.util.Attribute; + +/** + * This attribute is used by {@link GroupQueryNodeProcessor} processor and must + * be defined in the {@link QueryConfigHandler}. This attribute tells the + * processor which is the default boolean operator when no operator is defined + * between terms.
+ * + */ +public interface DefaultOperatorAttribute extends Attribute { + public static enum Operator { + AND, OR; + } + + public void setOperator(Operator operator); + public Operator getOperator(); +} + diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultOperatorAttributeImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultOperatorAttributeImpl.java new file mode 100644 index 00000000000..1e377051259 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultOperatorAttributeImpl.java @@ -0,0 +1,89 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.GroupQueryNodeProcessor; +import org.apache.lucene.util.AttributeImpl; + +/** + * 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.
+ * + * @see org.apache.lucene.queryParser.original.config.DefaultOperatorAttribute + */ +public class DefaultOperatorAttributeImpl extends AttributeImpl + implements DefaultOperatorAttribute { + + private static final long serialVersionUID = -6804760312723049526L; + + private Operator operator = Operator.OR; + + public DefaultOperatorAttributeImpl() { + // empty constructor + } + + public void setOperator(Operator operator) { + + if (operator == null) { + throw new IllegalArgumentException("default operator cannot be null!"); + } + + this.operator = operator; + + } + + public Operator getOperator() { + return this.operator; + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public void copyTo(AttributeImpl target) { + throw new UnsupportedOperationException(); + } + + public boolean equals(Object other) { + + if (other instanceof DefaultOperatorAttributeImpl) { + DefaultOperatorAttributeImpl defaultOperatorAttr = (DefaultOperatorAttributeImpl) other; + + if (defaultOperatorAttr.getOperator() == this.getOperator()) { + return true; + + } + + } + + return false; + + } + + public int hashCode() { + return getOperator().hashCode() * 31; + } + + public String toString() { + return ""; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultPhraseSlopAttribute.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultPhraseSlopAttribute.java new file mode 100644 index 00000000000..2226ac72889 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultPhraseSlopAttribute.java @@ -0,0 +1,34 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.PhraseSlopQueryNodeProcessor; +import org.apache.lucene.util.Attribute; + +/** + * This attribute is used by {@link PhraseSlopQueryNodeProcessor} processor and + * must be defined in the {@link QueryConfigHandler}. This attribute tells the + * processor what is the default phrase slop when no slop is defined in a + * phrase.
+ * + */ +public interface DefaultPhraseSlopAttribute extends Attribute { + public void setDefaultPhraseSlop(int defaultPhraseSlop); + public int getDefaultPhraseSlop(); +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultPhraseSlopAttributeImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultPhraseSlopAttributeImpl.java new file mode 100644 index 00000000000..2a18c03bce5 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/DefaultPhraseSlopAttributeImpl.java @@ -0,0 +1,82 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.PhraseSlopQueryNodeProcessor; +import org.apache.lucene.util.AttributeImpl; + +/** + * 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.
+ * + * @see org.apache.lucene.queryParser.original.config.DefaultOperatorAttribute + */ +public class DefaultPhraseSlopAttributeImpl extends AttributeImpl + implements DefaultPhraseSlopAttribute { + + private static final long serialVersionUID = -2104763012527049527L; + + private int defaultPhraseSlop = 0; + + public DefaultPhraseSlopAttributeImpl() { + defaultPhraseSlop = 0; //default value in 2.4 + } + + public void setDefaultPhraseSlop(int defaultPhraseSlop) { + this.defaultPhraseSlop = defaultPhraseSlop; + } + + public int getDefaultPhraseSlop() { + return this.defaultPhraseSlop; + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public void copyTo(AttributeImpl target) { + throw new UnsupportedOperationException(); + } + + public boolean equals(Object other) { + + if (other instanceof DefaultPhraseSlopAttributeImpl + && other != null + && ((DefaultPhraseSlopAttributeImpl) other).defaultPhraseSlop == this.defaultPhraseSlop) { + + return true; + + } + + return false; + + } + + public int hashCode() { + return Integer.valueOf(this.defaultPhraseSlop).hashCode(); + } + + public String toString() { + return ""; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldBoostMapAttribute.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldBoostMapAttribute.java new file mode 100644 index 00000000000..79e889ba59f --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldBoostMapAttribute.java @@ -0,0 +1,35 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Map; + +import org.apache.lucene.queryParser.core.config.FieldConfig; +import org.apache.lucene.util.Attribute; + +/** + * This attribute enables the user to define a default boost per field. + * it's used by {@link FieldBoostMapFCListener#buildFieldConfig(FieldConfig)} + */ +public interface FieldBoostMapAttribute extends Attribute { + /** + * @param boosts a mapping from field name to its default boost + */ + public void setFieldBoostMap(Map boosts); + public Map getFieldBoostMap(); +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldBoostMapAttributeImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldBoostMapAttributeImpl.java new file mode 100644 index 00000000000..6856fae4ca0 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldBoostMapAttributeImpl.java @@ -0,0 +1,89 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.lucene.queryParser.core.config.FieldConfig; +import org.apache.lucene.queryParser.original.processors.MultiFieldQueryNodeProcessor; +import org.apache.lucene.util.AttributeImpl; + +/** + * 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.
+ *
+ * + * @see org.apache.lucene.queryParser.original.config.BoostAttribute + */ +public class FieldBoostMapAttributeImpl extends AttributeImpl + implements FieldBoostMapAttribute { + + private static final long serialVersionUID = -2104763012523049527L; + + private Map boosts = new LinkedHashMap(); + + + public FieldBoostMapAttributeImpl() { + // empty constructor + } + + public void setFieldBoostMap(Map boosts) { + this.boosts = boosts; + } + + public Map getFieldBoostMap() { + return this.boosts; + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public void copyTo(AttributeImpl target) { + throw new UnsupportedOperationException(); + } + + public boolean equals(Object other) { + + if (other instanceof FieldBoostMapAttributeImpl && other != null + && ((FieldBoostMapAttributeImpl) other).boosts.equals(this.boosts) ) { + + return true; + + } + + return false; + + } + + public int hashCode() { + final int prime = 97; + if (this.boosts != null) + return this.boosts.hashCode() * prime; + else + return Float.valueOf(prime).hashCode(); + } + + public String toString() { + return ""; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldBoostMapFCListener.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldBoostMapFCListener.java new file mode 100644 index 00000000000..3c7ffa258a2 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldBoostMapFCListener.java @@ -0,0 +1,59 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.FieldConfig; +import org.apache.lucene.queryParser.core.config.FieldConfigListener; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; + +/** + * This listener listens for every field configuration request and assign a + * {@link BoostAttribute} to the equivalent {@link FieldConfig} based on a + * defined map: fieldName -> boostValue store in {@link FieldBoostMapAttribute} + * in the {@link FieldBoostMapAttribute}. + * + * @see BoostAttribute + * @see FieldBoostMapAttribute + * @see FieldConfig + * @see FieldConfigListener + */ +public class FieldBoostMapFCListener implements FieldConfigListener { + + private static final long serialVersionUID = -5929802948798314067L; + + private QueryConfigHandler config = null; + + public FieldBoostMapFCListener(QueryConfigHandler config) { + this.config = config; + } + + public void buildFieldConfig(FieldConfig fieldConfig) { + if (this.config.hasAttribute(FieldBoostMapAttribute.class)) { + FieldBoostMapAttribute fieldBoostMapAttr = (FieldBoostMapAttribute) this.config.getAttribute(FieldBoostMapAttribute.class); + BoostAttribute boostAttr = (BoostAttribute) fieldConfig.addAttribute(BoostAttribute.class); + + Float boost = fieldBoostMapAttr.getFieldBoostMap().get(fieldConfig.getFieldName()); + + if (boost != null) { + boostAttr.setBoost(boost.floatValue()); + } + + } + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldDateResolutionFCListener.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldDateResolutionFCListener.java new file mode 100644 index 00000000000..383a338c320 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldDateResolutionFCListener.java @@ -0,0 +1,73 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.document.DateTools; +import org.apache.lucene.queryParser.core.config.FieldConfig; +import org.apache.lucene.queryParser.core.config.FieldConfigListener; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; + +/** + * This listener listens for every field configuration request and assign a + * {@link DateResolutionAttribute} to the equivalent {@link FieldConfig} based on a + * defined map: fieldName -> DateTools.Resolution stored in {@link FieldDateResolutionMapAttribute} + * in the {@link DateResolutionAttribute}. + * + * @see DateResolutionAttribute + * @see FieldDateResolutionMapAttribute + * @see FieldConfig + * @see FieldConfigListener + */ +public class FieldDateResolutionFCListener implements FieldConfigListener { + + private static final long serialVersionUID = -5929802948798314067L; + + private QueryConfigHandler config = null; + + public FieldDateResolutionFCListener(QueryConfigHandler config) { + this.config = config; + } + + public void buildFieldConfig(FieldConfig fieldConfig) { + DateResolutionAttribute fieldDateResAttr = (DateResolutionAttribute) fieldConfig + .addAttribute(DateResolutionAttribute.class); + DateTools.Resolution dateRes = null; + + if (this.config.hasAttribute(FieldDateResolutionMapAttribute.class)) { + FieldDateResolutionMapAttribute dateResMapAttr = (FieldDateResolutionMapAttribute) this.config + .addAttribute(FieldDateResolutionMapAttribute.class); + dateRes = dateResMapAttr.getFieldDateResolutionMap().get( + fieldConfig.getFieldName().toString()); + } + + if (dateRes == null) { + + if (this.config.hasAttribute(DateResolutionAttribute.class)) { + DateResolutionAttribute dateResAttr = (DateResolutionAttribute) this.config + .addAttribute(DateResolutionAttribute.class); + dateRes = dateResAttr.getDateResolution(); + + } + + } + + fieldDateResAttr.setDateResolution(dateRes); + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldDateResolutionMapAttribute.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldDateResolutionMapAttribute.java new file mode 100644 index 00000000000..2a293c2a880 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldDateResolutionMapAttribute.java @@ -0,0 +1,35 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Map; + +import org.apache.lucene.document.DateTools; +import org.apache.lucene.util.Attribute; + +/** + * This attribute enables the user to define a default DateResolution per field. + * it's used by {@link FieldDateResolutionFCListener#buildFieldConfig(org.apache.lucene.queryParser.core.config.FieldConfig)} + */ +public interface FieldDateResolutionMapAttribute extends Attribute { + /** + * @param dateRes a mapping from field name to its default boost + */ + public void setFieldDateResolutionMap(Map dateRes); + public Map getFieldDateResolutionMap(); +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldDateResolutionMapAttributeImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldDateResolutionMapAttributeImpl.java new file mode 100644 index 00000000000..04bffd6826d --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FieldDateResolutionMapAttributeImpl.java @@ -0,0 +1,86 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.HashMap; +import java.util.Map; + +import org.apache.lucene.document.DateTools; +import org.apache.lucene.document.DateTools.Resolution; +import org.apache.lucene.util.AttributeImpl; + +/** + * This attribute enables the user to define a default DateResolution per field. + * it's used by {@link FieldDateResolutionFCListener#buildFieldConfig(org.apache.lucene.queryParser.core.config.FieldConfig)} + * + * @see FieldDateResolutionMapAttribute + */ +public class FieldDateResolutionMapAttributeImpl extends AttributeImpl + implements FieldDateResolutionMapAttribute { + + private static final long serialVersionUID = -2104763012523049527L; + + private Map dateRes = new HashMap(); + + + public FieldDateResolutionMapAttributeImpl() { + // empty constructor + } + + public void setFieldDateResolutionMap(Map dateRes) { + this.dateRes = dateRes; + } + + public Map getFieldDateResolutionMap() { + return this.dateRes; + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public void copyTo(AttributeImpl target) { + throw new UnsupportedOperationException(); + } + + public boolean equals(Object other) { + + if (other instanceof FieldDateResolutionMapAttributeImpl && other != null + && ((FieldDateResolutionMapAttributeImpl) other).dateRes.equals(this.dateRes) ) { + + return true; + + } + + return false; + + } + + public int hashCode() { + final int prime = 97; + if (this.dateRes != null) + return this.dateRes.hashCode() * prime; + else + return Float.valueOf(prime).hashCode(); + } + + public String toString() { + return ""; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FuzzyAttribute.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FuzzyAttribute.java new file mode 100644 index 00000000000..5767365c08a --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FuzzyAttribute.java @@ -0,0 +1,36 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.PhraseSlopQueryNodeProcessor; +import org.apache.lucene.util.Attribute; + +/** + * This attribute is used by {@link PhraseSlopQueryNodeProcessor} processor and + * must be defined in the {@link QueryConfigHandler}. This attribute tells the + * processor what is the default phrase slop when no slop is defined in a + * phrase.
+ * + */ +public interface FuzzyAttribute extends Attribute { + public void setPrefixLength(int prefixLength); + public int getPrefixLength(); + public void setFuzzyMinSimilarity(float minSimilarity); + public float getFuzzyMinSimilarity(); +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FuzzyAttributeImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FuzzyAttributeImpl.java new file mode 100644 index 00000000000..7b8a46efee7 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/FuzzyAttributeImpl.java @@ -0,0 +1,91 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.PhraseSlopQueryNodeProcessor; +import org.apache.lucene.search.FuzzyQuery; +import org.apache.lucene.util.AttributeImpl; + +/** + * 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.
+ * + * @see org.apache.lucene.queryParser.original.config.FuzzyAttribute + */ +public class FuzzyAttributeImpl extends AttributeImpl + implements FuzzyAttribute { + + private static final long serialVersionUID = -2104763012527049527L; + + private int prefixLength = FuzzyQuery.defaultPrefixLength; + + private float minSimilarity = FuzzyQuery.defaultMinSimilarity; + + public FuzzyAttributeImpl() { + // empty constructor + } + + public void setPrefixLength(int prefixLength) { + this.prefixLength = prefixLength; + } + + public int getPrefixLength() { + return this.prefixLength; + } + + public void setFuzzyMinSimilarity(float minSimilarity) { + this.minSimilarity = minSimilarity; + } + + public float getFuzzyMinSimilarity() { + return this.minSimilarity; + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public void copyTo(AttributeImpl target) { + throw new UnsupportedOperationException(); + } + + public boolean equals(Object other) { + + if (other instanceof FuzzyAttributeImpl && other != null + && ((FuzzyAttributeImpl) other).prefixLength == this.prefixLength) { + + return true; + + } + + return false; + + } + + public int hashCode() { + return Integer.valueOf(this.prefixLength).hashCode(); + } + + public String toString() { + return ""; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LocaleAttribute.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LocaleAttribute.java new file mode 100644 index 00000000000..de382c399fe --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LocaleAttribute.java @@ -0,0 +1,35 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Locale; + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor; +import org.apache.lucene.util.Attribute; + +/** + * This attribute is used by processor {@link ParametricRangeQueryNodeProcessor} + * and must be defined in the {@link QueryConfigHandler}. This attribute tells + * the processor what is the default {@link Locale} used to parse a date.
+ * + */ +public interface LocaleAttribute extends Attribute { + public void setLocale(Locale locale); + public Locale getLocale(); +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LocaleAttributeImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LocaleAttributeImpl.java new file mode 100644 index 00000000000..9e7df973ba9 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LocaleAttributeImpl.java @@ -0,0 +1,87 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Locale; + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor; +import org.apache.lucene.util.AttributeImpl; + +/** + * 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.
+ * + * @see org.apache.lucene.queryParser.original.config.LocaleAttribute + */ +public class LocaleAttributeImpl extends AttributeImpl + implements LocaleAttribute { + + private static final long serialVersionUID = -6804760312720049526L; + + private Locale locale = Locale.getDefault(); + + public LocaleAttributeImpl() { + locale = Locale.getDefault(); //default in 2.4 + } + + public void setLocale(Locale locale) { + this.locale = locale; + } + + public Locale getLocale() { + return this.locale; + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public void copyTo(AttributeImpl target) { + throw new UnsupportedOperationException(); + } + + public boolean equals(Object other) { + + if (other instanceof LocaleAttributeImpl) { + LocaleAttributeImpl localeAttr = (LocaleAttributeImpl) 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 ""; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LowercaseExpandedTermsAttribute.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LowercaseExpandedTermsAttribute.java new file mode 100644 index 00000000000..d2d7294759f --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LowercaseExpandedTermsAttribute.java @@ -0,0 +1,35 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Locale; + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor; +import org.apache.lucene.util.Attribute; + +/** + * This attribute is used by processor {@link ParametricRangeQueryNodeProcessor} + * and must be defined in the {@link QueryConfigHandler}. This attribute tells + * the processor what is the default {@link Locale} used to parse a date.
+ * + */ +public interface LowercaseExpandedTermsAttribute extends Attribute { + public void setLowercaseExpandedTerms(boolean lowercaseExpandedTerms); + public boolean isLowercaseExpandedTerms(); +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LowercaseExpandedTermsAttributeImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LowercaseExpandedTermsAttributeImpl.java new file mode 100644 index 00000000000..7be77333001 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/LowercaseExpandedTermsAttributeImpl.java @@ -0,0 +1,82 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Locale; + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor; +import org.apache.lucene.util.AttributeImpl; + +/** + * 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.
+ * + * @see org.apache.lucene.queryParser.original.config.LowercaseExpandedTermsAttribute + */ +public class LowercaseExpandedTermsAttributeImpl extends AttributeImpl + implements LowercaseExpandedTermsAttribute { + + private static final long serialVersionUID = -2804760312723049527L; + + private boolean lowercaseExpandedTerms = true; + + public LowercaseExpandedTermsAttributeImpl() { + lowercaseExpandedTerms = true; // default in 2.4 + } + + public void setLowercaseExpandedTerms(boolean lowercaseExpandedTerms) { + this.lowercaseExpandedTerms = lowercaseExpandedTerms; + } + + public boolean isLowercaseExpandedTerms() { + return this.lowercaseExpandedTerms; + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public void copyTo(AttributeImpl target) { + throw new UnsupportedOperationException(); + } + + public boolean equals(Object other) { + + if (other instanceof LowercaseExpandedTermsAttributeImpl + && ((LowercaseExpandedTermsAttributeImpl) other).lowercaseExpandedTerms == this.lowercaseExpandedTerms) { + + return true; + + } + + return false; + + } + + public int hashCode() { + return this.lowercaseExpandedTerms ? -1 : Integer.MAX_VALUE; + } + + public String toString() { + return ""; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiFieldAttribute.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiFieldAttribute.java new file mode 100644 index 00000000000..e5d02f8cc2a --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiFieldAttribute.java @@ -0,0 +1,33 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.MultiFieldQueryNodeProcessor; +import org.apache.lucene.util.Attribute; + +/** + * This attribute is used by {@link MultiFieldQueryNodeProcessor} processor and + * must be defined in the {@link QueryConfigHandler}. This attribute tells the + * processor to which fields the terms in the query should be expanded.
+ * + */ +public interface MultiFieldAttribute extends Attribute { + public void setFields(CharSequence[] fields); + public CharSequence[] getFields(); +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiFieldAttributeImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiFieldAttributeImpl.java new file mode 100644 index 00000000000..ca523875c92 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiFieldAttributeImpl.java @@ -0,0 +1,81 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Arrays; + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.MultiFieldQueryNodeProcessor; +import org.apache.lucene.util.AttributeImpl; + +/** + * 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.
+ * + * @see org.apache.lucene.queryParser.original.config.MultiFieldAttribute + */ +public class MultiFieldAttributeImpl extends AttributeImpl + implements MultiFieldAttribute { + + private static final long serialVersionUID = -6809760312720049526L; + + private CharSequence[] fields; + + public MultiFieldAttributeImpl() { + // empty constructor + } + + public void setFields(CharSequence[] fields) { + this.fields = fields; + } + + public CharSequence[] getFields() { + return this.fields; + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public void copyTo(AttributeImpl target) { + throw new UnsupportedOperationException(); + } + + public boolean equals(Object other) { + + if (other instanceof MultiFieldAttributeImpl) { + MultiFieldAttributeImpl fieldsAttr = (MultiFieldAttributeImpl) other; + + return Arrays.equals(this.fields, fieldsAttr.fields); + + } + + return false; + + } + + public int hashCode() { + return Arrays.hashCode(this.fields); + } + + public String toString() { + return ""; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiTermRewriteMethodAttribute.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiTermRewriteMethodAttribute.java new file mode 100644 index 00000000000..3f52ab9d0ac --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiTermRewriteMethodAttribute.java @@ -0,0 +1,37 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor; +import org.apache.lucene.search.MultiTermQuery; +import org.apache.lucene.search.MultiTermQuery.RewriteMethod; +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 which {@link RewriteMethod} to + * use.
+ * + */ +public interface MultiTermRewriteMethodAttribute extends Attribute { + public void setMultiTermRewriteMethod(MultiTermQuery.RewriteMethod method); + + public MultiTermQuery.RewriteMethod getMultiTermRewriteMethod(); +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiTermRewriteMethodAttributeImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiTermRewriteMethodAttributeImpl.java new file mode 100644 index 00000000000..dd096640828 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/MultiTermRewriteMethodAttributeImpl.java @@ -0,0 +1,83 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor; +import org.apache.lucene.search.MultiTermQuery; +import org.apache.lucene.search.MultiTermQuery.RewriteMethod; +import org.apache.lucene.util.AttributeImpl; + +/** + * 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 which {@link RewriteMethod} to + * use.
+ * + * @see MultiTermRewriteMethodAttribute + */ +public class MultiTermRewriteMethodAttributeImpl extends AttributeImpl + implements MultiTermRewriteMethodAttribute { + + private static final long serialVersionUID = -2104763012723049527L; + + private MultiTermQuery.RewriteMethod multiTermRewriteMethod = MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT; + + public MultiTermRewriteMethodAttributeImpl() { + // empty constructor + } + + public void setMultiTermRewriteMethod(MultiTermQuery.RewriteMethod method) { + multiTermRewriteMethod = method; + } + + public MultiTermQuery.RewriteMethod getMultiTermRewriteMethod() { + return multiTermRewriteMethod; + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public void copyTo(AttributeImpl target) { + throw new UnsupportedOperationException(); + } + + public boolean equals(Object other) { + + if (other instanceof MultiTermRewriteMethodAttributeImpl + && ((MultiTermRewriteMethodAttributeImpl) other).multiTermRewriteMethod == this.multiTermRewriteMethod) { + + return true; + + } + + return false; + + } + + public int hashCode() { + return multiTermRewriteMethod.hashCode(); + } + + public String toString() { + return ""; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/OriginalQueryConfigHandler.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/OriginalQueryConfigHandler.java new file mode 100644 index 00000000000..7c9a70a82be --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/OriginalQueryConfigHandler.java @@ -0,0 +1,55 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.OriginalQueryNodeProcessorPipeline; + +/** + * This query configuration handler is used for almost every processor defined + * in the {@link OriginalQueryNodeProcessorPipeline} processor pipeline. It holds + * attributes that reproduces the configuration that could be set on the old + * lucene 2.4 QueryParser class.
+ * + * @see OriginalQueryNodeProcessorPipeline + */ +public class OriginalQueryConfigHandler extends QueryConfigHandler { + + + + public OriginalQueryConfigHandler() { + // Add listener that will build the FieldConfig attributes. + addFieldConfigListener(new FieldBoostMapFCListener(this)); + addFieldConfigListener(new FieldDateResolutionFCListener(this)); + + // Default Values + addAttribute(RangeCollatorAttribute.class); + addAttribute(DefaultOperatorAttribute.class); + addAttribute(AnalyzerAttribute.class); + addAttribute(FuzzyAttribute.class); + addAttribute(LowercaseExpandedTermsAttribute.class); + addAttribute(MultiTermRewriteMethodAttribute.class); + addAttribute(AllowLeadingWildcardAttribute.class); + addAttribute(PositionIncrementsAttribute.class); + addAttribute(LocaleAttribute.class); + addAttribute(DefaultPhraseSlopAttribute.class); + //addAttribute(DateResolutionAttribute.class); + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/PositionIncrementsAttribute.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/PositionIncrementsAttribute.java new file mode 100644 index 00000000000..b95d35e94df --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/PositionIncrementsAttribute.java @@ -0,0 +1,33 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.AnalyzerQueryNodeProcessor; +import org.apache.lucene.util.Attribute; + +/** + * This attribute is used by {@link AnalyzerQueryNodeProcessor} processor and + * must be defined in the {@link QueryConfigHandler}. This attribute tells the + * processor if the position increment is enabled.
+ * + */ +public interface PositionIncrementsAttribute extends Attribute { + public void setPositionIncrementsEnabled(boolean positionIncrementsEnabled); + public boolean isPositionIncrementsEnabled(); +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/PositionIncrementsAttributeImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/PositionIncrementsAttributeImpl.java new file mode 100644 index 00000000000..5e2b1b31c17 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/PositionIncrementsAttributeImpl.java @@ -0,0 +1,81 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.AnalyzerQueryNodeProcessor; +import org.apache.lucene.util.AttributeImpl; + +/** + * 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.
+ * + * @see org.apache.lucene.queryParser.original.config.PositionIncrementsAttribute + */ +public class PositionIncrementsAttributeImpl extends AttributeImpl + implements PositionIncrementsAttribute { + + private static final long serialVersionUID = -2804763012793049527L; + + private boolean positionIncrementsEnabled = false; + + public PositionIncrementsAttributeImpl() { + positionIncrementsEnabled = false; //default in 2.4 + } + + public void setPositionIncrementsEnabled(boolean positionIncrementsEnabled) { + this.positionIncrementsEnabled = positionIncrementsEnabled; + } + + public boolean isPositionIncrementsEnabled() { + return this.positionIncrementsEnabled; + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public void copyTo(AttributeImpl target) { + throw new UnsupportedOperationException(); + } + + public boolean equals(Object other) { + + if (other instanceof PositionIncrementsAttributeImpl + && other != null + && ((PositionIncrementsAttributeImpl) other).positionIncrementsEnabled == this.positionIncrementsEnabled) { + + return true; + + } + + return false; + + } + + public int hashCode() { + return this.positionIncrementsEnabled ? -1 : Integer.MAX_VALUE; + } + + public String toString() { + return ""; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/RangeCollatorAttribute.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/RangeCollatorAttribute.java new file mode 100644 index 00000000000..53b7936fd20 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/RangeCollatorAttribute.java @@ -0,0 +1,37 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.text.Collator; + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor; +import org.apache.lucene.search.TermRangeQuery; +import org.apache.lucene.util.Attribute; + +/** + * This attribute is used by {@link ParametricRangeQueryNodeProcessor} processor + * and must be defined in the {@link QueryConfigHandler}. This attribute tells + * the processor which {@link Collator} should be used for a + * {@link TermRangeQuery}
+ * + */ +public interface RangeCollatorAttribute extends Attribute { + public void setDateResolution(Collator rangeCollator); + public Collator getRangeCollator(); +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/RangeCollatorAttributeImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/RangeCollatorAttributeImpl.java new file mode 100644 index 00000000000..7850805cd61 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/RangeCollatorAttributeImpl.java @@ -0,0 +1,89 @@ +package org.apache.lucene.queryParser.original.config; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.text.Collator; + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor; +import org.apache.lucene.search.TermRangeQuery; +import org.apache.lucene.util.AttributeImpl; + +/** + * This attribute is used by {@link ParametricRangeQueryNodeProcessor} processor + * and must be defined in the {@link QueryConfigHandler}. This attribute tells + * the processor which {@link Collator} should be used for a + * {@link TermRangeQuery}
+ * + * @see org.apache.lucene.queryParser.original.config.RangeCollatorAttribute + */ +public class RangeCollatorAttributeImpl extends AttributeImpl + implements RangeCollatorAttribute { + + private static final long serialVersionUID = -6804360312723049526L; + + private Collator rangeCollator; + + public RangeCollatorAttributeImpl() { + rangeCollator = null; // default value for 2.4 + } + + public void setDateResolution(Collator rangeCollator) { + this.rangeCollator = rangeCollator; + } + + public Collator getRangeCollator() { + return this.rangeCollator; + } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public void copyTo(AttributeImpl target) { + throw new UnsupportedOperationException(); + } + + public boolean equals(Object other) { + + if (other instanceof RangeCollatorAttributeImpl) { + RangeCollatorAttributeImpl rangeCollatorAttr = (RangeCollatorAttributeImpl) 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 ""; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/package.html b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/package.html new file mode 100644 index 00000000000..f89fb95462d --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/config/package.html @@ -0,0 +1,34 @@ + + + + + + + + +

Original Lucene Query Configuration

+

+The package org.apache.lucene.queryParser.original.config contains the Lucene +query configuration handler and all the attributes used by it. This configuration +handler reproduces almost everything that could be set on the old query parser. +

+

+OriginalQueryConfigHandler is the class that should be used to configure the OriginalQueryNodeProcessorPipeline. +

+ + diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/BooleanModifierNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/BooleanModifierNode.java new file mode 100644 index 00000000000..44ae93e8eb5 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/BooleanModifierNode.java @@ -0,0 +1,39 @@ +package org.apache.lucene.queryParser.original.nodes; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.nodes.ModifierQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.original.processors.GroupQueryNodeProcessor; + +/** + * A {@link BooleanModifierNode} has the same behaviour as + * {@link ModifierQueryNode}, it only indicates that this modifier was added by + * {@link GroupQueryNodeProcessor} and not by the user.
+ * + * @see ModifierQueryNode + */ +public class BooleanModifierNode extends ModifierQueryNode { + + private static final long serialVersionUID = -557816496416587068L; + + public BooleanModifierNode(QueryNode node, Modifier mod) { + super(node, mod); + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/MultiPhraseQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/MultiPhraseQueryNode.java new file mode 100644 index 00000000000..41d97ea2739 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/MultiPhraseQueryNode.java @@ -0,0 +1,108 @@ +package org.apache.lucene.queryParser.original.nodes; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.queryParser.core.nodes.FieldableNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNodeImpl; +import org.apache.lucene.queryParser.core.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 ""; + StringBuilder sb = new StringBuilder(); + sb.append(""); + for (QueryNode child : getChildren()) { + sb.append("\n"); + sb.append(child.toString()); + } + sb.append("\n"); + 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 children = getChildren(); + + if (children == null || children.size() == 0) { + return null; + + } else { + return ((FieldableNode) children.get(0)).getField(); + } + + } + + public void setField(CharSequence fieldName) { + List children = getChildren(); + + if (children != null) { + + for (QueryNode child : children) { + + if (child instanceof FieldableNode) { + ((FieldableNode) child).setField(fieldName); + } + + } + + } + + } + +} // end class MultitermQueryNode diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/OriginalBooleanQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/OriginalBooleanQueryNode.java new file mode 100644 index 00000000000..be95c0d08f6 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/OriginalBooleanQueryNode.java @@ -0,0 +1,55 @@ +package org.apache.lucene.queryParser.original.nodes; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.queryParser.core.nodes.BooleanQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.Similarity; + +/** + * A {@link OriginalBooleanQueryNode} has the same behavior as + * {@link BooleanQueryNode}. It only indicates if the coord should be enabled or + * not for this boolean query.
+ * + * @see Similarity#coord(int, int) + * @see BooleanQuery + */ +public class OriginalBooleanQueryNode extends BooleanQueryNode { + + private static final long serialVersionUID = 1938287817191138787L; + + private boolean disableCoord; + + /** + * @param clauses + */ + public OriginalBooleanQueryNode(List clauses, boolean disableCoord) { + super(clauses); + + this.disableCoord = disableCoord; + + } + + public boolean isDisableCoord() { + return this.disableCoord; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/RangeQueryNode.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/RangeQueryNode.java new file mode 100644 index 00000000000..914da00ba83 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/RangeQueryNode.java @@ -0,0 +1,80 @@ +package org.apache.lucene.queryParser.original.nodes; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.text.Collator; + +import org.apache.lucene.queryParser.core.nodes.ParametricQueryNode; +import org.apache.lucene.queryParser.core.nodes.ParametricRangeQueryNode; +import org.apache.lucene.queryParser.original.config.RangeCollatorAttribute; +import org.apache.lucene.queryParser.original.processors.ParametricRangeQueryNodeProcessor; +import org.apache.lucene.search.MultiTermQuery; + +/** + * This query node represents a range query. It also holds which collator will + * be used by the range query and if the constant score rewrite is enabled.
+ * + * @see ParametricRangeQueryNodeProcessor + * @see RangeCollatorAttribute + * @see org.apache.lucene.search.RangeQuery + */ +public class RangeQueryNode extends ParametricRangeQueryNode { + + private static final long serialVersionUID = 7400866652044314657L; + + private Collator collator; + + private MultiTermQuery.RewriteMethod multiTermRewriteMethod; + + /** + * @param lower + * @param upper + */ + public RangeQueryNode(ParametricQueryNode lower, ParametricQueryNode upper, + Collator collator, MultiTermQuery.RewriteMethod multiTermRewriteMethod) { + super(lower, upper); + + this.multiTermRewriteMethod = multiTermRewriteMethod; + this.collator = collator; + + } + + public String toString() { + StringBuilder sb = new StringBuilder("\n\t"); + sb.append(this.getUpperBound()).append("\n\t"); + sb.append(this.getLowerBound()).append("\n"); + sb.append("\n"); + + return sb.toString(); + + } + + /** + * @return the collator + */ + public Collator getCollator() { + return this.collator; + } + + /** + * @return the rewrite method + */ + public MultiTermQuery.RewriteMethod getMultiTermRewriteMethod() { + return multiTermRewriteMethod; + } +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/package.html b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/package.html new file mode 100644 index 00000000000..e73399e8890 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/nodes/package.html @@ -0,0 +1,31 @@ + + + + + + + + +

Original Lucene Query Nodes

+

+The package org.apache.lucene.queryParser.original.nodes contains QueryNode classes +that are used specifically for Lucene query node tree. Any other generic QueryNode is +defined under org.apache.lucene.queryParser.nodes. +

+ + diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/package.html b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/package.html new file mode 100644 index 00000000000..e47b7b6d152 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/package.html @@ -0,0 +1,50 @@ + + + + + + + + +Contains the implementation of the Lucene query parser using the flexible query parser frameworks + +

Lucene Flexible Query Parser Implementation

+

+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. +

+

+The classes contained in the package org.apache.lucene.queryParser.original +are used to reproduce the same behavior as the old query parser. +

+ +

+Check org.apache.lucene.queryParser.original.OriginalQueryParserHelper to quick start using the Lucene query parser. +

+ +

+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. +

+ + + diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/EscapeQuerySyntaxImpl.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/EscapeQuerySyntaxImpl.java new file mode 100644 index 00000000000..935888c83d6 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/EscapeQuerySyntaxImpl.java @@ -0,0 +1,296 @@ +package org.apache.lucene.queryParser.original.parser; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Locale; + +import org.apache.lucene.messages.MessageImpl; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.parser.EscapeQuerySyntax; +import org.apache.lucene.queryParser.core.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 A to + * A. + * + */ + 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)); + } + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/JavaCharStream.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/JavaCharStream.java new file mode 100644 index 00000000000..3e9f18a50f9 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/JavaCharStream.java @@ -0,0 +1,617 @@ +/* Generated By:JavaCC: Do not edit this line. JavaCharStream.java Version 4.1 */ +/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ +package org.apache.lucene.queryParser.original.parser; + +/** + * 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=065d79d49fcd02f542903038e37bd9d9 (do not edit this line) */ diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/OriginalSyntaxParser.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/OriginalSyntaxParser.java new file mode 100644 index 00000000000..24723062bc7 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/OriginalSyntaxParser.java @@ -0,0 +1,955 @@ +/* Generated By:JavaCC: Do not edit this line. OriginalSyntaxParser.java */ +package org.apache.lucene.queryParser.original.parser; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.StringReader; +import java.util.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.core.QueryNodeError; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.QueryNodeParseException; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.nodes.AndQueryNode; +import org.apache.lucene.queryParser.core.nodes.BooleanQueryNode; +import org.apache.lucene.queryParser.core.nodes.BoostQueryNode; +import org.apache.lucene.queryParser.core.nodes.FieldQueryNode; +import org.apache.lucene.queryParser.core.nodes.FuzzyQueryNode; +import org.apache.lucene.queryParser.core.nodes.ModifierQueryNode; +import org.apache.lucene.queryParser.core.nodes.GroupQueryNode; +import org.apache.lucene.queryParser.core.nodes.OpaqueQueryNode; +import org.apache.lucene.queryParser.core.nodes.OrQueryNode; +import org.apache.lucene.queryParser.core.nodes.ParametricQueryNode; +import org.apache.lucene.queryParser.core.nodes.ParametricRangeQueryNode; +import org.apache.lucene.queryParser.core.nodes.PrefixWildcardQueryNode; +import org.apache.lucene.queryParser.core.nodes.SlopQueryNode; +import org.apache.lucene.queryParser.core.nodes.ProximityQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNodeImpl; +import org.apache.lucene.queryParser.core.nodes.QuotedFieldQueryNode; +import org.apache.lucene.queryParser.core.nodes.WildcardQueryNode; +import org.apache.lucene.queryParser.core.parser.SyntaxParser; + +@SuppressWarnings("all") +public class OriginalSyntaxParser implements SyntaxParser, OriginalSyntaxParserConstants { + + private static final int CONJ_NONE =0; + private static final int CONJ_AND =2; + private static final int CONJ_OR =2; + + + // syntax parser constructor + public OriginalSyntaxParser() { + this(new StringReader("")); + } + /** Parses a query string, returning a {@link org.apache.lucene.queryParser.core.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 ::= ["+", "-"] [ ":"] ( | "(" 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) { } + 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 OriginalSyntaxParserTokenManager 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 OriginalSyntaxParser(java.io.InputStream stream) { + this(stream, null); + } + /** Constructor with InputStream and supplied encoding */ + public OriginalSyntaxParser(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 OriginalSyntaxParserTokenManager(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 OriginalSyntaxParser(java.io.Reader stream) { + jj_input_stream = new JavaCharStream(stream, 1, 1); + token_source = new OriginalSyntaxParserTokenManager(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 OriginalSyntaxParser(OriginalSyntaxParserTokenManager 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(OriginalSyntaxParserTokenManager 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 jj_expentries = new java.util.ArrayList(); + 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< 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; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/OriginalSyntaxParser.jj b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/OriginalSyntaxParser.jj new file mode 100644 index 00000000000..125edc07e9e --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/OriginalSyntaxParser.jj @@ -0,0 +1,484 @@ +/** + * Original file is based on the TextParser.jj from lucene 2.3 + */ + +options { + STATIC=false; + JAVA_UNICODE_ESCAPE=true; + USER_CHAR_STREAM=false; + IGNORE_CASE=false; + JDK_VERSION="1.5"; +} + +PARSER_BEGIN(OriginalSyntaxParser) +package org.apache.lucene.queryParser.original.parser; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; + +import org.apache.lucene.messages.Message; +import org.apache.lucene.messages.MessageImpl; +import org.apache.lucene.queryParser.core.QueryNodeError; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.QueryNodeParseException; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.nodes.AndQueryNode; +import org.apache.lucene.queryParser.core.nodes.BooleanQueryNode; +import org.apache.lucene.queryParser.core.nodes.BoostQueryNode; +import org.apache.lucene.queryParser.core.nodes.FieldQueryNode; +import org.apache.lucene.queryParser.core.nodes.FuzzyQueryNode; +import org.apache.lucene.queryParser.core.nodes.ModifierQueryNode; +import org.apache.lucene.queryParser.core.nodes.GroupQueryNode; +import org.apache.lucene.queryParser.core.nodes.OpaqueQueryNode; +import org.apache.lucene.queryParser.core.nodes.OrQueryNode; +import org.apache.lucene.queryParser.core.nodes.ParametricQueryNode; +import org.apache.lucene.queryParser.core.nodes.ParametricRangeQueryNode; +import org.apache.lucene.queryParser.core.nodes.PrefixWildcardQueryNode; +import org.apache.lucene.queryParser.core.nodes.SlopQueryNode; +import org.apache.lucene.queryParser.core.nodes.ProximityQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNodeImpl; +import org.apache.lucene.queryParser.core.nodes.QuotedFieldQueryNode; +import org.apache.lucene.queryParser.core.nodes.WildcardQueryNode; +import org.apache.lucene.queryParser.core.parser.SyntaxParser; + +@SuppressWarnings("all") +public class OriginalSyntaxParser implements SyntaxParser { + + private static final int CONJ_NONE =0; + private static final int CONJ_AND =2; + private static final int CONJ_OR =2; + + + // syntax parser constructor + public OriginalSyntaxParser() { + this(new StringReader("")); + } + /** Parses a query string, returning a {@link org.apache.lucene.queryParser.core.nodes.QueryNode}. + * @param query the query string to be parsed. + * @throws ParseException if the parsing fails + */ + public QueryNode parse(CharSequence query, CharSequence field) throws QueryNodeParseException { + ReInit(new StringReader(query.toString())); + try { + // TopLevelQuery is a Query followed by the end-of-input (EOF) + QueryNode querynode = TopLevelQuery(field); + return querynode; + } + catch (ParseException tme) { + tme.setQuery(query); + throw tme; + } + catch (Error tme) { + Message message = new MessageImpl(QueryParserMessages.INVALID_SYNTAX_CANNOT_PARSE, query, tme.getMessage()); + QueryNodeParseException e = new QueryNodeParseException(tme); + e.setQuery(query); + e.setNonLocalizedMessage(message); + throw e; + } + } + +} + +PARSER_END(OriginalSyntaxParser) + +/* ***************** */ +/* 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> ) > +} + + SKIP : { + < <_WHITESPACE>> +} + + TOKEN : { + +| +| +| +| +| +| +| +| +| : Boost +| )* "\""> +| (<_TERM_CHAR>)* > +| )+ ( "." (<_NUM_CHAR>)+ )? )? > +| (<_TERM_CHAR>)* "*" ) > +| | [ "*", "?" ]) (<_TERM_CHAR> | ( [ "*", "?" ] ))* > +| : RangeIn +| : RangeEx +} + + TOKEN : { +)+ ( "." (<_NUM_CHAR>)+ )? > : DEFAULT +} + + TOKEN : { + +| : DEFAULT +| +| +} + + TOKEN : { + +| : DEFAULT +| +| +} + +// * Query ::= ( Clause )* +// * Clause ::= ["+", "-"] [ ":"] ( | "(" Query ")" ) + +int Conjunction() : { + int ret = CONJ_NONE; +} +{ + [ + { ret = CONJ_AND; } + | { ret = CONJ_OR; } + ] + { return ret; } +} + +ModifierQueryNode.Modifier Modifiers() : { + ModifierQueryNode.Modifier ret = ModifierQueryNode.Modifier.MOD_NONE; +} +{ + [ + { ret = ModifierQueryNode.Modifier.MOD_REQ; } + | { ret = ModifierQueryNode.Modifier.MOD_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) + { + 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) + ( + 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) + ( + 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= {field=EscapeQuerySyntaxImpl.discardEscapeChar(fieldToken.image);} + | {field="*";} + ) + ] + + ( + q=Term(field) + | q=Query(field) ( boost=)? {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= { q = new FieldQueryNode(field, EscapeQuerySyntaxImpl.discardEscapeChar(term.image), term.beginColumn, term.endColumn); } + | term= { wildcard=true; q = new WildcardQueryNode(field, EscapeQuerySyntaxImpl.discardEscapeChar(term.image), term.beginColumn, term.endColumn); } + | term= { prefix=true; q = new PrefixWildcardQueryNode(field, EscapeQuerySyntaxImpl.discardEscapeChar(term.image), term.beginColumn, term.endColumn); } + | term= { wildcard=true; q = new WildcardQueryNode(field, EscapeQuerySyntaxImpl.discardEscapeChar(term.image), term.beginColumn, term.endColumn); } + | term= + ) + [ fuzzySlop= { fuzzy=true; } ] + [ boost= [ fuzzySlop= { 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); + } + } + | ( ( goop1=|goop1= ) + [ ] ( goop2=|goop2= ) + ) + [ boost= ] + { + 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); + } + | ( ( goop1=|goop1= ) + [ ] ( goop2=|goop2= ) + ) + [ boost= ] + { + 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= {q = new QuotedFieldQueryNode(field, EscapeQuerySyntaxImpl.discardEscapeChar(term.image.substring(1, term.image.length()-1)), term.beginColumn + 1, term.endColumn - 1);} + [ fuzzySlop= ] + [ boost= ] + { + 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; + } +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/OriginalSyntaxParserConstants.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/OriginalSyntaxParserConstants.java new file mode 100644 index 00000000000..6fa5a47570b --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/OriginalSyntaxParserConstants.java @@ -0,0 +1,125 @@ +/* Generated By:JavaCC: Do not edit this line. OriginalSyntaxParserConstants.java */ +package org.apache.lucene.queryParser.original.parser; + + +/** + * Token literal values and constants. + * Generated by org.javacc.parser.OtherFilesGen#start() + */ +public interface OriginalSyntaxParserConstants { + + /** 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 = { + "", + "<_NUM_CHAR>", + "<_ESCAPED_CHAR>", + "<_TERM_START_CHAR>", + "<_TERM_CHAR>", + "<_WHITESPACE>", + "<_QUOTED_CHAR>", + "", + "", + "", + "", + "\"+\"", + "\"-\"", + "\"(\"", + "\")\"", + "\":\"", + "\"*\"", + "\"^\"", + "", + "", + "", + "", + "", + "\"[\"", + "\"{\"", + "", + "\"TO\"", + "\"]\"", + "", + "", + "\"TO\"", + "\"}\"", + "", + "", + }; + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/OriginalSyntaxParserTokenManager.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/OriginalSyntaxParserTokenManager.java new file mode 100644 index 00000000000..2ff8d395816 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/OriginalSyntaxParserTokenManager.java @@ -0,0 +1,1247 @@ +/* Generated By:JavaCC: Do not edit this line. OriginalSyntaxParserTokenManager.java */ +package org.apache.lucene.queryParser.original.parser; +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** Token Manager. */ +@SuppressWarnings("unused") +public class OriginalSyntaxParserTokenManager implements OriginalSyntaxParserConstants +{ + + /** 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; + } +} +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); +} +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 OriginalSyntaxParserTokenManager(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 OriginalSyntaxParserTokenManager(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); +} + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/ParseException.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/ParseException.java new file mode 100644 index 00000000000..15f87d7cad0 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/ParseException.java @@ -0,0 +1,197 @@ +/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 4.1 */ +/* JavaCCOptions:KEEP_LINE_COL=null */ +package org.apache.lucene.queryParser.original.parser; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import org.apache.lucene.messages.Message; +import org.apache.lucene.messages.MessageImpl; +import org.apache.lucene.queryParser.core.QueryNodeParseException; +import org.apache.lucene.queryParser.core.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 + * serialized 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) + */ diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/Token.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/Token.java new file mode 100644 index 00000000000..f877707971e --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/Token.java @@ -0,0 +1,131 @@ +/* Generated By:JavaCC: Do not edit this line. Token.java Version 4.1 */ +/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ +package org.apache.lucene.queryParser.original.parser; + +/** + * Describes the input token stream. + */ + +public class Token implements java.io.Serializable { + + /** + * The version identifier for this Serializable class. + * Increment only if the serialized 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=f9eb36a076cde62bf39ccbf828bc2117 (do not edit this line) */ diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/TokenMgrError.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/TokenMgrError.java new file mode 100644 index 00000000000..07af72b6277 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/TokenMgrError.java @@ -0,0 +1,147 @@ +/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 4.1 */ +/* JavaCCOptions: */ +package org.apache.lucene.queryParser.original.parser; + +/** Token Manager Error. */ +public class TokenMgrError extends Error +{ + + /** + * The version identifier for this Serializable class. + * Increment only if the serialized 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 ? " " : ("\"" + 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=91ba9c9f5e0e552a815530d639ce15ed (do not edit this line) */ diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/package.html b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/package.html new file mode 100644 index 00000000000..464b26dbf4f --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/parser/package.html @@ -0,0 +1,33 @@ + + + + + + + + +

Lucene Query Parser

+

+The package org.apache.lucene.queryParser.original.parser contains the query parser. +

+

+This text parser only performs the syntax validation and creates an QueryNode tree +from a query string. +

+ + diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/AllowLeadingWildcardProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/AllowLeadingWildcardProcessor.java new file mode 100644 index 00000000000..75b55b25d98 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/AllowLeadingWildcardProcessor.java @@ -0,0 +1,98 @@ +package org.apache.lucene.queryParser.original.processors; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.messages.MessageImpl; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.WildcardQueryNode; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorImpl; +import org.apache.lucene.queryParser.original.config.AllowLeadingWildcardAttribute; +import org.apache.lucene.queryParser.original.parser.EscapeQuerySyntaxImpl; + +/** + * 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 '?').
+ * + * @see AllowLeadingWildcardAttribute + */ +public class AllowLeadingWildcardProcessor extends QueryNodeProcessorImpl { + + public AllowLeadingWildcardProcessor() { + // empty constructor + } + + public QueryNode process(QueryNode queryTree) throws QueryNodeException { + + if (getQueryConfigHandler().hasAttribute( + AllowLeadingWildcardAttribute.class)) { + + if (!((AllowLeadingWildcardAttribute) getQueryConfigHandler() + .getAttribute(AllowLeadingWildcardAttribute.class)) + .isAllowLeadingWildcard()) { + return super.process(queryTree); + } + + } + + return queryTree; + + } + + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { + + if (node instanceof WildcardQueryNode) { + WildcardQueryNode wildcardNode = (WildcardQueryNode) node; + + switch (wildcardNode.getText().charAt(0)) { + + case '*': + case '?': + throw new QueryNodeException(new MessageImpl( + QueryParserMessages.LEADING_WILDCARD_NOT_ALLOWED, node + .toQueryString(new EscapeQuerySyntaxImpl()))); + + } + + } + + return node; + + } + + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { + + return node; + + } + + protected List setChildrenOrder(List children) + throws QueryNodeException { + + return children; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/AnalyzerQueryNodeProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/AnalyzerQueryNodeProcessor.java new file mode 100644 index 00000000000..e6877e74b4c --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/AnalyzerQueryNodeProcessor.java @@ -0,0 +1,337 @@ +package org.apache.lucene.queryParser.original.processors; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.CachingTokenFilter; +import org.apache.lucene.analysis.TokenStream; +import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute; +import org.apache.lucene.analysis.tokenattributes.TermAttribute; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.core.nodes.FieldQueryNode; +import org.apache.lucene.queryParser.core.nodes.FuzzyQueryNode; +import org.apache.lucene.queryParser.core.nodes.GroupQueryNode; +import org.apache.lucene.queryParser.core.nodes.NoTokenFoundQueryNode; +import org.apache.lucene.queryParser.core.nodes.ParametricQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.TextableQueryNode; +import org.apache.lucene.queryParser.core.nodes.TokenizedPhraseQueryNode; +import org.apache.lucene.queryParser.core.nodes.WildcardQueryNode; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorImpl; +import org.apache.lucene.queryParser.original.config.AnalyzerAttribute; +import org.apache.lucene.queryParser.original.config.PositionIncrementsAttribute; +import org.apache.lucene.queryParser.original.nodes.OriginalBooleanQueryNode; +import org.apache.lucene.queryParser.original.nodes.MultiPhraseQueryNode; + +/** + * This processor verifies if the attribute {@link AnalyzerQueryNodeProcessor} + * is defined in the {@link QueryConfigHandler}. If it is and the analyzer is + * not null, 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.
+ *
+ * If the analyzer return only one term, the returned term is set to the + * {@link FieldQueryNode} and it's returned.
+ *
+ * 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.
+ *
+ * If no term is returned by the analyzer a {@link NoTokenFoundQueryNode} object + * is returned.
+ * + * @see Analyzer + * @see TokenStream + */ +public class AnalyzerQueryNodeProcessor extends QueryNodeProcessorImpl { + + private Analyzer analyzer; + + private boolean positionIncrementsEnabled; + + public AnalyzerQueryNodeProcessor() { + // empty constructor + } + + public QueryNode process(QueryNode queryTree) throws QueryNodeException { + + if (getQueryConfigHandler().hasAttribute(AnalyzerAttribute.class)) { + + this.analyzer = ((AnalyzerAttribute) getQueryConfigHandler() + .getAttribute(AnalyzerAttribute.class)).getAnalyzer(); + + this.positionIncrementsEnabled = false; + + if (getQueryConfigHandler().hasAttribute( + PositionIncrementsAttribute.class)) { + + if (((PositionIncrementsAttribute) getQueryConfigHandler() + .getAttribute(PositionIncrementsAttribute.class)) + .isPositionIncrementsEnabled()) { + + this.positionIncrementsEnabled = true; + + } + + } + + if (this.analyzer != null) { + return super.process(queryTree); + } + + } + + return queryTree; + + } + + @Override + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { + + if (node instanceof TextableQueryNode + && !(node instanceof WildcardQueryNode) + && !(node instanceof FuzzyQueryNode) + && !(node instanceof ParametricQueryNode)) { + + FieldQueryNode fieldNode = ((FieldQueryNode) node); + String text = fieldNode.getTextAsString(); + String field = fieldNode.getFieldAsString(); + + TokenStream source = this.analyzer.tokenStream(field, new StringReader( + text)); + CachingTokenFilter buffer = new CachingTokenFilter(source); + + PositionIncrementAttribute posIncrAtt = null; + int numTokens = 0; + int positionCount = 0; + boolean severalTokensAtSamePosition = false; + + if (buffer.hasAttribute(PositionIncrementAttribute.class)) { + posIncrAtt = (PositionIncrementAttribute) buffer + .getAttribute(PositionIncrementAttribute.class); + } + + try { + + while (buffer.incrementToken()) { + numTokens++; + int positionIncrement = (posIncrAtt != null) ? posIncrAtt + .getPositionIncrement() : 1; + if (positionIncrement != 0) { + positionCount += positionIncrement; + + } else { + severalTokensAtSamePosition = true; + } + + } + + } catch (IOException e) { + // ignore + } + + try { + // rewind the buffer stream + buffer.reset(); + + // close original stream - all tokens buffered + source.close(); + } catch (IOException e) { + // ignore + } + + if (!buffer.hasAttribute(TermAttribute.class)) { + return new NoTokenFoundQueryNode(); + } + + TermAttribute termAtt = (TermAttribute) buffer + .getAttribute(TermAttribute.class); + + if (numTokens == 0) { + return new NoTokenFoundQueryNode(); + + } else if (numTokens == 1) { + String term = null; + try { + boolean hasNext; + hasNext = buffer.incrementToken(); + assert hasNext == true; + term = termAtt.term(); + + } catch (IOException e) { + // safe to ignore, because we know the number of tokens + } + + fieldNode.setText(term); + + return fieldNode; + + } else if (severalTokensAtSamePosition) { + if (positionCount == 1) { + // no phrase query: + LinkedList children = new LinkedList(); + + for (int i = 0; i < numTokens; i++) { + String term = null; + try { + boolean hasNext = buffer.incrementToken(); + assert hasNext == true; + term = termAtt.term(); + + } catch (IOException e) { + // safe to ignore, because we know the number of tokens + } + + children.add(new FieldQueryNode(field, term, -1, -1)); + + } + + return new GroupQueryNode(new OriginalBooleanQueryNode(children, true)); + + } else { + // phrase query: + MultiPhraseQueryNode mpq = new MultiPhraseQueryNode(); + + List multiTerms = new ArrayList(); + int position = -1; + int i = 0; + for (; i < numTokens; i++) { + String term = null; + int positionIncrement = 1; + try { + boolean hasNext = buffer.incrementToken(); + assert hasNext == true; + term = termAtt.term(); + if (posIncrAtt != null) { + positionIncrement = posIncrAtt.getPositionIncrement(); + } + + } catch (IOException e) { + // safe to ignore, because we know the number of tokens + } + + if (positionIncrement > 0 && multiTerms.size() > 0) { + + for (FieldQueryNode termNode : multiTerms) { + + if (this.positionIncrementsEnabled) { + termNode.setPositionIncrement(position); + + } else { + termNode.setPositionIncrement(i); + } + + mpq.add(termNode); + + } + + multiTerms.clear(); + + } + + position += positionIncrement; + multiTerms.add(new FieldQueryNode(field, term, -1, -1)); + + } + + for (FieldQueryNode termNode : multiTerms) { + + if (this.positionIncrementsEnabled) { + termNode.setPositionIncrement(position); + + } else { + termNode.setPositionIncrement(i); + } + + mpq.add(termNode); + + } + + return mpq; + + } + + } else { + + TokenizedPhraseQueryNode pq = new TokenizedPhraseQueryNode(); + + int position = -1; + + for (int i = 0; i < numTokens; i++) { + String term = null; + int positionIncrement = 1; + + try { + boolean hasNext = buffer.incrementToken(); + assert hasNext == true; + term = termAtt.term(); + + if (posIncrAtt != null) { + positionIncrement = posIncrAtt.getPositionIncrement(); + } + + } catch (IOException e) { + // safe to ignore, because we know the number of tokens + } + + FieldQueryNode newFieldNode = new FieldQueryNode(field, term, -1, -1); + + if (this.positionIncrementsEnabled) { + position += positionIncrement; + newFieldNode.setPositionIncrement(position); + + } else { + newFieldNode.setPositionIncrement(i); + } + + pq.add(newFieldNode); + + } + + return pq; + + } + + } + + return node; + + } + + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { + + return node; + + } + + protected List setChildrenOrder(List children) + throws QueryNodeException { + + return children; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/BooleanSingleChildOptimizationQueryNodeProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/BooleanSingleChildOptimizationQueryNodeProcessor.java new file mode 100644 index 00000000000..1e8c4bd74a4 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/BooleanSingleChildOptimizationQueryNodeProcessor.java @@ -0,0 +1,88 @@ +package org.apache.lucene.queryParser.original.processors; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.nodes.BooleanQueryNode; +import org.apache.lucene.queryParser.core.nodes.ModifierQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.ModifierQueryNode.Modifier; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorImpl; +import org.apache.lucene.queryParser.original.nodes.BooleanModifierNode; + +/** + * 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}
+ * + * @see ModifierQueryNode + */ +public class BooleanSingleChildOptimizationQueryNodeProcessor extends + QueryNodeProcessorImpl { + + public BooleanSingleChildOptimizationQueryNodeProcessor() { + // empty constructor + } + + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { + + if (node instanceof BooleanQueryNode) { + List 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 setChildrenOrder(List children) + throws QueryNodeException { + + return children; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/BoostQueryNodeProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/BoostQueryNodeProcessor.java new file mode 100644 index 00000000000..b4f03ab82a7 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/BoostQueryNodeProcessor.java @@ -0,0 +1,84 @@ +package org.apache.lucene.queryParser.original.processors; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.config.FieldConfig; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.core.nodes.BoostQueryNode; +import org.apache.lucene.queryParser.core.nodes.FieldableNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorImpl; +import org.apache.lucene.queryParser.original.config.BoostAttribute; + +/** + * This processor iterates the query node tree looking for every + * {@link FieldableNode} that has the attribute {@link BoostAttribute} in its + * config. If there is, the boost is applied to that {@link FieldableNode}.
+ * + * @see BoostAttribute + * @see QueryConfigHandler + * @see FieldableNode + */ +public class BoostQueryNodeProcessor extends QueryNodeProcessorImpl { + + @Override + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { + + if (node instanceof FieldableNode && + (node.getParent() == null || !(node.getParent() instanceof FieldableNode))) { + + FieldableNode fieldNode = (FieldableNode) node; + QueryConfigHandler config = getQueryConfigHandler(); + + if (config != null) { + FieldConfig fieldConfig = config.getFieldConfig(fieldNode.getField()); + + if (fieldConfig != null && fieldConfig.hasAttribute(BoostAttribute.class)) { + BoostAttribute boostAttr = (BoostAttribute) fieldConfig.getAttribute(BoostAttribute.class); + + return new BoostQueryNode(node, boostAttr.getBoost()); + + } + + } + + } + + return node; + + } + + @Override + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { + + return node; + + } + + @Override + protected List setChildrenOrder(List children) + throws QueryNodeException { + + return children; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/DefaultPhraseSlopQueryNodeProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/DefaultPhraseSlopQueryNodeProcessor.java new file mode 100644 index 00000000000..141431b0f78 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/DefaultPhraseSlopQueryNodeProcessor.java @@ -0,0 +1,115 @@ +package org.apache.lucene.queryParser.original.processors; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.SlopQueryNode; +import org.apache.lucene.queryParser.core.nodes.TokenizedPhraseQueryNode; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorImpl; +import org.apache.lucene.queryParser.original.config.DefaultPhraseSlopAttribute; +import org.apache.lucene.queryParser.original.nodes.MultiPhraseQueryNode; + +/** + * 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.
+ * + * @see SlopQueryNode + * @see DefaultPhraseSlopAttribute + */ +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 setChildrenOrder(List children) + throws QueryNodeException { + + return children; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/FuzzyQueryNodeProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/FuzzyQueryNodeProcessor.java new file mode 100644 index 00000000000..1dfe86bb497 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/FuzzyQueryNodeProcessor.java @@ -0,0 +1,86 @@ +package org.apache.lucene.queryParser.original.processors; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.core.nodes.FuzzyQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorImpl; +import org.apache.lucene.queryParser.original.config.FuzzyAttribute; +import org.apache.lucene.search.FuzzyQuery; + +/** + * This processor iterates the query node tree looking for every + * {@link FuzzyQueryNode}, when this kind of node is found, it checks on the + * query configuration for {@link FuzzyAttribute}, gets the fuzzy prefix length + * and default similarity from it and set to the fuzzy node. For more + * information about fuzzy prefix length check: {@link FuzzyQuery}.
+ * + * @see FuzzyAttribute + * @see FuzzyQuery + * @see FuzzyQueryNode + */ +public class FuzzyQueryNodeProcessor extends QueryNodeProcessorImpl { + + @Override + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { + + return node; + + } + + @Override + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { + + if (node instanceof FuzzyQueryNode) { + FuzzyQueryNode fuzzyNode = (FuzzyQueryNode) node; + QueryConfigHandler config = getQueryConfigHandler(); + + if (config != null && config.hasAttribute(FuzzyAttribute.class)) { + FuzzyAttribute fuzzyAttr = (FuzzyAttribute) config + .getAttribute(FuzzyAttribute.class); + fuzzyNode.setPrefixLength(fuzzyAttr.getPrefixLength()); + + if (fuzzyNode.getSimilarity() < 0) { + fuzzyNode.setSimilarity(fuzzyAttr.getFuzzyMinSimilarity()); + + } + + } else if (fuzzyNode.getSimilarity() < 0) { + throw new IllegalArgumentException("No " + + FuzzyAttribute.class.getName() + " set in the config"); + } + + } + + return node; + + } + + @Override + protected List setChildrenOrder(List children) + throws QueryNodeException { + + return children; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/GroupQueryNodeProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/GroupQueryNodeProcessor.java new file mode 100644 index 00000000000..cca37c468e4 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/GroupQueryNodeProcessor.java @@ -0,0 +1,219 @@ +package org.apache.lucene.queryParser.original.processors; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.ArrayList; +import java.util.List; + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.core.nodes.AndQueryNode; +import org.apache.lucene.queryParser.core.nodes.BooleanQueryNode; +import org.apache.lucene.queryParser.core.nodes.GroupQueryNode; +import org.apache.lucene.queryParser.core.nodes.ModifierQueryNode; +import org.apache.lucene.queryParser.core.nodes.OrQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.ModifierQueryNode.Modifier; +import org.apache.lucene.queryParser.core.parser.SyntaxParser; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessor; +import org.apache.lucene.queryParser.original.config.DefaultOperatorAttribute; +import org.apache.lucene.queryParser.original.config.DefaultOperatorAttribute.Operator; +import org.apache.lucene.queryParser.original.nodes.BooleanModifierNode; + +/** + * The {@link SyntaxParser} + * 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.
+ *
+ * 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 org.apache.lucene.queryParser.original.config.OriginalQueryConfigHandler + */ +public class GroupQueryNodeProcessor implements QueryNodeProcessor { + + private ArrayList queryNodeList; + + private boolean latestNodeVerified; + + private QueryConfigHandler queryConfig; + + private Boolean usingAnd = false; + + public GroupQueryNodeProcessor() { + // empty constructor + } + + public QueryNode process(QueryNode queryTree) throws QueryNodeException { + + if (!getQueryConfigHandler().hasAttribute(DefaultOperatorAttribute.class)) { + throw new IllegalArgumentException( + "DefaultOperatorAttribute should be set on the QueryConfigHandler"); + } + + usingAnd = Operator.AND == ((DefaultOperatorAttribute) getQueryConfigHandler() + .getAttribute(DefaultOperatorAttribute.class)).getOperator(); + + if (queryTree instanceof GroupQueryNode) { + queryTree = ((GroupQueryNode) queryTree).getChild(); + } + + this.queryNodeList = new ArrayList(); + this.latestNodeVerified = false; + readTree(queryTree); + + List 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 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; + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/LowercaseExpandedTermsQueryNodeProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/LowercaseExpandedTermsQueryNodeProcessor.java new file mode 100644 index 00000000000..c779fccfb31 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/LowercaseExpandedTermsQueryNodeProcessor.java @@ -0,0 +1,93 @@ +package org.apache.lucene.queryParser.original.processors; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.core.nodes.FieldQueryNode; +import org.apache.lucene.queryParser.core.nodes.FuzzyQueryNode; +import org.apache.lucene.queryParser.core.nodes.ParametricQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.WildcardQueryNode; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorImpl; +import org.apache.lucene.queryParser.original.config.LowercaseExpandedTermsAttribute; + +/** + * This processor verifies if the attribute + * {@link LowercaseExpandedTermsAttribute} is defined in the + * {@link QueryConfigHandler}. If it is and the expanded terms should be + * lower-cased, it looks for every {@link WildcardQueryNode}, + * {@link FuzzyQueryNode} and {@link ParametricQueryNode} and lower-case its + * term.
+ * + * @see LowercaseExpandedTermsAttribute + */ +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 setChildrenOrder(List children) + throws QueryNodeException { + + return children; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/MatchAllDocsQueryNodeProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/MatchAllDocsQueryNodeProcessor.java new file mode 100644 index 00000000000..08f5a325803 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/MatchAllDocsQueryNodeProcessor.java @@ -0,0 +1,73 @@ +package org.apache.lucene.queryParser.original.processors; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.nodes.MatchAllDocsQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.WildcardQueryNode; +import org.apache.lucene.queryParser.core.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 setChildrenOrder(List children) + throws QueryNodeException { + + return children; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/MultiFieldQueryNodeProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/MultiFieldQueryNodeProcessor.java new file mode 100644 index 00000000000..a03ddeed813 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/MultiFieldQueryNodeProcessor.java @@ -0,0 +1,131 @@ +package org.apache.lucene.queryParser.original.processors; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.LinkedList; +import java.util.List; + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.core.nodes.BooleanQueryNode; +import org.apache.lucene.queryParser.core.nodes.FieldableNode; +import org.apache.lucene.queryParser.core.nodes.GroupQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorImpl; +import org.apache.lucene.queryParser.original.config.MultiFieldAttribute; + +/** + * 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.
+ *
+ * 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.
+ * + * @see MultiFieldAttribute + */ +public class MultiFieldQueryNodeProcessor extends QueryNodeProcessorImpl { + + private boolean processChildren = true; + + public MultiFieldQueryNodeProcessor() { + // empty constructor + } + + protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { + + return node; + + } + + protected void processChildren(QueryNode queryTree) throws QueryNodeException { + + if (this.processChildren) { + super.processChildren(queryTree); + + } else { + this.processChildren = true; + } + + } + + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { + + if (node instanceof FieldableNode) { + this.processChildren = false; + FieldableNode fieldNode = (FieldableNode) node; + + if (fieldNode.getField() == null) { + + if (!getQueryConfigHandler().hasAttribute(MultiFieldAttribute.class)) { + throw new IllegalArgumentException( + "MultiFieldAttribute should be set on the QueryConfigHandler"); + } + + CharSequence[] fields = ((MultiFieldAttribute) getQueryConfigHandler() + .getAttribute(MultiFieldAttribute.class)).getFields(); + + if (fields != null && fields.length > 0) { + fieldNode.setField(fields[0]); + + if (fields.length == 1) { + return fieldNode; + + } else { + LinkedList children = new LinkedList(); + children.add(fieldNode); + + for (int i = 1; i < fields.length; i++) { + try { + fieldNode = (FieldableNode) fieldNode.cloneTree(); + fieldNode.setField(fields[i]); + + children.add(fieldNode); + + } catch (CloneNotSupportedException e) { + // should never happen + } + + } + + return new GroupQueryNode(new BooleanQueryNode(children)); + + } + + } + + } + + } + + return node; + + } + + protected List setChildrenOrder(List children) + throws QueryNodeException { + + return children; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/OriginalQueryNodeProcessorPipeline.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/OriginalQueryNodeProcessorPipeline.java new file mode 100644 index 00000000000..39669def82b --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/OriginalQueryNodeProcessorPipeline.java @@ -0,0 +1,70 @@ +package org.apache.lucene.queryParser.original.processors; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.core.processors.NoChildOptimizationQueryNodeProcessor; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorPipeline; +import org.apache.lucene.queryParser.core.processors.RemoveDeletedQueryNodesProcessor; +import org.apache.lucene.queryParser.original.builders.OriginalQueryTreeBuilder; +import org.apache.lucene.queryParser.original.config.OriginalQueryConfigHandler; +import org.apache.lucene.queryParser.original.parser.OriginalSyntaxParser; +import org.apache.lucene.search.Query; + +/** + * This pipeline has all the processors needed to process a query node tree, + * generated by {@link OriginalSyntaxParser}, already assembled.
+ *
+ * The order they are assembled affects the results.
+ *
+ * This processor pipeline was designed to work with + * {@link OriginalQueryConfigHandler}.
+ *
+ * The result query node tree can be used to build a {@link Query} object using + * {@link OriginalQueryTreeBuilder}.
+ * + * @see OriginalQueryTreeBuilder + * @see OriginalQueryConfigHandler + * @see OriginalSyntaxParser + */ +public class OriginalQueryNodeProcessorPipeline extends + QueryNodeProcessorPipeline { + + public OriginalQueryNodeProcessorPipeline(QueryConfigHandler queryConfig) { + super(queryConfig); + + addProcessor(new MultiFieldQueryNodeProcessor()); + addProcessor(new FuzzyQueryNodeProcessor()); + addProcessor(new MatchAllDocsQueryNodeProcessor()); + addProcessor(new LowercaseExpandedTermsQueryNodeProcessor()); + addProcessor(new ParametricRangeQueryNodeProcessor()); + addProcessor(new AllowLeadingWildcardProcessor()); + addProcessor(new PrefixWildcardQueryNodeProcessor()); + addProcessor(new AnalyzerQueryNodeProcessor()); + addProcessor(new PhraseSlopQueryNodeProcessor()); + addProcessor(new GroupQueryNodeProcessor()); + addProcessor(new NoChildOptimizationQueryNodeProcessor()); + addProcessor(new RemoveDeletedQueryNodesProcessor()); + addProcessor(new RemoveEmptyNonLeafQueryNodeProcessor()); + addProcessor(new BooleanSingleChildOptimizationQueryNodeProcessor()); + addProcessor(new DefaultPhraseSlopQueryNodeProcessor()); + addProcessor(new BoostQueryNodeProcessor()); + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/ParametricRangeQueryNodeProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/ParametricRangeQueryNodeProcessor.java new file mode 100644 index 00000000000..7158922360a --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/ParametricRangeQueryNodeProcessor.java @@ -0,0 +1,188 @@ +package org.apache.lucene.queryParser.original.processors; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.text.Collator; +import java.text.DateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import org.apache.lucene.document.DateField; +import org.apache.lucene.document.DateTools; +import org.apache.lucene.document.DateTools.Resolution; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.config.FieldConfig; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.core.nodes.ParametricQueryNode; +import org.apache.lucene.queryParser.core.nodes.ParametricRangeQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.ParametricQueryNode.CompareOperator; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorImpl; +import org.apache.lucene.queryParser.original.config.MultiTermRewriteMethodAttribute; +import org.apache.lucene.queryParser.original.config.DateResolutionAttribute; +import org.apache.lucene.queryParser.original.config.LocaleAttribute; +import org.apache.lucene.queryParser.original.config.RangeCollatorAttribute; +import org.apache.lucene.queryParser.original.nodes.RangeQueryNode; +import org.apache.lucene.search.MultiTermQuery; + +/** + * 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.
+ *
+ * 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.
+ *
+ * If a {@link DateResolutionAttribute} is defined and the {@link Resolution} is + * not null it will also be used to parse the date value.
+ *
+ * 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 null, it's set on the + * {@link RangeQueryNode}.
+ * + * @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( + MultiTermRewriteMethodAttribute.class)) { + throw new IllegalArgumentException( + "MultiTermRewriteMethodAttribute should be set on the QueryConfigHandler"); + } + + MultiTermQuery.RewriteMethod rewriteMethod = ((MultiTermRewriteMethodAttribute) getQueryConfigHandler() + .getAttribute(MultiTermRewriteMethodAttribute.class)) + .getMultiTermRewriteMethod(); + + 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, rewriteMethod); + + } + + return node; + + } + + protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { + + return node; + + } + + protected List setChildrenOrder(List children) + throws QueryNodeException { + + return children; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/PhraseSlopQueryNodeProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/PhraseSlopQueryNodeProcessor.java new file mode 100644 index 00000000000..086809cca28 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/PhraseSlopQueryNodeProcessor.java @@ -0,0 +1,71 @@ +package org.apache.lucene.queryParser.original.processors; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.SlopQueryNode; +import org.apache.lucene.queryParser.core.nodes.TokenizedPhraseQueryNode; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorImpl; +import org.apache.lucene.queryParser.original.nodes.MultiPhraseQueryNode; + +/** + * 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}.
+ * + * @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 setChildrenOrder(List children) + throws QueryNodeException { + + return children; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/PrefixWildcardQueryNodeProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/PrefixWildcardQueryNodeProcessor.java new file mode 100644 index 00000000000..afee0cfb820 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/PrefixWildcardQueryNodeProcessor.java @@ -0,0 +1,72 @@ +package org.apache.lucene.queryParser.original.processors; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.nodes.PrefixWildcardQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorImpl; +import org.apache.lucene.queryParser.original.parser.OriginalSyntaxParser; +import org.apache.lucene.search.PrefixQuery; + +/** + * The {@link OriginalSyntaxParser} 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.
+ * + * @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 setChildrenOrder(List children) + throws QueryNodeException { + + return children; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/RemoveEmptyNonLeafQueryNodeProcessor.java b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/RemoveEmptyNonLeafQueryNodeProcessor.java new file mode 100644 index 00000000000..d922cb31c0d --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/RemoveEmptyNonLeafQueryNodeProcessor.java @@ -0,0 +1,112 @@ +package org.apache.lucene.queryParser.original.processors; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.LinkedList; +import java.util.List; + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.nodes.GroupQueryNode; +import org.apache.lucene.queryParser.core.nodes.MatchNoDocsQueryNode; +import org.apache.lucene.queryParser.core.nodes.ModifierQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.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.
+ *
+ * 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.
+ * + * @see QueryNode + * @see MatchNoDocsQueryNode + */ +public class RemoveEmptyNonLeafQueryNodeProcessor extends + QueryNodeProcessorImpl { + + private LinkedList childrenBuffer = new LinkedList(); + + public RemoveEmptyNonLeafQueryNodeProcessor() { + // empty constructor + } + + public QueryNode process(QueryNode queryTree) throws QueryNodeException { + queryTree = super.process(queryTree); + + if (!queryTree.isLeaf()) { + + List 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 setChildrenOrder(List children) + throws QueryNodeException { + + try { + + for (QueryNode child : children) { + + if (!child.isLeaf()) { + + List 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; + + } + +} diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/package.html b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/package.html new file mode 100644 index 00000000000..16d11107580 --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/original/processors/package.html @@ -0,0 +1,33 @@ + + + + + + + + +

Lucene Query Node Processors

+

+The package org.apache.lucene.queryParser.original.processors contains every processor needed to assembly a pipeline +that modifies the query node tree according to the actual Lucene queries. +

+

+This processors are already assembled correctly in the OriginalQueryNodeProcessorPipeline. +

+ + diff --git a/contrib/queryparser/src/java/org/apache/lucene/queryParser/package.html b/contrib/queryparser/src/java/org/apache/lucene/queryParser/package.html new file mode 100644 index 00000000000..82767b91d4c --- /dev/null +++ b/contrib/queryparser/src/java/org/apache/lucene/queryParser/package.html @@ -0,0 +1,131 @@ + + + + + + + + +

Flexible Query Parser

+

+Features: +

    +
  1. Full support for lucene 2.4.2 syntax
  2. +
  3. Full support for boolean logic (not enabled)
  4. +
  5. QueryNode Trees - support for several syntaxes, + that can be converted into similar syntax QueryNode trees.
  6. +
  7. QueryNode Processors - Optimize, validate, rewrite the + QueryNode trees
  8. +
  9. Processors Pipelines - Select your favorite Processor + and build a processor pipeline, to implement the features you need
  10. +
  11. Config Interfaces - Allow the consumer of the Query Parser to implement + a diff Config Handler Objects to suite their needs.
  12. +
  13. Original Builders - convert QueryNode's into several lucene + representations. Supported conversion is using a 2.4 compatible logic
  14. +
  15. QueryNode tree's can be converted to a lucene 2.4 syntax string, using toQueryString
  16. +
+

+ + +

+This new query parser was designed to have very generic +architecture, so that it can be easily used for different +products with varying query syntaxes. This code is much more +flexible and extensible than the Lucene query parser in 2.4.X. +

+

+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. +

+

+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': +

+

+ AND
+ / \
+A B
+

+

+The three layers are:
+1. QueryParser
+2. QueryNodeProcessor
+3. QueryBuilder
+

+

+1. This layer is the text parsing layer which simply transforms the +query text string into a {@link org.apache.lucene.queryParser.core.nodes.QueryNode} tree. Every text parser +must implement the interface {@link org.apache.lucene.queryParser.core.parser.SyntaxParser}. +Lucene default implementations implements it using 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 a configurable map of builders, which map {@link org.apache.lucene.queryParser.core.nodes.QueryNode} types to its specific +builder that will transform the QueryNode into Lucene Query object. +

+

+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. +

+

+This design allows to develop different query syntaxes very quickly. +

+

+A original lucene-compatible syntax is implemented using this new query parser +API and is located under org.apache.lucene.queryParser.original. +

+To make it simpler to use the new query parser +the class {@link org.apache.lucene.queryParser.original.OriginalQueryParserHelper} may be helpful, +specially for people that do not want to extend the Query Parser. +It uses the default Lucene query processors, text parser and builders, so +you don't need to worry about dealing with those. + +{@link org.apache.lucene.queryParser.original.OriginalQueryParserHelper} usage: +

    +OriginalQueryParserHelper qpHelper = new OriginalQueryParserHelper(); + +

    +OriginalQueryConfigHandler config = qpHelper.getQueryConfigHandler(); +

    +config.setAllowLeadingWildcard(true); +

    +config.setAnalyzer(new WhitespaceAnalyzer()); +

    +Query query = qpHelper.parse("apache AND lucene", "defaultField"); +
+To make it easy for people who are using current Lucene's query parser to switch to +the new one, there is a {@link org.apache.lucene.queryParser.original.QueryParserWrapper} under org.apache.lucene.queryParser.original +that keeps the old query parser interface, but uses the new query parser infrastructure. +

+

+
+ + diff --git a/contrib/queryparser/src/java/overview.html b/contrib/queryparser/src/java/overview.html new file mode 100644 index 00000000000..c0afd906b52 --- /dev/null +++ b/contrib/queryparser/src/java/overview.html @@ -0,0 +1,39 @@ + + + + Apache Lucene Flexible Query Parser + + + +

Apache Lucene Flexible Query Parser

+ +

+This contrib project contains the new Lucene query parser implementation, which is going to replace the old query parser on Lucene 3.0. +

+ +

+It's currently divided in 3 main packages: +

    +
  • {@link org.apache.lucene.messages}: it contains the API to defined lazily loaded messages. This message API is used by the new query parser to support localized messages.
  • +
  • {@link org.apache.lucene.queryParser.core}: it contains the query parser API classes, which should be extended by query parser implementations.
  • +
  • {@link org.apache.lucene.queryParser.original}: it contains the current Lucene query parser implementation using the new query parser API.
  • +
+

+ + + diff --git a/contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle.java b/contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle.java new file mode 100644 index 00000000000..d12b6d55e99 --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle.java @@ -0,0 +1,40 @@ +package org.apache.lucene.messages; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +public class MessagesTestBundle extends NLS { + + private static final String BUNDLE_NAME = MessagesTestBundle.class.getName(); + + private MessagesTestBundle() { + // should never be instantiated + } + + static { + // register all string ids with NLS class and initialize static string + // values + NLS.initializeMessages(BUNDLE_NAME, MessagesTestBundle.class); + } + + // static string must match the strings in the property files. + public static String Q0001E_INVALID_SYNTAX; + public static String Q0004E_INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION; + + // this message is missing from the properties file + public static String Q0005E_MESSAGE_NOT_IN_BUNDLE; +} diff --git a/contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle.properties b/contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle.properties new file mode 100644 index 00000000000..870ff7312a5 --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle.properties @@ -0,0 +1,3 @@ +Q0001E_INVALID_SYNTAX = Syntax Error: {0} + +Q0004E_INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION = Truncated unicode escape sequence. diff --git a/contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle_ja.properties b/contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle_ja.properties new file mode 100644 index 00000000000..2235294ca91 --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/messages/MessagesTestBundle_ja.properties @@ -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 diff --git a/contrib/queryparser/src/test/org/apache/lucene/messages/TestNLS.java b/contrib/queryparser/src/test/org/apache/lucene/messages/TestNLS.java new file mode 100644 index 00000000000..35e35a973f3 --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/messages/TestNLS.java @@ -0,0 +1,81 @@ +package org.apache.lucene.messages; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Locale; + +import junit.framework.TestCase; + +/** + */ +public class TestNLS extends TestCase { + public void testMessageLoading() { + Message invalidSyntax = new MessageImpl( + MessagesTestBundle.Q0001E_INVALID_SYNTAX, "XXX"); + assertEquals("Syntax Error: XXX", invalidSyntax.getLocalizedMessage()); + } + + public void testMessageLoading_ja() { + Message invalidSyntax = new MessageImpl( + MessagesTestBundle.Q0001E_INVALID_SYNTAX, "XXX"); + assertEquals("構文エラー: XXX", invalidSyntax + .getLocalizedMessage(Locale.JAPANESE)); + } + + public void testNLSLoading() { + String message = NLS + .getLocalizedMessage(MessagesTestBundle.Q0004E_INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION); + assertEquals("Truncated unicode escape sequence.", message); + + message = NLS.getLocalizedMessage(MessagesTestBundle.Q0001E_INVALID_SYNTAX, + "XXX"); + assertEquals("Syntax Error: XXX", message); + } + + public void testNLSLoading_ja() { + String message = NLS.getLocalizedMessage( + MessagesTestBundle.Q0004E_INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION, + Locale.JAPANESE); + assertEquals("切り捨てられたユニコード・エスケープ・シーケンス。", message); + + message = NLS.getLocalizedMessage(MessagesTestBundle.Q0001E_INVALID_SYNTAX, + Locale.JAPANESE, "XXX"); + assertEquals("構文エラー: XXX", message); + } + + public void testNLSLoading_xx_XX() { + Locale locale = new Locale("xx", "XX", ""); + String message = NLS.getLocalizedMessage( + MessagesTestBundle.Q0004E_INVALID_SYNTAX_ESCAPE_UNICODE_TRUNCATION, + locale); + assertEquals("Truncated unicode escape sequence.", message); + + message = NLS.getLocalizedMessage(MessagesTestBundle.Q0001E_INVALID_SYNTAX, + locale, "XXX"); + assertEquals("Syntax Error: XXX", message); + } + + public void testMissingMessage() { + Locale locale = Locale.ENGLISH; + String message = NLS.getLocalizedMessage( + MessagesTestBundle.Q0005E_MESSAGE_NOT_IN_BUNDLE, locale); + + assertEquals("Message with key:Q0005E_MESSAGE_NOT_IN_BUNDLE and locale: " + + locale.toString() + " not found.", message); + } +} diff --git a/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiAnalyzerQPHelper.java b/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiAnalyzerQPHelper.java new file mode 100644 index 00000000000..e3a0434ad61 --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiAnalyzerQPHelper.java @@ -0,0 +1,326 @@ +package org.apache.lucene.queryParser.original; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.IOException; +import java.io.Reader; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.LowerCaseFilter; +import org.apache.lucene.analysis.Token; +import org.apache.lucene.analysis.TokenFilter; +import org.apache.lucene.analysis.TokenStream; +import org.apache.lucene.analysis.standard.StandardTokenizer; +import org.apache.lucene.analysis.tokenattributes.OffsetAttribute; +import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute; +import org.apache.lucene.analysis.tokenattributes.TermAttribute; +import org.apache.lucene.analysis.tokenattributes.TypeAttribute; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.original.OriginalQueryParserHelper; +import org.apache.lucene.queryParser.original.config.DefaultOperatorAttribute.Operator; +import org.apache.lucene.util.LuceneTestCase; + +/** + * This test case is a copy of the core Lucene query parser test, it was adapted + * to use new QueryParserHelper instead of the old query parser. + * + * Test QueryParser's ability to deal with Analyzers that return more than one + * token per position or that return tokens with a position increment > 1. + */ +public class TestMultiAnalyzerQPHelper extends LuceneTestCase { + + private static int multiToken = 0; + + public void testMultiAnalyzer() throws QueryNodeException { + + OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + qp.setAnalyzer(new MultiAnalyzer()); + + // trivial, no multiple tokens: + assertEquals("foo", qp.parse("foo", "").toString()); + assertEquals("foo", qp.parse("\"foo\"", "").toString()); + assertEquals("foo foobar", qp.parse("foo foobar", "").toString()); + assertEquals("\"foo foobar\"", qp.parse("\"foo foobar\"", "").toString()); + assertEquals("\"foo foobar blah\"", qp.parse("\"foo foobar blah\"", "") + .toString()); + + // two tokens at the same position: + assertEquals("(multi multi2) foo", qp.parse("multi foo", "").toString()); + assertEquals("foo (multi multi2)", qp.parse("foo multi", "").toString()); + assertEquals("(multi multi2) (multi multi2)", qp.parse("multi multi", "") + .toString()); + assertEquals("+(foo (multi multi2)) +(bar (multi multi2))", qp.parse( + "+(foo multi) +(bar multi)", "").toString()); + assertEquals("+(foo (multi multi2)) field:\"bar (multi multi2)\"", qp + .parse("+(foo multi) field:\"bar multi\"", "").toString()); + + // phrases: + assertEquals("\"(multi multi2) foo\"", qp.parse("\"multi foo\"", "") + .toString()); + assertEquals("\"foo (multi multi2)\"", qp.parse("\"foo multi\"", "") + .toString()); + assertEquals("\"foo (multi multi2) foobar (multi multi2)\"", qp.parse( + "\"foo multi foobar multi\"", "").toString()); + + // fields: + assertEquals("(field:multi field:multi2) field:foo", qp.parse( + "field:multi field:foo", "").toString()); + assertEquals("field:\"(multi multi2) foo\"", qp.parse( + "field:\"multi foo\"", "").toString()); + + // three tokens at one position: + assertEquals("triplemulti multi3 multi2", qp.parse("triplemulti", "") + .toString()); + assertEquals("foo (triplemulti multi3 multi2) foobar", qp.parse( + "foo triplemulti foobar", "").toString()); + + // phrase with non-default slop: + assertEquals("\"(multi multi2) foo\"~10", qp.parse("\"multi foo\"~10", "") + .toString()); + + // phrase with non-default boost: + assertEquals("\"(multi multi2) foo\"^2.0", qp.parse("\"multi foo\"^2", "") + .toString()); + + // phrase after changing default slop + qp.setDefaultPhraseSlop(99); + assertEquals("\"(multi multi2) foo\"~99 bar", qp.parse("\"multi foo\" bar", + "").toString()); + assertEquals("\"(multi multi2) foo\"~99 \"foo bar\"~2", qp.parse( + "\"multi foo\" \"foo bar\"~2", "").toString()); + qp.setDefaultPhraseSlop(0); + + // non-default operator: + qp.setDefaultOperator(Operator.AND); + assertEquals("+(multi multi2) +foo", qp.parse("multi foo", "").toString()); + + } + + // public void testMultiAnalyzerWithSubclassOfQueryParser() throws + // ParseException { + // this test doesn't make sense when using the new QueryParser API + // DumbQueryParser qp = new DumbQueryParser("", new MultiAnalyzer()); + // qp.setPhraseSlop(99); // modified default slop + // + // // direct call to (super's) getFieldQuery to demonstrate differnce + // // between phrase and multiphrase with modified default slop + // assertEquals("\"foo bar\"~99", + // qp.getSuperFieldQuery("","foo bar").toString()); + // assertEquals("\"(multi multi2) bar\"~99", + // qp.getSuperFieldQuery("","multi bar").toString()); + // + // + // // ask sublcass to parse phrase with modified default slop + // assertEquals("\"(multi multi2) foo\"~99 bar", + // qp.parse("\"multi foo\" bar").toString()); + // + // } + + public void testPosIncrementAnalyzer() throws QueryNodeException { + OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + qp.setAnalyzer(new PosIncrementAnalyzer()); + + assertEquals("quick brown", qp.parse("the quick brown", "").toString()); + assertEquals("\"quick brown\"", qp.parse("\"the quick brown\"", "") + .toString()); + assertEquals("quick brown fox", qp.parse("the quick brown fox", "") + .toString()); + assertEquals("\"quick brown fox\"", qp.parse("\"the quick brown fox\"", "") + .toString()); + } + + /** + * Expands "multi" to "multi" and "multi2", both at the same position, and + * expands "triplemulti" to "triplemulti", "multi3", and "multi2". + */ + private class MultiAnalyzer extends Analyzer { + + public MultiAnalyzer() { + } + + public TokenStream tokenStream(String fieldName, Reader reader) { + TokenStream result = new StandardTokenizer(reader); + result = new TestFilter(result); + result = new LowerCaseFilter(result); + return result; + } + } + + private final class TestFilter extends TokenFilter { + + private String prevType; + private int prevStartOffset; + private int prevEndOffset; + + TermAttribute termAtt; + PositionIncrementAttribute posIncrAtt; + OffsetAttribute offsetAtt; + TypeAttribute typeAtt; + + public TestFilter(TokenStream in) { + super(in); + termAtt = (TermAttribute) addAttribute(TermAttribute.class); + posIncrAtt = (PositionIncrementAttribute) addAttribute(PositionIncrementAttribute.class); + offsetAtt = (OffsetAttribute) addAttribute(OffsetAttribute.class); + typeAtt = (TypeAttribute) addAttribute(TypeAttribute.class); + + } + + /* + * (non-Javadoc) + * + * @see + * org.apache.lucene.analysis.TokenStream#next(org.apache.lucene.analysis + * .Token) + */ + @Override + public Token next(Token reusableToken) throws IOException { + + if (multiToken > 0) { + reusableToken.setTermBuffer("multi" + (multiToken + 1)); + reusableToken.setStartOffset(prevStartOffset); + reusableToken.setEndOffset(prevEndOffset); + reusableToken.setType(prevType); + reusableToken.setPositionIncrement(0); + multiToken--; + return reusableToken; + } else { + boolean next = (reusableToken = input.next(token)) != null; + if (next == false) { + return null; + } + prevType = reusableToken.type(); + prevStartOffset = reusableToken.startOffset(); + prevEndOffset = reusableToken.endOffset(); + String text = reusableToken.term(); + if (text.equals("triplemulti")) { + multiToken = 2; + return reusableToken; + } else if (text.equals("multi")) { + multiToken = 1; + return reusableToken; + } else { + return reusableToken; + } + } + + } + + private Token token = new Token(); + + public final boolean incrementToken() throws java.io.IOException { + if (multiToken > 0) { + termAtt.setTermBuffer("multi" + (multiToken + 1)); + offsetAtt.setOffset(prevStartOffset, prevEndOffset); + typeAtt.setType(prevType); + posIncrAtt.setPositionIncrement(0); + multiToken--; + return true; + } else { + boolean next = input.incrementToken(); + if (next == false) { + return false; + } + prevType = typeAtt.type(); + prevStartOffset = offsetAtt.startOffset(); + prevEndOffset = offsetAtt.endOffset(); + String text = termAtt.term(); + if (text.equals("triplemulti")) { + multiToken = 2; + return true; + } else if (text.equals("multi")) { + multiToken = 1; + return true; + } else { + return true; + } + } + } + + } + + /** + * Analyzes "the quick brown" as: quick(incr=2) brown(incr=1). Does not work + * correctly for input other than "the quick brown ...". + */ + private class PosIncrementAnalyzer extends Analyzer { + + public PosIncrementAnalyzer() { + } + + public TokenStream tokenStream(String fieldName, Reader reader) { + TokenStream result = new StandardTokenizer(reader); + result = new TestPosIncrementFilter(result); + result = new LowerCaseFilter(result); + return result; + } + } + + private class TestPosIncrementFilter extends TokenFilter { + + TermAttribute termAtt; + PositionIncrementAttribute posIncrAtt; + + public TestPosIncrementFilter(TokenStream in) { + super(in); + termAtt = (TermAttribute) addAttribute(TermAttribute.class); + posIncrAtt = (PositionIncrementAttribute) addAttribute(PositionIncrementAttribute.class); + } + + private Token token = new Token(); + + /* + * (non-Javadoc) + * + * @see org.apache.lucene.analysis.TokenStream#next() + */ + @Override + public Token next(Token reusableToken) throws IOException { + while (null != (reusableToken = input.next(token))) { + String term = reusableToken.term(); + if (term.equals("the")) { + // stopword, do nothing + } else if (term.equals("quick")) { + reusableToken.setPositionIncrement(2); + return reusableToken; + } else { + reusableToken.setPositionIncrement(1); + return reusableToken; + } + } + return null; + } + + public final boolean incrementToken() throws java.io.IOException { + while (input.incrementToken()) { + if (termAtt.term().equals("the")) { + // stopword, do nothing + } else if (termAtt.term().equals("quick")) { + posIncrAtt.setPositionIncrement(2); + return true; + } else { + posIncrAtt.setPositionIncrement(1); + return true; + } + } + return false; + } + + } + +} diff --git a/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiAnalyzerWrapper.java b/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiAnalyzerWrapper.java new file mode 100644 index 00000000000..fcfcab4567e --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiAnalyzerWrapper.java @@ -0,0 +1,320 @@ +package org.apache.lucene.queryParser.original; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.IOException; +import java.io.Reader; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.LowerCaseFilter; +import org.apache.lucene.analysis.Token; +import org.apache.lucene.analysis.TokenFilter; +import org.apache.lucene.analysis.TokenStream; +import org.apache.lucene.analysis.standard.StandardTokenizer; +import org.apache.lucene.analysis.tokenattributes.OffsetAttribute; +import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute; +import org.apache.lucene.analysis.tokenattributes.TermAttribute; +import org.apache.lucene.analysis.tokenattributes.TypeAttribute; +import org.apache.lucene.queryParser.ParseException; +import org.apache.lucene.queryParser.original.QueryParserWrapper; +import org.apache.lucene.util.LuceneTestCase; + +/** + * This test case is a copy of the core Lucene query parser test, it was adapted + * to use new QueryParserWrapper instead of the old query parser. + * + * Test QueryParser's ability to deal with Analyzers that return more than one + * token per position or that return tokens with a position increment > 1. + * + */ +public class TestMultiAnalyzerWrapper extends LuceneTestCase { + + private static int multiToken = 0; + + public void testMultiAnalyzer() throws ParseException { + + QueryParserWrapper qp = new QueryParserWrapper("", new MultiAnalyzer()); + + // trivial, no multiple tokens: + assertEquals("foo", qp.parse("foo").toString()); + assertEquals("foo", qp.parse("\"foo\"").toString()); + assertEquals("foo foobar", qp.parse("foo foobar").toString()); + assertEquals("\"foo foobar\"", qp.parse("\"foo foobar\"").toString()); + assertEquals("\"foo foobar blah\"", qp.parse("\"foo foobar blah\"") + .toString()); + + // two tokens at the same position: + assertEquals("(multi multi2) foo", qp.parse("multi foo").toString()); + assertEquals("foo (multi multi2)", qp.parse("foo multi").toString()); + assertEquals("(multi multi2) (multi multi2)", qp.parse("multi multi") + .toString()); + assertEquals("+(foo (multi multi2)) +(bar (multi multi2))", qp.parse( + "+(foo multi) +(bar multi)").toString()); + assertEquals("+(foo (multi multi2)) field:\"bar (multi multi2)\"", qp + .parse("+(foo multi) field:\"bar multi\"").toString()); + + // phrases: + assertEquals("\"(multi multi2) foo\"", qp.parse("\"multi foo\"").toString()); + assertEquals("\"foo (multi multi2)\"", qp.parse("\"foo multi\"").toString()); + assertEquals("\"foo (multi multi2) foobar (multi multi2)\"", qp.parse( + "\"foo multi foobar multi\"").toString()); + + // fields: + assertEquals("(field:multi field:multi2) field:foo", qp.parse( + "field:multi field:foo").toString()); + assertEquals("field:\"(multi multi2) foo\"", qp + .parse("field:\"multi foo\"").toString()); + + // three tokens at one position: + assertEquals("triplemulti multi3 multi2", qp.parse("triplemulti") + .toString()); + assertEquals("foo (triplemulti multi3 multi2) foobar", qp.parse( + "foo triplemulti foobar").toString()); + + // phrase with non-default slop: + assertEquals("\"(multi multi2) foo\"~10", qp.parse("\"multi foo\"~10") + .toString()); + + // phrase with non-default boost: + assertEquals("\"(multi multi2) foo\"^2.0", qp.parse("\"multi foo\"^2") + .toString()); + + // phrase after changing default slop + qp.setPhraseSlop(99); + assertEquals("\"(multi multi2) foo\"~99 bar", qp.parse("\"multi foo\" bar") + .toString()); + assertEquals("\"(multi multi2) foo\"~99 \"foo bar\"~2", qp.parse( + "\"multi foo\" \"foo bar\"~2").toString()); + qp.setPhraseSlop(0); + + // non-default operator: + qp.setDefaultOperator(QueryParserWrapper.AND_OPERATOR); + assertEquals("+(multi multi2) +foo", qp.parse("multi foo").toString()); + + } + + // public void testMultiAnalyzerWithSubclassOfQueryParser() throws + // ParseException { + // this test doesn't make sense when using the new QueryParser API + // DumbQueryParser qp = new DumbQueryParser("", new MultiAnalyzer()); + // qp.setPhraseSlop(99); // modified default slop + // + // // direct call to (super's) getFieldQuery to demonstrate differnce + // // between phrase and multiphrase with modified default slop + // assertEquals("\"foo bar\"~99", + // qp.getSuperFieldQuery("","foo bar").toString()); + // assertEquals("\"(multi multi2) bar\"~99", + // qp.getSuperFieldQuery("","multi bar").toString()); + // + // + // // ask sublcass to parse phrase with modified default slop + // assertEquals("\"(multi multi2) foo\"~99 bar", + // qp.parse("\"multi foo\" bar").toString()); + // + // } + + public void testPosIncrementAnalyzer() throws ParseException { + QueryParserWrapper qp = new QueryParserWrapper("", + new PosIncrementAnalyzer()); + assertEquals("quick brown", qp.parse("the quick brown").toString()); + assertEquals("\"quick brown\"", qp.parse("\"the quick brown\"").toString()); + assertEquals("quick brown fox", qp.parse("the quick brown fox").toString()); + assertEquals("\"quick brown fox\"", qp.parse("\"the quick brown fox\"") + .toString()); + } + + /** + * Expands "multi" to "multi" and "multi2", both at the same position, and + * expands "triplemulti" to "triplemulti", "multi3", and "multi2". + */ + private class MultiAnalyzer extends Analyzer { + + public MultiAnalyzer() { + } + + public TokenStream tokenStream(String fieldName, Reader reader) { + TokenStream result = new StandardTokenizer(reader); + result = new TestFilter(result); + result = new LowerCaseFilter(result); + return result; + } + } + + private final class TestFilter extends TokenFilter { + + private String prevType; + private int prevStartOffset; + private int prevEndOffset; + + TermAttribute termAtt; + PositionIncrementAttribute posIncrAtt; + OffsetAttribute offsetAtt; + TypeAttribute typeAtt; + + public TestFilter(TokenStream in) { + super(in); + termAtt = (TermAttribute) addAttribute(TermAttribute.class); + posIncrAtt = (PositionIncrementAttribute) addAttribute(PositionIncrementAttribute.class); + offsetAtt = (OffsetAttribute) addAttribute(OffsetAttribute.class); + typeAtt = (TypeAttribute) addAttribute(TypeAttribute.class); + + } + + /* + * (non-Javadoc) + * + * @see + * org.apache.lucene.analysis.TokenStream#next(org.apache.lucene.analysis + * .Token) + */ + @Override + public Token next(Token reusableToken) throws IOException { + + if (multiToken > 0) { + reusableToken.setTermBuffer("multi" + (multiToken + 1)); + reusableToken.setStartOffset(prevStartOffset); + reusableToken.setEndOffset(prevEndOffset); + reusableToken.setType(prevType); + reusableToken.setPositionIncrement(0); + multiToken--; + return reusableToken; + } else { + boolean next = (reusableToken = input.next(token)) != null; + if (next == false) { + return null; + } + prevType = reusableToken.type(); + prevStartOffset = reusableToken.startOffset(); + prevEndOffset = reusableToken.endOffset(); + String text = reusableToken.term(); + if (text.equals("triplemulti")) { + multiToken = 2; + return reusableToken; + } else if (text.equals("multi")) { + multiToken = 1; + return reusableToken; + } else { + return reusableToken; + } + } + + } + + private Token token = new Token(); + + public final boolean incrementToken() throws java.io.IOException { + if (multiToken > 0) { + termAtt.setTermBuffer("multi" + (multiToken + 1)); + offsetAtt.setOffset(prevStartOffset, prevEndOffset); + typeAtt.setType(prevType); + posIncrAtt.setPositionIncrement(0); + multiToken--; + return true; + } else { + boolean next = input.incrementToken(); + if (next == false) { + return false; + } + prevType = typeAtt.type(); + prevStartOffset = offsetAtt.startOffset(); + prevEndOffset = offsetAtt.endOffset(); + String text = termAtt.term(); + if (text.equals("triplemulti")) { + multiToken = 2; + return true; + } else if (text.equals("multi")) { + multiToken = 1; + return true; + } else { + return true; + } + } + } + + } + + /** + * Analyzes "the quick brown" as: quick(incr=2) brown(incr=1). Does not work + * correctly for input other than "the quick brown ...". + */ + private class PosIncrementAnalyzer extends Analyzer { + + public PosIncrementAnalyzer() { + } + + public TokenStream tokenStream(String fieldName, Reader reader) { + TokenStream result = new StandardTokenizer(reader); + result = new TestPosIncrementFilter(result); + result = new LowerCaseFilter(result); + return result; + } + } + + private class TestPosIncrementFilter extends TokenFilter { + + TermAttribute termAtt; + PositionIncrementAttribute posIncrAtt; + + public TestPosIncrementFilter(TokenStream in) { + super(in); + termAtt = (TermAttribute) addAttribute(TermAttribute.class); + posIncrAtt = (PositionIncrementAttribute) addAttribute(PositionIncrementAttribute.class); + } + + private Token token = new Token(); + + /* + * (non-Javadoc) + * + * @see org.apache.lucene.analysis.TokenStream#next() + */ + @Override + public Token next(Token reusableToken) throws IOException { + while (null != (reusableToken = input.next(token))) { + String term = reusableToken.term(); + if (term.equals("the")) { + // stopword, do nothing + } else if (term.equals("quick")) { + reusableToken.setPositionIncrement(2); + return reusableToken; + } else { + reusableToken.setPositionIncrement(1); + return reusableToken; + } + } + return null; + } + + public final boolean incrementToken() throws java.io.IOException { + while (input.incrementToken()) { + if (termAtt.term().equals("the")) { + // stopword, do nothing + } else if (termAtt.term().equals("quick")) { + posIncrAtt.setPositionIncrement(2); + return true; + } else { + posIncrAtt.setPositionIncrement(1); + return true; + } + } + return false; + } + + } + +} diff --git a/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiFieldQPHelper.java b/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiFieldQPHelper.java new file mode 100644 index 00000000000..3430d3cd082 --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiFieldQPHelper.java @@ -0,0 +1,368 @@ +package org.apache.lucene.queryParser.original; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.Reader; +import java.util.HashMap; +import java.util.Map; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.Token; +import org.apache.lucene.analysis.TokenStream; +import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.original.config.OriginalQueryConfigHandler; +import org.apache.lucene.queryParser.original.config.DefaultOperatorAttribute.Operator; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.BooleanClause.Occur; +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.RAMDirectory; +import org.apache.lucene.util.LuceneTestCase; + +/** + * This test case is a copy of the core Lucene query parser test, it was adapted + * to use new QueryParserHelper instead of the old query parser. + * + * Tests QueryParser. + */ +public class TestMultiFieldQPHelper extends LuceneTestCase { + + /** + * test stop words arsing for both the non static form, and for the + * corresponding static form (qtxt, fields[]). + */ + public void tesStopwordsParsing() throws Exception { + assertStopQueryEquals("one", "b:one t:one"); + assertStopQueryEquals("one stop", "b:one t:one"); + assertStopQueryEquals("one (stop)", "b:one t:one"); + assertStopQueryEquals("one ((stop))", "b:one t:one"); + assertStopQueryEquals("stop", null); + assertStopQueryEquals("(stop)", null); + assertStopQueryEquals("((stop))", null); + } + + // verify parsing of query using a stopping analyzer + private void assertStopQueryEquals(String qtxt, String expectedRes) + throws Exception { + String[] fields = { "b", "t" }; + Occur occur[] = { Occur.SHOULD, Occur.SHOULD }; + TestQPHelper.QPTestAnalyzer a = new TestQPHelper.QPTestAnalyzer(); + OriginalQueryParserHelper mfqp = new OriginalQueryParserHelper(); + mfqp.setMultiFields(fields); + mfqp.setAnalyzer(a); + + Query q = mfqp.parse(qtxt, null); + assertEquals(expectedRes, q.toString()); + + q = QueryParserUtil.parse(qtxt, fields, occur, a); + assertEquals(expectedRes, q.toString()); + } + + public void testSimple() throws Exception { + String[] fields = { "b", "t" }; + OriginalQueryParserHelper mfqp = new OriginalQueryParserHelper(); + mfqp.setMultiFields(fields); + mfqp.setAnalyzer(new StandardAnalyzer()); + + Query q = mfqp.parse("one", null); + assertEquals("b:one t:one", q.toString()); + + q = mfqp.parse("one two", null); + assertEquals("(b:one t:one) (b:two t:two)", q.toString()); + + q = mfqp.parse("+one +two", null); + assertEquals("+(b:one t:one) +(b:two t:two)", q.toString()); + + q = mfqp.parse("+one -two -three", null); + assertEquals("+(b:one t:one) -(b:two t:two) -(b:three t:three)", q + .toString()); + + q = mfqp.parse("one^2 two", null); + assertEquals("((b:one t:one)^2.0) (b:two t:two)", q.toString()); + + q = mfqp.parse("one~ two", null); + assertEquals("(b:one~0.5 t:one~0.5) (b:two t:two)", q.toString()); + + q = mfqp.parse("one~0.8 two^2", null); + assertEquals("(b:one~0.8 t:one~0.8) ((b:two t:two)^2.0)", q.toString()); + + q = mfqp.parse("one* two*", null); + assertEquals("(b:one* t:one*) (b:two* t:two*)", q.toString()); + + q = mfqp.parse("[a TO c] two", null); + assertEquals("(b:[a TO c] t:[a TO c]) (b:two t:two)", q.toString()); + + q = mfqp.parse("w?ldcard", null); + assertEquals("b:w?ldcard t:w?ldcard", q.toString()); + + q = mfqp.parse("\"foo bar\"", null); + assertEquals("b:\"foo bar\" t:\"foo bar\"", q.toString()); + + q = mfqp.parse("\"aa bb cc\" \"dd ee\"", null); + assertEquals("(b:\"aa bb cc\" t:\"aa bb cc\") (b:\"dd ee\" t:\"dd ee\")", q + .toString()); + + q = mfqp.parse("\"foo bar\"~4", null); + assertEquals("b:\"foo bar\"~4 t:\"foo bar\"~4", q.toString()); + + // LUCENE-1213: QueryParser was ignoring slop when phrase + // had a field. + q = mfqp.parse("b:\"foo bar\"~4", null); + assertEquals("b:\"foo bar\"~4", q.toString()); + + // make sure that terms which have a field are not touched: + q = mfqp.parse("one f:two", null); + assertEquals("(b:one t:one) f:two", q.toString()); + + // AND mode: + mfqp.setDefaultOperator(Operator.AND); + q = mfqp.parse("one two", null); + assertEquals("+(b:one t:one) +(b:two t:two)", q.toString()); + q = mfqp.parse("\"aa bb cc\" \"dd ee\"", null); + assertEquals("+(b:\"aa bb cc\" t:\"aa bb cc\") +(b:\"dd ee\" t:\"dd ee\")", + q.toString()); + + } + + public void testBoostsSimple() throws Exception { + Map boosts = new HashMap(); + boosts.put("b", new Float(5)); + boosts.put("t", new Float(10)); + String[] fields = { "b", "t" }; + OriginalQueryParserHelper mfqp = new OriginalQueryParserHelper(); + mfqp.setMultiFields(fields); + mfqp.setFieldsBoost(boosts); + mfqp.setAnalyzer(new StandardAnalyzer()); + + // Check for simple + Query q = mfqp.parse("one", null); + assertEquals("b:one^5.0 t:one^10.0", q.toString()); + + // Check for AND + q = mfqp.parse("one AND two", null); + assertEquals("+(b:one^5.0 t:one^10.0) +(b:two^5.0 t:two^10.0)", q + .toString()); + + // Check for OR + q = mfqp.parse("one OR two", null); + assertEquals("(b:one^5.0 t:one^10.0) (b:two^5.0 t:two^10.0)", q.toString()); + + // Check for AND and a field + q = mfqp.parse("one AND two AND foo:test", null); + assertEquals("+(b:one^5.0 t:one^10.0) +(b:two^5.0 t:two^10.0) +foo:test", q + .toString()); + + q = mfqp.parse("one^3 AND two^4", null); + assertEquals("+((b:one^5.0 t:one^10.0)^3.0) +((b:two^5.0 t:two^10.0)^4.0)", + q.toString()); + } + + public void testStaticMethod1() throws QueryNodeException { + String[] fields = { "b", "t" }; + String[] queries = { "one", "two" }; + Query q = QueryParserUtil.parse(queries, fields, new StandardAnalyzer()); + assertEquals("b:one t:two", q.toString()); + + String[] queries2 = { "+one", "+two" }; + q = QueryParserUtil.parse(queries2, fields, new StandardAnalyzer()); + assertEquals("(+b:one) (+t:two)", q.toString()); + + String[] queries3 = { "one", "+two" }; + q = QueryParserUtil.parse(queries3, fields, new StandardAnalyzer()); + assertEquals("b:one (+t:two)", q.toString()); + + String[] queries4 = { "one +more", "+two" }; + q = QueryParserUtil.parse(queries4, fields, new StandardAnalyzer()); + assertEquals("(b:one +b:more) (+t:two)", q.toString()); + + String[] queries5 = { "blah" }; + try { + q = QueryParserUtil.parse(queries5, fields, new StandardAnalyzer()); + fail(); + } catch (IllegalArgumentException e) { + // expected exception, array length differs + } + + // check also with stop words for this static form (qtxts[], fields[]). + TestQPHelper.QPTestAnalyzer stopA = new TestQPHelper.QPTestAnalyzer(); + + String[] queries6 = { "((+stop))", "+((stop))" }; + q = QueryParserUtil.parse(queries6, fields, stopA); + assertEquals("", q.toString()); + + String[] queries7 = { "one ((+stop)) +more", "+((stop)) +two" }; + q = QueryParserUtil.parse(queries7, fields, stopA); + assertEquals("(b:one +b:more) (+t:two)", q.toString()); + + } + + public void testStaticMethod2() throws QueryNodeException { + String[] fields = { "b", "t" }; + BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST, + BooleanClause.Occur.MUST_NOT }; + Query q = QueryParserUtil.parse("one", fields, flags, + new StandardAnalyzer()); + assertEquals("+b:one -t:one", q.toString()); + + q = QueryParserUtil.parse("one two", fields, flags, new StandardAnalyzer()); + assertEquals("+(b:one b:two) -(t:one t:two)", q.toString()); + + try { + BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST }; + q = QueryParserUtil.parse("blah", fields, flags2, new StandardAnalyzer()); + fail(); + } catch (IllegalArgumentException e) { + // expected exception, array length differs + } + } + + public void testStaticMethod2Old() throws QueryNodeException { + String[] fields = { "b", "t" }; + BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST, + BooleanClause.Occur.MUST_NOT }; + OriginalQueryParserHelper parser = new OriginalQueryParserHelper(); + parser.setMultiFields(fields); + parser.setAnalyzer(new StandardAnalyzer()); + + Query q = QueryParserUtil.parse("one", fields, flags, + new StandardAnalyzer());// , fields, flags, new + // StandardAnalyzer()); + assertEquals("+b:one -t:one", q.toString()); + + q = QueryParserUtil.parse("one two", fields, flags, new StandardAnalyzer()); + assertEquals("+(b:one b:two) -(t:one t:two)", q.toString()); + + try { + BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST }; + q = QueryParserUtil.parse("blah", fields, flags2, new StandardAnalyzer()); + fail(); + } catch (IllegalArgumentException e) { + // expected exception, array length differs + } + } + + public void testStaticMethod3() throws QueryNodeException { + String[] queries = { "one", "two", "three" }; + String[] fields = { "f1", "f2", "f3" }; + BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST, + BooleanClause.Occur.MUST_NOT, BooleanClause.Occur.SHOULD }; + Query q = QueryParserUtil.parse(queries, fields, flags, + new StandardAnalyzer()); + assertEquals("+f1:one -f2:two f3:three", q.toString()); + + try { + BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST }; + q = QueryParserUtil + .parse(queries, fields, flags2, new StandardAnalyzer()); + fail(); + } catch (IllegalArgumentException e) { + // expected exception, array length differs + } + } + + public void testStaticMethod3Old() throws QueryNodeException { + String[] queries = { "one", "two" }; + String[] fields = { "b", "t" }; + BooleanClause.Occur[] flags = { BooleanClause.Occur.MUST, + BooleanClause.Occur.MUST_NOT }; + Query q = QueryParserUtil.parse(queries, fields, flags, + new StandardAnalyzer()); + assertEquals("+b:one -t:two", q.toString()); + + try { + BooleanClause.Occur[] flags2 = { BooleanClause.Occur.MUST }; + q = QueryParserUtil + .parse(queries, fields, flags2, new StandardAnalyzer()); + fail(); + } catch (IllegalArgumentException e) { + // expected exception, array length differs + } + } + + public void testAnalyzerReturningNull() throws QueryNodeException { + String[] fields = new String[] { "f1", "f2", "f3" }; + OriginalQueryParserHelper parser = new OriginalQueryParserHelper(); + parser.setMultiFields(fields); + parser.setAnalyzer(new AnalyzerReturningNull()); + + Query q = parser.parse("bla AND blo", null); + assertEquals("+(f2:bla f3:bla) +(f2:blo f3:blo)", q.toString()); + // the following queries are not affected as their terms are not + // analyzed anyway: + q = parser.parse("bla*", null); + assertEquals("f1:bla* f2:bla* f3:bla*", q.toString()); + q = parser.parse("bla~", null); + assertEquals("f1:bla~0.5 f2:bla~0.5 f3:bla~0.5", q.toString()); + q = parser.parse("[a TO c]", null); + assertEquals("f1:[a TO c] f2:[a TO c] f3:[a TO c]", q.toString()); + } + + public void testStopWordSearching() throws Exception { + Analyzer analyzer = new StandardAnalyzer(); + Directory ramDir = new RAMDirectory(); + IndexWriter iw = new IndexWriter(ramDir, analyzer, true, + IndexWriter.MaxFieldLength.LIMITED); + Document doc = new Document(); + doc.add(new Field("body", "blah the footest blah", Field.Store.NO, + Field.Index.ANALYZED)); + iw.addDocument(doc); + iw.close(); + + OriginalQueryParserHelper mfqp = new OriginalQueryParserHelper(); + + mfqp.setMultiFields(new String[] { "body" }); + mfqp.setAnalyzer(analyzer); + mfqp.setDefaultOperator(Operator.AND); + Query q = mfqp.parse("the footest", null); + IndexSearcher is = new IndexSearcher(ramDir); + ScoreDoc[] hits = is.search(q, null, 1000).scoreDocs; + assertEquals(1, hits.length); + is.close(); + } + + /** + * Return empty tokens for field "f1". + */ + private static class AnalyzerReturningNull extends Analyzer { + StandardAnalyzer stdAnalyzer = new StandardAnalyzer(); + + public AnalyzerReturningNull() { + } + + public TokenStream tokenStream(String fieldName, Reader reader) { + if ("f1".equals(fieldName)) { + return new EmptyTokenStream(); + } else { + return stdAnalyzer.tokenStream(fieldName, reader); + } + } + + private static class EmptyTokenStream extends TokenStream { + public Token next(final Token reusableToken) { + return null; + } + } + } + +} diff --git a/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiFieldQueryParserWrapper.java b/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiFieldQueryParserWrapper.java new file mode 100644 index 00000000000..02ce64ee2d7 --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestMultiFieldQueryParserWrapper.java @@ -0,0 +1,366 @@ +package org.apache.lucene.queryParser.original; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.Reader; +import java.util.HashMap; +import java.util.Map; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.Token; +import org.apache.lucene.analysis.TokenStream; +import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.queryParser.ParseException; +import org.apache.lucene.queryParser.original.MultiFieldQueryParserWrapper; +import org.apache.lucene.queryParser.original.QueryParserWrapper; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.BooleanClause.Occur; +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.RAMDirectory; +import org.apache.lucene.util.LuceneTestCase; + +/** + * Tests multi field query parsing using the {@link MultiFieldQueryParserWrapper}. + */ +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 }; + TestQueryParserWrapper.QPTestAnalyzer a = new TestQueryParserWrapper.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[]). + TestQueryParserWrapper.QPTestAnalyzer stopA = new TestQueryParserWrapper.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; + } + } + } + +} diff --git a/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestQPHelper.java b/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestQPHelper.java new file mode 100644 index 00000000000..ddc1e2aa43d --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestQPHelper.java @@ -0,0 +1,1130 @@ +package org.apache.lucene.queryParser.original; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.IOException; +import java.io.Reader; +import java.text.Collator; +import java.text.DateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +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.core.QueryNodeException; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.nodes.FuzzyQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.WildcardQueryNode; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorImpl; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorPipeline; +import org.apache.lucene.queryParser.original.config.OriginalQueryConfigHandler; +import org.apache.lucene.queryParser.original.config.DefaultOperatorAttribute.Operator; +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.MultiTermQuery; +import org.apache.lucene.search.PhraseQuery; +import org.apache.lucene.search.PrefixQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.TermRangeQuery; +import org.apache.lucene.search.WildcardQuery; +import org.apache.lucene.store.RAMDirectory; +import org.apache.lucene.util.LuceneTestCase; + +/** + * This test case is a copy of the core Lucene query parser test, it was adapted + * to use new QueryParserHelper instead of the old query parser. + * + * Tests QueryParser. + */ +public class TestQPHelper extends LuceneTestCase { + + public static Analyzer qpAnalyzer = new QPTestAnalyzer(); + + public static class QPTestFilter extends TokenFilter { + TermAttribute termAtt; + OffsetAttribute offsetAtt; + + /** + * Filter which discards the token 'stop' and which expands the token + * 'phrase' into 'phrase1 phrase2' + */ + public QPTestFilter(TokenStream in) { + super(in); + termAtt = (TermAttribute) addAttribute(TermAttribute.class); + offsetAtt = (OffsetAttribute) addAttribute(OffsetAttribute.class); + } + + boolean inPhrase = false; + int savedStart = 0, savedEnd = 0; + + public Token next(Token reusableToken) throws IOException { + Token token = reusableToken; + + if (inPhrase) { + inPhrase = false; + token.setTermBuffer("phrase2"); + token.setStartOffset(savedStart); + token.setEndOffset(savedEnd); + return reusableToken; + } else + while ((token = this.input.next(reusableToken)) != null) { + if (token.term().equals("phrase")) { + inPhrase = true; + savedStart = token.startOffset(); + savedEnd = token.endOffset(); + token.setTermBuffer("phrase1"); + token.setStartOffset(savedStart); + token.setEndOffset(savedEnd); + return token; + } else if (!token.term().equals("stop")) + return token; + } + + return null; + + } + + public boolean incrementToken() throws IOException { + if (inPhrase) { + inPhrase = false; + termAtt.setTermBuffer("phrase2"); + offsetAtt.setOffset(savedStart, savedEnd); + return true; + } else + while (input.incrementToken()) { + if (termAtt.term().equals("phrase")) { + inPhrase = true; + savedStart = offsetAtt.startOffset(); + savedEnd = offsetAtt.endOffset(); + termAtt.setTermBuffer("phrase1"); + offsetAtt.setOffset(savedStart, savedEnd); + return true; + } else if (!termAtt.term().equals("stop")) + return true; + } + return false; + } + } + + public static class QPTestAnalyzer extends Analyzer { + + /** Filters LowerCaseTokenizer with StopFilter. */ + public final TokenStream tokenStream(String fieldName, Reader reader) { + return new QPTestFilter(new LowerCaseTokenizer(reader)); + } + } + + public static class QPTestParser extends OriginalQueryParserHelper { + public QPTestParser(Analyzer a) { + ((QueryNodeProcessorPipeline)getQueryNodeProcessor()) + .addProcessor(new QPTestParserQueryNodeProcessor()); + this.setAnalyzer(a); + + } + + private static class QPTestParserQueryNodeProcessor extends + QueryNodeProcessorImpl { + + protected QueryNode postProcessNode(QueryNode node) + throws QueryNodeException { + + return node; + + } + + protected QueryNode preProcessNode(QueryNode node) + throws QueryNodeException { + + if (node instanceof WildcardQueryNode || node instanceof FuzzyQueryNode) { + + throw new QueryNodeException(new MessageImpl( + QueryParserMessages.EMPTY_MESSAGE)); + + } + + return node; + + } + + protected List setChildrenOrder(List children) + throws QueryNodeException { + + return children; + + } + + } + + } + + private int originalMaxClauses; + + public void setUp() throws Exception { + super.setUp(); + originalMaxClauses = BooleanQuery.getMaxClauseCount(); + } + + public OriginalQueryParserHelper getParser(Analyzer a) throws Exception { + if (a == null) + a = new SimpleAnalyzer(); + OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + qp.setAnalyzer(a); + + qp.setDefaultOperator(Operator.OR); + + return qp; + + } + + public Query getQuery(String query, Analyzer a) throws Exception { + return getParser(a).parse(query, "field"); + } + + public void assertQueryEquals(String query, Analyzer a, String result) + throws Exception { + Query q = getQuery(query, a); + String s = q.toString("field"); + if (!s.equals(result)) { + fail("Query /" + query + "/ yielded /" + s + "/, expecting /" + result + + "/"); + } + } + + public void assertQueryEquals(OriginalQueryParserHelper qp, String field, + String query, String result) throws Exception { + Query q = qp.parse(query, field); + String s = q.toString(field); + if (!s.equals(result)) { + fail("Query /" + query + "/ yielded /" + s + "/, expecting /" + result + + "/"); + } + } + + public void assertEscapedQueryEquals(String query, Analyzer a, String result) + throws Exception { + String escapedQuery = QueryParserUtil.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 { + OriginalQueryParserHelper qp = getParser(null); + qp.setLowercaseExpandedTerms(lowercase); + qp.setAllowLeadingWildcard(allowLeadingWildcard); + Query q = qp.parse(query, "field"); + String s = q.toString("field"); + if (!s.equals(result)) { + fail("WildcardQuery /" + query + "/ yielded /" + s + "/, expecting /" + + result + "/"); + } + } + + public void assertWildcardQueryEquals(String query, boolean lowercase, + String result) throws Exception { + assertWildcardQueryEquals(query, lowercase, result, false); + } + + public void assertWildcardQueryEquals(String query, String result) + throws Exception { + OriginalQueryParserHelper qp = getParser(null); + Query q = qp.parse(query, "field"); + String s = q.toString("field"); + if (!s.equals(result)) { + fail("WildcardQuery /" + query + "/ yielded /" + s + "/, expecting /" + + result + "/"); + } + } + + public Query getQueryDOA(String query, Analyzer a) throws Exception { + if (a == null) + a = new SimpleAnalyzer(); + OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + qp.setAnalyzer(a); + qp.setDefaultOperator(Operator.AND); + + return qp.parse(query, "field"); + + } + + public void assertQueryEqualsDOA(String query, Analyzer a, String result) + throws Exception { + Query q = getQueryDOA(query, a); + String s = q.toString("field"); + if (!s.equals(result)) { + fail("Query /" + query + "/ yielded /" + s + "/, expecting /" + result + + "/"); + } + } + + public void testCJK() throws Exception { + // Test Ideographic Space - As wide as a CJK character cell (fullwidth) + // used google to translate the word "term" to japanese -> ?? + assertQueryEquals("term\u3000term\u3000term", null, + "term\u0020term\u0020term"); + assertQueryEquals("??\u3000??\u3000??", null, "??\u0020??\u0020??"); + } + + public void testSimple() throws Exception { + assertQueryEquals("\"term germ\"~2", null, "\"term germ\"~2"); + assertQueryEquals("term term term", null, "term term term"); + assertQueryEquals("t�rm term term", new WhitespaceAnalyzer(), + "t�rm term term"); + assertQueryEquals("�mlaut", new WhitespaceAnalyzer(), "�mlaut"); + + assertQueryEquals("\"\"", new KeywordAnalyzer(), ""); + assertQueryEquals("foo:\"\"", new KeywordAnalyzer(), "foo:"); + + assertQueryEquals("a AND b", null, "+a +b"); + assertQueryEquals("(a AND b)", null, "+a +b"); + assertQueryEquals("c OR (a AND b)", null, "c (+a +b)"); + + assertQueryEquals("a AND NOT b", null, "+a -b"); + + assertQueryEquals("a AND -b", null, "+a -b"); + + assertQueryEquals("a AND !b", null, "+a -b"); + + assertQueryEquals("a && b", null, "+a +b"); + + assertQueryEquals("a && ! b", null, "+a -b"); + + assertQueryEquals("a OR b", null, "a b"); + assertQueryEquals("a || b", null, "a b"); + + assertQueryEquals("a OR !b", null, "a -b"); + + assertQueryEquals("a OR ! b", null, "a -b"); + + assertQueryEquals("a OR -b", null, "a -b"); + + assertQueryEquals("+term -term term", null, "+term -term term"); + assertQueryEquals("foo:term AND field:anotherTerm", null, + "+foo:term +anotherterm"); + assertQueryEquals("term AND \"phrase phrase\"", null, + "+term +\"phrase phrase\""); + assertQueryEquals("\"hello there\"", null, "\"hello there\""); + assertTrue(getQuery("a AND b", null) instanceof BooleanQuery); + assertTrue(getQuery("hello", null) instanceof TermQuery); + assertTrue(getQuery("\"hello there\"", null) instanceof PhraseQuery); + + assertQueryEquals("germ term^2.0", null, "germ term^2.0"); + assertQueryEquals("(term)^2.0", null, "term^2.0"); + assertQueryEquals("(germ term)^2.0", null, "(germ term)^2.0"); + assertQueryEquals("term^2.0", null, "term^2.0"); + assertQueryEquals("term^2", null, "term^2.0"); + assertQueryEquals("\"germ term\"^2.0", null, "\"germ term\"^2.0"); + assertQueryEquals("\"term germ\"^2", null, "\"term germ\"^2.0"); + + assertQueryEquals("(foo OR bar) AND (baz OR boo)", null, + "+(foo bar) +(baz boo)"); + assertQueryEquals("((a OR b) AND NOT c) OR d", null, "(+(a b) -c) d"); + assertQueryEquals("+(apple \"steve jobs\") -(foo bar baz)", null, + "+(apple \"steve jobs\") -(foo bar baz)"); + assertQueryEquals("+title:(dog OR cat) -author:\"bob dole\"", null, + "+(title:dog title:cat) -author:\"bob dole\""); + + } + + public void testPunct() throws Exception { + Analyzer a = new WhitespaceAnalyzer(); + assertQueryEquals("a&b", a, "a&b"); + assertQueryEquals("a&&b", a, "a&&b"); + assertQueryEquals(".NET", a, ".NET"); + } + + public void testSlop() throws Exception { + + assertQueryEquals("\"term germ\"~2", null, "\"term germ\"~2"); + assertQueryEquals("\"term germ\"~2 flork", null, "\"term germ\"~2 flork"); + assertQueryEquals("\"term\"~2", null, "term"); + assertQueryEquals("\" \"~2 germ", null, "germ"); + assertQueryEquals("\"term germ\"~2^2", null, "\"term germ\"~2^2.0"); + } + + public void testNumber() throws Exception { + // The numbers go away because SimpleAnalzyer ignores them + assertQueryEquals("3", null, ""); + assertQueryEquals("term 1.0 1 2", null, "term"); + assertQueryEquals("term term1 term2", null, "term term term"); + + Analyzer a = new StandardAnalyzer(); + assertQueryEquals("3", a, "3"); + assertQueryEquals("term 1.0 1 2", a, "term 1.0 1 2"); + assertQueryEquals("term term1 term2", a, "term term1 term2"); + } + + public void testWildcard() throws Exception { + assertQueryEquals("term*", null, "term*"); + assertQueryEquals("term*^2", null, "term*^2.0"); + assertQueryEquals("term~", null, "term~0.5"); + assertQueryEquals("term~0.7", null, "term~0.7"); + + assertQueryEquals("term~^2", null, "term~0.5^2.0"); + + assertQueryEquals("term^2~", null, "term~0.5^2.0"); + assertQueryEquals("term*germ", null, "term*germ"); + assertQueryEquals("term*germ^3", null, "term*germ^3.0"); + + assertTrue(getQuery("term*", null) instanceof PrefixQuery); + assertTrue(getQuery("term*^2", null) instanceof PrefixQuery); + assertTrue(getQuery("term~", null) instanceof FuzzyQuery); + assertTrue(getQuery("term~0.7", null) instanceof FuzzyQuery); + FuzzyQuery fq = (FuzzyQuery) getQuery("term~0.7", null); + assertEquals(0.7f, fq.getMinSimilarity(), 0.1f); + assertEquals(FuzzyQuery.defaultPrefixLength, fq.getPrefixLength()); + fq = (FuzzyQuery) getQuery("term~", null); + assertEquals(0.5f, fq.getMinSimilarity(), 0.1f); + assertEquals(FuzzyQuery.defaultPrefixLength, fq.getPrefixLength()); + + assertQueryNodeException("term~1.1"); // value > 1, throws exception + + assertTrue(getQuery("term*germ", null) instanceof WildcardQuery); + + /* + * Tests to see that wild card terms are (or are not) properly lower-cased + * with propery parser configuration + */ + // First prefix queries: + // by default, convert to lowercase: + assertWildcardQueryEquals("Term*", true, "term*"); + // explicitly set lowercase: + assertWildcardQueryEquals("term*", true, "term*"); + assertWildcardQueryEquals("Term*", true, "term*"); + assertWildcardQueryEquals("TERM*", true, "term*"); + // explicitly disable lowercase conversion: + assertWildcardQueryEquals("term*", false, "term*"); + assertWildcardQueryEquals("Term*", false, "Term*"); + assertWildcardQueryEquals("TERM*", false, "TERM*"); + // Then 'full' wildcard queries: + // by default, convert to lowercase: + assertWildcardQueryEquals("Te?m", "te?m"); + // explicitly set lowercase: + assertWildcardQueryEquals("te?m", true, "te?m"); + assertWildcardQueryEquals("Te?m", true, "te?m"); + assertWildcardQueryEquals("TE?M", true, "te?m"); + assertWildcardQueryEquals("Te?m*gerM", true, "te?m*germ"); + // explicitly disable lowercase conversion: + assertWildcardQueryEquals("te?m", false, "te?m"); + assertWildcardQueryEquals("Te?m", false, "Te?m"); + assertWildcardQueryEquals("TE?M", false, "TE?M"); + assertWildcardQueryEquals("Te?m*gerM", false, "Te?m*gerM"); + // Fuzzy queries: + assertWildcardQueryEquals("Term~", "term~0.5"); + assertWildcardQueryEquals("Term~", true, "term~0.5"); + assertWildcardQueryEquals("Term~", false, "Term~0.5"); + // Range queries: + + // TODO: implement this on QueryParser + // Q0002E_INVALID_SYNTAX_CANNOT_PARSE: Syntax Error, cannot parse '[A TO + // C]': Lexical error at line 1, column 1. Encountered: "[" (91), after + // : "" + assertWildcardQueryEquals("[A TO C]", "[a TO c]"); + assertWildcardQueryEquals("[A TO C]", true, "[a TO c]"); + assertWildcardQueryEquals("[A TO C]", false, "[A TO C]"); + // Test suffix queries: first disallow + try { + assertWildcardQueryEquals("*Term", true, "*term"); + fail(); + } catch (QueryNodeException pe) { + // expected exception + } + try { + assertWildcardQueryEquals("?Term", true, "?term"); + fail(); + } catch (QueryNodeException pe) { + // expected exception + } + // Test suffix queries: then allow + assertWildcardQueryEquals("*Term", true, "*term", true); + assertWildcardQueryEquals("?Term", true, "?term", true); + } + + public void testLeadingWildcardType() throws Exception { + OriginalQueryParserHelper qp = getParser(null); + qp.setAllowLeadingWildcard(true); + assertEquals(WildcardQuery.class, qp.parse("t*erm*", "field").getClass()); + assertEquals(WildcardQuery.class, qp.parse("?term*", "field").getClass()); + assertEquals(WildcardQuery.class, qp.parse("*term*", "field").getClass()); + } + + public void testQPA() throws Exception { + assertQueryEquals("term term^3.0 term", qpAnalyzer, "term term^3.0 term"); + assertQueryEquals("term stop^3.0 term", qpAnalyzer, "term term"); + + assertQueryEquals("term term term", qpAnalyzer, "term term term"); + assertQueryEquals("term +stop term", qpAnalyzer, "term term"); + assertQueryEquals("term -stop term", qpAnalyzer, "term term"); + + assertQueryEquals("drop AND (stop) AND roll", qpAnalyzer, "+drop +roll"); + assertQueryEquals("term +(stop) term", qpAnalyzer, "term term"); + assertQueryEquals("term -(stop) term", qpAnalyzer, "term term"); + + assertQueryEquals("drop AND stop AND roll", qpAnalyzer, "+drop +roll"); + assertQueryEquals("term phrase term", qpAnalyzer, + "term \"phrase1 phrase2\" term"); + + assertQueryEquals("term AND NOT phrase term", qpAnalyzer, + "+term -\"phrase1 phrase2\" term"); + + assertQueryEquals("stop^3", qpAnalyzer, ""); + assertQueryEquals("stop", qpAnalyzer, ""); + assertQueryEquals("(stop)^3", qpAnalyzer, ""); + assertQueryEquals("((stop))^3", qpAnalyzer, ""); + assertQueryEquals("(stop^3)", qpAnalyzer, ""); + assertQueryEquals("((stop)^3)", qpAnalyzer, ""); + assertQueryEquals("(stop)", qpAnalyzer, ""); + assertQueryEquals("((stop))", qpAnalyzer, ""); + assertTrue(getQuery("term term term", qpAnalyzer) instanceof BooleanQuery); + assertTrue(getQuery("term +stop", qpAnalyzer) instanceof TermQuery); + } + + public void testRange() throws Exception { + assertQueryEquals("[ a TO z]", null, "[a TO z]"); + assertEquals(MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT, ((TermRangeQuery)getQuery("[ a TO z]", null)).getRewriteMethod()); + + OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + + qp.setMultiTermRewriteMethod(MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE); + assertEquals(MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE,((TermRangeQuery)qp.parse("[ a TO z]", "field")).getRewriteMethod()); + + 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); + + OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + qp.setAnalyzer(new WhitespaceAnalyzer()); + + // Neither Java 1.4.2 nor 1.5.0 has Farsi Locale collation available in + // RuleBasedCollator. However, the Arabic Locale seems to order the + // Farsi + // characters properly. + Collator c = Collator.getInstance(new Locale("ar")); + qp.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.setMultiTermRewriteMethod(MultiTermQuery.CONSTANT_SCORE_FILTER_REWRITE); + ScoreDoc[] result = is.search(qp.parse("[ \u062F TO \u0698 ]", "content"), + null, 1000).scoreDocs; + assertEquals("The index Term should not be included.", 0, result.length); + + result = is.search(qp.parse("[ \u0633 TO \u0638 ]", "content"), null, 1000).scoreDocs; + assertEquals("The index Term should be included.", 1, result.length); + + // Test RangeQuery + qp.setMultiTermRewriteMethod(MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE); + result = is.search(qp.parse("[ \u062F TO \u0698 ]", "content"), null, 1000).scoreDocs; + assertEquals("The index Term should not be included.", 0, result.length); + + result = is.search(qp.parse("[ \u0633 TO \u0638 ]", "content"), null, 1000).scoreDocs; + assertEquals("The index Term should be included.", 1, result.length); + + is.close(); + } + + /** for testing legacy DateField support */ + private String getLegacyDate(String s) throws Exception { + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); + return DateField.dateToString(df.parse(s)); + } + + /** for testing DateTools support */ + private String getDate(String s, DateTools.Resolution resolution) + throws Exception { + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); + return getDate(df.parse(s), resolution); + } + + /** for testing DateTools support */ + private String getDate(Date d, DateTools.Resolution resolution) + throws Exception { + if (resolution == null) { + return DateField.dateToString(d); + } else { + return DateTools.dateToString(d, resolution); + } + } + + private String getLocalizedDate(int year, int month, int day, + boolean extendLastDate) { + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); + Calendar calendar = Calendar.getInstance(); + calendar.set(year, month, day); + if (extendLastDate) { + calendar.set(Calendar.HOUR_OF_DAY, 23); + calendar.set(Calendar.MINUTE, 59); + calendar.set(Calendar.SECOND, 59); + calendar.set(Calendar.MILLISECOND, 999); + } + return df.format(calendar.getTime()); + } + + /** for testing legacy DateField support */ + public void testLegacyDateRange() throws Exception { + String startDate = getLocalizedDate(2002, 1, 1, false); + String endDate = getLocalizedDate(2002, 1, 4, false); + Calendar endDateExpected = Calendar.getInstance(); + endDateExpected.set(2002, 1, 4, 23, 59, 59); + endDateExpected.set(Calendar.MILLISECOND, 999); + assertQueryEquals("[ " + startDate + " TO " + endDate + "]", null, "[" + + getLegacyDate(startDate) + " TO " + + DateField.dateToString(endDateExpected.getTime()) + "]"); + assertQueryEquals("{ " + startDate + " " + endDate + " }", null, "{" + + getLegacyDate(startDate) + " TO " + getLegacyDate(endDate) + "}"); + } + + public void testDateRange() throws Exception { + String startDate = getLocalizedDate(2002, 1, 1, false); + String endDate = getLocalizedDate(2002, 1, 4, false); + Calendar endDateExpected = Calendar.getInstance(); + endDateExpected.set(2002, 1, 4, 23, 59, 59); + endDateExpected.set(Calendar.MILLISECOND, 999); + final String defaultField = "default"; + final String monthField = "month"; + final String hourField = "hour"; + OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + + // Don't set any date resolution and verify if DateField is used + assertDateRangeQueryEquals(qp, defaultField, startDate, endDate, + endDateExpected.getTime(), null); + + Map dateRes = new HashMap(); + + // set a field specific date resolution + dateRes.put(monthField, DateTools.Resolution.MONTH); + qp.setDateResolution(dateRes); + + // 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 + dateRes.put(hourField, DateTools.Resolution.HOUR); + qp.setDateResolution(dateRes); + + // 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(OriginalQueryParserHelper qp, + String field, String startDate, String endDate, Date endDateInclusive, + DateTools.Resolution resolution) throws Exception { + assertQueryEquals(qp, field, field + ":[" + startDate + " TO " + endDate + + "]", "[" + getDate(startDate, resolution) + " TO " + + getDate(endDateInclusive, resolution) + "]"); + assertQueryEquals(qp, field, field + ":{" + startDate + " TO " + endDate + + "}", "{" + getDate(startDate, resolution) + " TO " + + getDate(endDate, resolution) + "}"); + } + + public void testEscaped() throws Exception { + Analyzer a = new WhitespaceAnalyzer(); + + /* + * assertQueryEquals("\\[brackets", a, "\\[brackets"); + * assertQueryEquals("\\[brackets", null, "brackets"); + * assertQueryEquals("\\\\", a, "\\\\"); assertQueryEquals("\\+blah", a, + * "\\+blah"); assertQueryEquals("\\(blah", a, "\\(blah"); + * + * assertQueryEquals("\\-blah", a, "\\-blah"); assertQueryEquals("\\!blah", + * a, "\\!blah"); assertQueryEquals("\\{blah", a, "\\{blah"); + * assertQueryEquals("\\}blah", a, "\\}blah"); assertQueryEquals("\\:blah", + * a, "\\:blah"); assertQueryEquals("\\^blah", a, "\\^blah"); + * assertQueryEquals("\\[blah", a, "\\[blah"); assertQueryEquals("\\]blah", + * a, "\\]blah"); assertQueryEquals("\\\"blah", a, "\\\"blah"); + * assertQueryEquals("\\(blah", a, "\\(blah"); assertQueryEquals("\\)blah", + * a, "\\)blah"); assertQueryEquals("\\~blah", a, "\\~blah"); + * assertQueryEquals("\\*blah", a, "\\*blah"); assertQueryEquals("\\?blah", + * a, "\\?blah"); //assertQueryEquals("foo \\&\\& bar", a, + * "foo \\&\\& bar"); //assertQueryEquals("foo \\|| bar", a, + * "foo \\|| bar"); //assertQueryEquals("foo \\AND bar", a, + * "foo \\AND bar"); + */ + + assertQueryEquals("\\a", a, "a"); + + assertQueryEquals("a\\-b:c", a, "a-b:c"); + assertQueryEquals("a\\+b:c", a, "a+b:c"); + assertQueryEquals("a\\:b:c", a, "a:b:c"); + assertQueryEquals("a\\\\b:c", a, "a\\b:c"); + + assertQueryEquals("a:b\\-c", a, "a:b-c"); + assertQueryEquals("a:b\\+c", a, "a:b+c"); + assertQueryEquals("a:b\\:c", a, "a:b:c"); + assertQueryEquals("a:b\\\\c", a, "a:b\\c"); + + assertQueryEquals("a:b\\-c*", a, "a:b-c*"); + assertQueryEquals("a:b\\+c*", a, "a:b+c*"); + assertQueryEquals("a:b\\:c*", a, "a:b:c*"); + + assertQueryEquals("a:b\\\\c*", a, "a:b\\c*"); + + assertQueryEquals("a:b\\-?c", a, "a:b-?c"); + assertQueryEquals("a:b\\+?c", a, "a:b+?c"); + assertQueryEquals("a:b\\:?c", a, "a:b:?c"); + + assertQueryEquals("a:b\\\\?c", a, "a:b\\?c"); + + assertQueryEquals("a:b\\-c~", a, "a:b-c~0.5"); + assertQueryEquals("a:b\\+c~", a, "a:b+c~0.5"); + assertQueryEquals("a:b\\:c~", a, "a:b:c~0.5"); + assertQueryEquals("a:b\\\\c~", a, "a:b\\c~0.5"); + + // TODO: implement Range queries on QueryParser + assertQueryEquals("[ a\\- TO a\\+ ]", null, "[a- TO a+]"); + assertQueryEquals("[ a\\: TO a\\~ ]", null, "[a: TO a~]"); + assertQueryEquals("[ a\\\\ TO a\\* ]", null, "[a\\ TO a*]"); + + assertQueryEquals( + "[\"c\\:\\\\temp\\\\\\~foo0.txt\" TO \"c\\:\\\\temp\\\\\\~foo9.txt\"]", + a, "[c:\\temp\\~foo0.txt TO c:\\temp\\~foo9.txt]"); + + assertQueryEquals("a\\\\\\+b", a, "a\\+b"); + + assertQueryEquals("a \\\"b c\\\" d", a, "a \"b c\" d"); + assertQueryEquals("\"a \\\"b c\\\" d\"", a, "\"a \"b c\" d\""); + assertQueryEquals("\"a \\+b c d\"", a, "\"a +b c d\""); + + assertQueryEquals("c\\:\\\\temp\\\\\\~foo.txt", a, "c:\\temp\\~foo.txt"); + + assertQueryNodeException("XY\\"); // there must be a character after the + // escape char + + // test unicode escaping + assertQueryEquals("a\\u0062c", a, "abc"); + assertQueryEquals("XY\\u005a", a, "XYZ"); + assertQueryEquals("XY\\u005A", a, "XYZ"); + assertQueryEquals("\"a \\\\\\u0028\\u0062\\\" c\"", a, "\"a \\(b\" c\""); + + assertQueryNodeException("XY\\u005G"); // test non-hex character in escaped + // unicode sequence + assertQueryNodeException("XY\\u005"); // test incomplete escaped unicode + // sequence + + // Tests bug LUCENE-800 + assertQueryEquals("(item:\\\\ item:ABCD\\\\)", a, "item:\\ item:ABCD\\"); + assertQueryNodeException("(item:\\\\ item:ABCD\\\\))"); // unmatched closing + // paranthesis + assertQueryEquals("\\*", a, "*"); + assertQueryEquals("\\\\", a, "\\"); // escaped backslash + + assertQueryNodeException("\\"); // a backslash must always be escaped + + // LUCENE-1189 + assertQueryEquals("(\"a\\\\\") or (\"b\")", a, "a\\ or b"); + } + + public void testQueryStringEscaping() throws Exception { + Analyzer a = new WhitespaceAnalyzer(); + + assertEscapedQueryEquals("a-b:c", a, "a\\-b\\:c"); + assertEscapedQueryEquals("a+b:c", a, "a\\+b\\:c"); + assertEscapedQueryEquals("a:b:c", a, "a\\:b\\:c"); + assertEscapedQueryEquals("a\\b:c", a, "a\\\\b\\:c"); + + assertEscapedQueryEquals("a:b-c", a, "a\\:b\\-c"); + assertEscapedQueryEquals("a:b+c", a, "a\\:b\\+c"); + assertEscapedQueryEquals("a:b:c", a, "a\\:b\\:c"); + assertEscapedQueryEquals("a:b\\c", a, "a\\:b\\\\c"); + + assertEscapedQueryEquals("a:b-c*", a, "a\\:b\\-c\\*"); + assertEscapedQueryEquals("a:b+c*", a, "a\\:b\\+c\\*"); + assertEscapedQueryEquals("a:b:c*", a, "a\\:b\\:c\\*"); + + assertEscapedQueryEquals("a:b\\\\c*", a, "a\\:b\\\\\\\\c\\*"); + + assertEscapedQueryEquals("a:b-?c", a, "a\\:b\\-\\?c"); + assertEscapedQueryEquals("a:b+?c", a, "a\\:b\\+\\?c"); + assertEscapedQueryEquals("a:b:?c", a, "a\\:b\\:\\?c"); + + assertEscapedQueryEquals("a:b?c", a, "a\\:b\\?c"); + + assertEscapedQueryEquals("a:b-c~", a, "a\\:b\\-c\\~"); + assertEscapedQueryEquals("a:b+c~", a, "a\\:b\\+c\\~"); + assertEscapedQueryEquals("a:b:c~", a, "a\\:b\\:c\\~"); + assertEscapedQueryEquals("a:b\\c~", a, "a\\:b\\\\c\\~"); + + assertEscapedQueryEquals("[ a - TO a+ ]", null, "\\[ a \\- TO a\\+ \\]"); + assertEscapedQueryEquals("[ a : TO a~ ]", null, "\\[ a \\: TO a\\~ \\]"); + assertEscapedQueryEquals("[ a\\ TO a* ]", null, "\\[ a\\\\ TO a\\* \\]"); + + // LUCENE-881 + assertEscapedQueryEquals("|| abc ||", a, "\\|\\| abc \\|\\|"); + assertEscapedQueryEquals("&& abc &&", a, "\\&\\& abc \\&\\&"); + } + + public void testTabNewlineCarriageReturn() throws Exception { + assertQueryEqualsDOA("+weltbank +worlbank", null, "+weltbank +worlbank"); + + assertQueryEqualsDOA("+weltbank\n+worlbank", null, "+weltbank +worlbank"); + assertQueryEqualsDOA("weltbank \n+worlbank", null, "+weltbank +worlbank"); + assertQueryEqualsDOA("weltbank \n +worlbank", null, "+weltbank +worlbank"); + + assertQueryEqualsDOA("+weltbank\r+worlbank", null, "+weltbank +worlbank"); + assertQueryEqualsDOA("weltbank \r+worlbank", null, "+weltbank +worlbank"); + assertQueryEqualsDOA("weltbank \r +worlbank", null, "+weltbank +worlbank"); + + assertQueryEqualsDOA("+weltbank\r\n+worlbank", null, "+weltbank +worlbank"); + assertQueryEqualsDOA("weltbank \r\n+worlbank", null, "+weltbank +worlbank"); + assertQueryEqualsDOA("weltbank \r\n +worlbank", null, "+weltbank +worlbank"); + assertQueryEqualsDOA("weltbank \r \n +worlbank", null, + "+weltbank +worlbank"); + + assertQueryEqualsDOA("+weltbank\t+worlbank", null, "+weltbank +worlbank"); + assertQueryEqualsDOA("weltbank \t+worlbank", null, "+weltbank +worlbank"); + assertQueryEqualsDOA("weltbank \t +worlbank", null, "+weltbank +worlbank"); + } + + public void testSimpleDAO() throws Exception { + assertQueryEqualsDOA("term term term", null, "+term +term +term"); + assertQueryEqualsDOA("term +term term", null, "+term +term +term"); + assertQueryEqualsDOA("term term +term", null, "+term +term +term"); + assertQueryEqualsDOA("term +term +term", null, "+term +term +term"); + assertQueryEqualsDOA("-term term term", null, "-term +term +term"); + } + + public void testBoost() throws Exception { + StandardAnalyzer oneStopAnalyzer = new StandardAnalyzer( + new String[] { "on" }); + OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + qp.setAnalyzer(oneStopAnalyzer); + + Query q = qp.parse("on^1.0", "field"); + assertNotNull(q); + q = qp.parse("\"hello\"^2.0", "field"); + assertNotNull(q); + assertEquals(q.getBoost(), (float) 2.0, (float) 0.5); + q = qp.parse("hello^2.0", "field"); + assertNotNull(q); + assertEquals(q.getBoost(), (float) 2.0, (float) 0.5); + q = qp.parse("\"on\"^1.0", "field"); + assertNotNull(q); + + OriginalQueryParserHelper qp2 = new OriginalQueryParserHelper(); + qp2.setAnalyzer(new StandardAnalyzer()); + + q = qp2.parse("the^3", "field"); + // "the" is a stop word so the result is an empty query: + assertNotNull(q); + assertEquals("", q.toString()); + assertEquals(1.0f, q.getBoost(), 0.01f); + } + + public void assertQueryNodeException(String queryString) throws Exception { + try { + getQuery(queryString, null); + } catch (QueryNodeException expected) { + return; + } + fail("ParseException expected, not thrown"); + } + + public void testException() throws Exception { + assertQueryNodeException("\"some phrase"); + assertQueryNodeException("(foo bar"); + assertQueryNodeException("foo bar))"); + assertQueryNodeException("field:term:with:colon some more terms"); + assertQueryNodeException("(sub query)^5.0^2.0 plus more"); + assertQueryNodeException("secret AND illegal) AND access:confidential"); + } + + public void testCustomQueryParserWildcard() { + try { + new QPTestParser(new WhitespaceAnalyzer()).parse("a?t", "contents"); + fail("Wildcard queries should not be allowed"); + } catch (QueryNodeException expected) { + // expected exception + } + } + + public void testCustomQueryParserFuzzy() throws Exception { + try { + new QPTestParser(new WhitespaceAnalyzer()).parse("xunit~", "contents"); + fail("Fuzzy queries should not be allowed"); + } catch (QueryNodeException expected) { + // expected exception + } + } + + public void testBooleanQuery() throws Exception { + BooleanQuery.setMaxClauseCount(2); + try { + OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + qp.setAnalyzer(new WhitespaceAnalyzer()); + + qp.parse("one two three", "field"); + fail("ParseException expected due to too many boolean clauses"); + } catch (QueryNodeException expected) { + // too many boolean clauses, so ParseException is expected + } + } + + /** + * This test differs from TestPrecedenceQueryParser + */ + public void testPrecedence() throws Exception { + OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + qp.setAnalyzer(new WhitespaceAnalyzer()); + + Query query1 = qp.parse("A AND B OR C AND D", "field"); + Query query2 = qp.parse("+A +B +C +D", "field"); + + assertEquals(query1, query2); + } + + public void testLocalDateFormat() throws IOException, QueryNodeException { + + RAMDirectory ramDir = new RAMDirectory(); + IndexWriter iw = new IndexWriter(ramDir, new WhitespaceAnalyzer(), true, + IndexWriter.MaxFieldLength.LIMITED); + addDateDoc("a", 2005, 12, 2, 10, 15, 33, iw); + addDateDoc("b", 2005, 12, 4, 22, 15, 00, iw); + iw.close(); + IndexSearcher is = new IndexSearcher(ramDir); + assertHits(1, "[12/1/2005 TO 12/3/2005]", is); + assertHits(2, "[12/1/2005 TO 12/4/2005]", is); + assertHits(1, "[12/3/2005 TO 12/4/2005]", is); + assertHits(1, "{12/1/2005 TO 12/3/2005}", is); + assertHits(1, "{12/1/2005 TO 12/4/2005}", is); + assertHits(0, "{12/3/2005 TO 12/4/2005}", is); + is.close(); + } + + public void testStarParsing() throws Exception { + // final int[] type = new int[1]; + // OriginalQueryParserHelper qp = new OriginalQueryParserHelper("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 { + OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + qp.setAnalyzer( + new StopAnalyzer(new String[] { "the", "foo" })); + + Query result = qp.parse("a:the OR a:foo", "a"); + assertNotNull("result is null and it shouldn't be", result); + assertTrue("result is not a BooleanQuery", result instanceof BooleanQuery); + assertTrue(((BooleanQuery) result).clauses().size() + " does not equal: " + + 0, ((BooleanQuery) result).clauses().size() == 0); + result = qp.parse("a:woo OR a:the", "a"); + assertNotNull("result is null and it shouldn't be", result); + assertTrue("result is not a TermQuery", result instanceof TermQuery); + result = qp.parse( + "(fieldX:xxxxx OR fieldy:xxxxxxxx)^2 AND (fieldx:the OR fieldy:foo)", + "a"); + assertNotNull("result is null and it shouldn't be", result); + assertTrue("result is not a BooleanQuery", result instanceof BooleanQuery); + System.out.println("Result: " + result); + assertTrue(((BooleanQuery) result).clauses().size() + " does not equal: " + + 2, ((BooleanQuery) result).clauses().size() == 2); + } + + public void testPositionIncrement() throws Exception { + boolean dflt = StopFilter.getEnablePositionIncrementsDefault(); + StopFilter.setEnablePositionIncrementsDefault(true); + try { + OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + qp.setAnalyzer( + 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, "a"); + // System.out.println("Query text: "+qtxt); + // System.out.println("Result: "+pq); + Term t[] = pq.getTerms(); + int pos[] = pq.getPositions(); + for (int i = 0; i < t.length; i++) { + // System.out.println(i+". "+t[i]+" pos: "+pos[i]); + assertEquals("term " + i + " = " + t[i] + " has wrong term-position!", + expectedPositions[i], pos[i]); + } + + } finally { + StopFilter.setEnablePositionIncrementsDefault(dflt); + } + } + + public void testMatchAllDocs() throws Exception { + OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + qp.setAnalyzer(new WhitespaceAnalyzer()); + + assertEquals(new MatchAllDocsQuery(), qp.parse("*:*", "field")); + assertEquals(new MatchAllDocsQuery(), qp.parse("(*:*)", "field")); + BooleanQuery bq = (BooleanQuery) qp.parse("+*:* -*:*", "field"); + assertTrue(bq.getClauses()[0].getQuery() instanceof MatchAllDocsQuery); + assertTrue(bq.getClauses()[1].getQuery() instanceof MatchAllDocsQuery); + } + + private void assertHits(int expected, String query, IndexSearcher is) + throws IOException, QueryNodeException { + OriginalQueryParserHelper qp = new OriginalQueryParserHelper(); + qp.setAnalyzer(new WhitespaceAnalyzer()); + qp.setLocale(Locale.ENGLISH); + + Query q = qp.parse(query, "date"); + ScoreDoc[] hits = is.search(q, null, 1000).scoreDocs; + assertEquals(expected, hits.length); + } + + private static void addDateDoc(String content, int year, int month, int day, + int hour, int minute, int second, IndexWriter iw) throws IOException { + Document d = new Document(); + d.add(new Field("f", content, Field.Store.YES, Field.Index.ANALYZED)); + Calendar cal = Calendar.getInstance(); + cal.set(year, month - 1, day, hour, minute, second); + d.add(new Field("date", DateField.dateToString(cal.getTime()), + Field.Store.YES, Field.Index.NOT_ANALYZED)); + iw.addDocument(d); + } + + public void tearDown() throws Exception { + super.tearDown(); + BooleanQuery.setMaxClauseCount(originalMaxClauses); + } + +} diff --git a/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestQueryParserWrapper.java b/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestQueryParserWrapper.java new file mode 100644 index 00000000000..8360f1e9ccc --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/queryParser/original/TestQueryParserWrapper.java @@ -0,0 +1,1122 @@ +package org.apache.lucene.queryParser.original; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.IOException; +import java.io.Reader; +import java.text.Collator; +import java.text.DateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.KeywordAnalyzer; +import org.apache.lucene.analysis.LowerCaseTokenizer; +import org.apache.lucene.analysis.SimpleAnalyzer; +import org.apache.lucene.analysis.StopAnalyzer; +import org.apache.lucene.analysis.StopFilter; +import org.apache.lucene.analysis.Token; +import org.apache.lucene.analysis.TokenFilter; +import org.apache.lucene.analysis.TokenStream; +import org.apache.lucene.analysis.WhitespaceAnalyzer; +import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.apache.lucene.analysis.tokenattributes.OffsetAttribute; +import org.apache.lucene.analysis.tokenattributes.TermAttribute; +import org.apache.lucene.document.DateField; +import org.apache.lucene.document.DateTools; +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.Term; +import org.apache.lucene.messages.MessageImpl; +import org.apache.lucene.queryParser.ParseException; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.nodes.FuzzyQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.nodes.WildcardQueryNode; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorImpl; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorPipeline; +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.MultiTermQuery; +import org.apache.lucene.search.PhraseQuery; +import org.apache.lucene.search.PrefixQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.TermRangeQuery; +import org.apache.lucene.search.WildcardQuery; +import org.apache.lucene.store.RAMDirectory; +import org.apache.lucene.util.LuceneTestCase; + +/** + * This test case is a copy of the core Lucene query parser test, it was adapted + * to use new {@link QueryParserWrapper} instead of the old query parser. + * + * Tests QueryParser. + */ +public class TestQueryParserWrapper extends LuceneTestCase { + + public static Analyzer qpAnalyzer = new QPTestAnalyzer(); + + public static class QPTestFilter extends TokenFilter { + TermAttribute termAtt; + OffsetAttribute offsetAtt; + + /** + * Filter which discards the token 'stop' and which expands the token + * 'phrase' into 'phrase1 phrase2' + */ + public QPTestFilter(TokenStream in) { + super(in); + termAtt = (TermAttribute) addAttribute(TermAttribute.class); + offsetAtt = (OffsetAttribute) addAttribute(OffsetAttribute.class); + } + + boolean inPhrase = false; + int savedStart = 0, savedEnd = 0; + + public Token next(Token reusableToken) throws IOException { + Token token = reusableToken; + + if (inPhrase) { + inPhrase = false; + token.setTermBuffer("phrase2"); + token.setStartOffset(savedStart); + token.setEndOffset(savedEnd); + return reusableToken; + } else + while ((token = this.input.next(reusableToken)) != null) { + if (token.term().equals("phrase")) { + inPhrase = true; + savedStart = token.startOffset(); + savedEnd = token.endOffset(); + token.setTermBuffer("phrase1"); + token.setStartOffset(savedStart); + token.setEndOffset(savedEnd); + return token; + } else if (!token.term().equals("stop")) + return token; + } + + return null; + + } + + public boolean incrementToken() throws IOException { + if (inPhrase) { + inPhrase = false; + termAtt.setTermBuffer("phrase2"); + offsetAtt.setOffset(savedStart, savedEnd); + return true; + } else + while (input.incrementToken()) { + if (termAtt.term().equals("phrase")) { + inPhrase = true; + savedStart = offsetAtt.startOffset(); + savedEnd = offsetAtt.endOffset(); + termAtt.setTermBuffer("phrase1"); + offsetAtt.setOffset(savedStart, savedEnd); + return true; + } else if (!termAtt.term().equals("stop")) + return true; + } + return false; + } + } + + public static class QPTestAnalyzer extends Analyzer { + + /** Filters LowerCaseTokenizer with StopFilter. */ + public final TokenStream tokenStream(String fieldName, Reader reader) { + return new QPTestFilter(new LowerCaseTokenizer(reader)); + } + } + + public static class QPTestParser extends QueryParserWrapper { + public QPTestParser(String f, Analyzer a) { + super(f, a); + + QueryNodeProcessorPipeline newProcessorPipeline = new QueryNodeProcessorPipeline( + getQueryProcessor().getQueryConfigHandler()); + newProcessorPipeline.addProcessor(new QPTestParserQueryNodeProcessor()); + newProcessorPipeline.addProcessor(getQueryProcessor()); + + setQueryProcessor(newProcessorPipeline); + + } + + protected Query getFuzzyQuery(String field, String termStr, + float minSimilarity) throws ParseException { + throw new ParseException("Fuzzy queries not allowed"); + } + + protected Query getWildcardQuery(String field, String termStr) + throws ParseException { + throw new ParseException("Wildcard queries not allowed"); + } + + private static class QPTestParserQueryNodeProcessor extends + QueryNodeProcessorImpl { + + protected QueryNode postProcessNode(QueryNode node) + throws QueryNodeException { + + return node; + + } + + protected QueryNode preProcessNode(QueryNode node) + throws QueryNodeException { + + if (node instanceof WildcardQueryNode || node instanceof FuzzyQueryNode) { + + throw new QueryNodeException(new MessageImpl( + QueryParserMessages.EMPTY_MESSAGE)); + + } + + return node; + + } + + protected List setChildrenOrder(List 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]"); + assertEquals(MultiTermQuery.CONSTANT_SCORE_AUTO_REWRITE_DEFAULT, ((TermRangeQuery)getQuery("[ a TO z]", null)).getRewriteMethod()); + + QueryParserWrapper qp = new QueryParserWrapper("field", + new SimpleAnalyzer()); + + qp.setMultiTermRewriteMethod(MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE); + assertEquals(MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE,((TermRangeQuery)qp.parse("[ a TO z]")).getRewriteMethod()); + + 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.setMultiTermRewriteMethod(MultiTermQuery.CONSTANT_SCORE_FILTER_REWRITE); + 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.setMultiTermRewriteMethod(MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE); + 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); + } + +} diff --git a/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpanOrQueryNodeBuilder.java b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpanOrQueryNodeBuilder.java new file mode 100644 index 00000000000..ca300b17ca9 --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpanOrQueryNodeBuilder.java @@ -0,0 +1,56 @@ +package org.apache.lucene.queryParser.spans; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.builders.QueryTreeBuilder; +import org.apache.lucene.queryParser.core.nodes.BooleanQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.original.builders.OriginalQueryBuilder; +import org.apache.lucene.search.spans.SpanOrQuery; +import org.apache.lucene.search.spans.SpanQuery; + +/** + * This builder creates {@link SpanOrQuery}s from a {@link BooleanQueryNode}.
+ *
+ * + * It assumes that the {@link BooleanQueryNode} instance has at least one child. + */ +public class SpanOrQueryNodeBuilder implements OriginalQueryBuilder { + + public SpanOrQuery build(QueryNode node) throws QueryNodeException { + + // validates node + BooleanQueryNode booleanNode = (BooleanQueryNode) node; + + List 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); + + } + +} diff --git a/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpanTermQueryNodeBuilder.java b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpanTermQueryNodeBuilder.java new file mode 100644 index 00000000000..5270d45af9c --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpanTermQueryNodeBuilder.java @@ -0,0 +1,41 @@ +package org.apache.lucene.queryParser.spans; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.index.Term; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.nodes.FieldQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.original.builders.OriginalQueryBuilder; +import org.apache.lucene.search.spans.SpanTermQuery; + +/** + * This builder creates {@link SpanTermQuery}s from a {@link FieldQueryNode} + * object. + */ +public class SpanTermQueryNodeBuilder implements OriginalQueryBuilder { + + public SpanTermQuery build(QueryNode node) throws QueryNodeException { + FieldQueryNode fieldQueryNode = (FieldQueryNode) node; + + return new SpanTermQuery(new Term(fieldQueryNode.getFieldAsString(), + fieldQueryNode.getTextAsString())); + + } + +} diff --git a/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansQueryConfigHandler.java b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansQueryConfigHandler.java new file mode 100644 index 00000000000..520d4efeb73 --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansQueryConfigHandler.java @@ -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.core.config.FieldConfig; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; + +/** + * This query config handler only adds the {@link UniqueFieldAttribute} to it.
+ *
+ * + * 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; + + } + +} diff --git a/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansQueryTreeBuilder.java b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansQueryTreeBuilder.java new file mode 100644 index 00000000000..0f88d407ffe --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansQueryTreeBuilder.java @@ -0,0 +1,51 @@ +package org.apache.lucene.queryParser.spans; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.builders.QueryTreeBuilder; +import org.apache.lucene.queryParser.core.nodes.BooleanQueryNode; +import org.apache.lucene.queryParser.core.nodes.FieldQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.original.builders.OriginalQueryBuilder; +import org.apache.lucene.search.spans.SpanQuery; + +/** + * Sets up a query tree builder to build a span query tree from a query node + * tree.
+ *
+ * + * The defined map is:
+ * - every BooleanQueryNode instance is delegated to the SpanOrQueryNodeBuilder
+ * - every FieldQueryNode instance is delegated to the SpanTermQueryNodeBuilder
+ * + */ +public class SpansQueryTreeBuilder extends QueryTreeBuilder implements + OriginalQueryBuilder { + + public SpansQueryTreeBuilder() { + setBuilder(BooleanQueryNode.class, new SpanOrQueryNodeBuilder()); + setBuilder(FieldQueryNode.class, new SpanTermQueryNodeBuilder()); + + } + + public SpanQuery build(QueryNode queryTree) throws QueryNodeException { + return (SpanQuery) super.build(queryTree); + } + +} diff --git a/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansValidatorQueryNodeProcessor.java b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansValidatorQueryNodeProcessor.java new file mode 100644 index 00000000000..335adb447d2 --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/SpansValidatorQueryNodeProcessor.java @@ -0,0 +1,72 @@ +package org.apache.lucene.queryParser.spans; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.messages.MessageImpl; +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.messages.QueryParserMessages; +import org.apache.lucene.queryParser.core.nodes.AndQueryNode; +import org.apache.lucene.queryParser.core.nodes.BooleanQueryNode; +import org.apache.lucene.queryParser.core.nodes.FieldQueryNode; +import org.apache.lucene.queryParser.core.nodes.OrQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.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.
+ *
+ * + * 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 setChildrenOrder(List children) + throws QueryNodeException { + + return children; + + } + +} diff --git a/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/TestSpanQueryParser.java b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/TestSpanQueryParser.java new file mode 100644 index 00000000000..049953c8b6c --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/TestSpanQueryParser.java @@ -0,0 +1,233 @@ +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.core.QueryNodeException; +import org.apache.lucene.queryParser.core.nodes.OrQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.parser.SyntaxParser; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorPipeline; +import org.apache.lucene.queryParser.original.parser.OriginalSyntaxParser; +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.
+ *
+ * + * It tests queries likes "term", "field:term" "term1 term2" "term1 OR term2", + * which are all already supported by the current syntax parser ( + * {@link OriginalSyntaxParser}).
+ *
+ * + * 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}.
+ *
+ * + * Another functionality that will be added is the ability to convert every + * field defined in the query to an unique specific field.
+ *
+ * + * The query generation is divided in three different steps: parsing (syntax), + * processing (semantic) and building.
+ *
+ * + * The parsing phase, as already mentioned will be performed by the current + * query parser: {@link OriginalSyntaxParser}.
+ *
+ * + * The processing phase will be performed by a processor pipeline which is + * compound by 2 processors: {@link SpansValidatorQueryNodeProcessor} and + * {@link UniqueFieldQueryNodeProcessor}. + * + *
+ * 
+ *   {@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.
+ * 
+ * + * 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.
+ *
+ * + * @see SpansQueryConfigHandler + * @see SpansQueryTreeBuilder + * @see SpansValidatorQueryNodeProcessor + * @see SpanOrQueryNodeBuilder + * @see SpanTermQueryNodeBuilder + * @see OriginalSyntaxParser + * @see UniqueFieldQueryNodeProcessor + * @see UniqueFieldAttribute + */ +public class TestSpanQueryParser extends TestCase { + + private QueryNodeProcessorPipeline spanProcessorPipeline; + + private SpansQueryConfigHandler spanQueryConfigHandler; + + private SpansQueryTreeBuilder spansQueryTreeBuilder; + + private SyntaxParser queryParser = new OriginalSyntaxParser(); + + 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 + } + + } + +} diff --git a/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/TestSpanQueryParserSimpleSample.java b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/TestSpanQueryParserSimpleSample.java new file mode 100644 index 00000000000..623f3bad96f --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/TestSpanQueryParserSimpleSample.java @@ -0,0 +1,155 @@ +package org.apache.lucene.queryParser.spans; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import javax.management.Query; + +import junit.framework.TestCase; + +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.core.nodes.OrQueryNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.parser.SyntaxParser; +import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorPipeline; +import org.apache.lucene.queryParser.original.parser.OriginalSyntaxParser; +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.
+ *
+ * + * It tests queries likes "term", "field:term" "term1 term2" "term1 OR term2", + * which are all already supported by the current syntax parser ( + * {@link OriginalSyntaxParser}).
+ *
+ * + * 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}.
+ *
+ * + * Another functionality that will be added is the ability to convert every + * field defined in the query to an unique specific field.
+ *
+ * + * The query generation is divided in three different steps: parsing (syntax), + * processing (semantic) and building.
+ *
+ * + * The parsing phase, as already mentioned will be performed by the current + * query parser: {@link OriginalSyntaxParser}.
+ *
+ * + * The processing phase will be performed by a processor pipeline which is + * compound by 2 processors: {@link SpansValidatorQueryNodeProcessor} and + * {@link UniqueFieldQueryNodeProcessor}. + * + *
+ * 
+ *   {@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.
+ * 
+ * + * 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.
+ *
+ * + * @see TestSpanQueryParser for a more advanced example + * + * @see SpansQueryConfigHandler + * @see SpansQueryTreeBuilder + * @see SpansValidatorQueryNodeProcessor + * @see SpanOrQueryNodeBuilder + * @see SpanTermQueryNodeBuilder + * @see OriginalSyntaxParser + * @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 { + SyntaxParser queryParser = new OriginalSyntaxParser(); + + // convert the CharSequence into a QueryNode tree + QueryNode queryTree = queryParser.parse("body:text", null); + + // create a config handler with a attribute used in + // UniqueFieldQueryNodeProcessor + QueryConfigHandler spanQueryConfigHandler = new SpansQueryConfigHandler(); + UniqueFieldAttribute uniqueFieldAtt = (UniqueFieldAttribute) spanQueryConfigHandler + .getAttribute(UniqueFieldAttribute.class); + uniqueFieldAtt.setUniqueField("index"); + + // set up the processor pipeline with the ConfigHandler + // and create the pipeline for this simple demo + QueryNodeProcessorPipeline spanProcessorPipeline = new QueryNodeProcessorPipeline( + spanQueryConfigHandler); + // @see SpansValidatorQueryNodeProcessor + spanProcessorPipeline.addProcessor(new SpansValidatorQueryNodeProcessor()); + // @see UniqueFieldQueryNodeProcessor + spanProcessorPipeline.addProcessor(new UniqueFieldQueryNodeProcessor()); + + // print to show out the QueryNode tree before being processed + System.out.println(queryTree); + + // Process the QueryTree using our new Processors + queryTree = spanProcessorPipeline.process(queryTree); + + // print to show out the QueryNode tree after being processed + System.out.println(queryTree); + + // create a instance off the Builder + SpansQueryTreeBuilder spansQueryTreeBuilder = new SpansQueryTreeBuilder(); + + // convert QueryNode tree to span query Objects + SpanQuery spanquery = spansQueryTreeBuilder.build(queryTree); + + assertTrue(spanquery instanceof SpanTermQuery); + assertEquals(spanquery.toString(), "index:text"); + + } + +} diff --git a/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldAttribute.java b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldAttribute.java new file mode 100644 index 00000000000..adbae05cbe7 --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldAttribute.java @@ -0,0 +1,35 @@ +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.core.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}.
+ *
+ * + * @see UniqueFieldQueryNodeProcessor + */ +public interface UniqueFieldAttribute extends Attribute { + public void setUniqueField(CharSequence uniqueField); + + public CharSequence getUniqueField(); +} diff --git a/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldAttributeImpl.java b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldAttributeImpl.java new file mode 100644 index 00000000000..0cb8b4ab7dd --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldAttributeImpl.java @@ -0,0 +1,93 @@ +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.core.nodes.FieldableNode; +import org.apache.lucene.util.AttributeImpl; + +/** + * 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}.
+ *
+ * + * @see UniqueFieldQueryNodeProcessor + */ +public class UniqueFieldAttributeImpl extends AttributeImpl implements + UniqueFieldAttribute { + + private static final long serialVersionUID = 8553318595851064232L; + + private CharSequence uniqueField; + + public UniqueFieldAttributeImpl() { + 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(AttributeImpl target) { + + if (!(target instanceof UniqueFieldAttributeImpl)) { + throw new IllegalArgumentException( + "cannot copy the values from attribute UniqueFieldAttribute to an instance of " + + target.getClass().getName()); + } + + UniqueFieldAttributeImpl uniqueFieldAttr = (UniqueFieldAttributeImpl) target; + uniqueFieldAttr.uniqueField = uniqueField.toString(); + + } + + @Override + public boolean equals(Object other) { + + if (other instanceof UniqueFieldAttributeImpl) { + + return ((UniqueFieldAttributeImpl) other).uniqueField + .equals(this.uniqueField); + + } + + return false; + + } + + @Override + public int hashCode() { + return this.uniqueField.hashCode(); + } + + @Override + public String toString() { + return ""; + } + +} diff --git a/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldQueryNodeProcessor.java b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldQueryNodeProcessor.java new file mode 100644 index 00000000000..c20b1049491 --- /dev/null +++ b/contrib/queryparser/src/test/org/apache/lucene/queryParser/spans/UniqueFieldQueryNodeProcessor.java @@ -0,0 +1,84 @@ +package org.apache.lucene.queryParser.spans; + +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.List; + +import org.apache.lucene.queryParser.core.QueryNodeException; +import org.apache.lucene.queryParser.core.config.QueryConfigHandler; +import org.apache.lucene.queryParser.core.nodes.FieldableNode; +import org.apache.lucene.queryParser.core.nodes.QueryNode; +import org.apache.lucene.queryParser.core.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.
+ *
+ * + * @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 setChildrenOrder(List children) + throws QueryNodeException { + + return children; + + } + +} diff --git a/src/java/org/apache/lucene/queryParser/CharStream.java b/src/java/org/apache/lucene/queryParser/CharStream.java index 9e546d50a41..c67321c1b38 100644 --- a/src/java/org/apache/lucene/queryParser/CharStream.java +++ b/src/java/org/apache/lucene/queryParser/CharStream.java @@ -15,6 +15,8 @@ package org.apache.lucene.queryParser; * column number and the String that constitutes a token and are not used * by the lexer. Hence their implementation won't affect the generated lexer's * operation. + * + * @deprecated this class will be removed in Lucene 3.0, when the {@link QueryParser} is removed */ public interface CharStream { diff --git a/src/java/org/apache/lucene/queryParser/ComplexPhraseQueryParser.java b/src/java/org/apache/lucene/queryParser/ComplexPhraseQueryParser.java index 0531a5a49bb..f7c5dc1b8df 100644 --- a/src/java/org/apache/lucene/queryParser/ComplexPhraseQueryParser.java +++ b/src/java/org/apache/lucene/queryParser/ComplexPhraseQueryParser.java @@ -54,8 +54,8 @@ import org.apache.lucene.search.spans.SpanTermQuery; * currently simply feeds all phrase content through an analyzer to select * phrase terms - any "special" syntax such as * ~ * etc are not given special * status - * - * + * + * @deprecated use new the flexible query parser instead */ public class ComplexPhraseQueryParser extends QueryParser { private ArrayList/**/complexPhrases = null; diff --git a/src/java/org/apache/lucene/queryParser/FastCharStream.java b/src/java/org/apache/lucene/queryParser/FastCharStream.java index 3306c110396..415ab9d099e 100644 --- a/src/java/org/apache/lucene/queryParser/FastCharStream.java +++ b/src/java/org/apache/lucene/queryParser/FastCharStream.java @@ -16,6 +16,7 @@ package org.apache.lucene.queryParser; * WITHOUT 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 @@ import java.io.*; /** An efficient implementation of JavaCC's CharStream interface.

Note that * this does not do line-number counting, but instead keeps track of the * character position of the token in the input, as required by Lucene's {@link - * org.apache.lucene.analysis.Token} API. */ + * org.apache.lucene.analysis.Token} API. + * + * @deprecated this class will be removed in Lucene 3.0, when the {@link QueryParser} is removed + * + * */ public final class FastCharStream implements CharStream { char[] buffer = null; diff --git a/src/java/org/apache/lucene/queryParser/MultiFieldQueryParser.java b/src/java/org/apache/lucene/queryParser/MultiFieldQueryParser.java index 0784c4f36ec..8d29c791f0a 100644 --- a/src/java/org/apache/lucene/queryParser/MultiFieldQueryParser.java +++ b/src/java/org/apache/lucene/queryParser/MultiFieldQueryParser.java @@ -20,7 +20,6 @@ package org.apache.lucene.queryParser; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Vector; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.search.BooleanClause; @@ -32,6 +31,8 @@ import org.apache.lucene.search.Query; /** * A QueryParser which constructs queries to search multiple fields. * + * @deprecated use the equivalent class defined in the new queryparser project, + * currently located in contrib: org.apache.lucene.queryParser.original.OriginalQueryParserHelper * * @version $Revision$ */ diff --git a/src/java/org/apache/lucene/queryParser/ParseException.java b/src/java/org/apache/lucene/queryParser/ParseException.java index fdb47847a38..465bd9b155d 100644 --- a/src/java/org/apache/lucene/queryParser/ParseException.java +++ b/src/java/org/apache/lucene/queryParser/ParseException.java @@ -10,6 +10,9 @@ package org.apache.lucene.queryParser; * * You can modify this class to customize your error reporting * mechanisms so long as you retain the public fields. + * + * @deprecated use the equivalent class defined in the new queryparser project, + * currently located in contrib: org.apache.lucene.queryParser.original.parser.ParseException */ public class ParseException extends Exception { diff --git a/src/java/org/apache/lucene/queryParser/QueryParser.java b/src/java/org/apache/lucene/queryParser/QueryParser.java index 81acf6928e1..d1ed9abb6b5 100644 --- a/src/java/org/apache/lucene/queryParser/QueryParser.java +++ b/src/java/org/apache/lucene/queryParser/QueryParser.java @@ -97,6 +97,9 @@ import org.apache.lucene.util.Parameter; *

* *

Note that QueryParser is not thread-safe.

+ * + * @deprecated use the equivalent class defined in the new queryparser project, + * currently located in contrib: org.apache.lucene.queryParser.original.OriginalQueryParserHelper */ public class QueryParser implements QueryParserConstants { diff --git a/src/java/org/apache/lucene/queryParser/QueryParser.jj b/src/java/org/apache/lucene/queryParser/QueryParser.jj index 9fd125c90f3..0c99696103a 100644 --- a/src/java/org/apache/lucene/queryParser/QueryParser.jj +++ b/src/java/org/apache/lucene/queryParser/QueryParser.jj @@ -120,7 +120,11 @@ import org.apache.lucene.util.Parameter; * use a different method for date conversion. *

* - *

Note that QueryParser is not thread-safe.

+ *

Note that QueryParser is not thread-safe.

+ * + * @deprecated use the equivalent class defined in the new queryparser project, + * currently located in contrib: org.apache.lucene.queryParser.original.LuceneQueryParserHelper + * */ public class QueryParser { diff --git a/src/java/org/apache/lucene/queryParser/QueryParserConstants.java b/src/java/org/apache/lucene/queryParser/QueryParserConstants.java index 0073663cb42..3359f7c80d3 100644 --- a/src/java/org/apache/lucene/queryParser/QueryParserConstants.java +++ b/src/java/org/apache/lucene/queryParser/QueryParserConstants.java @@ -5,6 +5,10 @@ package org.apache.lucene.queryParser; /** * Token literal values and constants. * Generated by org.javacc.parser.OtherFilesGen#start() + * + * @deprecated use the equivalent class defined in the new queryparser project, + * currently located in contrib: org.apache.lucene.queryParser.original.parser.TextParserConstants + * */ public interface QueryParserConstants { diff --git a/src/java/org/apache/lucene/queryParser/QueryParserTokenManager.java b/src/java/org/apache/lucene/queryParser/QueryParserTokenManager.java index 2dc793f1dc5..3686967b791 100644 --- a/src/java/org/apache/lucene/queryParser/QueryParserTokenManager.java +++ b/src/java/org/apache/lucene/queryParser/QueryParserTokenManager.java @@ -34,7 +34,11 @@ import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.WildcardQuery; import org.apache.lucene.util.Parameter; -/** Token Manager. */ +/** Token Manager. + * + * @deprecated use the equivalent class defined in the new queryparser project, + * currently located in contrib: org.apache.lucene.queryParser.original.parser.TextParserTokenManager + */ public class QueryParserTokenManager implements QueryParserConstants { diff --git a/src/java/org/apache/lucene/queryParser/Token.java b/src/java/org/apache/lucene/queryParser/Token.java index 97677981cd7..173af6867b6 100644 --- a/src/java/org/apache/lucene/queryParser/Token.java +++ b/src/java/org/apache/lucene/queryParser/Token.java @@ -4,6 +4,10 @@ package org.apache.lucene.queryParser; /** * Describes the input token stream. + * + * @deprecated use the equivalent class defined in the new queryparser project, + * currently located in contrib: org.apache.lucene.queryParser.original.parser.Token + * */ public class Token { diff --git a/src/java/org/apache/lucene/queryParser/TokenMgrError.java b/src/java/org/apache/lucene/queryParser/TokenMgrError.java index 2208bc238ae..601be367be2 100644 --- a/src/java/org/apache/lucene/queryParser/TokenMgrError.java +++ b/src/java/org/apache/lucene/queryParser/TokenMgrError.java @@ -2,7 +2,12 @@ /* JavaCCOptions: */ package org.apache.lucene.queryParser; -/** Token Manager Error. */ +/** Token Manager Error. + * + * @deprecated use the equivalent class defined in the new queryparser project, + * currently located in contrib: org.apache.lucene.queryParser.original.parser.TokenMgrError + * + */ public class TokenMgrError extends Error { diff --git a/src/java/org/apache/lucene/queryParser/package.html b/src/java/org/apache/lucene/queryParser/package.html index a254ed47979..90e146e9282 100644 --- a/src/java/org/apache/lucene/queryParser/package.html +++ b/src/java/org/apache/lucene/queryParser/package.html @@ -20,6 +20,8 @@ +NOTE: Please look into lucene contrib/queryparser for the new flexible queryparser api. + A simple query parser implemented with JavaCC.

Note that JavaCC defines lots of public classes, methods and fields that do not need to be public.  These clutter the documentation.