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
PayloadTermQuery.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 
20 using IndexReader = Lucene.Net.Index.IndexReader;
21 using Term = Lucene.Net.Index.Term;
22 using TermPositions = Lucene.Net.Index.TermPositions;
23 using ComplexExplanation = Lucene.Net.Search.ComplexExplanation;
24 using Explanation = Lucene.Net.Search.Explanation;
25 using Scorer = Lucene.Net.Search.Scorer;
26 using Searcher = Lucene.Net.Search.Searcher;
27 using Similarity = Lucene.Net.Search.Similarity;
28 using Weight = Lucene.Net.Search.Weight;
29 using SpanScorer = Lucene.Net.Search.Spans.SpanScorer;
30 using SpanTermQuery = Lucene.Net.Search.Spans.SpanTermQuery;
31 using SpanWeight = Lucene.Net.Search.Spans.SpanWeight;
32 using TermSpans = Lucene.Net.Search.Spans.TermSpans;
33 
34 namespace Lucene.Net.Search.Payloads
35 {
36 
37  /// <summary> This class is very similar to
38  /// <see cref="Lucene.Net.Search.Spans.SpanTermQuery" /> except that it factors
39  /// in the value of the payload located at each of the positions where the
40  /// <see cref="Lucene.Net.Index.Term" /> occurs.
41  /// <p/>
42  /// In order to take advantage of this, you must override
43  /// <see cref="Lucene.Net.Search.Similarity.ScorePayload(int, String, int, int, byte[],int,int)" />
44  /// which returns 1 by default.
45  /// <p/>
46  /// Payload scores are aggregated using a pluggable <see cref="PayloadFunction" />.
47  ///
48  /// </summary>
49  [Serializable]
51  {
52  protected internal PayloadFunction function;
53  private bool includeSpanScore;
54 
55  public PayloadTermQuery(Term term, PayloadFunction function):this(term, function, true)
56  {
57  }
58 
59  public PayloadTermQuery(Term term, PayloadFunction function, bool includeSpanScore):base(term)
60  {
61  this.function = function;
62  this.includeSpanScore = includeSpanScore;
63  }
64 
65  public override Weight CreateWeight(Searcher searcher)
66  {
67  return new PayloadTermWeight(this, this, searcher);
68  }
69 
70  [Serializable]
71  protected internal class PayloadTermWeight:SpanWeight
72  {
73  private void InitBlock(PayloadTermQuery enclosingInstance)
74  {
75  this.enclosingInstance = enclosingInstance;
76  }
77  private PayloadTermQuery enclosingInstance;
78  public PayloadTermQuery Enclosing_Instance
79  {
80  get
81  {
82  return enclosingInstance;
83  }
84 
85  }
86 
87  public PayloadTermWeight(PayloadTermQuery enclosingInstance, PayloadTermQuery query, Searcher searcher):base(query, searcher)
88  {
89  InitBlock(enclosingInstance);
90  }
91 
92  public override Scorer Scorer(IndexReader reader, bool scoreDocsInOrder, bool topScorer)
93  {
94  return new PayloadTermSpanScorer(this, (TermSpans) internalQuery.GetSpans(reader), this, similarity, reader.Norms(internalQuery.Field));
95  }
96 
97  protected internal class PayloadTermSpanScorer:SpanScorer
98  {
99  private void InitBlock(PayloadTermWeight enclosingInstance)
100  {
101  this.enclosingInstance = enclosingInstance;
102  }
103  private PayloadTermWeight enclosingInstance;
104  public PayloadTermWeight Enclosing_Instance
105  {
106  get
107  {
108  return enclosingInstance;
109  }
110 
111  }
112  // TODO: is this the best way to allocate this?
113  protected internal byte[] payload = new byte[256];
114  protected internal TermPositions positions;
115  protected internal float payloadScore;
116  protected internal int payloadsSeen;
117 
118  public PayloadTermSpanScorer(PayloadTermWeight enclosingInstance, TermSpans spans, Weight weight, Similarity similarity, byte[] norms):base(spans, weight, similarity, norms)
119  {
120  InitBlock(enclosingInstance);
121  positions = spans.Positions;
122  }
123 
124  public /*protected internal*/ override bool SetFreqCurrentDoc()
125  {
126  if (!more)
127  {
128  return false;
129  }
130  doc = spans.Doc();
131  freq = 0.0f;
132  payloadScore = 0;
133  payloadsSeen = 0;
134  Similarity similarity1 = Similarity;
135  while (more && doc == spans.Doc())
136  {
137  int matchLength = spans.End() - spans.Start();
138 
139  freq += similarity1.SloppyFreq(matchLength);
140  ProcessPayload(similarity1);
141 
142  more = spans.Next(); // this moves positions to the next match in this
143  // document
144  }
145  return more || (freq != 0);
146  }
147 
148  protected internal virtual void ProcessPayload(Similarity similarity)
149  {
150  if (positions.IsPayloadAvailable)
151  {
152  payload = positions.GetPayload(payload, 0);
153  payloadScore = Enclosing_Instance.Enclosing_Instance.function.CurrentScore(doc, Enclosing_Instance.Enclosing_Instance.internalTerm.Field, spans.Start(), spans.End(), payloadsSeen, payloadScore, similarity.ScorePayload(doc, Enclosing_Instance.Enclosing_Instance.internalTerm.Field, spans.Start(), spans.End(), payload, 0, positions.PayloadLength));
154  payloadsSeen++;
155  }
156  else
157  {
158  // zero out the payload?
159  }
160  }
161 
162  /// <summary> </summary>
163  /// <returns> <see cref="GetSpanScore()" /> * <see cref="GetPayloadScore()" />
164  /// </returns>
165  /// <throws> IOException </throws>
166  public override float Score()
167  {
168 
169  return Enclosing_Instance.Enclosing_Instance.includeSpanScore?GetSpanScore() * GetPayloadScore():GetPayloadScore();
170  }
171 
172  /// <summary> Returns the SpanScorer score only.
173  /// <p/>
174  /// Should not be overriden without good cause!
175  ///
176  /// </summary>
177  /// <returns> the score for just the Span part w/o the payload
178  /// </returns>
179  /// <throws> IOException </throws>
180  /// <summary>
181  /// </summary>
182  /// <seealso cref="Score()">
183  /// </seealso>
184  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
185  protected internal virtual float GetSpanScore()
186  {
187  return base.Score();
188  }
189 
190  /// <summary> The score for the payload
191  ///
192  /// </summary>
193  /// <returns> The score, as calculated by
194  /// <see cref="PayloadFunction.DocScore(int, String, int, float)" />
195  /// </returns>
196  [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
197  protected internal virtual float GetPayloadScore()
198  {
199  return Enclosing_Instance.Enclosing_Instance.function.DocScore(doc, Enclosing_Instance.Enclosing_Instance.internalTerm.Field, payloadsSeen, payloadScore);
200  }
201 
202  protected internal override Explanation Explain(int doc)
203  {
204  ComplexExplanation result = new ComplexExplanation();
205  Explanation nonPayloadExpl = base.Explain(doc);
206  result.AddDetail(nonPayloadExpl);
207  // QUESTION: Is there a way to avoid this skipTo call? We need to know
208  // whether to load the payload or not
209  Explanation payloadBoost = new Explanation();
210  result.AddDetail(payloadBoost);
211 
212  float payloadScore = GetPayloadScore();
213  payloadBoost.Value = payloadScore;
214  // GSI: I suppose we could toString the payload, but I don't think that
215  // would be a good idea
216  payloadBoost.Description = "scorePayload(...)";
217  result.Value = nonPayloadExpl.Value * payloadScore;
218  result.Description = "btq, product of:";
219  result.Match = nonPayloadExpl.Value == 0?false:true; // LUCENE-1303
220  return result;
221  }
222  }
223  }
224 
225  public override int GetHashCode()
226  {
227  int prime = 31;
228  int result = base.GetHashCode();
229  result = prime * result + ((function == null)?0:function.GetHashCode());
230  result = prime * result + (includeSpanScore?1231:1237);
231  return result;
232  }
233 
234  public override bool Equals(System.Object obj)
235  {
236  if (this == obj)
237  return true;
238  if (!base.Equals(obj))
239  return false;
240  if (GetType() != obj.GetType())
241  return false;
242  PayloadTermQuery other = (PayloadTermQuery) obj;
243  if (function == null)
244  {
245  if (other.function != null)
246  return false;
247  }
248  else if (!function.Equals(other.function))
249  return false;
250  if (includeSpanScore != other.includeSpanScore)
251  return false;
252  return true;
253  }
254  }
255 }