001: package org.apache.lucene.search.spans;
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.Collection;
023: import java.util.List;
024: import java.util.ArrayList;
025: import java.util.Iterator;
026: import java.util.Set;
027:
028: import org.apache.lucene.index.IndexReader;
029: import org.apache.lucene.search.Query;
030: import org.apache.lucene.util.ToStringUtils;
031:
032: /** Matches spans which are near one another. One can specify <i>slop</i>, the
033: * maximum number of intervening unmatched positions, as well as whether
034: * matches are required to be in-order. */
035: public class SpanNearQuery extends SpanQuery {
036: private List clauses;
037: private int slop;
038: private boolean inOrder;
039:
040: private String field;
041:
042: /** Construct a SpanNearQuery. Matches spans matching a span from each
043: * clause, with up to <code>slop</code> total unmatched positions between
044: * them. * When <code>inOrder</code> is true, the spans from each clause
045: * must be * ordered as in <code>clauses</code>. */
046: public SpanNearQuery(SpanQuery[] clauses, int slop, boolean inOrder) {
047:
048: // copy clauses array into an ArrayList
049: this .clauses = new ArrayList(clauses.length);
050: for (int i = 0; i < clauses.length; i++) {
051: SpanQuery clause = clauses[i];
052: if (i == 0) { // check field
053: field = clause.getField();
054: } else if (!clause.getField().equals(field)) {
055: throw new IllegalArgumentException(
056: "Clauses must have same field.");
057: }
058: this .clauses.add(clause);
059: }
060:
061: this .slop = slop;
062: this .inOrder = inOrder;
063: }
064:
065: /** Return the clauses whose spans are matched. */
066: public SpanQuery[] getClauses() {
067: return (SpanQuery[]) clauses.toArray(new SpanQuery[clauses
068: .size()]);
069: }
070:
071: /** Return the maximum number of intervening unmatched positions permitted.*/
072: public int getSlop() {
073: return slop;
074: }
075:
076: /** Return true if matches are required to be in-order.*/
077: public boolean isInOrder() {
078: return inOrder;
079: }
080:
081: public String getField() {
082: return field;
083: }
084:
085: /** Returns a collection of all terms matched by this query.
086: * @deprecated use extractTerms instead
087: * @see #extractTerms(Set)
088: */
089: public Collection getTerms() {
090: Collection terms = new ArrayList();
091: Iterator i = clauses.iterator();
092: while (i.hasNext()) {
093: SpanQuery clause = (SpanQuery) i.next();
094: terms.addAll(clause.getTerms());
095: }
096: return terms;
097: }
098:
099: public void extractTerms(Set terms) {
100: Iterator i = clauses.iterator();
101: while (i.hasNext()) {
102: SpanQuery clause = (SpanQuery) i.next();
103: clause.extractTerms(terms);
104: }
105: }
106:
107: public String toString(String field) {
108: StringBuffer buffer = new StringBuffer();
109: buffer.append("spanNear([");
110: Iterator i = clauses.iterator();
111: while (i.hasNext()) {
112: SpanQuery clause = (SpanQuery) i.next();
113: buffer.append(clause.toString(field));
114: if (i.hasNext()) {
115: buffer.append(", ");
116: }
117: }
118: buffer.append("], ");
119: buffer.append(slop);
120: buffer.append(", ");
121: buffer.append(inOrder);
122: buffer.append(")");
123: buffer.append(ToStringUtils.boost(getBoost()));
124: return buffer.toString();
125: }
126:
127: public Spans getSpans(final IndexReader reader) throws IOException {
128: if (clauses.size() == 0) // optimize 0-clause case
129: return new SpanOrQuery(getClauses()).getSpans(reader);
130:
131: if (clauses.size() == 1) // optimize 1-clause case
132: return ((SpanQuery) clauses.get(0)).getSpans(reader);
133:
134: return inOrder ? (Spans) new NearSpansOrdered(this , reader)
135: : (Spans) new NearSpansUnordered(this , reader);
136: }
137:
138: public Query rewrite(IndexReader reader) throws IOException {
139: SpanNearQuery clone = null;
140: for (int i = 0; i < clauses.size(); i++) {
141: SpanQuery c = (SpanQuery) clauses.get(i);
142: SpanQuery query = (SpanQuery) c.rewrite(reader);
143: if (query != c) { // clause rewrote: must clone
144: if (clone == null)
145: clone = (SpanNearQuery) this .clone();
146: clone.clauses.set(i, query);
147: }
148: }
149: if (clone != null) {
150: return clone; // some clauses rewrote
151: } else {
152: return this ; // no clauses rewrote
153: }
154: }
155:
156: /** Returns true iff <code>o</code> is equal to this. */
157: public boolean equals(Object o) {
158: if (this == o)
159: return true;
160: if (!(o instanceof SpanNearQuery))
161: return false;
162:
163: final SpanNearQuery spanNearQuery = (SpanNearQuery) o;
164:
165: if (inOrder != spanNearQuery.inOrder)
166: return false;
167: if (slop != spanNearQuery.slop)
168: return false;
169: if (!clauses.equals(spanNearQuery.clauses))
170: return false;
171:
172: return getBoost() == spanNearQuery.getBoost();
173: }
174:
175: public int hashCode() {
176: int result;
177: result = clauses.hashCode();
178: // Mix bits before folding in things like boost, since it could cancel the
179: // last element of clauses. This particular mix also serves to
180: // differentiate SpanNearQuery hashcodes from others.
181: result ^= (result << 14) | (result >>> 19); // reversible
182: result += Float.floatToRawIntBits(getBoost());
183: result += slop;
184: result ^= (inOrder ? 0x99AFD3BD : 0);
185: return result;
186: }
187: }
|