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
FunctionQuery.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 
19 using System;
20 using Lucene.Net.Index;
21 using Lucene.Net.Search;
22 using Lucene.Net.Search.Function;
23 
24 namespace Lucene.Net.Spatial.Util
25 {
26  /// <summary>
27  /// Port of Solr's FunctionQuery (v1.4)
28  ///
29  /// Returns a score for each document based on a ValueSource,
30  /// often some function of the value of a field.
31  ///
32  /// <b>Note: This API is experimental and may change in non backward-compatible ways in the future</b>
33  /// </summary>
34  public class FunctionQuery : Query
35  {
36  protected readonly ValueSource func;
37 
39  {
40  this.func = func;
41  }
42 
43  /// <summary>
44  ///
45  /// </summary>
46  /// <returns>The associated ValueSource</returns>
47  public ValueSource GetValueSource()
48  {
49  return func;
50  }
51 
52  public override Query Rewrite(Index.IndexReader reader)
53  {
54  return this;
55  }
56 
57  public override void ExtractTerms(System.Collections.Generic.ISet<Term> terms)
58  {
59  //base.ExtractTerms(terms);
60  }
61 
62  protected class FunctionWeight : Weight
63  {
64  protected Searcher searcher;
65  protected float queryNorm;
66  protected float queryWeight;
67  protected readonly FunctionQuery enclosingInstance;
68 
70  {
71  enclosingInstance = q;
72  this.searcher = searcher;
73  //q.func.CreateWeight(searcher);
74  }
75 
76  internal float GetQueryNorm()
77  {
78  return queryNorm;
79  }
80 
81  public override Query Query
82  {
83  get { return enclosingInstance; }
84  }
85 
86  public override float Value
87  {
88  get { return queryWeight; }
89  }
90 
91  public override float GetSumOfSquaredWeights()
92  {
93  queryWeight = enclosingInstance.Boost;
94  return queryWeight * queryWeight;
95  }
96 
97  public override void Normalize(float norm)
98  {
99  this.queryNorm = norm;
100  queryWeight *= this.queryNorm;
101  }
102 
103  public override Scorer Scorer(IndexReader reader, bool scoreDocsInOrder, bool topScorer)
104  {
105  return new AllScorer(enclosingInstance.GetSimilarity(searcher), reader, this);
106  }
107 
108  public override Explanation Explain(IndexReader reader, int doc)
109  {
110  return ((AllScorer)Scorer(reader, true, true)).Explain(doc);
111  }
112  }
113 
114  protected class AllScorer : Scorer
115  {
116  readonly IndexReader reader;
117  readonly FunctionWeight weight;
118  readonly int maxDoc;
119  readonly float qWeight;
120  int doc = -1;
121  readonly DocValues vals;
122  readonly bool hasDeletions;
123 
124  public AllScorer(Similarity similarity, IndexReader reader, FunctionWeight w)
125  : base(similarity)
126  {
127  this.weight = w;
128  this.qWeight = w.Value;
129  this.reader = reader;
130  this.maxDoc = reader.MaxDoc;
131  this.hasDeletions = reader.HasDeletions;
132  vals = ((FunctionQuery)w.Query).func.GetValues(reader);
133  }
134 
135  public override int DocID()
136  {
137  return doc;
138  }
139 
140  // instead of matching all docs, we could also embed a query.
141  // the score could either ignore the subscore, or boost it.
142  // Containment: floatline(foo:myTerm, "myFloatField", 1.0, 0.0f)
143  // Boost: foo:myTerm^floatline("myFloatField",1.0,0.0f)
144  public override int NextDoc()
145  {
146  for (; ; )
147  {
148  ++doc;
149  if (doc >= maxDoc)
150  {
151  return doc = NO_MORE_DOCS;
152  }
153  if (hasDeletions && reader.IsDeleted(doc)) continue;
154  return doc;
155  }
156  }
157 
158  public override int Advance(int target)
159  {
160  // this will work even if target==NO_MORE_DOCS
161  doc = target - 1;
162  return NextDoc();
163  }
164 
165  public override float Score()
166  {
167  float score = qWeight * vals.FloatVal(doc);
168 
169  // Current Lucene priority queues can't handle NaN and -Infinity, so
170  // map to -Float.MAX_VALUE. This conditional handles both -infinity
171  // and NaN since comparisons with NaN are always false.
172  return score > float.NegativeInfinity ? score : -float.MaxValue;
173  }
174 
175  public /*override*/ Explanation Explain(int doc)
176  {
177  float sc = qWeight * vals.FloatVal(doc);
178 
179  Explanation result = new ComplexExplanation
180  (true, sc, "FunctionQuery(" + ((FunctionQuery)weight.Query).func + "), product of:");
181 
182  result.AddDetail(vals.Explain(doc));
183  result.AddDetail(new Explanation(weight.Query.Boost, "boost"));
184  result.AddDetail(new Explanation(weight.GetQueryNorm(), "queryNorm"));
185  return result;
186  }
187  }
188 
189  public override Weight CreateWeight(Searcher searcher)
190  {
191  return new FunctionQuery.FunctionWeight(searcher, this);
192  }
193 
194  public override string ToString(string field)
195  {
196  float boost = Boost;
197  return (boost != 1.0 ? "(" : "") + func.ToString()
198  + (boost == 1.0 ? "" : ")^" + boost);
199  }
200 
201  public override bool Equals(object o)
202  {
203  var other = o as FunctionQuery;
204 
205  if (other == null) return false;
206 
207  return this.Boost == other.Boost && this.func.Equals(other.func);
208  }
209 
210  public override int GetHashCode()
211  {
212  return (int) (func.GetHashCode() * 31 + BitConverter.DoubleToInt64Bits(Boost));
213  }
214  }
215 }