-
Notifications
You must be signed in to change notification settings - Fork 623
/
FunctionQuery.cs
217 lines (185 loc) · 7.65 KB
/
FunctionQuery.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
// Lucene version compatibility level 4.8.1
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Util;
using System.Collections;
using System.Collections.Generic;
using System.IO;
namespace Lucene.Net.Queries.Function
{
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// <summary>
/// Returns a score for each document based on a <see cref="Function.ValueSource"/>,
/// often some function of the value of a field.
///
/// <b>Note: This API is experimental and may change in non backward-compatible ways in the future</b>
/// </summary>
public class FunctionQuery : Query
{
private readonly ValueSource func;
/// <param name="func"> defines the function to be used for scoring </param>
public FunctionQuery(ValueSource func)
{
this.func = func;
}
/// <returns> The associated <see cref="Function.ValueSource"/> </returns>
public virtual ValueSource ValueSource => func;
public override Query Rewrite(IndexReader reader)
{
return this;
}
public override void ExtractTerms(ISet<Term> terms)
{
}
protected internal class FunctionWeight : Weight
{
private readonly FunctionQuery outerInstance;
protected readonly IndexSearcher m_searcher;
protected internal float m_queryNorm;
protected float m_queryWeight;
protected internal readonly IDictionary m_context;
public FunctionWeight(FunctionQuery outerInstance, IndexSearcher searcher)
{
this.outerInstance = outerInstance;
this.m_searcher = searcher;
this.m_context = ValueSource.NewContext(searcher);
outerInstance.func.CreateWeight(m_context, searcher);
}
public override Query Query => outerInstance;
public override float GetValueForNormalization()
{
m_queryWeight = outerInstance.Boost;
return m_queryWeight * m_queryWeight;
}
public override void Normalize(float norm, float topLevelBoost)
{
this.m_queryNorm = norm * topLevelBoost;
m_queryWeight *= this.m_queryNorm;
}
public override Scorer GetScorer(AtomicReaderContext ctx, IBits acceptDocs)
{
return new AllScorer(outerInstance, ctx, acceptDocs, this, m_queryWeight);
}
public override Explanation Explain(AtomicReaderContext ctx, int doc)
{
return ((AllScorer)GetScorer(ctx, ctx.AtomicReader.LiveDocs)).Explain(doc);
}
}
protected class AllScorer : Scorer
{
private readonly FunctionQuery outerInstance;
private readonly IndexReader reader;
private readonly FunctionWeight weight;
private readonly int maxDoc;
private readonly float qWeight;
private int doc = -1;
private readonly FunctionValues vals;
private readonly IBits acceptDocs;
/// <exception cref="IOException"/>
public AllScorer(FunctionQuery outerInstance, AtomicReaderContext context, IBits acceptDocs, FunctionWeight w, float qWeight)
: base(w)
{
this.outerInstance = outerInstance;
this.weight = w;
this.qWeight = qWeight;
this.reader = context.Reader;
this.maxDoc = reader.MaxDoc;
this.acceptDocs = acceptDocs;
vals = outerInstance.func.GetValues(weight.m_context, context);
}
public override int DocID => doc;
// instead of matching all docs, we could also embed a query.
// the score could either ignore the subscore, or boost it.
// Containment: floatline(foo:myTerm, "myFloatField", 1.0, 0.0f)
// Boost: foo:myTerm^floatline("myFloatField",1.0,0.0f)
public override int NextDoc()
{
for (; ; )
{
++doc;
if (doc >= maxDoc)
{
return doc = NO_MORE_DOCS;
}
if (acceptDocs != null && !acceptDocs.Get(doc))
{
continue;
}
return doc;
}
}
public override int Advance(int target)
{
// this will work even if target==NO_MORE_DOCS
doc = target - 1;
return NextDoc();
}
public override float GetScore()
{
float score = qWeight * vals.SingleVal(doc);
// Current Lucene priority queues can't handle NaN and -Infinity, so
// map to -Float.MAX_VALUE. This conditional handles both -infinity
// and NaN since comparisons with NaN are always false.
return score > float.NegativeInfinity ? score : -float.MaxValue;
}
public override long GetCost()
{
return maxDoc;
}
public override int Freq => 1;
public virtual Explanation Explain(int d)
{
float sc = qWeight * vals.SingleVal(d);
Explanation result = new ComplexExplanation(true, sc, "FunctionQuery(" + outerInstance.func + "), product of:");
result.AddDetail(vals.Explain(d));
result.AddDetail(new Explanation(outerInstance.Boost, "boost"));
result.AddDetail(new Explanation(weight.m_queryNorm, "queryNorm"));
return result;
}
}
public override Weight CreateWeight(IndexSearcher searcher)
{
return new FunctionQuery.FunctionWeight(this, searcher);
}
/// <summary>
/// Prints a user-readable version of this query.
/// </summary>
public override string ToString(string field)
{
float boost = Boost;
return (boost != 1.0 ? "(" : "") + func + (boost == 1.0 ? "" : ")^" + boost);
}
/// <summary>
/// Returns true if <paramref name="o"/> is equal to this.
/// </summary>
public override bool Equals(object o)
{
if (o is null) return false;
if (!(o is FunctionQuery other)) return false;
return Boost == other.Boost
&& func.Equals(other.func);
}
/// <summary>
/// Returns a hash code value for this object.
/// </summary>
public override int GetHashCode()
{
return func.GetHashCode() * 31 + J2N.BitConversion.SingleToInt32Bits(Boost);
}
}
}