blob: 251a33ec0c0b8e0693b3622267bc5dbf6d6b0138 [file] [log] [blame]
using System;
using System.Globalization;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Util;
using Lucene.Net.Util.Mutable;
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>
/// Represents field values as different types.
/// Normally created via a <see cref="ValueSource"/> for a particular field and reader.
/// </summary>
// FunctionValues is distinct from ValueSource because
// there needs to be an object created at query evaluation time that
// is not referenced by the query itself because:
// - Query objects should be MT safe
// - For caching, Query objects are often used as keys... you don't
// want the Query carrying around big objects
public abstract class FunctionValues
{
public virtual byte ByteVal(int doc)
{
throw new NotSupportedException();
}
/// <summary>
/// NOTE: This was shortVal() in Lucene
/// </summary>
public virtual short Int16Val(int doc)
{
throw new NotSupportedException();
}
/// <summary>
/// NOTE: This was floatVal() in Lucene
/// </summary>
public virtual float SingleVal(int doc)
{
throw new NotSupportedException();
}
/// <summary>
/// NOTE: This was intVal() in Lucene
/// </summary>
public virtual int Int32Val(int doc)
{
throw new NotSupportedException();
}
/// <summary>
/// NOTE: This was longVal() in Lucene
/// </summary>
public virtual long Int64Val(int doc)
{
throw new NotSupportedException();
}
public virtual double DoubleVal(int doc)
{
throw new NotSupportedException();
}
// TODO: should we make a termVal, returns BytesRef?
public virtual string StrVal(int doc)
{
throw new NotSupportedException();
}
public virtual bool BoolVal(int doc)
{
return Int32Val(doc) != 0;
}
/// <summary>
/// returns the bytes representation of the str val - TODO: should this return the indexed raw bytes not? </summary>
public virtual bool BytesVal(int doc, BytesRef target)
{
string s = StrVal(doc);
if (s == null)
{
target.Length = 0;
return false;
}
target.CopyChars(s);
return true;
}
/// <summary>
/// Native <see cref="object"/> representation of the value </summary>
public virtual object ObjectVal(int doc)
{
// most FunctionValues are functions, so by default return a Float()
return SingleVal(doc);
}
/// <summary>
/// Returns <c>true</c> if there is a value for this document </summary>
public virtual bool Exists(int doc)
{
return true;
}
/// <param name="doc"> The doc to retrieve to sort ordinal for </param>
/// <returns> the sort ordinal for the specified doc
/// TODO: Maybe we can just use intVal for this... </returns>
public virtual int OrdVal(int doc)
{
throw new NotSupportedException();
}
/// <returns> the number of unique sort ordinals this instance has </returns>
public virtual int NumOrd => throw new NotSupportedException();
public abstract string ToString(int doc);
/// <summary>
/// Abstraction of the logic required to fill the value of a specified doc into
/// a reusable <see cref="MutableValue"/>. Implementations of <see cref="FunctionValues"/>
/// are encouraged to define their own implementations of <see cref="ValueFiller"/> if their
/// value is not a <see cref="float"/>.
///
/// @lucene.experimental
/// </summary>
public abstract class ValueFiller
{
/// <summary>
/// <see cref="MutableValue"/> will be reused across calls </summary>
public abstract MutableValue Value { get; }
/// <summary>
/// <see cref="MutableValue"/> will be reused across calls. Returns <c>true</c> if the value exists. </summary>
public abstract void FillValue(int doc);
/// <summary>
/// This class may be used to create <see cref="ValueFiller"/> instances anonymously.
/// </summary>
// LUCENENET specific - used to mimick the inline class behavior in Java.
internal class AnonymousValueFiller<T> : ValueFiller where T : MutableValue
{
private readonly T mutableValue;
private readonly Action<int, T> fillValue;
public AnonymousValueFiller(T mutableValue, Action<int, T> fillValue)
{
this.mutableValue = mutableValue ?? throw new ArgumentNullException(nameof(mutableValue));
this.fillValue = fillValue ?? throw new ArgumentNullException(nameof(fillValue));
}
public override MutableValue Value => mutableValue;
public override void FillValue(int doc)
{
fillValue(doc, mutableValue);
}
}
}
/// <summary>
/// @lucene.experimental </summary>
public virtual ValueFiller GetValueFiller()
{
return new ValueFiller.AnonymousValueFiller<MutableValueSingle>(new MutableValueSingle(), fillValue: (doc, mutableValue) =>
{
mutableValue.Value = SingleVal(doc);
});
}
//For Functions that can work with multiple values from the same document. This does not apply to all functions
public virtual void ByteVal(int doc, byte[] vals)
{
throw new NotSupportedException();
}
/// <summary>
/// NOTE: This was shortVal() in Lucene
/// </summary>
public virtual void Int16Val(int doc, short[] vals)
{
throw new NotSupportedException();
}
/// <summary>
/// NOTE: This was floatVal() in Lucene
/// </summary>
public virtual void SingleVal(int doc, float[] vals)
{
throw new NotSupportedException();
}
/// <summary>
/// NOTE: This was intVal() in Lucene
/// </summary>
public virtual void Int32Val(int doc, int[] vals)
{
throw new NotSupportedException();
}
/// <summary>
/// NOTE: This was longVal() in Lucene
/// </summary>
public virtual void Int64Val(int doc, long[] vals)
{
throw new NotSupportedException();
}
public virtual void DoubleVal(int doc, double[] vals)
{
throw new NotSupportedException();
}
// TODO: should we make a termVal, fills BytesRef[]?
public virtual void StrVal(int doc, string[] vals)
{
throw new NotSupportedException();
}
public virtual Explanation Explain(int doc)
{
return new Explanation(SingleVal(doc), ToString(doc));
}
public virtual ValueSourceScorer GetScorer(IndexReader reader)
{
return new ValueSourceScorer(reader, this);
}
// A RangeValueSource can't easily be a ValueSource that takes another ValueSource
// because it needs different behavior depending on the type of fields. There is also
// a setup cost - parsing and normalizing params, and doing a binary search on the StringIndex.
// TODO: change "reader" to AtomicReaderContext
public virtual ValueSourceScorer GetRangeScorer(IndexReader reader, string lowerVal, string upperVal,
bool includeLower, bool includeUpper)
{
float lower;
float upper;
if (lowerVal == null)
{
lower = float.NegativeInfinity;
}
else
{
lower = Convert.ToSingle(lowerVal, CultureInfo.InvariantCulture);
}
if (upperVal == null)
{
upper = float.PositiveInfinity;
}
else
{
upper = Convert.ToSingle(upperVal, CultureInfo.InvariantCulture);
}
float l = lower;
float u = upper;
if (includeLower && includeUpper)
{
return new ValueSourceScorer.AnonymousValueSourceScorer(reader, this, matchesValue: (doc) =>
{
float docVal = SingleVal(doc);
return docVal >= l && docVal <= u;
});
}
else if (includeLower && !includeUpper)
{
return new ValueSourceScorer.AnonymousValueSourceScorer(reader, this, matchesValue: (doc) =>
{
float docVal = SingleVal(doc);
return docVal >= l && docVal < u;
});
}
else if (!includeLower && includeUpper)
{
return new ValueSourceScorer.AnonymousValueSourceScorer(reader, this, matchesValue: (doc) =>
{
float docVal = SingleVal(doc);
return docVal > l && docVal <= u;
});
}
else
{
return new ValueSourceScorer.AnonymousValueSourceScorer(reader, this, matchesValue: (doc) =>
{
float docVal = SingleVal(doc);
return docVal > l && docVal < u;
});
}
}
}
}