/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using IndexReader = Lucene.Net.Index.IndexReader; using Query = Lucene.Net.Search.Query; using ToStringUtils = Lucene.Net.Util.ToStringUtils; namespace Lucene.Net.Search.Spans { /// Matches spans which are near one another. One can specify slop, the /// maximum number of intervening unmatched positions, as well as whether /// matches are required to be in-order. /// [Serializable] public class SpanNearQuery : SpanQuery { private System.Collections.ArrayList clauses; private int slop; private bool inOrder; private System.String field; /// Construct a SpanNearQuery. Matches spans matching a span from each /// clause, with up to slop total unmatched positions between /// them. * When inOrder is true, the spans from each clause /// must be * ordered as in clauses. /// public SpanNearQuery(SpanQuery[] clauses, int slop, bool inOrder) { // copy clauses array into an ArrayList this.clauses = new System.Collections.ArrayList(clauses.Length); for (int i = 0; i < clauses.Length; i++) { SpanQuery clause = clauses[i]; if (i == 0) { // check field field = clause.GetField(); } else if (!clause.GetField().Equals(field)) { throw new System.ArgumentException("Clauses must have same field."); } this.clauses.Add(clause); } this.slop = slop; this.inOrder = inOrder; } /// Return the clauses whose spans are matched. public virtual SpanQuery[] GetClauses() { return (SpanQuery[]) clauses.ToArray(typeof(SpanQuery)); } /// Return the maximum number of intervening unmatched positions permitted. public virtual int GetSlop() { return slop; } /// Return true if matches are required to be in-order. public virtual bool IsInOrder() { return inOrder; } public override System.String GetField() { return field; } /// Returns a collection of all terms matched by this query. /// use extractTerms instead /// /// /// public override System.Collections.ICollection GetTerms() { System.Collections.ArrayList terms = new System.Collections.ArrayList(); System.Collections.IEnumerator i = clauses.GetEnumerator(); while (i.MoveNext()) { SpanQuery clause = (SpanQuery) i.Current; terms.AddRange(clause.GetTerms()); } return terms; } public override void ExtractTerms(System.Collections.Hashtable terms) { System.Collections.IEnumerator i = clauses.GetEnumerator(); while (i.MoveNext()) { SpanQuery clause = (SpanQuery) i.Current; clause.ExtractTerms(terms); } } public override System.String ToString(System.String field) { System.Text.StringBuilder buffer = new System.Text.StringBuilder(); buffer.Append("spanNear(["); System.Collections.IEnumerator i = clauses.GetEnumerator(); while (i.MoveNext()) { SpanQuery clause = (SpanQuery) i.Current; buffer.Append(clause.ToString(field)); buffer.Append(", "); } if (clauses.Count > 0) buffer.Length -= 2; buffer.Append("], "); buffer.Append(slop); buffer.Append(", "); buffer.Append(inOrder); buffer.Append(")"); buffer.Append(ToStringUtils.Boost(GetBoost())); return buffer.ToString(); } public override Spans GetSpans(IndexReader reader) { if (clauses.Count == 0) // optimize 0-clause case return new SpanOrQuery(GetClauses()).GetPayloadSpans(reader); if (clauses.Count == 1) // optimize 1-clause case return ((SpanQuery) clauses[0]).GetPayloadSpans(reader); return inOrder ? (PayloadSpans) new NearSpansOrdered(this, reader) : (PayloadSpans) new NearSpansUnordered(this, reader); } public override PayloadSpans GetPayloadSpans(IndexReader reader) { return (PayloadSpans) GetSpans(reader); } public override Query Rewrite(IndexReader reader) { SpanNearQuery clone = null; for (int i = 0; i < clauses.Count; i++) { SpanQuery c = (SpanQuery) clauses[i]; SpanQuery query = (SpanQuery) c.Rewrite(reader); if (query != c) { // clause rewrote: must clone if (clone == null) clone = (SpanNearQuery) this.Clone(); clone.clauses[i] = query; } } if (clone != null) { return clone; // some clauses rewrote } else { return this; // no clauses rewrote } } /// Returns true iff o is equal to this. public override bool Equals(object o) { if (this == o) return true; if (!(o is SpanNearQuery)) return false; SpanNearQuery spanNearQuery = (SpanNearQuery) o; if (inOrder != spanNearQuery.inOrder) return false; if (slop != spanNearQuery.slop) return false; if (clauses.Count != spanNearQuery.clauses.Count) return false; System.Collections.IEnumerator iter1 = clauses.GetEnumerator(); System.Collections.IEnumerator iter2 = spanNearQuery.clauses.GetEnumerator(); while (iter1.MoveNext() && iter2.MoveNext()) { SpanQuery item1 = (SpanQuery) iter1.Current; SpanQuery item2 = (SpanQuery) iter2.Current; if (!item1.Equals(item2)) return false; } return GetBoost() == spanNearQuery.GetBoost(); } public override int GetHashCode() { long result; result = clauses.GetHashCode(); // Mix bits before folding in things like boost, since it could cancel the // last element of clauses. This particular mix also serves to // differentiate SpanNearQuery hashcodes from others. result ^= ((result << 14) | (result >> 19)); // reversible result += System.Convert.ToInt32(GetBoost()); result += slop; result ^= (inOrder ? (long) 0x99AFD3BD : 0); return (int) result; } } }