Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
SpanNearQuery.cs
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 using System;
19 using System.Linq;
20 using Lucene.Net.Index;
21 using Lucene.Net.Support;
22 using IndexReader = Lucene.Net.Index.IndexReader;
23 using ToStringUtils = Lucene.Net.Util.ToStringUtils;
24 using Query = Lucene.Net.Search.Query;
25 
26 namespace Lucene.Net.Search.Spans
27 {
28 
29  /// <summary>Matches spans which are near one another. One can specify <i>slop</i>, the
30  /// maximum number of intervening unmatched positions, as well as whether
31  /// matches are required to be in-order.
32  /// </summary>
33  [Serializable]
34  public class SpanNearQuery : SpanQuery, System.ICloneable
35  {
36  protected internal System.Collections.Generic.IList<SpanQuery> clauses;
37  protected internal int internalSlop;
38  protected internal bool inOrder;
39 
40  protected internal System.String internalField;
41  private readonly bool collectPayloads;
42 
43  /// <summary>Construct a SpanNearQuery. Matches spans matching a span from each
44  /// clause, with up to <c>slop</c> total unmatched positions between
45  /// them. * When <c>inOrder</c> is true, the spans from each clause
46  /// must be * ordered as in <c>clauses</c>.
47  /// </summary>
48  public SpanNearQuery(SpanQuery[] clauses, int slop, bool inOrder):this(clauses, slop, inOrder, true)
49  {
50  }
51 
52  public SpanNearQuery(SpanQuery[] clauses, int slop, bool inOrder, bool collectPayloads)
53  {
54 
55  // copy clauses array into an ArrayList
56  this.clauses = new System.Collections.Generic.List<SpanQuery>(clauses.Length);
57  for (int i = 0; i < clauses.Length; i++)
58  {
59  SpanQuery clause = clauses[i];
60  if (i == 0)
61  {
62  // check field
63  internalField = clause.Field;
64  }
65  else if (!clause.Field.Equals(internalField))
66  {
67  throw new System.ArgumentException("Clauses must have same field.");
68  }
69  this.clauses.Add(clause);
70  }
71  this.collectPayloads = collectPayloads;
72  this.internalSlop = slop;
73  this.inOrder = inOrder;
74  }
75 
76  /// <summary>Return the clauses whose spans are matched. </summary>
77  public virtual SpanQuery[] GetClauses()
78  {
79  // Return a copy
80  return clauses.ToArray();
81  }
82 
83  /// <summary>Return the maximum number of intervening unmatched positions permitted.</summary>
84  public virtual int Slop
85  {
86  get { return internalSlop; }
87  }
88 
89  /// <summary>Return true if matches are required to be in-order.</summary>
90  public virtual bool IsInOrder
91  {
92  get { return inOrder; }
93  }
94 
95  public override string Field
96  {
97  get { return internalField; }
98  }
99 
100  public override void ExtractTerms(System.Collections.Generic.ISet<Term> terms)
101  {
102  foreach (SpanQuery clause in clauses)
103  {
104  clause.ExtractTerms(terms);
105  }
106  }
107 
108  public override System.String ToString(System.String field)
109  {
110  System.Text.StringBuilder buffer = new System.Text.StringBuilder();
111  buffer.Append("spanNear([");
112  System.Collections.Generic.IEnumerator<SpanQuery> i = clauses.GetEnumerator();
113  while (i.MoveNext())
114  {
115  SpanQuery clause = i.Current;
116  buffer.Append(clause.ToString(field));
117  buffer.Append(", ");
118  }
119  if (clauses.Count > 0) buffer.Length -= 2;
120  buffer.Append("], ");
121  buffer.Append(internalSlop);
122  buffer.Append(", ");
123  buffer.Append(inOrder);
124  buffer.Append(")");
125  buffer.Append(ToStringUtils.Boost(Boost));
126  return buffer.ToString();
127  }
128 
129  public override Spans GetSpans(IndexReader reader)
130  {
131  if (clauses.Count == 0)
132  // optimize 0-clause case
133  return new SpanOrQuery(GetClauses()).GetSpans(reader);
134 
135  if (clauses.Count == 1)
136  // optimize 1-clause case
137  return clauses[0].GetSpans(reader);
138 
139  return inOrder?(Spans) new NearSpansOrdered(this, reader, collectPayloads):(Spans) new NearSpansUnordered(this, reader);
140  }
141 
142  public override Query Rewrite(IndexReader reader)
143  {
144  SpanNearQuery clone = null;
145  for (int i = 0; i < clauses.Count; i++)
146  {
147  SpanQuery c = clauses[i];
148  SpanQuery query = (SpanQuery) c.Rewrite(reader);
149  if (query != c)
150  {
151  // clause rewrote: must clone
152  if (clone == null)
153  clone = (SpanNearQuery) this.Clone();
154  clone.clauses[i] = query;
155  }
156  }
157  if (clone != null)
158  {
159  return clone; // some clauses rewrote
160  }
161  else
162  {
163  return this; // no clauses rewrote
164  }
165  }
166 
167  public override System.Object Clone()
168  {
169  int sz = clauses.Count;
170  SpanQuery[] newClauses = new SpanQuery[sz];
171 
172  for (int i = 0; i < sz; i++)
173  {
174  SpanQuery clause = clauses[i];
175  newClauses[i] = (SpanQuery) clause.Clone();
176  }
177  SpanNearQuery spanNearQuery = new SpanNearQuery(newClauses, internalSlop, inOrder);
178  spanNearQuery.Boost = Boost;
179  return spanNearQuery;
180  }
181 
182  /// <summary>Returns true iff <c>o</c> is equal to this. </summary>
183  public override bool Equals(System.Object o)
184  {
185  if (this == o)
186  return true;
187  if (!(o is SpanNearQuery))
188  return false;
189 
190  SpanNearQuery spanNearQuery = (SpanNearQuery) o;
191 
192  if (inOrder != spanNearQuery.inOrder)
193  return false;
194  if (internalSlop != spanNearQuery.internalSlop)
195  return false;
196  if (clauses.Count != spanNearQuery.clauses.Count)
197  return false;
198  System.Collections.IEnumerator iter1 = clauses.GetEnumerator();
199  System.Collections.IEnumerator iter2 = spanNearQuery.clauses.GetEnumerator();
200  while (iter1.MoveNext() && iter2.MoveNext())
201  {
202  SpanQuery item1 = (SpanQuery)iter1.Current;
203  SpanQuery item2 = (SpanQuery)iter2.Current;
204  if (!item1.Equals(item2))
205  return false;
206  }
207 
208  return Boost == spanNearQuery.Boost;
209  }
210 
211  public override int GetHashCode()
212  {
213  long result = 0;
214  //mgarski .NET uses the arraylist's location, not contents to calculate the hash
215  // need to start with result being the hash of the contents.
216  foreach (SpanQuery sq in clauses)
217  {
218  result += sq.GetHashCode();
219  }
220  // Mix bits before folding in things like boost, since it could cancel the
221  // last element of clauses. This particular mix also serves to
222  // differentiate SpanNearQuery hashcodes from others.
223  result ^= ((result << 14) | (Number.URShift(result, 19))); // reversible
224  result += System.Convert.ToInt32(Boost);
225  result += internalSlop;
226  result ^= (inOrder ? (long) 0x99AFD3BD : 0);
227  return (int) result;
228  }
229  }
230 }