/*
* 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.
*/
using System;
using IndexReader = Lucene.Net.Index.IndexReader;
using ToStringUtils = Lucene.Net.Util.ToStringUtils;
using Explanation = Lucene.Net.Search.Explanation;
using Scorer = Lucene.Net.Search.Scorer;
using Searcher = Lucene.Net.Search.Searcher;
using Similarity = Lucene.Net.Search.Similarity;
using Weight = Lucene.Net.Search.Weight;
using NearSpansOrdered = Lucene.Net.Search.Spans.NearSpansOrdered;
using NearSpansUnordered = Lucene.Net.Search.Spans.NearSpansUnordered;
using SpanNearQuery = Lucene.Net.Search.Spans.SpanNearQuery;
using SpanQuery = Lucene.Net.Search.Spans.SpanQuery;
using SpanScorer = Lucene.Net.Search.Spans.SpanScorer;
using SpanWeight = Lucene.Net.Search.Spans.SpanWeight;
namespace Lucene.Net.Search.Payloads
{
/// This class is very similar to
/// except that it factors
/// in the value of the payloads located at each of the positions where the
/// occurs.
///
/// In order to take advantage of this, you must override
///
/// which returns 1 by default.
///
/// Payload scores are aggregated using a pluggable .
///
///
///
///
[Serializable]
public class PayloadNearQuery:SpanNearQuery, System.ICloneable
{
protected internal System.String fieldName;
protected internal PayloadFunction function;
public PayloadNearQuery(SpanQuery[] clauses, int slop, bool inOrder):this(clauses, slop, inOrder, new AveragePayloadFunction())
{
}
public PayloadNearQuery(SpanQuery[] clauses, int slop, bool inOrder, PayloadFunction function):base(clauses, slop, inOrder)
{
fieldName = clauses[0].GetField(); // all clauses must have same field
this.function = function;
}
public override Weight CreateWeight(Searcher searcher)
{
return new PayloadNearSpanWeight(this, this, searcher);
}
public override System.Object Clone()
{
int sz = clauses.Count;
SpanQuery[] newClauses = new SpanQuery[sz];
for (int i = 0; i < sz; i++)
{
SpanQuery clause = (SpanQuery) clauses[i];
newClauses[i] = (SpanQuery) clause.Clone();
}
PayloadNearQuery boostingNearQuery = new PayloadNearQuery(newClauses, slop, inOrder);
boostingNearQuery.SetBoost(GetBoost());
return boostingNearQuery;
}
public override System.String ToString(System.String field)
{
System.Text.StringBuilder buffer = new System.Text.StringBuilder();
buffer.Append("payloadNear([");
System.Collections.IEnumerator i = clauses.GetEnumerator();
while (i.MoveNext())
{
SpanQuery clause = (SpanQuery) i.Current;
buffer.Append(clause.ToString(field));
if (i.MoveNext())
{
buffer.Append(", ");
}
}
buffer.Append("], ");
buffer.Append(slop);
buffer.Append(", ");
buffer.Append(inOrder);
buffer.Append(")");
buffer.Append(ToStringUtils.Boost(GetBoost()));
return buffer.ToString();
}
// @Override
public override int GetHashCode()
{
int prime = 31;
int result = base.GetHashCode();
result = prime * result + ((fieldName == null)?0:fieldName.GetHashCode());
result = prime * result + ((function == null)?0:function.GetHashCode());
return result;
}
// @Override
public override bool Equals(System.Object obj)
{
if (this == obj)
return true;
if (!base.Equals(obj))
return false;
if (GetType() != obj.GetType())
return false;
PayloadNearQuery other = (PayloadNearQuery) obj;
if (fieldName == null)
{
if (other.fieldName != null)
return false;
}
else if (!fieldName.Equals(other.fieldName))
return false;
if (function == null)
{
if (other.function != null)
return false;
}
else if (!function.Equals(other.function))
return false;
return true;
}
[Serializable]
public class PayloadNearSpanWeight:SpanWeight
{
private void InitBlock(PayloadNearQuery enclosingInstance)
{
this.enclosingInstance = enclosingInstance;
}
private PayloadNearQuery enclosingInstance;
public PayloadNearQuery Enclosing_Instance
{
get
{
return enclosingInstance;
}
}
public PayloadNearSpanWeight(PayloadNearQuery enclosingInstance, SpanQuery query, Searcher searcher):base(query, searcher)
{
InitBlock(enclosingInstance);
}
public virtual Scorer Scorer(IndexReader reader)
{
return new PayloadNearSpanScorer(enclosingInstance, query.GetSpans(reader), this, similarity, reader.Norms(query.GetField()));
}
public override Scorer Scorer(IndexReader reader, bool scoreDocsInOrder, bool topScorer)
{
return new PayloadNearSpanScorer(enclosingInstance, query.GetSpans(reader), this, similarity, reader.Norms(query.GetField()));
}
}
public class PayloadNearSpanScorer:SpanScorer
{
private void InitBlock(PayloadNearQuery enclosingInstance)
{
this.enclosingInstance = enclosingInstance;
similarity = GetSimilarity();
}
private PayloadNearQuery enclosingInstance;
public PayloadNearQuery Enclosing_Instance
{
get
{
return enclosingInstance;
}
}
new internal Lucene.Net.Search.Spans.Spans spans;
protected internal float payloadScore;
private int payloadsSeen;
internal Similarity similarity;
protected internal PayloadNearSpanScorer(PayloadNearQuery enclosingInstance, Lucene.Net.Search.Spans.Spans spans, Weight weight, Similarity similarity, byte[] norms):base(spans, weight, similarity, norms)
{
InitBlock(enclosingInstance);
this.spans = spans;
}
// Get the payloads associated with all underlying subspans
public virtual void GetPayloads(Lucene.Net.Search.Spans.Spans[] subSpans)
{
for (int i = 0; i < subSpans.Length; i++)
{
if (subSpans[i] is NearSpansOrdered)
{
if (((NearSpansOrdered) subSpans[i]).IsPayloadAvailable())
{
ProcessPayloads(((NearSpansOrdered) subSpans[i]).GetPayload(), subSpans[i].Start(), subSpans[i].End());
}
GetPayloads(((NearSpansOrdered) subSpans[i]).GetSubSpans());
}
else if (subSpans[i] is NearSpansUnordered)
{
if (((NearSpansUnordered) subSpans[i]).IsPayloadAvailable())
{
ProcessPayloads(((NearSpansUnordered) subSpans[i]).GetPayload(), subSpans[i].Start(), subSpans[i].End());
}
GetPayloads(((NearSpansUnordered) subSpans[i]).GetSubSpans());
}
}
}
/// By default, uses the to score the payloads, but
/// can be overridden to do other things.
///
///
/// The payloads
///
/// The start position of the span being scored
///
/// The end position of the span being scored
///
///
///
///
protected internal virtual void ProcessPayloads(System.Collections.Generic.ICollection payLoads, int start, int end)
{
foreach (byte[] thePayload in payLoads)
{
payloadScore = Enclosing_Instance.function.CurrentScore(doc, Enclosing_Instance.fieldName, start, end, payloadsSeen, payloadScore, similarity.ScorePayload(doc, Enclosing_Instance.fieldName, spans.Start(), spans.End(), thePayload, 0, thePayload.Length));
++payloadsSeen;
}
}
//
public /*protected internal*/ override bool SetFreqCurrentDoc()
{
if (!more)
{
return false;
}
Lucene.Net.Search.Spans.Spans[] spansArr = new Lucene.Net.Search.Spans.Spans[1];
spansArr[0] = spans;
payloadScore = 0;
payloadsSeen = 0;
GetPayloads(spansArr);
return base.SetFreqCurrentDoc();
}
public override float Score()
{
return base.Score() * Enclosing_Instance.function.DocScore(doc, Enclosing_Instance.fieldName, payloadsSeen, payloadScore);
}
public override Explanation Explain(int doc)
{
Explanation result = new Explanation();
Explanation nonPayloadExpl = base.Explain(doc);
result.AddDetail(nonPayloadExpl);
Explanation payloadBoost = new Explanation();
result.AddDetail(payloadBoost);
float avgPayloadScore = (payloadsSeen > 0?(payloadScore / payloadsSeen):1);
payloadBoost.SetValue(avgPayloadScore);
payloadBoost.SetDescription("scorePayload(...)");
result.SetValue(nonPayloadExpl.GetValue() * avgPayloadScore);
result.SetDescription("bnq, product of:");
return result;
}
}
}
}