Skip to content

Commit

Permalink
BREAKING: Lucene.Net.Search.FieldComparer: Redesigned implementation …
Browse files Browse the repository at this point in the history
…to use reference types for numerics (from J2N) to avoid boxing (fixes #429)
  • Loading branch information
NightOwl888 committed Dec 11, 2021
1 parent 142035c commit 0f44778
Show file tree
Hide file tree
Showing 29 changed files with 336 additions and 277 deletions.
10 changes: 4 additions & 6 deletions src/Lucene.Net.Expressions/ExpressionComparator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
using Lucene.Net.Search;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using JCG = J2N.Collections.Generic;

namespace Lucene.Net.Expressions
Expand All @@ -28,7 +26,7 @@ namespace Lucene.Net.Expressions
*/

/// <summary>A custom comparer for sorting documents by an expression</summary>
internal class ExpressionComparer : FieldComparer<double>
internal class ExpressionComparer : FieldComparer<J2N.Numerics.Double>
{
private readonly double[] values;
private double bottom;
Expand Down Expand Up @@ -75,9 +73,9 @@ public override void SetBottom(int slot)
bottom = values[slot];
}

public override void SetTopValue(object value)
public override void SetTopValue(J2N.Numerics.Double value)
{
topValue = (double)value;
topValue = value ?? throw new ArgumentNullException(nameof(value)); // LUCENENET specific - throw ArgumentNullException rather than getting a cast exception
}

public override int CompareBottom(int doc)
Expand All @@ -98,7 +96,7 @@ public override FieldComparer SetNextReader(AtomicReaderContext context)
}

// LUCENENET NOTE: This was value(int) in Lucene.
public override IComparable this[int slot] => values[slot];
public override J2N.Numerics.Double this[int slot] => values[slot]; // LUCENENET NOTE: Implicit cast will instantiate new instance

public override int CompareTop(int doc)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ public virtual IEnumerable<ISearchGroup<TGroupValue>> GetTopGroups(int groupOffs
searchGroup.SortValues = new object[sortFieldCount];
for (int sortFieldIDX = 0; sortFieldIDX < sortFieldCount; sortFieldIDX++)
{
searchGroup.SortValues[sortFieldIDX] = comparers[sortFieldIDX][group.ComparerSlot];
searchGroup.SortValues[sortFieldIDX] = comparers[sortFieldIDX].GetValue(group.ComparerSlot);
}
}
result.Add(searchGroup);
Expand Down
4 changes: 2 additions & 2 deletions src/Lucene.Net.Grouping/BlockGroupingCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -437,10 +437,10 @@ public virtual ITopGroups<TGroupValue> GetTopGroups<TGroupValue>(Sort withinGrou

if (fillSortFields)
{
groupSortValues = new IComparable[comparers.Length];
groupSortValues = new object[comparers.Length];
for (int sortFieldIDX = 0; sortFieldIDX < comparers.Length; sortFieldIDX++)
{
groupSortValues[sortFieldIDX] = comparers[sortFieldIDX][og.comparerSlot];
groupSortValues[sortFieldIDX] = comparers[sortFieldIDX].GetValue(og.comparerSlot);
}
}
else
Expand Down
2 changes: 1 addition & 1 deletion src/Lucene.Net.Join/Support/ToParentBlockJoinCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ private ITopGroups<int> AccumulateGroups(int slot, int offset, int maxDocsPerGro
groupSortValues = new object[comparers.Length];
for (int sortFieldIdx = 0; sortFieldIdx < comparers.Length; sortFieldIdx++)
{
groupSortValues[sortFieldIdx] = comparers[sortFieldIdx][og.Slot];
groupSortValues[sortFieldIdx] = comparers[sortFieldIdx].GetValue(og.Slot);
}
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ private static FixedBitSet ToFixedBitSet(DocIdSetIterator iterator, int numBits)
}

// LUCENENET NOTE: This was value(int) in Lucene.
public override IComparable this[int slot] => _wrappedComparer[slot];
public override object this[int slot] => _wrappedComparer.GetValue(slot);

/// <summary>
/// Concrete implementation of <see cref="ToParentBlockJoinSortField"/> to sorts the parent docs with the lowest values
Expand Down
2 changes: 1 addition & 1 deletion src/Lucene.Net.Join/ToParentBlockJoinCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ private ITopGroups<int> AccumulateGroups(int slot, int offset, int maxDocsPerGro
groupSortValues = new object[comparers.Length];
for (int sortFieldIdx = 0; sortFieldIdx < comparers.Length; sortFieldIdx++)
{
groupSortValues[sortFieldIdx] = comparers[sortFieldIdx][og.Slot];
groupSortValues[sortFieldIdx] = comparers[sortFieldIdx].GetValue(og.Slot);
}
}
else
Expand Down
2 changes: 1 addition & 1 deletion src/Lucene.Net.Join/ToParentBlockJoinFieldComparator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ private static FixedBitSet ToFixedBitSet(DocIdSetIterator iterator, int numBits)
}

