1 package org.apache.lucene.queryParser.standard.processors;
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership.
7 * The ASF licenses this file to You under the Apache License, Version 2.0
8 * (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
20 import java.io.IOException;
21 import java.io.StringReader;
22 import java.util.ArrayList;
23 import java.util.LinkedList;
24 import java.util.List;
26 import org.apache.lucene.analysis.Analyzer;
27 import org.apache.lucene.analysis.CachingTokenFilter;
28 import org.apache.lucene.analysis.TokenStream;
29 import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
30 import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
31 import org.apache.lucene.queryParser.core.QueryNodeException;
32 import org.apache.lucene.queryParser.core.config.QueryConfigHandler;
33 import org.apache.lucene.queryParser.core.nodes.BooleanQueryNode;
34 import org.apache.lucene.queryParser.core.nodes.FieldQueryNode;
35 import org.apache.lucene.queryParser.core.nodes.FuzzyQueryNode;
36 import org.apache.lucene.queryParser.core.nodes.GroupQueryNode;
37 import org.apache.lucene.queryParser.core.nodes.NoTokenFoundQueryNode;
38 import org.apache.lucene.queryParser.core.nodes.ParametricQueryNode;
39 import org.apache.lucene.queryParser.core.nodes.QueryNode;
40 import org.apache.lucene.queryParser.core.nodes.QuotedFieldQueryNode;
41 import org.apache.lucene.queryParser.core.nodes.TextableQueryNode;
42 import org.apache.lucene.queryParser.core.nodes.TokenizedPhraseQueryNode;
43 import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorImpl;
44 import org.apache.lucene.queryParser.standard.config.StandardQueryConfigHandler.ConfigurationKeys;
45 import org.apache.lucene.queryParser.standard.nodes.MultiPhraseQueryNode;
46 import org.apache.lucene.queryParser.standard.nodes.StandardBooleanQueryNode;
47 import org.apache.lucene.queryParser.standard.nodes.WildcardQueryNode;
50 * This processor verifies if {@link ConfigurationKeys#ANALYZER}
51 * is defined in the {@link QueryConfigHandler}. If it is and the analyzer is
52 * not <code>null</code>, it looks for every {@link FieldQueryNode} that is not
53 * {@link WildcardQueryNode}, {@link FuzzyQueryNode} or
54 * {@link ParametricQueryNode} contained in the query node tree, then it applies
55 * the analyzer to that {@link FieldQueryNode} object. <br/>
57 * If the analyzer return only one term, the returned term is set to the
58 * {@link FieldQueryNode} and it's returned. <br/>
60 * If the analyzer return more than one term, a {@link TokenizedPhraseQueryNode}
61 * or {@link MultiPhraseQueryNode} is created, whether there is one or more
62 * terms at the same position, and it's returned. <br/>
64 * If no term is returned by the analyzer a {@link NoTokenFoundQueryNode} object
67 * @see ConfigurationKeys#ANALYZER
71 public class AnalyzerQueryNodeProcessor extends QueryNodeProcessorImpl {
73 private Analyzer analyzer;
75 private boolean positionIncrementsEnabled;
77 public AnalyzerQueryNodeProcessor() {
82 public QueryNode process(QueryNode queryTree) throws QueryNodeException {
83 Analyzer analyzer = getQueryConfigHandler().get(ConfigurationKeys.ANALYZER);
85 if (analyzer != null) {
86 this.analyzer = analyzer;
87 this.positionIncrementsEnabled = false;
88 Boolean positionIncrementsEnabled = getQueryConfigHandler().get(ConfigurationKeys.ENABLE_POSITION_INCREMENTS);
90 if (positionIncrementsEnabled != null) {
91 this.positionIncrementsEnabled = positionIncrementsEnabled;
94 if (this.analyzer != null) {
95 return super.process(queryTree);
105 protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException {
107 if (node instanceof TextableQueryNode
108 && !(node instanceof WildcardQueryNode)
109 && !(node instanceof FuzzyQueryNode)
110 && !(node instanceof ParametricQueryNode)) {
112 FieldQueryNode fieldNode = ((FieldQueryNode) node);
113 String text = fieldNode.getTextAsString();
114 String field = fieldNode.getFieldAsString();
118 source = this.analyzer.reusableTokenStream(field, new StringReader(text));
120 } catch (IOException e1) {
121 throw new RuntimeException(e1);
123 CachingTokenFilter buffer = new CachingTokenFilter(source);
125 PositionIncrementAttribute posIncrAtt = null;
127 int positionCount = 0;
128 boolean severalTokensAtSamePosition = false;
130 if (buffer.hasAttribute(PositionIncrementAttribute.class)) {
131 posIncrAtt = buffer.getAttribute(PositionIncrementAttribute.class);
136 while (buffer.incrementToken()) {
138 int positionIncrement = (posIncrAtt != null) ? posIncrAtt
139 .getPositionIncrement() : 1;
140 if (positionIncrement != 0) {
141 positionCount += positionIncrement;
144 severalTokensAtSamePosition = true;
149 } catch (IOException e) {
154 // rewind the buffer stream
157 // close original stream - all tokens buffered
159 } catch (IOException e) {
163 if (!buffer.hasAttribute(CharTermAttribute.class)) {
164 return new NoTokenFoundQueryNode();
167 CharTermAttribute termAtt = buffer.getAttribute(CharTermAttribute.class);
169 if (numTokens == 0) {
170 return new NoTokenFoundQueryNode();
172 } else if (numTokens == 1) {
176 hasNext = buffer.incrementToken();
177 assert hasNext == true;
178 term = termAtt.toString();
180 } catch (IOException e) {
181 // safe to ignore, because we know the number of tokens
184 fieldNode.setText(term);
188 } else if (severalTokensAtSamePosition || !(node instanceof QuotedFieldQueryNode)) {
189 if (positionCount == 1 || !(node instanceof QuotedFieldQueryNode)) {
191 LinkedList<QueryNode> children = new LinkedList<QueryNode>();
193 for (int i = 0; i < numTokens; i++) {
196 boolean hasNext = buffer.incrementToken();
197 assert hasNext == true;
198 term = termAtt.toString();
200 } catch (IOException e) {
201 // safe to ignore, because we know the number of tokens
204 children.add(new FieldQueryNode(field, term, -1, -1));
207 return new GroupQueryNode(
208 new StandardBooleanQueryNode(children, positionCount==1));
211 MultiPhraseQueryNode mpq = new MultiPhraseQueryNode();
213 List<FieldQueryNode> multiTerms = new ArrayList<FieldQueryNode>();
216 int termGroupCount = 0;
217 for (; i < numTokens; i++) {
219 int positionIncrement = 1;
221 boolean hasNext = buffer.incrementToken();
222 assert hasNext == true;
223 term = termAtt.toString();
224 if (posIncrAtt != null) {
225 positionIncrement = posIncrAtt.getPositionIncrement();
228 } catch (IOException e) {
229 // safe to ignore, because we know the number of tokens
232 if (positionIncrement > 0 && multiTerms.size() > 0) {
234 for (FieldQueryNode termNode : multiTerms) {
236 if (this.positionIncrementsEnabled) {
237 termNode.setPositionIncrement(position);
239 termNode.setPositionIncrement(termGroupCount);
246 // Only increment once for each "group" of
247 // terms that were in the same position:
254 position += positionIncrement;
255 multiTerms.add(new FieldQueryNode(field, term, -1, -1));
259 for (FieldQueryNode termNode : multiTerms) {
261 if (this.positionIncrementsEnabled) {
262 termNode.setPositionIncrement(position);
265 termNode.setPositionIncrement(termGroupCount);
278 TokenizedPhraseQueryNode pq = new TokenizedPhraseQueryNode();
282 for (int i = 0; i < numTokens; i++) {
284 int positionIncrement = 1;
287 boolean hasNext = buffer.incrementToken();
288 assert hasNext == true;
289 term = termAtt.toString();
291 if (posIncrAtt != null) {
292 positionIncrement = posIncrAtt.getPositionIncrement();
295 } catch (IOException e) {
296 // safe to ignore, because we know the number of tokens
299 FieldQueryNode newFieldNode = new FieldQueryNode(field, term, -1, -1);
301 if (this.positionIncrementsEnabled) {
302 position += positionIncrement;
303 newFieldNode.setPositionIncrement(position);
306 newFieldNode.setPositionIncrement(i);
309 pq.add(newFieldNode);
324 protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException {
331 protected List<QueryNode> setChildrenOrder(List<QueryNode> children)
332 throws QueryNodeException {