1 package org.apache.lucene.search; 2 3 18 19 import java.io.IOException ; 20 import java.util.Iterator ; 21 import java.util.Set ; 22 import java.util.Vector ; 23 24 import org.apache.lucene.index.IndexReader; 25 import org.apache.lucene.util.ToStringUtils; 26 27 31 public class BooleanQuery extends Query { 32 33 36 public static int maxClauseCount = 1024; 37 38 43 public static class TooManyClauses extends RuntimeException {} 44 45 50 public static int getMaxClauseCount() { return maxClauseCount; } 51 52 65 public static void setMaxClauseCount(int maxClauseCount) { 66 if (maxClauseCount < 1) 67 throw new IllegalArgumentException ("maxClauseCount must be >= 1"); 68 BooleanQuery.maxClauseCount = maxClauseCount; 69 } 70 71 private Vector clauses = new Vector (); 72 private boolean disableCoord; 73 74 75 public BooleanQuery() {} 76 77 86 public BooleanQuery(boolean disableCoord) { 87 this.disableCoord = disableCoord; 88 } 89 90 94 public boolean isCoordDisabled() { return disableCoord; } 95 96 public Similarity getSimilarity(Searcher searcher) { 99 Similarity result = super.getSimilarity(searcher); 100 if (disableCoord) { result = new SimilarityDelegator(result) { 102 public float coord(int overlap, int maxOverlap) { 103 return 1.0f; 104 } 105 }; 106 } 107 return result; 108 } 109 110 132 public void setMinimumNumberShouldMatch(int min) { 133 this.minNrShouldMatch = min; 134 } 135 protected int minNrShouldMatch = 0; 136 137 141 public int getMinimumNumberShouldMatch() { 142 return minNrShouldMatch; 143 } 144 145 165 public void add(Query query, boolean required, boolean prohibited) { 166 add(new BooleanClause(query, required, prohibited)); 167 } 168 169 174 public void add(Query query, BooleanClause.Occur occur) { 175 add(new BooleanClause(query, occur)); 176 } 177 178 182 public void add(BooleanClause clause) { 183 if (clauses.size() >= maxClauseCount) 184 throw new TooManyClauses(); 185 186 clauses.addElement(clause); 187 } 188 189 190 public BooleanClause[] getClauses() { 191 return (BooleanClause[])clauses.toArray(new BooleanClause[0]); 192 } 193 194 private class BooleanWeight implements Weight { 195 protected Similarity similarity; 196 protected Vector weights = new Vector (); 197 198 public BooleanWeight(Searcher searcher) 199 throws IOException { 200 this.similarity = getSimilarity(searcher); 201 for (int i = 0 ; i < clauses.size(); i++) { 202 BooleanClause c = (BooleanClause)clauses.elementAt(i); 203 weights.add(c.getQuery().createWeight(searcher)); 204 } 205 } 206 207 public Query getQuery() { return BooleanQuery.this; } 208 public float getValue() { return getBoost(); } 209 210 public float sumOfSquaredWeights() throws IOException { 211 float sum = 0.0f; 212 for (int i = 0 ; i < weights.size(); i++) { 213 BooleanClause c = (BooleanClause)clauses.elementAt(i); 214 Weight w = (Weight)weights.elementAt(i); 215 if (!c.isProhibited()) 216 sum += w.sumOfSquaredWeights(); } 218 219 sum *= getBoost() * getBoost(); 221 return sum ; 222 } 223 224 225 public void normalize(float norm) { 226 norm *= getBoost(); for (int i = 0 ; i < weights.size(); i++) { 228 BooleanClause c = (BooleanClause)clauses.elementAt(i); 229 Weight w = (Weight)weights.elementAt(i); 230 if (!c.isProhibited()) 231 w.normalize(norm); 232 } 233 } 234 235 236 public Scorer scorer(IndexReader reader) throws IOException { 237 boolean allRequired = true; 244 boolean noneBoolean = true; 245 for (int i = 0 ; i < weights.size(); i++) { 246 BooleanClause c = (BooleanClause)clauses.elementAt(i); 247 if (!c.isRequired()) 248 allRequired = false; 249 if (c.getQuery() instanceof BooleanQuery) 250 noneBoolean = false; 251 } 252 253 if (allRequired && noneBoolean) { ConjunctionScorer result = 255 new ConjunctionScorer(similarity); 256 for (int i = 0 ; i < weights.size(); i++) { 257 Weight w = (Weight)weights.elementAt(i); 258 Scorer subScorer = w.scorer(reader); 259 if (subScorer == null) 260 return null; 261 result.add(subScorer); 262 } 263 return result; 264 } 265 266 BooleanScorer result = new BooleanScorer(similarity); 268 269 for (int i = 0 ; i < weights.size(); i++) { 270 BooleanClause c = (BooleanClause)clauses.elementAt(i); 271 Weight w = (Weight)weights.elementAt(i); 272 Scorer subScorer = w.scorer(reader); 273 if (subScorer != null) 274 result.add(subScorer, c.isRequired(), c.isProhibited()); 275 else if (c.isRequired()) 276 return null; 277 } 278 279 return result; 280 } 281 282 public Explanation explain(IndexReader reader, int doc) 283 throws IOException { 284 Explanation sumExpl = new Explanation(); 285 sumExpl.setDescription("sum of:"); 286 int coord = 0; 287 int maxCoord = 0; 288 float sum = 0.0f; 289 for (int i = 0 ; i < weights.size(); i++) { 290 BooleanClause c = (BooleanClause)clauses.elementAt(i); 291 Weight w = (Weight)weights.elementAt(i); 292 Explanation e = w.explain(reader, doc); 293 if (!c.isProhibited()) maxCoord++; 294 if (e.getValue() > 0) { 295 if (!c.isProhibited()) { 296 sumExpl.addDetail(e); 297 sum += e.getValue(); 298 coord++; 299 } else { 300 return new Explanation(0.0f, "match prohibited"); 301 } 302 } else if (c.isRequired()) { 303 return new Explanation(0.0f, "match required"); 304 } 305 } 306 sumExpl.setValue(sum); 307 308 if (coord == 1) sumExpl = sumExpl.getDetails()[0]; 311 float coordFactor = similarity.coord(coord, maxCoord); 312 if (coordFactor == 1.0f) return sumExpl; else { 315 Explanation result = new Explanation(); 316 result.setDescription("product of:"); 317 result.addDetail(sumExpl); 318 result.addDetail(new Explanation(coordFactor, 319 "coord("+coord+"/"+maxCoord+")")); 320 result.setValue(sum*coordFactor); 321 return result; 322 } 323 } 324 } 325 326 private class BooleanWeight2 extends BooleanWeight { 327 328 public BooleanWeight2(Searcher searcher) 329 throws IOException { 330 super(searcher); 331 } 332 333 336 public Scorer scorer(IndexReader reader) throws IOException { 337 BooleanScorer2 result = new BooleanScorer2(similarity, 338 minNrShouldMatch); 339 340 for (int i = 0 ; i < weights.size(); i++) { 341 BooleanClause c = (BooleanClause)clauses.elementAt(i); 342 Weight w = (Weight)weights.elementAt(i); 343 Scorer subScorer = w.scorer(reader); 344 if (subScorer != null) 345 result.add(subScorer, c.isRequired(), c.isProhibited()); 346 else if (c.isRequired()) 347 return null; 348 } 349 350 return result; 351 } 352 } 353 354 355 private static boolean useScorer14 = false; 356 357 public static void setUseScorer14(boolean use14) { 358 useScorer14 = use14; 359 } 360 361 public static boolean getUseScorer14() { 362 return useScorer14; 363 } 364 365 protected Weight createWeight(Searcher searcher) throws IOException { 366 367 if (0 < minNrShouldMatch) { 368 return new BooleanWeight2(searcher); 370 } 371 372 return getUseScorer14() ? (Weight) new BooleanWeight(searcher) 373 : (Weight) new BooleanWeight2(searcher); 374 } 375 376 public Query rewrite(IndexReader reader) throws IOException { 377 if (clauses.size() == 1) { BooleanClause c = (BooleanClause)clauses.elementAt(0); 379 if (!c.isProhibited()) { 381 Query query = c.getQuery().rewrite(reader); 383 if (getBoost() != 1.0f) { if (query == c.getQuery()) query = (Query)query.clone(); query.setBoost(getBoost() * query.getBoost()); 387 } 388 389 return query; 390 } 391 } 392 393 BooleanQuery clone = null; for (int i = 0 ; i < clauses.size(); i++) { 395 BooleanClause c = (BooleanClause)clauses.elementAt(i); 396 Query query = c.getQuery().rewrite(reader); 397 if (query != c.getQuery()) { if (clone == null) 399 clone = (BooleanQuery)this.clone(); 400 clone.clauses.setElementAt 401 (new BooleanClause(query, c.getOccur()), i); 402 } 403 } 404 if (clone != null) { 405 return clone; } else 407 return this; } 409 410 public void extractTerms(Set terms) { 412 for (Iterator i = clauses.iterator(); i.hasNext();) { 413 BooleanClause clause = (BooleanClause) i.next(); 414 clause.getQuery().extractTerms(terms); 415 } 416 } 417 418 public Object clone() { 419 BooleanQuery clone = (BooleanQuery)super.clone(); 420 clone.clauses = (Vector )this.clauses.clone(); 421 return clone; 422 } 423 424 425 public String toString(String field) { 426 StringBuffer buffer = new StringBuffer (); 427 boolean needParens=(getBoost() != 1.0) || (getMinimumNumberShouldMatch()>0) ; 428 if (needParens) { 429 buffer.append("("); 430 } 431 432 for (int i = 0 ; i < clauses.size(); i++) { 433 BooleanClause c = (BooleanClause)clauses.elementAt(i); 434 if (c.isProhibited()) 435 buffer.append("-"); 436 else if (c.isRequired()) 437 buffer.append("+"); 438 439 Query subQuery = c.getQuery(); 440 if (subQuery instanceof BooleanQuery) { buffer.append("("); 442 buffer.append(c.getQuery().toString(field)); 443 buffer.append(")"); 444 } else 445 buffer.append(c.getQuery().toString(field)); 446 447 if (i != clauses.size()-1) 448 buffer.append(" "); 449 } 450 451 if (needParens) { 452 buffer.append(")"); 453 } 454 455 if (getMinimumNumberShouldMatch()>0) { 456 buffer.append('~'); 457 buffer.append(getMinimumNumberShouldMatch()); 458 } 459 460 if (getBoost() != 1.0f) 461 { 462 buffer.append(ToStringUtils.boost(getBoost())); 463 } 464 465 return buffer.toString(); 466 } 467 468 469 public boolean equals(Object o) { 470 if (!(o instanceof BooleanQuery)) 471 return false; 472 BooleanQuery other = (BooleanQuery)o; 473 return (this.getBoost() == other.getBoost()) 474 && this.clauses.equals(other.clauses) 475 && this.getMinimumNumberShouldMatch() == other.getMinimumNumberShouldMatch(); 476 } 477 478 479 public int hashCode() { 480 return Float.floatToIntBits(getBoost()) ^ clauses.hashCode() 481 + getMinimumNumberShouldMatch(); 482 } 483 484 } 485 | Popular Tags |