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.List;
023: import java.util.Collection;
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.util.PriorityQueue;
030: import org.apache.lucene.util.ToStringUtils;
031: import org.apache.lucene.search.Query;
032:
033: /** Matches the union of its clauses.*/
034: public class SpanOrQuery extends SpanQuery {
035: private List clauses;
036: private String field;
037:
038: /** Construct a SpanOrQuery merging the provided clauses. */
039: public SpanOrQuery(SpanQuery[] clauses) {
040:
041: // copy clauses array into an ArrayList
042: this .clauses = new ArrayList(clauses.length);
043: for (int i = 0; i < clauses.length; i++) {
044: SpanQuery clause = clauses[i];
045: if (i == 0) { // check field
046: field = clause.getField();
047: } else if (!clause.getField().equals(field)) {
048: throw new IllegalArgumentException(
049: "Clauses must have same field.");
050: }
051: this .clauses.add(clause);
052: }
053: }
054:
055: /** Return the clauses whose spans are matched. */
056: public SpanQuery[] getClauses() {
057: return (SpanQuery[]) clauses.toArray(new SpanQuery[clauses
058: .size()]);
059: }
060:
061: public String getField() {
062: return field;
063: }
064:
065: /** Returns a collection of all terms matched by this query.
066: * @deprecated use extractTerms instead
067: * @see #extractTerms(Set)
068: */
069: public Collection getTerms() {
070: Collection terms = new ArrayList();
071: Iterator i = clauses.iterator();
072: while (i.hasNext()) {
073: SpanQuery clause = (SpanQuery) i.next();
074: terms.addAll(clause.getTerms());
075: }
076: return terms;
077: }
078:
079: public void extractTerms(Set terms) {
080: Iterator i = clauses.iterator();
081: while (i.hasNext()) {
082: SpanQuery clause = (SpanQuery) i.next();
083: clause.extractTerms(terms);
084: }
085: }
086:
087: public Query rewrite(IndexReader reader) throws IOException {
088: SpanOrQuery clone = null;
089: for (int i = 0; i < clauses.size(); i++) {
090: SpanQuery c = (SpanQuery) clauses.get(i);
091: SpanQuery query = (SpanQuery) c.rewrite(reader);
092: if (query != c) { // clause rewrote: must clone
093: if (clone == null)
094: clone = (SpanOrQuery) this .clone();
095: clone.clauses.set(i, query);
096: }
097: }
098: if (clone != null) {
099: return clone; // some clauses rewrote
100: } else {
101: return this ; // no clauses rewrote
102: }
103: }
104:
105: public String toString(String field) {
106: StringBuffer buffer = new StringBuffer();
107: buffer.append("spanOr([");
108: Iterator i = clauses.iterator();
109: while (i.hasNext()) {
110: SpanQuery clause = (SpanQuery) i.next();
111: buffer.append(clause.toString(field));
112: if (i.hasNext()) {
113: buffer.append(", ");
114: }
115: }
116: buffer.append("])");
117: buffer.append(ToStringUtils.boost(getBoost()));
118: return buffer.toString();
119: }
120:
121: public boolean equals(Object o) {
122: if (this == o)
123: return true;
124: if (o == null || getClass() != o.getClass())
125: return false;
126:
127: final SpanOrQuery that = (SpanOrQuery) o;
128:
129: if (!clauses.equals(that.clauses))
130: return false;
131: if (!field.equals(that.field))
132: return false;
133:
134: return getBoost() == that.getBoost();
135: }
136:
137: public int hashCode() {
138: int h = clauses.hashCode();
139: h ^= (h << 10) | (h >>> 23);
140: h ^= Float.floatToRawIntBits(getBoost());
141: return h;
142: }
143:
144: private class SpanQueue extends PriorityQueue {
145: public SpanQueue(int size) {
146: initialize(size);
147: }
148:
149: protected final boolean lessThan(Object o1, Object o2) {
150: Spans spans1 = (Spans) o1;
151: Spans spans2 = (Spans) o2;
152: if (spans1.doc() == spans2.doc()) {
153: if (spans1.start() == spans2.start()) {
154: return spans1.end() < spans2.end();
155: } else {
156: return spans1.start() < spans2.start();
157: }
158: } else {
159: return spans1.doc() < spans2.doc();
160: }
161: }
162: }
163:
164: public Spans getSpans(final IndexReader reader) throws IOException {
165: if (clauses.size() == 1) // optimize 1-clause case
166: return ((SpanQuery) clauses.get(0)).getSpans(reader);
167:
168: return new Spans() {
169: private SpanQueue queue = null;
170:
171: private boolean initSpanQueue(int target)
172: throws IOException {
173: queue = new SpanQueue(clauses.size());
174: Iterator i = clauses.iterator();
175: while (i.hasNext()) {
176: Spans spans = ((SpanQuery) i.next())
177: .getSpans(reader);
178: if (((target == -1) && spans.next())
179: || ((target != -1) && spans.skipTo(target))) {
180: queue.put(spans);
181: }
182: }
183: return queue.size() != 0;
184: }
185:
186: public boolean next() throws IOException {
187: if (queue == null) {
188: return initSpanQueue(-1);
189: }
190:
191: if (queue.size() == 0) { // all done
192: return false;
193: }
194:
195: if (top().next()) { // move to next
196: queue.adjustTop();
197: return true;
198: }
199:
200: queue.pop(); // exhausted a clause
201: return queue.size() != 0;
202: }
203:
204: private Spans top() {
205: return (Spans) queue.top();
206: }
207:
208: public boolean skipTo(int target) throws IOException {
209: if (queue == null) {
210: return initSpanQueue(target);
211: }
212:
213: while (queue.size() != 0 && top().doc() < target) {
214: if (top().skipTo(target)) {
215: queue.adjustTop();
216: } else {
217: queue.pop();
218: }
219: }
220:
221: return queue.size() != 0;
222: }
223:
224: public int doc() {
225: return top().doc();
226: }
227:
228: public int start() {
229: return top().start();
230: }
231:
232: public int end() {
233: return top().end();
234: }
235:
236: public String toString() {
237: return "spans("
238: + SpanOrQuery.this
239: + ")@"
240: + ((queue == null) ? "START"
241: : (queue.size() > 0 ? (doc() + ":"
242: + start() + "-" + end())
243: : "END"));
244: }
245:
246: };
247: }
248:
249: }
|