pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / src / java / org / apache / lucene / search / spans / SpanNotQuery.java
1 package org.apache.lucene.search.spans;
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 org.apache.lucene.index.IndexReader;
21 import org.apache.lucene.index.Term;
22 import org.apache.lucene.search.Query;
23 import org.apache.lucene.util.ToStringUtils;
24
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.Set;
29
30 /** Removes matches which overlap with another SpanQuery. */
31 public class SpanNotQuery extends SpanQuery implements Cloneable {
32   private SpanQuery include;
33   private SpanQuery exclude;
34
35   /** Construct a SpanNotQuery matching spans from <code>include</code> which
36    * have no overlap with spans from <code>exclude</code>.*/
37   public SpanNotQuery(SpanQuery include, SpanQuery exclude) {
38     this.include = include;
39     this.exclude = exclude;
40
41     if (!include.getField().equals(exclude.getField()))
42       throw new IllegalArgumentException("Clauses must have same field.");
43   }
44
45   /** Return the SpanQuery whose matches are filtered. */
46   public SpanQuery getInclude() { return include; }
47
48   /** Return the SpanQuery whose matches must not overlap those returned. */
49   public SpanQuery getExclude() { return exclude; }
50
51   @Override
52   public String getField() { return include.getField(); }
53
54   @Override
55   public void extractTerms(Set<Term> terms) { include.extractTerms(terms); }
56
57   @Override
58   public String toString(String field) {
59     StringBuilder buffer = new StringBuilder();
60     buffer.append("spanNot(");
61     buffer.append(include.toString(field));
62     buffer.append(", ");
63     buffer.append(exclude.toString(field));
64     buffer.append(")");
65     buffer.append(ToStringUtils.boost(getBoost()));
66     return buffer.toString();
67   }
68
69   @Override
70   public Object clone() {
71     SpanNotQuery spanNotQuery = new SpanNotQuery((SpanQuery)include.clone(),(SpanQuery) exclude.clone());
72     spanNotQuery.setBoost(getBoost());
73     return  spanNotQuery;
74   }
75
76   @Override
77   public Spans getSpans(final IndexReader reader) throws IOException {
78     return new Spans() {
79         private Spans includeSpans = include.getSpans(reader);
80         private boolean moreInclude = true;
81
82         private Spans excludeSpans = exclude.getSpans(reader);
83         private boolean moreExclude = excludeSpans.next();
84
85         @Override
86         public boolean next() throws IOException {
87           if (moreInclude)                        // move to next include
88             moreInclude = includeSpans.next();
89
90           while (moreInclude && moreExclude) {
91
92             if (includeSpans.doc() > excludeSpans.doc()) // skip exclude
93               moreExclude = excludeSpans.skipTo(includeSpans.doc());
94
95             while (moreExclude                    // while exclude is before
96                    && includeSpans.doc() == excludeSpans.doc()
97                    && excludeSpans.end() <= includeSpans.start()) {
98               moreExclude = excludeSpans.next();  // increment exclude
99             }
100
101             if (!moreExclude                      // if no intersection
102                 || includeSpans.doc() != excludeSpans.doc()
103                 || includeSpans.end() <= excludeSpans.start())
104               break;                              // we found a match
105
106             moreInclude = includeSpans.next();    // intersected: keep scanning
107           }
108           return moreInclude;
109         }
110
111         @Override
112         public boolean skipTo(int target) throws IOException {
113           if (moreInclude)                        // skip include
114             moreInclude = includeSpans.skipTo(target);
115
116           if (!moreInclude)
117             return false;
118
119           if (moreExclude                         // skip exclude
120               && includeSpans.doc() > excludeSpans.doc())
121             moreExclude = excludeSpans.skipTo(includeSpans.doc());
122
123           while (moreExclude                      // while exclude is before
124                  && includeSpans.doc() == excludeSpans.doc()
125                  && excludeSpans.end() <= includeSpans.start()) {
126             moreExclude = excludeSpans.next();    // increment exclude
127           }
128
129           if (!moreExclude                      // if no intersection
130                 || includeSpans.doc() != excludeSpans.doc()
131                 || includeSpans.end() <= excludeSpans.start())
132             return true;                          // we found a match
133
134           return next();                          // scan to next match
135         }
136
137         @Override
138         public int doc() { return includeSpans.doc(); }
139         @Override
140         public int start() { return includeSpans.start(); }
141         @Override
142         public int end() { return includeSpans.end(); }
143
144       // TODO: Remove warning after API has been finalized
145       @Override
146       public Collection<byte[]> getPayload() throws IOException {
147         ArrayList<byte[]> result = null;
148         if (includeSpans.isPayloadAvailable()) {
149           result = new ArrayList<byte[]>(includeSpans.getPayload());
150         }
151         return result;
152       }
153
154       // TODO: Remove warning after API has been finalized
155       @Override
156       public boolean isPayloadAvailable() {
157         return includeSpans.isPayloadAvailable();
158       }
159
160       @Override
161       public String toString() {
162           return "spans(" + SpanNotQuery.this.toString() + ")";
163         }
164
165       };
166   }
167
168   @Override
169   public Query rewrite(IndexReader reader) throws IOException {
170     SpanNotQuery clone = null;
171
172     SpanQuery rewrittenInclude = (SpanQuery) include.rewrite(reader);
173     if (rewrittenInclude != include) {
174       clone = (SpanNotQuery) this.clone();
175       clone.include = rewrittenInclude;
176     }
177     SpanQuery rewrittenExclude = (SpanQuery) exclude.rewrite(reader);
178     if (rewrittenExclude != exclude) {
179       if (clone == null) clone = (SpanNotQuery) this.clone();
180       clone.exclude = rewrittenExclude;
181     }
182
183     if (clone != null) {
184       return clone;                        // some clauses rewrote
185     } else {
186       return this;                         // no clauses rewrote
187     }
188   }
189
190     /** Returns true iff <code>o</code> is equal to this. */
191   @Override
192   public boolean equals(Object o) {
193     if (this == o) return true;
194     if (!(o instanceof SpanNotQuery)) return false;
195
196     SpanNotQuery other = (SpanNotQuery)o;
197     return this.include.equals(other.include)
198             && this.exclude.equals(other.exclude)
199             && this.getBoost() == other.getBoost();
200   }
201
202   @Override
203   public int hashCode() {
204     int h = include.hashCode();
205     h = (h<<1) | (h >>> 31);  // rotate left
206     h ^= exclude.hashCode();
207     h = (h<<1) | (h >>> 31);  // rotate left
208     h ^= Float.floatToRawIntBits(getBoost());
209     return h;
210   }
211
212 }