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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 using IndexReader = Mono.Lucene.Net.Index.IndexReader;
21 using Term = Mono.Lucene.Net.Index.Term;
22 using TermPositions = Mono.Lucene.Net.Index.TermPositions;
23 using ComplexExplanation = Mono.Lucene.Net.Search.ComplexExplanation;
24 using Explanation = Mono.Lucene.Net.Search.Explanation;
25 using Scorer = Mono.Lucene.Net.Search.Scorer;
26 using Searcher = Mono.Lucene.Net.Search.Searcher;
27 using Similarity = Mono.Lucene.Net.Search.Similarity;
28 using Weight = Mono.Lucene.Net.Search.Weight;
29 using SpanScorer = Mono.Lucene.Net.Search.Spans.SpanScorer;
30 using SpanTermQuery = Mono.Lucene.Net.Search.Spans.SpanTermQuery;
31 using SpanWeight = Mono.Lucene.Net.Search.Spans.SpanWeight;
32 using TermSpans = Mono.Lucene.Net.Search.Spans.TermSpans;
34 namespace Mono.Lucene.Net.Search.Payloads
37 /// <summary> This class is very similar to
38 /// {@link Mono.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 /// {@link Mono.Lucene.Net.Index.Term} occurs.
42 /// In order to take advantage of this, you must override
43 /// {@link Mono.Lucene.Net.Search.Similarity#ScorePayload(String, byte[],int,int)}
44 /// which returns 1 by default.
46 /// Payload scores are aggregated using a pluggable {@link PayloadFunction}.
50 public class PayloadTermQuery:SpanTermQuery
52 protected internal PayloadFunction function;
53 private bool includeSpanScore;
55 public PayloadTermQuery(Term term, PayloadFunction function):this(term, function, true)
59 public PayloadTermQuery(Term term, PayloadFunction function, bool includeSpanScore):base(term)
61 this.function = function;
62 this.includeSpanScore = includeSpanScore;
65 public override Weight CreateWeight(Searcher searcher)
67 return new PayloadTermWeight(this, this, searcher);
71 protected internal class PayloadTermWeight:SpanWeight
73 private void InitBlock(PayloadTermQuery enclosingInstance)
75 this.enclosingInstance = enclosingInstance;
77 private PayloadTermQuery enclosingInstance;
78 public PayloadTermQuery Enclosing_Instance
82 return enclosingInstance;
87 public PayloadTermWeight(PayloadTermQuery enclosingInstance, PayloadTermQuery query, Searcher searcher):base(query, searcher)
89 InitBlock(enclosingInstance);
92 public override Scorer Scorer(IndexReader reader, bool scoreDocsInOrder, bool topScorer)
94 return new PayloadTermSpanScorer(this, (TermSpans) query.GetSpans(reader), this, similarity, reader.Norms(query.GetField()));
97 protected internal class PayloadTermSpanScorer:SpanScorer
99 private void InitBlock(PayloadTermWeight enclosingInstance)
101 this.enclosingInstance = enclosingInstance;
103 private PayloadTermWeight enclosingInstance;
104 public PayloadTermWeight Enclosing_Instance
108 return enclosingInstance;
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;
118 public PayloadTermSpanScorer(PayloadTermWeight enclosingInstance, TermSpans spans, Weight weight, Similarity similarity, byte[] norms):base(spans, weight, similarity, norms)
120 InitBlock(enclosingInstance);
121 positions = spans.GetPositions();
124 public /*protected internal*/ override bool SetFreqCurrentDoc()
134 Similarity similarity1 = GetSimilarity();
135 while (more && doc == spans.Doc())
137 int matchLength = spans.End() - spans.Start();
139 freq += similarity1.SloppyFreq(matchLength);
140 ProcessPayload(similarity1);
142 more = spans.Next(); // this moves positions to the next match in this
145 return more || (freq != 0);
148 protected internal virtual void ProcessPayload(Similarity similarity)
150 if (positions.IsPayloadAvailable())
152 payload = positions.GetPayload(payload, 0);
153 payloadScore = Enclosing_Instance.Enclosing_Instance.function.CurrentScore(doc, Enclosing_Instance.Enclosing_Instance.term.Field(), spans.Start(), spans.End(), payloadsSeen, payloadScore, similarity.ScorePayload(doc, Enclosing_Instance.Enclosing_Instance.term.Field(), spans.Start(), spans.End(), payload, 0, positions.GetPayloadLength()));
158 // zero out the payload?
162 /// <summary> </summary>
163 /// <returns> {@link #GetSpanScore()} * {@link #GetPayloadScore()}
165 /// <throws> IOException </throws>
166 public override float Score()
169 return Enclosing_Instance.Enclosing_Instance.includeSpanScore?GetSpanScore() * GetPayloadScore():GetPayloadScore();
172 /// <summary> Returns the SpanScorer score only.
174 /// Should not be overriden without good cause!
177 /// <returns> the score for just the Span part w/o the payload
179 /// <throws> IOException </throws>
182 /// <seealso cref="Score()">
184 protected internal virtual float GetSpanScore()
189 /// <summary> The score for the payload
192 /// <returns> The score, as calculated by
193 /// {@link PayloadFunction#DocScore(int, String, int, float)}
195 protected internal virtual float GetPayloadScore()
197 return Enclosing_Instance.Enclosing_Instance.function.DocScore(doc, Enclosing_Instance.Enclosing_Instance.term.Field(), payloadsSeen, payloadScore);
200 public override Explanation Explain(int doc)
202 ComplexExplanation result = new ComplexExplanation();
203 Explanation nonPayloadExpl = base.Explain(doc);
204 result.AddDetail(nonPayloadExpl);
205 // QUESTION: Is there a way to avoid this skipTo call? We need to know
206 // whether to load the payload or not
207 Explanation payloadBoost = new Explanation();
208 result.AddDetail(payloadBoost);
210 float payloadScore = GetPayloadScore();
211 payloadBoost.SetValue(payloadScore);
212 // GSI: I suppose we could toString the payload, but I don't think that
213 // would be a good idea
214 payloadBoost.SetDescription("scorePayload(...)");
215 result.SetValue(nonPayloadExpl.GetValue() * payloadScore);
216 result.SetDescription("btq, product of:");
217 result.SetMatch(nonPayloadExpl.GetValue() == 0?false:true); // LUCENE-1303
223 public override int GetHashCode()
226 int result = base.GetHashCode();
227 result = prime * result + ((function == null)?0:function.GetHashCode());
228 result = prime * result + (includeSpanScore?1231:1237);
232 public override bool Equals(System.Object obj)
236 if (!base.Equals(obj))
238 if (GetType() != obj.GetType())
240 PayloadTermQuery other = (PayloadTermQuery) obj;
241 if (function == null)
243 if (other.function != null)
246 else if (!function.Equals(other.function))
248 if (includeSpanScore != other.includeSpanScore)