Merge pull request #409 from Alkarex/patch-1
[mono.git] / mcs / tools / monkeydoc / Lucene.Net / Lucene.Net / Search / Payloads / PayloadTermQuery.cs
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 = 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;
33
34 namespace Mono.Lucene.Net.Search.Payloads
35 {
36         
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.
41         /// <p/>
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.
45         /// <p/>
46         /// Payload scores are aggregated using a pluggable {@link PayloadFunction}.
47         /// 
48         /// </summary>
49         [Serializable]
50         public class PayloadTermQuery:SpanTermQuery
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) query.GetSpans(reader), this, similarity, reader.Norms(query.GetField()));
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.GetPositions();
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 = GetSimilarity();
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.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()));
154                                                 payloadsSeen++;
155                                         }
156                                         else
157                                         {
158                                                 // zero out the payload?
159                                         }
160                                 }
161                                 
162                                 /// <summary> </summary>
163                                 /// <returns> {@link #GetSpanScore()} * {@link #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                                 protected internal virtual float GetSpanScore()
185                                 {
186                                         return base.Score();
187                                 }
188                                 
189                                 /// <summary> The score for the payload
190                                 /// 
191                                 /// </summary>
192                                 /// <returns> The score, as calculated by
193                                 /// {@link PayloadFunction#DocScore(int, String, int, float)}
194                                 /// </returns>
195                                 protected internal virtual float GetPayloadScore()
196                                 {
197                                         return Enclosing_Instance.Enclosing_Instance.function.DocScore(doc, Enclosing_Instance.Enclosing_Instance.term.Field(), payloadsSeen, payloadScore);
198                                 }
199                                 
200                                 public override Explanation Explain(int doc)
201                                 {
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);
209                                         
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
218                                         return result;
219                                 }
220                         }
221                 }
222                 
223                 public override int GetHashCode()
224                 {
225                         int prime = 31;
226                         int result = base.GetHashCode();
227                         result = prime * result + ((function == null)?0:function.GetHashCode());
228                         result = prime * result + (includeSpanScore?1231:1237);
229                         return result;
230                 }
231                 
232                 public  override bool Equals(System.Object obj)
233                 {
234                         if (this == obj)
235                                 return true;
236                         if (!base.Equals(obj))
237                                 return false;
238                         if (GetType() != obj.GetType())
239                                 return false;
240                         PayloadTermQuery other = (PayloadTermQuery) obj;
241                         if (function == null)
242                         {
243                                 if (other.function != null)
244                                         return false;
245                         }
246                         else if (!function.Equals(other.function))
247                                 return false;
248                         if (includeSpanScore != other.includeSpanScore)
249                                 return false;
250                         return true;
251                 }
252         }
253 }