// LUCENENET NOTE: This was value(int) in Lucene.
public override IComparable this[int slot] => _wrappedComparer[slot];
public override object this[int slot] => _wrappedComparer.GetValue(slot);

/// <summary>
/// Concrete implementation of <see cref="ToParentBlockJoinSortField"/> to sorts the parent docs with the lowest values
Expand Down
6 changes: 3 additions & 3 deletions src/Lucene.Net.Misc/Index/Sorter/BlockJoinComparatorSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public override FieldComparer NewComparer(string fieldname, int numHits, int sor
childSlots, parentReverseMul, parentComparers, childReverseMul, childComparers);
}

private class FieldComparerAnonymousClass : FieldComparer<int?>
private class FieldComparerAnonymousClass : FieldComparer<J2N.Numerics.Int32>
{
private readonly BlockJoinComparerSource outerInstance;

Expand Down Expand Up @@ -145,7 +145,7 @@ public override void SetBottom(int slot)
bottomChild = childSlots[slot];
}

public override void SetTopValue(object value)
public override void SetTopValue(J2N.Numerics.Int32 value)
{
// we dont have enough information (the docid is needed)
throw UnsupportedOperationException.Create("this comparer cannot be used with deep paging");
Expand Down Expand Up @@ -193,7 +193,7 @@ public override FieldComparer SetNextReader(AtomicReaderContext context)
}

// LUCENENET NOTE: This was value(int) in Lucene.
public override IComparable this[int slot] => throw
public override J2N.Numerics.Int32 this[int slot] => throw
// really our sort "value" is more complex...
UnsupportedOperationException.Create("filling sort field values is not yet supported");

Expand Down
18 changes: 11 additions & 7 deletions src/Lucene.Net.Queries/Function/ValueSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Lucene.Net.Search;
using System;
using System.Collections;
using JCG = J2N.Collections.Generic;

