blob: e075efb8ec12b4c702cd20f49255ba31b235dee6 [file] [log] [blame]
// Lucene version compatibility level 4.8.1
using J2N.Runtime.CompilerServices;
using Lucene.Net.Index;
using Lucene.Net.Search;
using System;
using System.Collections;
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>
/// Instantiates <see cref="FunctionValues"/> for a particular reader.
/// <para/>
/// Often used when creating a <see cref="FunctionQuery"/>.
/// </summary>
public abstract class ValueSource
{
/// <summary>
/// Gets the values for this reader and the context that was previously
/// passed to <see cref="CreateWeight"/>
/// </summary>
public abstract FunctionValues GetValues(IDictionary context, AtomicReaderContext readerContext); // LUCENENET TODO: API - See if we can use generic IDictionary here instead
public override abstract bool Equals(object o);
public override abstract int GetHashCode();
/// <summary>
/// description of field, used in Explain()
/// </summary>
public abstract string GetDescription();
public override string ToString()
{
return GetDescription();
}
/// <summary>
/// Implementations should propagate CreateWeight to sub-ValueSources which can optionally store
/// weight info in the context. The context object will be passed to GetValues()
/// where this info can be retrieved.
/// </summary>
public virtual void CreateWeight(IDictionary context, IndexSearcher searcher)
{
}
/// <summary>
/// Returns a new non-threadsafe context map.
/// </summary>
public static IDictionary NewContext(IndexSearcher searcher)
{
return new Hashtable(IdentityEqualityComparer<object>.Default)
{
["searcher"] = searcher
};
}
//
// Sorting by function
//
/// <summary>
/// EXPERIMENTAL: This method is subject to change.
/// <para/>
/// Get the <see cref="SortField"/> for this <see cref="ValueSource"/>. Uses the <see cref="GetValues(IDictionary, AtomicReaderContext)"/>
/// to populate the <see cref="SortField"/>.
/// </summary>
/// <param name="reverse"> <c>true</c> if this is a reverse sort. </param>
/// <returns> The <see cref="SortField"/> for the <see cref="ValueSource"/> </returns>
public virtual SortField GetSortField(bool reverse)
{
return new ValueSourceSortField(this, reverse);
}
internal class ValueSourceSortField : SortField
{
private readonly ValueSource outerInstance;
public ValueSourceSortField(ValueSource outerInstance, bool reverse)
: base(outerInstance.GetDescription(), SortFieldType.REWRITEABLE, reverse)
{
this.outerInstance = outerInstance;
}
public override SortField Rewrite(IndexSearcher searcher)
{
var context = NewContext(searcher);
outerInstance.CreateWeight(context, searcher);
return new SortField(Field, new ValueSourceComparerSource(outerInstance, context), IsReverse);
}
}
internal class ValueSourceComparerSource : FieldComparerSource
{
private readonly ValueSource outerInstance;
private readonly IDictionary context;
public ValueSourceComparerSource(ValueSource outerInstance, IDictionary context)
{
this.outerInstance = outerInstance;
this.context = context;
}
public override FieldComparer NewComparer(string fieldname, int numHits, int sortPos, bool reversed)
{
return new ValueSourceComparer(outerInstance, context, numHits);
}
}
/// <summary>
/// Implement a <see cref="FieldComparer"/> that works
/// off of the <see cref="FunctionValues"/> for a <see cref="ValueSource"/>
/// instead of the normal Lucene <see cref="FieldComparer"/> that works off of a <see cref="FieldCache"/>.
/// </summary>
internal class ValueSourceComparer : FieldComparer<double?>
{
private readonly ValueSource outerInstance;
private readonly double[] values;
private FunctionValues docVals;
private double bottom;
private readonly IDictionary fcontext;
private double topValue;
internal ValueSourceComparer(ValueSource outerInstance, IDictionary fcontext, int numHits)
{
this.outerInstance = outerInstance;
this.fcontext = fcontext;
values = new double[numHits];
}
public override int Compare(int slot1, int slot2)
{
return values[slot1].CompareTo(values[slot2]);
}
public override int CompareBottom(int doc)
{
return bottom.CompareTo(docVals.DoubleVal(doc));
}
public override void Copy(int slot, int doc)
{
values[slot] = docVals.DoubleVal(doc);
}
public override FieldComparer SetNextReader(AtomicReaderContext context)
{
docVals = outerInstance.GetValues(fcontext, context);
return this;
}
public override void SetBottom(int slot)
{
this.bottom = values[slot];
}
public override void SetTopValue(object value)
{
this.topValue = (double)value;
}
// LUCENENET NOTE: This was value(int) in Lucene.
public override IComparable this[int slot] => values[slot];
public override int CompareTop(int doc)
{
double docValue = docVals.DoubleVal(doc);
return topValue.CompareTo(docValue);
}
}
}
}