001: package org.apache.lucene.search;
002:
003: /**
004: * Licensed to the Apache Software Foundation (ASF) under one or more
005: * contributor license agreements. See the NOTICE file distributed with
006: * this work for additional information regarding copyright ownership.
007: * The ASF licenses this file to You under the Apache License, Version 2.0
008: * (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: */
019:
020: import java.io.IOException;
021:
022: import java.util.HashSet;
023: import java.util.Iterator;
024: import java.util.Set;
025:
026: import org.apache.lucene.index.IndexReader;
027:
028: /** The abstract base class for queries.
029: <p>Instantiable subclasses are:
030: <ul>
031: <li> {@link TermQuery}
032: <li> {@link MultiTermQuery}
033: <li> {@link BooleanQuery}
034: <li> {@link WildcardQuery}
035: <li> {@link PhraseQuery}
036: <li> {@link PrefixQuery}
037: <li> {@link MultiPhraseQuery}
038: <li> {@link FuzzyQuery}
039: <li> {@link RangeQuery}
040: <li> {@link org.apache.lucene.search.spans.SpanQuery}
041: </ul>
042: <p>A parser for queries is contained in:
043: <ul>
044: <li>{@link org.apache.lucene.queryParser.QueryParser QueryParser}
045: </ul>
046: */
047: public abstract class Query implements java.io.Serializable, Cloneable {
048: private float boost = 1.0f; // query boost factor
049:
050: /** Sets the boost for this query clause to <code>b</code>. Documents
051: * matching this clause will (in addition to the normal weightings) have
052: * their score multiplied by <code>b</code>.
053: */
054: public void setBoost(float b) {
055: boost = b;
056: }
057:
058: /** Gets the boost for this clause. Documents matching
059: * this clause will (in addition to the normal weightings) have their score
060: * multiplied by <code>b</code>. The boost is 1.0 by default.
061: */
062: public float getBoost() {
063: return boost;
064: }
065:
066: /** Prints a query to a string, with <code>field</code> assumed to be the
067: * default field and omitted.
068: * <p>The representation used is one that is supposed to be readable
069: * by {@link org.apache.lucene.queryParser.QueryParser QueryParser}. However,
070: * there are the following limitations:
071: * <ul>
072: * <li>If the query was created by the parser, the printed
073: * representation may not be exactly what was parsed. For example,
074: * characters that need to be escaped will be represented without
075: * the required backslash.</li>
076: * <li>Some of the more complicated queries (e.g. span queries)
077: * don't have a representation that can be parsed by QueryParser.</li>
078: * </ul>
079: */
080: public abstract String toString(String field);
081:
082: /** Prints a query to a string. */
083: public String toString() {
084: return toString("");
085: }
086:
087: /** Expert: Constructs an appropriate Weight implementation for this query.
088: *
089: * <p>Only implemented by primitive queries, which re-write to themselves.
090: */
091: protected Weight createWeight(Searcher searcher) throws IOException {
092: throw new UnsupportedOperationException();
093: }
094:
095: /** Expert: Constructs and initializes a Weight for a top-level query. */
096: public Weight weight(Searcher searcher) throws IOException {
097: Query query = searcher.rewrite(this );
098: Weight weight = query.createWeight(searcher);
099: float sum = weight.sumOfSquaredWeights();
100: float norm = getSimilarity(searcher).queryNorm(sum);
101: weight.normalize(norm);
102: return weight;
103: }
104:
105: /** Expert: called to re-write queries into primitive queries. For example,
106: * a PrefixQuery will be rewritten into a BooleanQuery that consists
107: * of TermQuerys.
108: */
109: public Query rewrite(IndexReader reader) throws IOException {
110: return this ;
111: }
112:
113: /** Expert: called when re-writing queries under MultiSearcher.
114: *
115: * Create a single query suitable for use by all subsearchers (in 1-1
116: * correspondence with queries). This is an optimization of the OR of
117: * all queries. We handle the common optimization cases of equal
118: * queries and overlapping clauses of boolean OR queries (as generated
119: * by MultiTermQuery.rewrite() and RangeQuery.rewrite()).
120: * Be careful overriding this method as queries[0] determines which
121: * method will be called and is not necessarily of the same type as
122: * the other queries.
123: */
124: public Query combine(Query[] queries) {
125: HashSet uniques = new HashSet();
126: for (int i = 0; i < queries.length; i++) {
127: Query query = queries[i];
128: BooleanClause[] clauses = null;
129: // check if we can split the query into clauses
130: boolean splittable = (query instanceof BooleanQuery);
131: if (splittable) {
132: BooleanQuery bq = (BooleanQuery) query;
133: splittable = bq.isCoordDisabled();
134: clauses = bq.getClauses();
135: for (int j = 0; splittable && j < clauses.length; j++) {
136: splittable = (clauses[j].getOccur() == BooleanClause.Occur.SHOULD);
137: }
138: }
139: if (splittable) {
140: for (int j = 0; j < clauses.length; j++) {
141: uniques.add(clauses[j].getQuery());
142: }
143: } else {
144: uniques.add(query);
145: }
146: }
147: // optimization: if we have just one query, just return it
148: if (uniques.size() == 1) {
149: return (Query) uniques.iterator().next();
150: }
151: Iterator it = uniques.iterator();
152: BooleanQuery result = new BooleanQuery(true);
153: while (it.hasNext())
154: result.add((Query) it.next(), BooleanClause.Occur.SHOULD);
155: return result;
156: }
157:
158: /**
159: * Expert: adds all terms occuring in this query to the terms set. Only
160: * works if this query is in its {@link #rewrite rewritten} form.
161: *
162: * @throws UnsupportedOperationException if this query is not yet rewritten
163: */
164: public void extractTerms(Set terms) {
165: // needs to be implemented by query subclasses
166: throw new UnsupportedOperationException();
167: }
168:
169: /** Expert: merges the clauses of a set of BooleanQuery's into a single
170: * BooleanQuery.
171: *
172: *<p>A utility for use by {@link #combine(Query[])} implementations.
173: */
174: public static Query mergeBooleanQueries(Query[] queries) {
175: HashSet allClauses = new HashSet();
176: for (int i = 0; i < queries.length; i++) {
177: BooleanClause[] clauses = ((BooleanQuery) queries[i])
178: .getClauses();
179: for (int j = 0; j < clauses.length; j++) {
180: allClauses.add(clauses[j]);
181: }
182: }
183:
184: boolean coordDisabled = queries.length == 0 ? false
185: : ((BooleanQuery) queries[0]).isCoordDisabled();
186: BooleanQuery result = new BooleanQuery(coordDisabled);
187: Iterator i = allClauses.iterator();
188: while (i.hasNext()) {
189: result.add((BooleanClause) i.next());
190: }
191: return result;
192: }
193:
194: /** Expert: Returns the Similarity implementation to be used for this query.
195: * Subclasses may override this method to specify their own Similarity
196: * implementation, perhaps one that delegates through that of the Searcher.
197: * By default the Searcher's Similarity implementation is returned.*/
198: public Similarity getSimilarity(Searcher searcher) {
199: return searcher.getSimilarity();
200: }
201:
202: /** Returns a clone of this query. */
203: public Object clone() {
204: try {
205: return (Query) super .clone();
206: } catch (CloneNotSupportedException e) {
207: throw new RuntimeException("Clone not supported: "
208: + e.getMessage());
209: }
210: }
211: }
|