namespace Lucene.Net.Queries.Function
{
Expand Down Expand Up @@ -131,7 +132,7 @@ public override FieldComparer NewComparer(string fieldname, int numHits, int sor
/// 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?>
internal class ValueSourceComparer : FieldComparer<J2N.Numerics.Double>
{
private readonly ValueSource outerInstance;

Expand All @@ -150,12 +151,14 @@ internal ValueSourceComparer(ValueSource outerInstance, IDictionary fcontext, in

public override int Compare(int slot1, int slot2)
{
return values[slot1].CompareTo(values[slot2]);
// LUCENENET specific - use JCG comparer to get the same logic as Java
return JCG.Comparer<double>.Default.Compare(values[slot1], values[slot2]);
}

public override int CompareBottom(int doc)
{
return bottom.CompareTo(docVals.DoubleVal(doc));
// LUCENENET specific - use JCG comparer to get the same logic as Java
return JCG.Comparer<double>.Default.Compare(bottom, docVals.DoubleVal(doc));
}

public override void Copy(int slot, int doc)
Expand All @@ -174,18 +177,19 @@ public override void SetBottom(int slot)
this.bottom = values[slot];
}

public override void SetTopValue(object value)
public override void SetTopValue(J2N.Numerics.Double value)
{
this.topValue = (double)value;
this.topValue = value ?? throw new ArgumentNullException(nameof(value)); // LUCENENET specific - throw ArgumentNullException rather than getting a cast exception
}

// LUCENENET NOTE: This was value(int) in Lucene.
public override IComparable this[int slot] => values[slot];
public override J2N.Numerics.Double this[int slot] => values[slot]; // LUCENENET NOTE: Implicit cast will instantiate new instance

public override int CompareTop(int doc)
{
double docValue = docVals.DoubleVal(doc);
return topValue.CompareTo(docValue);
// LUCENENET specific - use JCG comparer to get the same logic as Java
return JCG.Comparer<double>.Default.Compare(topValue, docValue);
}
}
}
Expand Down
14 changes: 5 additions & 9 deletions src/Lucene.Net.Sandbox/Queries/SortedSetSortField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace Lucene.Net.Sandbox.Queries
/// (see below) to ensure that all selections happen in constant-time for performance.
/// <para/>
/// Like sorting by string, this also supports sorting missing values as first or last,
/// via <see cref="MissingValue"/>.
/// via <see cref="SortField.SetMissingValue(object)"/>.
/// <para/>
/// Limitations:
/// <list type="bullet">
Expand Down Expand Up @@ -132,17 +132,13 @@ public override string ToString()
/// Note that this must be <see cref="SortField.STRING_FIRST"/> or
/// <see cref="SortField.STRING_LAST"/>.
/// </summary>
public override object MissingValue
public override void SetMissingValue(object value)
{
get => base.m_missingValue;
set
if (value != STRING_FIRST && value != STRING_LAST)
{
if (value != STRING_FIRST && value != STRING_LAST)
{
throw new ArgumentException("For SORTED_SET type, missing value must be either STRING_FIRST or STRING_LAST");
}
base.m_missingValue = value;
throw new ArgumentException("For SORTED_SET type, missing value must be either STRING_FIRST or STRING_LAST");
}
base.m_missingValue = value;
}

private class TermOrdValComparerAnonymousClass : FieldComparer.TermOrdValComparer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ protected internal virtual IList<LookupResult> CreateResults(IndexSearcher searc
FieldDoc fd = (FieldDoc)hits.ScoreDocs[i];
textDV.Get(fd.Doc, scratch);
string text = scratch.Utf8ToString();
long score = (long)fd.Fields[0];
long score = (J2N.Numerics.Int64)fd.Fields[0];

BytesRef payload;
if (payloadsDV != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ protected override FieldType GetTextFieldType()

textDV.Get(fd.Doc, scratch);
string text = scratch.Utf8ToString();
long weight = (long)fd.Fields[0];
long weight = (J2N.Numerics.Int64)fd.Fields[0];

BytesRef payload;
if (payloadsDV != null)
Expand Down
14 changes: 7 additions & 7 deletions src/Lucene.Net.Tests.Expressions/TestDemoExpressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public virtual void TestSortValues()
{
FieldDoc d = (FieldDoc)td.ScoreDocs[i];
float expected = (float)Math.Sqrt(d.Score);
float actual = (float)((double)d.Fields[0]);
float actual = ((J2N.Numerics.Double)d.Fields[0]).ToSingle();
Assert.AreEqual(expected, actual, CheckHits.ExplainToleranceDelta(expected, actual));
}
}
Expand All @@ -138,7 +138,7 @@ public virtual void TestTwoOfSameBinding()
{
FieldDoc d = (FieldDoc)td.ScoreDocs[i];
float expected = 2 * d.Score;
float actual = (float)((double)d.Fields[0]);
float actual = ((J2N.Numerics.Double)d.Fields[0]).ToSingle();
Assert.AreEqual(expected, actual, CheckHits.ExplainToleranceDelta
(expected, actual));
}
Expand All @@ -160,7 +160,7 @@ public virtual void TestExpressionRefersToExpression()
{
FieldDoc d = (FieldDoc)td.ScoreDocs[i];
float expected = 2 * d.Score;
float actual = (float)((double)d.Fields[0]);
float actual = ((J2N.Numerics.Double)d.Fields[0]).ToSingle();
Assert.AreEqual(expected, actual, CheckHits.ExplainToleranceDelta
(expected, actual));
}
Expand Down Expand Up @@ -199,7 +199,7 @@ private void DoTestLotsOfBindings(int n)
{
FieldDoc d = (FieldDoc)td.ScoreDocs[i_1];
float expected = n * d.Score;
float actual = (float)((double)d.Fields[0]);
float actual = ((J2N.Numerics.Double)d.Fields[0]).ToSingle();
Assert.AreEqual(expected, actual, CheckHits.ExplainToleranceDelta(expected, actual));
}
}
Expand All @@ -214,11 +214,11 @@ public virtual void TestDistanceSort()
Sort sort = new Sort(distance.GetSortField(bindings, false));
TopFieldDocs td = searcher.Search(new MatchAllDocsQuery(), null, 3, sort);
FieldDoc d = (FieldDoc)td.ScoreDocs[0];
Assert.AreEqual(0.4619D, (double)d.Fields[0], 1E-4);
Assert.AreEqual(0.4619D, (J2N.Numerics.Double)d.Fields[0], 1E-4);
d = (FieldDoc)td.ScoreDocs[1];
Assert.AreEqual(1.0546D, (double)d.Fields[0], 1E-4);
Assert.AreEqual(1.0546D, (J2N.Numerics.Double)d.Fields[0], 1E-4);
d = (FieldDoc)td.ScoreDocs[2];
Assert.AreEqual(5.2842D, (double)d.Fields[0], 1E-4);
Assert.AreEqual(5.2842D, (J2N.Numerics.Double)d.Fields[0], 1E-4);
}
}
}
12 changes: 7 additions & 5 deletions src/Lucene.Net.Tests.Grouping/TestGrouping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,8 @@ private IComparer<GroupDoc> GetComparer(Sort sort)
});
}

