001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.solr.search;
017:
018: import org.apache.lucene.search.Query;
019: import org.apache.lucene.search.BooleanQuery;
020: import org.apache.lucene.search.BooleanClause;
021: import org.apache.lucene.search.MatchAllDocsQuery;
022:
023: import java.util.List;
024: import java.util.Arrays;
025:
026: /**
027: * @author yonik
028: * @version $Id: QueryUtils.java 542653 2007-05-29 21:11:35Z yonik $
029: */
030: public class QueryUtils {
031:
032: /** return true if this query has no positive components */
033: static boolean isNegative(Query q) {
034: if (!(q instanceof BooleanQuery))
035: return false;
036: BooleanQuery bq = (BooleanQuery) q;
037: List<BooleanClause> clauses = bq.clauses();
038: if (clauses.size() == 0)
039: return false;
040: for (BooleanClause clause : clauses) {
041: if (!clause.isProhibited())
042: return false;
043: }
044: return true;
045: }
046:
047: /** Returns the original query if it was already a positive query, otherwise
048: * return the negative of the query (i.e., a positive query).
049: * <p>
050: * Example: both id:10 and id:-10 will return id:10
051: * <p>
052: * The caller can tell the sign of the original by a reference comparison between
053: * the original and returned query.
054: * @param q
055: * @return
056: */
057: static Query getAbs(Query q) {
058: if (!(q instanceof BooleanQuery))
059: return q;
060: BooleanQuery bq = (BooleanQuery) q;
061:
062: List<BooleanClause> clauses = bq.clauses();
063: if (clauses.size() == 0)
064: return q;
065:
066: for (BooleanClause clause : clauses) {
067: if (!clause.isProhibited())
068: return q;
069: }
070:
071: if (clauses.size() == 1) {
072: // if only one clause, dispense with the wrapping BooleanQuery
073: Query negClause = clauses.get(0).getQuery();
074: // we shouldn't need to worry about adjusting the boosts since the negative
075: // clause would have never been selected in a positive query, and hence would
076: // not contribute to a score.
077: return negClause;
078: } else {
079: BooleanQuery newBq = new BooleanQuery(bq.isCoordDisabled());
080: newBq.setBoost(bq.getBoost());
081: // ignore minNrShouldMatch... it doesn't make sense for a negative query
082:
083: // the inverse of -a -b is a OR b
084: for (BooleanClause clause : clauses) {
085: newBq
086: .add(clause.getQuery(),
087: BooleanClause.Occur.SHOULD);
088: }
089: return newBq;
090: }
091: }
092:
093: /** Makes negative queries suitable for querying by
094: * lucene.
095: */
096: static Query makeQueryable(Query q) {
097: return isNegative(q) ? fixNegativeQuery(q) : q;
098: }
099:
100: /** Fixes a negative query by adding a MatchAllDocs query clause.
101: * The query passed in *must* be a negative query.
102: */
103: static Query fixNegativeQuery(Query q) {
104: BooleanQuery newBq = (BooleanQuery) q.clone();
105: newBq.add(new MatchAllDocsQuery(), BooleanClause.Occur.MUST);
106: return newBq;
107: }
108:
109: }
|