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 {