1 package org.apache.lucene.search; 2 3 /** 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 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 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. 18 */ 19 20 import java.io.IOException; 21 22 import java.util.HashSet; 23 24 import java.util.Set; 25 26 import org.apache.lucene.index.IndexReader; 27 import org.apache.lucene.index.Term; 28 29 /** The abstract base class for queries. 30 <p>Instantiable subclasses are: 31 <ul> 32 <li> {@link TermQuery} 33 <li> {@link MultiTermQuery} 34 <li> {@link BooleanQuery} 35 <li> {@link WildcardQuery} 36 <li> {@link PhraseQuery} 37 <li> {@link PrefixQuery} 38 <li> {@link MultiPhraseQuery} 39 <li> {@link FuzzyQuery} 40 <li> {@link TermRangeQuery} 41 <li> {@link NumericRangeQuery} 42 <li> {@link org.apache.lucene.search.spans.SpanQuery} 43 </ul> 44 <p>A parser for queries is contained in: 45 <ul> 46 <li>{@link org.apache.lucene.queryParser.QueryParser QueryParser} 47 </ul> 48 */ 49 public abstract class Query implements java.io.Serializable, Cloneable { 50 private float boost = 1.0f; // query boost factor 51 52 /** Sets the boost for this query clause to <code>b</code>. Documents 53 * matching this clause will (in addition to the normal weightings) have 54 * their score multiplied by <code>b</code>. 55 */ 56 public void setBoost(float b) { boost = b; } 57 58 /** Gets the boost for this clause. Documents matching 59 * this clause will (in addition to the normal weightings) have their score 60 * multiplied by <code>b</code>. The boost is 1.0 by default. 61 */ 62 public float getBoost() { return boost; } 63 64 /** Prints a query to a string, with <code>field</code> assumed to be the 65 * default field and omitted. 66 * <p>The representation used is one that is supposed to be readable 67 * by {@link org.apache.lucene.queryParser.QueryParser QueryParser}. However, 68 * there are the following limitations: 69 * <ul> 70 * <li>If the query was created by the parser, the printed 71 * representation may not be exactly what was parsed. For example, 72 * characters that need to be escaped will be represented without 73 * the required backslash.</li> 74 * <li>Some of the more complicated queries (e.g. span queries) 75 * don't have a representation that can be parsed by QueryParser.</li> 76 * </ul> 77 */ 78 public abstract String toString(String field); 79 80 /** Prints a query to a string. */ 81 @Override 82 public String toString() { 83 return toString(""); 84 } 85 86 /** 87 * Expert: Constructs an appropriate Weight implementation for this query. 88 * 89 * <p> 90 * Only implemented by primitive queries, which re-write to themselves. 91 */ 92 public Weight createWeight(Searcher searcher) throws IOException { 93 throw new UnsupportedOperationException(); 94 } 95 96 /** 97 * Expert: Constructs and initializes a Weight for a top-level query. 98 */ 99 public Weight weight(Searcher searcher) throws IOException { 100 Query query = searcher.rewrite(this); 101 Weight weight = query.createWeight(searcher); 102 float sum = weight.sumOfSquaredWeights(); 103 float norm = getSimilarity(searcher).queryNorm(sum); 104 if (Float.isInfinite(norm) || Float.isNaN(norm)) 105 norm = 1.0f; 106 weight.normalize(norm); 107 return weight; 108 } 109 110 111 /** Expert: called to re-write queries into primitive queries. For example, 112 * a PrefixQuery will be rewritten into a BooleanQuery that consists 113 * of TermQuerys. 114 */ 115 public Query rewrite(IndexReader reader) throws IOException { 116 return this; 117 } 118 119 120 /** Expert: called when re-writing queries under MultiSearcher. 121 * 122 * Create a single query suitable for use by all subsearchers (in 1-1 123 * correspondence with queries). This is an optimization of the OR of 124 * all queries. We handle the common optimization cases of equal 125 * queries and overlapping clauses of boolean OR queries (as generated 126 * by MultiTermQuery.rewrite()). 127 * Be careful overriding this method as queries[0] determines which 128 * method will be called and is not necessarily of the same type as 129 * the other queries. 130 */ 131 public Query combine(Query[] queries) { 132 HashSet<Query> uniques = new HashSet<Query>(); 133 for (int i = 0; i < queries.length; i++) { 134 Query query = queries[i]; 135 BooleanClause[] clauses = null; 136 // check if we can split the query into clauses 137 boolean splittable = (query instanceof BooleanQuery); 138 if(splittable){ 139 BooleanQuery bq = (BooleanQuery) query; 140 splittable = bq.isCoordDisabled(); 141 clauses = bq.getClauses(); 142 for (int j = 0; splittable && j < clauses.length; j++) { 143 splittable = (clauses[j].getOccur() == BooleanClause.Occur.SHOULD); 144 } 145 } 146 if(splittable){ 147 for (int j = 0; j < clauses.length; j++) { 148 uniques.add(clauses[j].getQuery()); 149 } 150 } else { 151 uniques.add(query); 152 } 153 } 154 // optimization: if we have just one query, just return it 155 if(uniques.size() == 1){ 156 return uniques.iterator().next(); 157 } 158 BooleanQuery result = new BooleanQuery(true); 159 for (final Query query : uniques) 160 result.add(query, BooleanClause.Occur.SHOULD); 161 return result; 162 } 163 164 165 /** 166 * Expert: adds all terms occurring in this query to the terms set. Only 167 * works if this query is in its {@link #rewrite rewritten} form. 168 * 169 * @throws UnsupportedOperationException if this query is not yet rewritten 170 */ 171 public void extractTerms(Set<Term> terms) { 172 // needs to be implemented by query subclasses 173 throw new UnsupportedOperationException(); 174 } 175 176 177 178 /** Expert: merges the clauses of a set of BooleanQuery's into a single 179 * BooleanQuery. 180 * 181 *<p>A utility for use by {@link #combine(Query[])} implementations. 182 */ 183 public static Query mergeBooleanQueries(BooleanQuery... queries) { 184 HashSet<BooleanClause> allClauses = new HashSet<BooleanClause>(); 185 for (BooleanQuery booleanQuery : queries) { 186 for (BooleanClause clause : booleanQuery) { 187 allClauses.add(clause); 188 } 189 } 190 191 boolean coordDisabled = 192 queries.length==0? false : queries[0].isCoordDisabled(); 193 BooleanQuery result = new BooleanQuery(coordDisabled); 194 for(BooleanClause clause2 : allClauses) { 195 result.add(clause2); 196 } 197 return result; 198 } 199 200 201 /** Expert: Returns the Similarity implementation to be used for this query. 202 * Subclasses may override this method to specify their own Similarity 203 * implementation, perhaps one that delegates through that of the Searcher. 204 * By default the Searcher's Similarity implementation is returned.*/ 205 public Similarity getSimilarity(Searcher searcher) { 206 return searcher.getSimilarity(); 207 } 208 209 /** Returns a clone of this query. */ 210 @Override 211 public Object clone() { 212 try { 213 return super.clone(); 214 } catch (CloneNotSupportedException e) { 215 throw new RuntimeException("Clone not supported: " + e.getMessage()); 216 } 217 } 218 219 @Override 220 public int hashCode() { 221 final int prime = 31; 222 int result = 1; 223 result = prime * result + Float.floatToIntBits(boost); 224 return result; 225 } 226 227 @Override 228 public boolean equals(Object obj) { 229 if (this == obj) 230 return true; 231 if (obj == null) 232 return false; 233 if (getClass() != obj.getClass()) 234 return false; 235 Query other = (Query) obj; 236 if (Float.floatToIntBits(boost) != Float.floatToIntBits(other.boost)) 237 return false; 238 return true; 239 } 240 }