// LUCENENET NOTE: IComparable because in Java it was IComparable<?>, but note that
// there is no reason it cannot be object here because nothing actually calls IComparable.Compare().
private IComparable[] FillFields(GroupDoc d, Sort sort)
{
SortField[] sortFields = sort.GetSort();
Expand All @@ -492,7 +494,7 @@ private IComparable[] FillFields(GroupDoc d, Sort sort)
SortField sf = sortFields[fieldIDX];
if (sf.Type == SortFieldType.SCORE)
{
c = new float?(d.score);
c = J2N.Numerics.Single.GetInstance(d.score);
}
else if (sf.Field.Equals("sort1", StringComparison.Ordinal))
{
Expand All @@ -505,7 +507,7 @@ private IComparable[] FillFields(GroupDoc d, Sort sort)
else
{
assertEquals("id", sf.Field);
c = new int?(d.id);
c = J2N.Numerics.Int32.GetInstance(d.id);
}
fields[fieldIDX] = c;
}
Expand Down Expand Up @@ -963,15 +965,15 @@ public virtual void TestRandom()
// ReaderBlocks only increases maxDoc() vs reader, which
// means a monotonic shift in scores, so we can
// reliably remap them w/ Map:
IDictionary<string, IDictionary<float, float>> scoreMap = new Dictionary<string, IDictionary<float, float>>();
IDictionary<string, IDictionary<float, J2N.Numerics.Single>> scoreMap = new Dictionary<string, IDictionary<float, J2N.Numerics.Single>>();

// Tricky: must separately set .score2, because the doc
// block index was created with possible deletions!
//Console.WriteLine("fixup score2");
for (int contentID = 0; contentID < 3; contentID++)
{
//Console.WriteLine(" term=real" + contentID);
IDictionary<float, float> termScoreMap = new Dictionary<float, float>();
IDictionary<float, J2N.Numerics.Single> termScoreMap = new Dictionary<float, J2N.Numerics.Single>();
scoreMap.Put("real" + contentID, termScoreMap);
//Console.WriteLine("term=real" + contentID + " dfold=" + s.docFreq(new Term("content", "real"+contentID)) +
//" dfnew=" + sBlocks.docFreq(new Term("content", "real"+contentID)));
Expand Down Expand Up @@ -1366,7 +1368,7 @@ public virtual void TestRandom()
}

SortField[] sortFields = groupSort.GetSort();
IDictionary<float, float> termScoreMap = scoreMap[searchTerm];
IDictionary<float, J2N.Numerics.Single> termScoreMap = scoreMap[searchTerm];
for (int groupSortIDX = 0; groupSortIDX < sortFields.Length; groupSortIDX++)
{
if (sortFields[groupSortIDX].Type == SortFieldType.SCORE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public void TestSearchAfterWhenSortingByFunctionValues()
assertEquals(NUM_VALS - (afterIdx + 1), hits.ScoreDocs.Length);

// Verify that hits are actually "after"
int afterValue = (int)((double?)afterHit.Fields[0]);
int afterValue = ((J2N.Numerics.Double)afterHit.Fields[0]).ToInt32();
foreach (ScoreDoc hit in hits.ScoreDocs)
{
int val = Convert.ToInt32(reader.Document(hit.Doc).Get("value"), CultureInfo.InvariantCulture);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public void TestMissingFirst()

IndexSearcher searcher = NewSearcher(ir);
SortField sortField = new SortedSetSortField("value", false);
sortField.MissingValue = SortField.STRING_FIRST;
sortField.SetMissingValue(SortField.STRING_FIRST);
Sort sort = new Sort(sortField);

TopDocs td = searcher.Search(new MatchAllDocsQuery(), 10, sort);
Expand Down Expand Up @@ -164,7 +164,7 @@ public void TestMissingLast()

IndexSearcher searcher = NewSearcher(ir);
SortField sortField = new SortedSetSortField("value", false);
sortField.MissingValue = SortField.STRING_LAST;
sortField.SetMissingValue(SortField.STRING_LAST);
Sort sort = new Sort(sortField);

TopDocs td = searcher.Search(new MatchAllDocsQuery(), 10, sort);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public void TestMissingFirst()

IndexSearcher searcher = NewSearcher(ir);
SortField sortField = new SortedSetSortField("value", false);
sortField.MissingValue = SortField.STRING_FIRST;
sortField.SetMissingValue(SortField.STRING_FIRST);
Sort sort = new Sort(sortField);

TopDocs td = searcher.Search(new MatchAllDocsQuery(), 10, sort);
Expand Down Expand Up @@ -180,7 +180,7 @@ public void TestMissingLast()

IndexSearcher searcher = NewSearcher(ir);
SortField sortField = new SortedSetSortField("value", false);
sortField.MissingValue = SortField.STRING_LAST;
sortField.SetMissingValue(SortField.STRING_LAST);
Sort sort = new Sort(sortField);

TopDocs td = searcher.Search(new MatchAllDocsQuery(), 10, sort);
Expand Down
Loading

0 comments on commit 0f44778

Please sign in to comment.