blob: 8178834dbe3e0c2232b9e6daa1911f04e4904463 [file] [log] [blame]
// Lucene version compatibility level 4.8.1
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Util;
using Lucene.Net.Util.Mutable;
using System;
#if FEATURE_SERIALIZABLE_EXCEPTIONS
using System.Runtime.Serialization;
#endif
namespace Lucene.Net.Queries.Function.DocValues
{
/*
* 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>
/// Serves as base class for <see cref="FunctionValues"/> based on DocTermsIndex.
/// @lucene.internal
/// </summary>
public abstract class DocTermsIndexDocValues : FunctionValues
{
protected readonly SortedDocValues m_termsIndex;
protected readonly ValueSource m_vs;
protected readonly MutableValueStr m_val = new MutableValueStr();
protected readonly BytesRef m_spare = new BytesRef();
protected readonly CharsRef m_spareChars = new CharsRef();
protected DocTermsIndexDocValues(ValueSource vs, AtomicReaderContext context, string field) // LUCENENET: CA1012: Abstract types should not have constructors (marked protected)
{
try
{
m_termsIndex = FieldCache.DEFAULT.GetTermsIndex(context.AtomicReader, field);
}
catch (Exception e)
{
throw new DocTermsIndexException(field, e);
}
this.m_vs = vs;
}
protected abstract string ToTerm(string readableValue);
public override bool Exists(int doc)
{
return OrdVal(doc) >= 0;
}
public override int OrdVal(int doc)
{
return m_termsIndex.GetOrd(doc);
}
public override int NumOrd => m_termsIndex.ValueCount;
public override bool BytesVal(int doc, BytesRef target)
{
m_termsIndex.Get(doc, target);
return target.Length > 0;
}
public override string StrVal(int doc)
{
m_termsIndex.Get(doc, m_spare);
if (m_spare.Length == 0)
{
return null;
}
UnicodeUtil.UTF8toUTF16(m_spare, m_spareChars);
return m_spareChars.ToString();
}
public override bool BoolVal(int doc)
{
return Exists(doc);
}
public override abstract object ObjectVal(int doc); // force subclasses to override
public override ValueSourceScorer GetRangeScorer(IndexReader reader, string lowerVal, string upperVal, bool includeLower, bool includeUpper)
{
// TODO: are lowerVal and upperVal in indexed form or not?
lowerVal = lowerVal == null ? null : ToTerm(lowerVal);
upperVal = upperVal == null ? null : ToTerm(upperVal);
int lower = int.MinValue;
if (lowerVal != null)
{
lower = m_termsIndex.LookupTerm(new BytesRef(lowerVal));
if (lower < 0)
{
lower = -lower - 1;
}
else if (!includeLower)
{
lower++;
}
}
int upper = int.MaxValue;
if (upperVal != null)
{
upper = m_termsIndex.LookupTerm(new BytesRef(upperVal));
if (upper < 0)
{
upper = -upper - 2;
}
else if (!includeUpper)
{
upper--;
}
}
int ll = lower;
int uu = upper;
return new ValueSourceScorer.AnonymousValueSourceScorer(reader, this, matchesValue: (doc) =>
{
int ord = m_termsIndex.GetOrd(doc);
return ord >= ll && ord <= uu;
});
}
public override string ToString(int doc)
{
return m_vs.GetDescription() + '=' + StrVal(doc);
}
public override ValueFiller GetValueFiller()
{
return new ValueFiller.AnonymousValueFiller<MutableValueStr>(new MutableValueStr(), fillValue: (doc, mutableValue) =>
{
int ord = m_termsIndex.GetOrd(doc);
if (ord == -1)
{
mutableValue.Value.Bytes = BytesRef.EMPTY_BYTES;
mutableValue.Value.Offset = 0;
mutableValue.Value.Length = 0;
mutableValue.Exists = false;
}
else
{
m_termsIndex.LookupOrd(ord, mutableValue.Value);
mutableValue.Exists = true;
}
});
}
/// <summary>
/// Custom <see cref="Exception"/> to be thrown when the DocTermsIndex for a field cannot be generated
/// </summary>
// LUCENENET: It is no longer good practice to use binary serialization.
// See: https://github.com/dotnet/corefx/issues/23584#issuecomment-325724568
#if FEATURE_SERIALIZABLE_EXCEPTIONS
[Serializable]
#endif
public sealed class DocTermsIndexException : Exception
{
public DocTermsIndexException(string fieldName, Exception cause)
: base("Can't initialize DocTermsIndex to generate (function) FunctionValues for field: " + fieldName, cause)
{
}
#if FEATURE_SERIALIZABLE_EXCEPTIONS
// For testing
public DocTermsIndexException(string message)
: base(message)
{
}
/// <summary>
/// Initializes a new instance of this class with serialized data.
/// </summary>
/// <param name="info">The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The <see cref="StreamingContext"/> that contains contextual information about the source or destination.</param>
private DocTermsIndexException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
#endif
}
}
}