1 package org.apache.lucene.queryParser.standard;
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.text.Collator;
21 import java.util.Locale;
23 import java.util.TooManyListenersException;
25 import org.apache.lucene.analysis.Analyzer;
26 import org.apache.lucene.document.DateTools.Resolution;
27 import org.apache.lucene.document.DateTools;
28 import org.apache.lucene.queryParser.core.QueryNodeException;
29 import org.apache.lucene.queryParser.core.QueryParserHelper;
30 import org.apache.lucene.queryParser.core.config.QueryConfigHandler;
31 import org.apache.lucene.queryParser.standard.builders.StandardQueryTreeBuilder;
32 import org.apache.lucene.queryParser.standard.config.AllowLeadingWildcardAttribute;
33 import org.apache.lucene.queryParser.standard.config.AnalyzerAttribute;
34 import org.apache.lucene.queryParser.standard.config.DateResolutionAttribute;
35 import org.apache.lucene.queryParser.standard.config.DefaultOperatorAttribute;
36 import org.apache.lucene.queryParser.standard.config.DefaultPhraseSlopAttribute;
37 import org.apache.lucene.queryParser.standard.config.FieldBoostMapAttribute;
38 import org.apache.lucene.queryParser.standard.config.FieldDateResolutionMapAttribute;
39 import org.apache.lucene.queryParser.standard.config.FuzzyAttribute;
40 import org.apache.lucene.queryParser.standard.config.FuzzyConfig;
41 import org.apache.lucene.queryParser.standard.config.LocaleAttribute;
42 import org.apache.lucene.queryParser.standard.config.LowercaseExpandedTermsAttribute;
43 import org.apache.lucene.queryParser.standard.config.MultiFieldAttribute;
44 import org.apache.lucene.queryParser.standard.config.MultiTermRewriteMethodAttribute;
45 import org.apache.lucene.queryParser.standard.config.NumericConfig;
46 import org.apache.lucene.queryParser.standard.config.PositionIncrementsAttribute;
47 import org.apache.lucene.queryParser.standard.config.RangeCollatorAttribute;
48 import org.apache.lucene.queryParser.standard.config.StandardQueryConfigHandler;
49 import org.apache.lucene.queryParser.standard.config.StandardQueryConfigHandler.Operator;
50 import org.apache.lucene.queryParser.standard.config.StandardQueryConfigHandler.ConfigurationKeys;
51 import org.apache.lucene.queryParser.standard.nodes.RangeQueryNode;
52 import org.apache.lucene.queryParser.standard.parser.StandardSyntaxParser;
53 import org.apache.lucene.queryParser.standard.processors.StandardQueryNodeProcessorPipeline;
54 import org.apache.lucene.search.FuzzyQuery;
55 import org.apache.lucene.search.MultiTermQuery;
56 import org.apache.lucene.search.Query;
60 * This class is a helper that enables users to easily use the Lucene query
64 * To construct a Query object from a query string, use the
65 * {@link #parse(String, String)} method:
67 * StandardQueryParser queryParserHelper = new StandardQueryParser(); <br/>
68 * Query query = queryParserHelper.parse("a AND b", "defaultField");
71 * To change any configuration before parsing the query string do, for example:
74 * // the query config handler returned by {@link StandardQueryParser} is a
75 * {@link StandardQueryConfigHandler} <br/>
76 * queryParserHelper.getQueryConfigHandler().setAnalyzer(new
77 * WhitespaceAnalyzer());
80 * The syntax for query strings is as follows (copied from the old QueryParser
83 * A Query is a series of clauses. A clause may be prefixed by:
85 * <li>a plus (<code>+</code>) or a minus (<code>-</code>) sign, indicating that
86 * the clause is required or prohibited respectively; or
87 * <li>a term followed by a colon, indicating the field to be searched. This
88 * enables one to construct queries which search multiple fields.
91 * A clause may be either:
93 * <li>a term, indicating all the documents that contain this term; or
94 * <li>a nested query, enclosed in parentheses. Note that this may be used with
95 * a <code>+</code>/<code>-</code> prefix to require any of a set of terms.
98 * Thus, in BNF, the query grammar is:
101 * Query ::= ( Clause )*
102 * Clause ::= ["+", "-"] [<TERM> ":"] ( <TERM> | "(" Query ")" )
106 * Examples of appropriately formatted queries can be found in the <a
107 * href="../../../../../../queryparsersyntax.html">query syntax
112 * The text parser used by this helper is a {@link StandardSyntaxParser}.
115 * The query node processor used by this helper is a
116 * {@link StandardQueryNodeProcessorPipeline}.
119 * The builder used by this helper is a {@link StandardQueryTreeBuilder}.
122 * @see StandardQueryParser
123 * @see StandardQueryConfigHandler
124 * @see StandardSyntaxParser
125 * @see StandardQueryNodeProcessorPipeline
126 * @see StandardQueryTreeBuilder
128 public class StandardQueryParser extends QueryParserHelper {
131 * Constructs a {@link StandardQueryParser} object.
133 public StandardQueryParser() {
134 super(new StandardQueryConfigHandler(), new StandardSyntaxParser(),
135 new StandardQueryNodeProcessorPipeline(null),
136 new StandardQueryTreeBuilder());
140 * Constructs a {@link StandardQueryParser} object and sets an
141 * {@link Analyzer} to it. The same as:
144 * StandardQueryParser qp = new StandardQueryParser();
145 * qp.getQueryConfigHandler().setAnalyzer(analyzer);
148 * @param analyzer the analyzer to be used by this query parser helper
150 public StandardQueryParser(Analyzer analyzer) {
153 this.setAnalyzer(analyzer);
157 public String toString() {
158 return "<StandardQueryParser config=\"" + this.getQueryConfigHandler()
163 * Overrides {@link QueryParserHelper#parse(String, String)} so it casts the
164 * return object to {@link Query}. For more reference about this method, check
165 * {@link QueryParserHelper#parse(String, String)}.
167 * @param query the query string
168 * @param defaultField the default field used by the text parser
170 * @return the object built from the query
172 * @throws QueryNodeException if something wrong happens along the three
176 public Query parse(String query, String defaultField)
177 throws QueryNodeException {
179 return (Query) super.parse(query, defaultField);
184 * Gets implicit operator setting, which will be either {@link Operator#AND}
185 * or {@link Operator#OR}.
187 public StandardQueryConfigHandler.Operator getDefaultOperator() {
188 return getQueryConfigHandler().get(ConfigurationKeys.DEFAULT_OPERATOR);
192 * Sets the collator used to determine index term inclusion in ranges for
195 * <strong>WARNING:</strong> Setting the rangeCollator to a non-null collator
196 * using this method will cause every single index Term in the Field
197 * referenced by lowerTerm and/or upperTerm to be examined. Depending on the
198 * number of index Terms in this Field, the operation could be very slow.
200 * @param collator the collator to use when constructing
201 * {@link RangeQueryNode}s
203 public void setRangeCollator(Collator collator) {
204 RangeCollatorAttribute attr = getQueryConfigHandler().getAttribute(
205 RangeCollatorAttribute.class);
206 attr.setDateResolution(collator);
208 // uncomment code below when deprecated query parser attributes are removed
209 // getQueryConfigHandler().set(ConfigurationKeys.RANGE_COLLATOR, collator);
213 * @return the collator used to determine index term inclusion in ranges for
216 public Collator getRangeCollator() {
217 return getQueryConfigHandler().get(ConfigurationKeys.RANGE_COLLATOR);
221 * Sets the boolean operator of the QueryParser. In default mode (
222 * {@link Operator#OR}) terms without any modifiers are considered optional:
223 * for example <code>capital of Hungary</code> is equal to
224 * <code>capital OR of OR Hungary</code>.<br/>
225 * In {@link Operator#AND} mode terms are considered to be in conjunction: the
226 * above mentioned query is parsed as <code>capital AND of AND Hungary</code>
231 public void setDefaultOperator(DefaultOperatorAttribute.Operator operator) {
232 DefaultOperatorAttribute attr = getQueryConfigHandler().getAttribute(DefaultOperatorAttribute.class);
233 attr.setOperator(operator);
237 * Sets the boolean operator of the QueryParser. In default mode (
238 * {@link Operator#OR}) terms without any modifiers are considered optional:
239 * for example <code>capital of Hungary</code> is equal to
240 * <code>capital OR of OR Hungary</code>.<br/>
241 * In {@link Operator#AND} mode terms are considered to be in conjunction: the
242 * above mentioned query is parsed as <code>capital AND of AND Hungary</code>
244 public void setDefaultOperator(
245 org.apache.lucene.queryParser.standard.config.StandardQueryConfigHandler.Operator operator) {
247 DefaultOperatorAttribute.Operator attrOperator;
249 if (operator == org.apache.lucene.queryParser.standard.config.StandardQueryConfigHandler.Operator.AND) {
250 attrOperator = DefaultOperatorAttribute.Operator.AND;
252 attrOperator = DefaultOperatorAttribute.Operator.OR;
255 setDefaultOperator(attrOperator);
257 // uncomment code below when deprecated query parser attributes are removed
258 // getQueryConfigHandler().set(ConfigurationKeys.DEFAULT_OPERATOR, operator);
262 * Set to <code>true</code> to allow leading wildcard characters.
264 * When set, <code>*</code> or <code>?</code> are allowed as the first
265 * character of a PrefixQuery and WildcardQuery. Note that this can produce
266 * very slow queries on big indexes.
270 public void setLowercaseExpandedTerms(boolean lowercaseExpandedTerms) {
271 LowercaseExpandedTermsAttribute attr = getQueryConfigHandler()
272 .getAttribute(LowercaseExpandedTermsAttribute.class);
273 attr.setLowercaseExpandedTerms(lowercaseExpandedTerms);
274 // uncomment code below when deprecated query parser attributes are removed
275 // getQueryConfigHandler().set(ConfigurationKeys.LOWERCASE_EXPANDED_TERMS,
276 // lowercaseExpandedTerms);
280 * @see #setLowercaseExpandedTerms(boolean)
282 public boolean getLowercaseExpandedTerms() {
283 Boolean lowercaseExpandedTerms = getQueryConfigHandler().get(
284 ConfigurationKeys.LOWERCASE_EXPANDED_TERMS);
286 if (lowercaseExpandedTerms == null) {
290 return lowercaseExpandedTerms;
296 * Set to <code>true</code> to allow leading wildcard characters.
298 * When set, <code>*</code> or <code>?</code> are allowed as the first
299 * character of a PrefixQuery and WildcardQuery. Note that this can produce
300 * very slow queries on big indexes.
304 public void setAllowLeadingWildcard(boolean allowLeadingWildcard) {
305 AllowLeadingWildcardAttribute attr = getQueryConfigHandler().getAttribute(
306 AllowLeadingWildcardAttribute.class);
307 attr.setAllowLeadingWildcard(allowLeadingWildcard);
308 // uncomment code below when deprecated query parser attributes are removed
309 // getQueryConfigHandler().set(ConfigurationKeys.ALLOW_LEADING_WILDCARD,
310 // allowLeadingWildcard);
314 * Set to <code>true</code> to enable position increments in result query.
316 * When set, result phrase and multi-phrase queries will be aware of position
317 * increments. Useful when e.g. a StopFilter increases the position increment
318 * of the token that follows an omitted token.
322 public void setEnablePositionIncrements(boolean enabled) {
323 PositionIncrementsAttribute attr = getQueryConfigHandler().getAttribute(
324 PositionIncrementsAttribute.class);
325 attr.setPositionIncrementsEnabled(enabled);
326 // uncomment code below when deprecated query parser attributes are removed
327 // getQueryConfigHandler().set(ConfigurationKeys.ENABLE_POSITION_INCREMENTS,
332 * @see #setEnablePositionIncrements(boolean)
334 public boolean getEnablePositionIncrements() {
335 Boolean enablePositionsIncrements = getQueryConfigHandler().get(
336 ConfigurationKeys.ENABLE_POSITION_INCREMENTS);
338 if (enablePositionsIncrements == null) {
342 return enablePositionsIncrements;
348 * By default, it uses
349 * {@link MultiTermQuery#CONSTANT_SCORE_AUTO_REWRITE_DEFAULT} when creating a
350 * prefix, wildcard and range queries. This implementation is generally
351 * preferable because it a) Runs faster b) Does not have the scarcity of terms
352 * unduly influence score c) avoids any {@link TooManyListenersException}
353 * exception. However, if your application really needs to use the
354 * old-fashioned boolean queries expansion rewriting and the above points are
355 * not relevant then use this change the rewrite method.
357 public void setMultiTermRewriteMethod(MultiTermQuery.RewriteMethod method) {
358 MultiTermRewriteMethodAttribute attr = getQueryConfigHandler()
359 .getAttribute(MultiTermRewriteMethodAttribute.class);
360 attr.setMultiTermRewriteMethod(method);
361 // uncomment code below when deprecated query parser attributes are removed
362 // getQueryConfigHandler().set(ConfigurationKeys.MULTI_TERM_REWRITE_METHOD,
367 * @see #setMultiTermRewriteMethod(org.apache.lucene.search.MultiTermQuery.RewriteMethod)
369 public MultiTermQuery.RewriteMethod getMultiTermRewriteMethod() {
370 return getQueryConfigHandler().get(
371 ConfigurationKeys.MULTI_TERM_REWRITE_METHOD);
375 * Set the fields a query should be expanded to when the field is
378 * @param fields the fields used to expand the query
380 public void setMultiFields(CharSequence[] fields) {
382 if (fields == null) {
383 fields = new CharSequence[0];
386 MultiFieldAttribute attr = getQueryConfigHandler().addAttribute(
387 MultiFieldAttribute.class);
388 attr.setFields(fields);
389 // uncomment code below when deprecated query parser attributes are removed
390 // getQueryConfigHandler().set(ConfigurationKeys.MULTI_FIELDS, fields);
395 * Returns the fields used to expand the query when the field for a certain
396 * query is <code>null</code>
398 * @param fields the fields used to expand the query
400 public void getMultiFields(CharSequence[] fields) {
401 getQueryConfigHandler().get(ConfigurationKeys.MULTI_FIELDS);
405 * Set the prefix length for fuzzy queries. Default is 0.
407 * @param fuzzyPrefixLength The fuzzyPrefixLength to set.
409 public void setFuzzyPrefixLength(int fuzzyPrefixLength) {
410 FuzzyAttribute attr = getQueryConfigHandler().addAttribute(
411 FuzzyAttribute.class);
412 attr.setPrefixLength(fuzzyPrefixLength);
414 // uncomment code below when deprecated query parser attributes are removed
416 * QueryConfigHandler config = getQueryConfigHandler(); FuzzyConfig
417 * fuzzyConfig = config.get(ConfigurationKeys.FUZZY_CONFIG);
419 * if (fuzzyConfig == null) { fuzzyConfig = new FuzzyConfig();
420 * config.set(ConfigurationKeys.FUZZY_CONFIG, fuzzyConfig); }
422 * fuzzyConfig.setPrefixLength(fuzzyPrefixLength);
426 public void setNumericConfigMap(Map<String, NumericConfig> numericConfigMap) {
427 getQueryConfigHandler().set(ConfigurationKeys.NUMERIC_CONFIG_MAP,
431 public Map<String, NumericConfig> getNumericConfigMap() {
432 return getQueryConfigHandler().get(ConfigurationKeys.NUMERIC_CONFIG_MAP);
436 * Set locale used by date range parsing.
438 public void setLocale(Locale locale) {
439 LocaleAttribute attr = getQueryConfigHandler().addAttribute(
440 LocaleAttribute.class);
441 attr.setLocale(locale);
442 // uncomment code below when deprecated query parser attributes are removed
443 // getQueryConfigHandler().set(ConfigurationKeys.LOCALE, locale);
447 * Returns current locale, allowing access by subclasses.
449 public Locale getLocale() {
450 return getQueryConfigHandler().get(ConfigurationKeys.LOCALE);
454 * Sets the default slop for phrases. If zero, then exact phrase matches are
455 * required. Default value is zero.
457 * @deprecated renamed to {@link #setPhraseSlop(int)}
460 public void setDefaultPhraseSlop(int defaultPhraseSlop) {
461 setPhraseSlop(defaultPhraseSlop);
465 * Sets the default slop for phrases. If zero, then exact phrase matches are
466 * required. Default value is zero.
468 public void setPhraseSlop(int defaultPhraseSlop) {
469 DefaultPhraseSlopAttribute attr = getQueryConfigHandler().addAttribute(
470 DefaultPhraseSlopAttribute.class);
471 attr.setDefaultPhraseSlop(defaultPhraseSlop);
472 // uncomment code below when deprecated query parser attributes are removed
473 // getQueryConfigHandler().set(ConfigurationKeys.PHRASE_SLOP,
474 // defaultPhraseSlop);
477 public void setAnalyzer(Analyzer analyzer) {
478 AnalyzerAttribute attr = getQueryConfigHandler().getAttribute(
479 AnalyzerAttribute.class);
480 attr.setAnalyzer(analyzer);
481 // uncomment code below when deprecated query parser attributes are removed
482 // getQueryConfigHandler().set(ConfigurationKeys.ANALYZER, analyzer);
485 public Analyzer getAnalyzer() {
486 return getQueryConfigHandler().get(ConfigurationKeys.ANALYZER);
490 * @see #setAllowLeadingWildcard(boolean)
492 public boolean getAllowLeadingWildcard() {
493 Boolean allowLeadingWildcard = getQueryConfigHandler().get(
494 ConfigurationKeys.ALLOW_LEADING_WILDCARD);
496 if (allowLeadingWildcard == null) {
500 return allowLeadingWildcard;
505 * Get the minimal similarity for fuzzy queries.
507 public float getFuzzyMinSim() {
508 FuzzyConfig fuzzyConfig = getQueryConfigHandler().get(
509 ConfigurationKeys.FUZZY_CONFIG);
511 if (fuzzyConfig == null) {
512 return FuzzyQuery.defaultMinSimilarity;
514 return fuzzyConfig.getMinSimilarity();
519 * Get the prefix length for fuzzy queries.
521 * @return Returns the fuzzyPrefixLength.
523 public int getFuzzyPrefixLength() {
524 FuzzyConfig fuzzyConfig = getQueryConfigHandler().get(
525 ConfigurationKeys.FUZZY_CONFIG);
527 if (fuzzyConfig == null) {
528 return FuzzyQuery.defaultPrefixLength;
530 return fuzzyConfig.getPrefixLength();
535 * Gets the default slop for phrases.
537 public int getPhraseSlop() {
538 Integer phraseSlop = getQueryConfigHandler().get(
539 ConfigurationKeys.PHRASE_SLOP);
541 if (phraseSlop == null) {
550 * Set the minimum similarity for fuzzy queries. Default is defined on
551 * {@link FuzzyQuery#defaultMinSimilarity}.
553 public void setFuzzyMinSim(float fuzzyMinSim) {
554 FuzzyAttribute attr = getQueryConfigHandler().addAttribute(
555 FuzzyAttribute.class);
556 attr.setFuzzyMinSimilarity(fuzzyMinSim);
557 // uncomment code below when deprecated query parser attributes are removed
559 * QueryConfigHandler config = getQueryConfigHandler(); FuzzyConfig
560 * fuzzyConfig = config.get(ConfigurationKeys.FUZZY_CONFIG);
562 * if (fuzzyConfig == null) { fuzzyConfig = new FuzzyConfig();
563 * config.set(ConfigurationKeys.FUZZY_CONFIG, fuzzyConfig); }
565 * fuzzyConfig.setMinSimilarity(fuzzyMinSim);
570 * Sets the boost used for each field.
572 * @param boosts a collection that maps a field to its boost
574 public void setFieldsBoost(Map<String, Float> boosts) {
575 FieldBoostMapAttribute attr = getQueryConfigHandler().addAttribute(
576 FieldBoostMapAttribute.class);
577 attr.setFieldBoostMap(boosts);
578 // uncomment code below when deprecated query parser attributes are removed
579 // getQueryConfigHandler().set(ConfigurationKeys.FIELD_BOOST_MAP, boosts);
583 * Returns the field to boost map used to set boost for each field.
585 * @return the field to boost map
587 public Map<String, Float> getFieldsBoost() {
588 return getQueryConfigHandler().get(ConfigurationKeys.FIELD_BOOST_MAP);
592 * Sets the default {@link Resolution} used for certain field when no
593 * {@link Resolution} is defined for this field.
595 * @param dateResolution the default {@link Resolution}
597 public void setDateResolution(DateTools.Resolution dateResolution) {
598 DateResolutionAttribute attr = getQueryConfigHandler().addAttribute(
599 DateResolutionAttribute.class);
600 attr.setDateResolution(dateResolution);
601 // uncomment code below when deprecated query parser attributes are removed
602 // getQueryConfigHandler().set(ConfigurationKeys.DATE_RESOLUTION,
607 * Returns the default {@link Resolution} used for certain field when no
608 * {@link Resolution} is defined for this field.
610 * @return the default {@link Resolution}
612 public DateTools.Resolution getDateResolution() {
613 return getQueryConfigHandler().get(ConfigurationKeys.DATE_RESOLUTION);
617 * Sets the {@link Resolution} used for each field
619 * @param dateRes a collection that maps a field to its {@link Resolution}
621 * @deprecated this method was renamed to {@link #setDateResolutionMap(Map)}
624 public void setDateResolution(Map<CharSequence, DateTools.Resolution> dateRes) {
625 setDateResolutionMap(dateRes);
629 * Returns the field to {@link Resolution} map used to normalize each date
632 * @return the field to {@link Resolution} map
634 public Map<CharSequence, DateTools.Resolution> getDateResolutionMap() {
635 return getQueryConfigHandler().get(
636 ConfigurationKeys.FIELD_DATE_RESOLUTION_MAP);
640 * Sets the {@link Resolution} used for each field
642 * @param dateRes a collection that maps a field to its {@link Resolution}
644 public void setDateResolutionMap(
645 Map<CharSequence, DateTools.Resolution> dateRes) {
646 FieldDateResolutionMapAttribute attr = getQueryConfigHandler()
647 .addAttribute(FieldDateResolutionMapAttribute.class);
648 attr.setFieldDateResolutionMap(dateRes);
649 // uncomment code below when deprecated query parser attributes are removed
650 // getQueryConfigHandler().set(ConfigurationKeys.FIELD_DATE_RESOLUTION_MAP,