| 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; |
| }); |
| } |
| } |
| } |
| } |