must not be null!");
}
/*(non-Javadoc) @see Lucene.Net.Search.Query#rewrite(Lucene.Net.Index.IndexReader) */
public override Query Rewrite(IndexReader reader)
{
subQuery = subQuery.Rewrite(reader);
for (int i = 0; i < valSrcQueries.Length; i++)
{
valSrcQueries[i] = (ValueSourceQuery) valSrcQueries[i].Rewrite(reader);
}
return this;
}
/*(non-Javadoc) @see Lucene.Net.Search.Query#extractTerms(java.util.Set) */
public override void ExtractTerms(System.Collections.Hashtable terms)
{
subQuery.ExtractTerms(terms);
for (int i = 0; i < valSrcQueries.Length; i++)
{
valSrcQueries[i].ExtractTerms(terms);
}
}
/*(non-Javadoc) @see Lucene.Net.Search.Query#clone() */
public override object Clone()
{
CustomScoreQuery clone = (CustomScoreQuery) base.Clone();
clone.subQuery = (Query) subQuery.Clone();
clone.valSrcQueries = new ValueSourceQuery[valSrcQueries.Length];
for (int i = 0; i < valSrcQueries.Length; i++)
{
clone.valSrcQueries[i] = (ValueSourceQuery) valSrcQueries[i].Clone();
}
return clone;
}
/* (non-Javadoc) @see Lucene.Net.Search.Query#toString(java.lang.String) */
public override System.String ToString(System.String field)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder(Name()).Append("(");
sb.Append(subQuery.ToString(field));
for (int i = 0; i < valSrcQueries.Length; i++)
{
sb.Append(", ").Append(valSrcQueries[i].ToString(field));
}
sb.Append(")");
sb.Append(strict ? " STRICT" : "");
return sb.ToString() + ToStringUtils.Boost(GetBoost());
}
/// Returns true if o
is equal to this.
public override bool Equals(object o)
{
if (GetType() != o.GetType())
{
return false;
}
CustomScoreQuery other = (CustomScoreQuery) o;
if (this.GetBoost() != other.GetBoost() || !this.subQuery.Equals(other.subQuery) || this.valSrcQueries.Length != other.valSrcQueries.Length)
{
return false;
}
for (int i = 0; i < valSrcQueries.Length; i++)
{
//TODO simplify with Arrays.deepEquals() once moving to Java 1.5
if (!valSrcQueries[i].Equals(other.valSrcQueries[i]))
{
return false;
}
}
return true;
}
/// Returns a hash code value for this object.
public override int GetHashCode()
{
int valSrcHash = 0;
for (int i = 0; i < valSrcQueries.Length; i++)
{
//TODO simplify with Arrays.deepHashcode() once moving to Java 1.5
valSrcHash += valSrcQueries[i].GetHashCode();
}
return (GetType().GetHashCode() + subQuery.GetHashCode() + valSrcHash) ^ BitConverter.ToInt32(BitConverter.GetBytes(GetBoost()), 0);
}
/// Compute a custom score by the subQuery score and a number of
/// ValueSourceQuery scores.
///
/// Subclasses can override this method to modify the custom score.
///
/// If your custom scoring is different than the default herein you
/// should override at least one of the two customScore() methods.
/// If the number of ValueSourceQueries is always < 2 it is
/// sufficient to override the other
/// {@link #CustomScore(int, float, float) costomScore()}
/// method, which is simpler.
///
/// The default computation herein is:
///
/// ModifiedScore = valSrcScore * subQueryScore[0] * subQueryScore[1] * ...
///
///
///
/// id of scored doc.
///
/// score of that doc by the subQuery.
///
/// score of that doc by the ValueSourceQuery.
///
/// custom score.
///
public virtual float CustomScore(int doc, float subQueryScore, float[] valSrcScores)
{
if (valSrcScores.Length == 1)
{
return CustomScore(doc, subQueryScore, valSrcScores[0]);
}
if (valSrcScores.Length == 0)
{
return CustomScore(doc, subQueryScore, 1);
}
float score = subQueryScore;
for (int i = 0; i < valSrcScores.Length; i++)
{
score *= valSrcScores[i];
}
return score;
}
/// Compute a custom score by the subQuery score and the ValueSourceQuery score.
///
/// Subclasses can override this method to modify the custom score.
///
/// If your custom scoring is different than the default herein you
/// should override at least one of the two customScore() methods.
/// If the number of ValueSourceQueries is always < 2 it is
/// sufficient to override this costomScore() method, which is simpler.
///
/// The default computation herein is:
///
/// ModifiedScore = valSrcScore * subQueryScore
///
///
///
/// id of scored doc.
///
/// score of that doc by the subQuery.
///
/// score of that doc by the ValueSourceQuery.
///
/// custom score.
///
public virtual float CustomScore(int doc, float subQueryScore, float valSrcScore)
{
return subQueryScore * valSrcScore;
}
/// Explain the custom score.
/// Whenever overriding {@link #CustomScore(int, float, float[])},
/// this method should also be overridden to provide the correct explanation
/// for the part of the custom scoring.
///
///
/// doc being explained.
///
/// explanation for the sub-query part.
///
/// explanation for the value source part.
///
/// an explanation for the custom score
///
public virtual Explanation CustomExplain(int doc, Explanation subQueryExpl, Explanation[] valSrcExpls)
{
if (valSrcExpls.Length == 1)
{
return CustomExplain(doc, subQueryExpl, valSrcExpls[0]);
}
if (valSrcExpls.Length == 0)
{
return subQueryExpl;
}
float valSrcScore = 1;
for (int i = 0; i < valSrcExpls.Length; i++)
{
valSrcScore *= valSrcExpls[i].GetValue();
}
Explanation exp = new Explanation(valSrcScore * subQueryExpl.GetValue(), "custom score: product of:");
exp.AddDetail(subQueryExpl);
for (int i = 0; i < valSrcExpls.Length; i++)
{
exp.AddDetail(valSrcExpls[i]);
}
return exp;
}
/// Explain the custom score.
/// Whenever overriding {@link #CustomScore(int, float, float)},
/// this method should also be overridden to provide the correct explanation
/// for the part of the custom scoring.
///
///
/// doc being explained.
///
/// explanation for the sub-query part.
///
/// explanation for the value source part.
///
/// an explanation for the custom score
///
public virtual Explanation CustomExplain(int doc, Explanation subQueryExpl, Explanation valSrcExpl)
{
float valSrcScore = 1;
if (valSrcExpl != null)
{
valSrcScore *= valSrcExpl.GetValue();
}
Explanation exp = new Explanation(valSrcScore * subQueryExpl.GetValue(), "custom score: product of:");
exp.AddDetail(subQueryExpl);
exp.AddDetail(valSrcExpl);
return exp;
}
//=========================== W E I G H T ============================
[Serializable]
private class CustomWeight : Weight
{
private void InitBlock(CustomScoreQuery enclosingInstance)
{
this.enclosingInstance = enclosingInstance;
}
private CustomScoreQuery enclosingInstance;
public CustomScoreQuery Enclosing_Instance
{
get
{
return enclosingInstance;
}
}
internal Similarity similarity;
internal Weight subQueryWeight;
internal Weight[] valSrcWeights;
internal bool qStrict;
public CustomWeight(CustomScoreQuery enclosingInstance, Searcher searcher)
{
InitBlock(enclosingInstance);
this.similarity = Enclosing_Instance.GetSimilarity(searcher);
this.subQueryWeight = Enclosing_Instance.subQuery.Weight(searcher);
this.subQueryWeight = Enclosing_Instance.subQuery.Weight(searcher);
this.valSrcWeights = new Weight[Enclosing_Instance.valSrcQueries.Length];
for (int i = 0; i < Enclosing_Instance.valSrcQueries.Length; i++)
{
this.valSrcWeights[i] = Enclosing_Instance.valSrcQueries[i].CreateWeight(searcher);
}
this.qStrict = Enclosing_Instance.strict;
}
/*(non-Javadoc) @see Lucene.Net.Search.Weight#getQuery() */
public virtual Query GetQuery()
{
return Enclosing_Instance;
}
/*(non-Javadoc) @see Lucene.Net.Search.Weight#getValue() */
public virtual float GetValue()
{
return Enclosing_Instance.GetBoost();
}
/*(non-Javadoc) @see Lucene.Net.Search.Weight#sumOfSquaredWeights() */
public virtual float SumOfSquaredWeights()
{
float sum = subQueryWeight.SumOfSquaredWeights();
for (int i = 0; i < valSrcWeights.Length; i++)
{
if (qStrict)
{
valSrcWeights[i].SumOfSquaredWeights(); // do not include ValueSource part in the query normalization
}
else
{
sum += valSrcWeights[i].SumOfSquaredWeights();
}
}
sum *= Enclosing_Instance.GetBoost() * Enclosing_Instance.GetBoost(); // boost each sub-weight
return sum;
}
/*(non-Javadoc) @see Lucene.Net.Search.Weight#normalize(float) */
public virtual void Normalize(float norm)
{
norm *= Enclosing_Instance.GetBoost(); // incorporate boost
subQueryWeight.Normalize(norm);
for (int i = 0; i < valSrcWeights.Length; i++)
{
if (qStrict)
{
valSrcWeights[i].Normalize(1); // do not normalize the ValueSource part
}
else
{
valSrcWeights[i].Normalize(norm);
}
}
}
/*(non-Javadoc) @see Lucene.Net.Search.Weight#scorer(Lucene.Net.Index.IndexReader) */
public virtual Scorer Scorer(IndexReader reader)
{
Scorer subQueryScorer = subQueryWeight.Scorer(reader);
Scorer[] valSrcScorers = new Scorer[valSrcWeights.Length];
for (int i = 0; i < valSrcScorers.Length; i++)
{
valSrcScorers[i] = valSrcWeights[i].Scorer(reader);
}
return new CustomScorer(enclosingInstance, similarity, reader, this, subQueryScorer, valSrcScorers);
}
/*(non-Javadoc) @see Lucene.Net.Search.Weight#explain(Lucene.Net.Index.IndexReader, int) */
public virtual Explanation Explain(IndexReader reader, int doc)
{
return Scorer(reader).Explain(doc);
}
}
//=========================== S C O R E R ============================
/// A scorer that applies a (callback) function on scores of the subQuery.
private class CustomScorer : Scorer
{
private void InitBlock(CustomScoreQuery enclosingInstance)
{
this.enclosingInstance = enclosingInstance;
}
private CustomScoreQuery enclosingInstance;
public CustomScoreQuery Enclosing_Instance
{
get
{
return enclosingInstance;
}
}
private CustomWeight weight;
private float qWeight;
private Scorer subQueryScorer;
private Scorer[] valSrcScorers;
private IndexReader reader;
private float[] vScores; // reused in score() to avoid allocating this array for each doc
// constructor
internal CustomScorer(CustomScoreQuery enclosingInstance, Similarity similarity, IndexReader reader, CustomWeight w, Scorer subQueryScorer, Scorer[] valSrcScorers) : base(similarity)
{
InitBlock(enclosingInstance);
this.weight = w;
this.qWeight = w.GetValue();
this.subQueryScorer = subQueryScorer;
this.valSrcScorers = valSrcScorers;
this.reader = reader;
this.vScores = new float[valSrcScorers.Length];
}
/*(non-Javadoc) @see Lucene.Net.Search.Scorer#next() */
public override bool Next()
{
bool hasNext = subQueryScorer.Next();
if (hasNext)
{
for (int i = 0; i < valSrcScorers.Length; i++)
{
valSrcScorers[i].SkipTo(subQueryScorer.Doc());
}
}
return hasNext;
}
/*(non-Javadoc) @see Lucene.Net.Search.Scorer#doc() */
public override int Doc()
{
return subQueryScorer.Doc();
}
/*(non-Javadoc) @see Lucene.Net.Search.Scorer#score() */
public override float Score()
{
for (int i = 0; i < valSrcScorers.Length; i++)
{
vScores[i] = valSrcScorers[i].Score();
}
return qWeight * Enclosing_Instance.CustomScore(subQueryScorer.Doc(), subQueryScorer.Score(), vScores);
}
/*(non-Javadoc) @see Lucene.Net.Search.Scorer#skipTo(int) */
public override bool SkipTo(int target)
{
bool hasNext = subQueryScorer.SkipTo(target);
if (hasNext)
{
for (int i = 0; i < valSrcScorers.Length; i++)
{
valSrcScorers[i].SkipTo(subQueryScorer.Doc());
}
}
return hasNext;
}
/*(non-Javadoc) @see Lucene.Net.Search.Scorer#explain(int) */
public override Explanation Explain(int doc)
{
Explanation subQueryExpl = weight.subQueryWeight.Explain(reader, doc);
if (!subQueryExpl.IsMatch())
{
return subQueryExpl;
}
// match
Explanation[] valSrcExpls = new Explanation[valSrcScorers.Length];
for (int i = 0; i < valSrcScorers.Length; i++)
{
valSrcExpls[i] = valSrcScorers[i].Explain(doc);
}
Explanation customExp = Enclosing_Instance.CustomExplain(doc, subQueryExpl, valSrcExpls);
float sc = qWeight * customExp.GetValue();
Explanation res = new ComplexExplanation(true, sc, Enclosing_Instance.ToString() + ", product of:");
res.AddDetail(customExp);
res.AddDetail(new Explanation(qWeight, "queryBoost")); // actually using the q boost as q weight (== weight value)
return res;
}
}
/*(non-Javadoc) @see Lucene.Net.Search.Query#createWeight(Lucene.Net.Search.Searcher) */
protected internal override Weight CreateWeight(Searcher searcher)
{
return new CustomWeight(this, searcher);
}
/// Checks if this is strict custom scoring.
/// In strict custom scoring, the ValueSource part does not participate in weight normalization.
/// This may be useful when one wants full control over how scores are modified, and does
/// not care about normalizing by the ValueSource part.
/// One particular case where this is useful if for testing this query.
///
/// Note: only has effect when the ValueSource part is not null.
///
public virtual bool IsStrict()
{
return strict;
}
/// Set the strict mode of this query.
/// The strict mode to set.
///
///
///
public virtual void SetStrict(bool strict)
{
this.strict = strict;
}
/// A short name of this query, used in {@link #ToString(String)}.
public virtual System.String Name()
{
return "custom";
}
}
}