Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BREAKING: Remove covariance and LINQ use from Grouping, #1059 #1066

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
14795de
Break GroupingSearch into subclasses, #1059
paulirwin Dec 13, 2024
c0e8136
Fix failing tests
paulirwin Dec 13, 2024
0ab4690
Fix more failing unit tests; refactor out common AbstractFieldOrFunct…
paulirwin Dec 14, 2024
6c6b531
Remove IAbstractAllGroupsCollector<T> interface
paulirwin Dec 14, 2024
b36aca6
Make AbstractAllGroupsCollector.Groups be ICollection, remove some LI…
paulirwin Dec 14, 2024
8b54063
Remove ITopGroups and IAbstractSecondPassGroupingCollector interfaces
paulirwin Dec 14, 2024
c2a09d4
Remove IGroupDocs interface
paulirwin Dec 14, 2024
2e021c5
Remove IAbstractFirstPassGroupingCollector and ISearchGroup interface…
paulirwin Dec 15, 2024
cc6b1a2
Remove IAbstractDistinctValuesCollector interface
paulirwin Dec 15, 2024
4dfc917
Remove IGroupCount interface
paulirwin Dec 15, 2024
e1c5fb4
Remove IGroupCountCollector interface
paulirwin Dec 15, 2024
7116272
Remove IEnumerable/LINQ use in Grouping
paulirwin Dec 15, 2024
cb3e24b
Remove some O(n) extra list creation
paulirwin Dec 15, 2024
1c544b2
Remove some more IEnumerable spots
paulirwin Dec 15, 2024
8e8b3f7
Refactor to remove wrapping types and add back non-generic interfaces…
paulirwin Dec 15, 2024
4d07900
Return null if TopGroups returns null
paulirwin Dec 15, 2024
306766b
Add some XML doc comments
paulirwin Dec 15, 2024
833aea3
Add back removed XML comments during refactoring
paulirwin Dec 15, 2024
8acae9a
Add XML doc comments to GroupingSearch
paulirwin Dec 15, 2024
5fe9f7d
Add IAbstractGroupingSearch interface for symmetry with the other types
paulirwin Dec 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 19 additions & 14 deletions src/Lucene.Net.Grouping/AbstractAllGroupsCollector.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Lucene.Net.Index;
using Lucene.Net.Support;
using System.Collections.Generic;
using System.Linq;

namespace Lucene.Net.Search.Grouping
{
Expand All @@ -26,22 +26,22 @@ namespace Lucene.Net.Search.Grouping
/// query. Only the group value is collected, and the order
/// is undefined. This collector does not determine
/// the most relevant document of a group.
///
///
/// <para>
/// This is an abstract version. Concrete implementations define
/// what a group actually is and how it is internally collected.
/// </para>
/// @lucene.experimental
/// </summary>
/// <typeparam name="TGroupValue"></typeparam>
public abstract class AbstractAllGroupsCollector<TGroupValue> : IAbstractAllGroupsCollector<TGroupValue>
public abstract class AbstractAllGroupsCollector<TGroupValue> : IAbstractAllGroupsCollector
{
/// <summary>
/// Returns the total number of groups for the executed search.
/// This is a convenience method. The following code snippet has the same effect: <code>GetGroups().Count</code>
/// </summary>
/// <returns>The total number of groups for the executed search</returns>
public virtual int GroupCount => Groups.Count();
public virtual int GroupCount => Groups.Count;

/// <summary>
/// Returns the group values
Expand All @@ -51,7 +51,7 @@ public abstract class AbstractAllGroupsCollector<TGroupValue> : IAbstractAllGrou
/// </para>
/// </summary>
/// <returns>the group values</returns>
public abstract IEnumerable<TGroupValue> Groups { get; }
public abstract ICollection<TGroupValue> Groups { get; }


// Empty not necessary
Expand Down Expand Up @@ -88,29 +88,34 @@ public virtual void SetScorer(Scorer scorer)
public abstract void SetNextReader(AtomicReaderContext context);

public virtual bool AcceptsDocsOutOfOrder => true;

#region Explicit interface implementations

/// <summary>
/// LUCENENET specific method to provide an object-based implementation of <see cref="Groups"/>.
/// </summary>
ICollection<object> IAbstractAllGroupsCollector.Groups => new CastingCollectionAdapter<TGroupValue, object>(Groups);

#endregion
}

/// <summary>
/// LUCENENET specific interface used to apply covariance to TGroupValue
/// LUCENENET specific interface to provide a non-generic abstraction
/// for <see cref="AbstractAllGroupsCollector{TGroupValue}"/>.
/// </summary>
/// <typeparam name="TGroupValue"></typeparam>
public interface IAbstractAllGroupsCollector<out TGroupValue> : ICollector
public interface IAbstractAllGroupsCollector : ICollector
{
/// <summary>
/// Returns the total number of groups for the executed search.
/// This is a convenience method. The following code snippet has the same effect: <code>GetGroups().Count</code>
/// </summary>
/// <returns>The total number of groups for the executed search</returns>
int GroupCount { get; }

/// <summary>
/// Returns the group values
/// <para>
/// <para />
/// This is an unordered collections of group values. For each group that matched the query there is a <see cref="Util.BytesRef"/>
/// representing a group value.
/// </para>
/// </summary>
/// <returns>the group values</returns>
IEnumerable<TGroupValue> Groups { get; }
ICollection<object> Groups { get; }
}
}
73 changes: 51 additions & 22 deletions src/Lucene.Net.Grouping/AbstractDistinctValuesCollector.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Lucene.Net.Index;
using Lucene.Net.Support;
using System.Collections.Generic;
using JCG = J2N.Collections.Generic;

Expand All @@ -23,18 +24,23 @@ namespace Lucene.Net.Search.Grouping

/// <summary>
/// A second pass grouping collector that keeps track of distinct values for a specified field for the top N group.
///
///
/// @lucene.experimental
/// </summary>
/// <typeparam name="GC"></typeparam>
public abstract class AbstractDistinctValuesCollector<GC> : IAbstractDistinctValuesCollector<GC>
where GC : AbstractDistinctValuesCollector.IGroupCount<object>
/// <typeparam name="GC">The type of group counts</typeparam>
/// <typeparam name="TGroupValue">The type of the group values</typeparam>
/// <remarks>
/// The <typeparamref name="TGroupValue"/> type parameter is LUCENENET specific to allow for
/// strongly-typed group values.
/// </remarks>
public abstract class AbstractDistinctValuesCollector<GC, TGroupValue> : IAbstractDistinctValuesCollector
where GC : AbstractDistinctValuesCollector.GroupCount<TGroupValue>
{
/// <summary>
/// Returns all unique values for each top N group.
/// </summary>
/// <returns>all unique values for each top N group</returns>
public abstract IEnumerable<GC> Groups { get; }
public abstract IList<GC> Groups { get; }

public virtual bool AcceptsDocsOutOfOrder => true;

Expand Down Expand Up @@ -69,59 +75,82 @@ public virtual void SetScorer(Scorer scorer)
/// </summary>
/// <param name="context">next atomic reader context </param>
public abstract void SetNextReader(AtomicReaderContext context);

#region Explicit interface implementations

/// <summary>
/// LUCENENET specific implementation to provide a non-generic abstraction
/// </summary>
IList<AbstractDistinctValuesCollector.IGroupCount> IAbstractDistinctValuesCollector.Groups
=> new CastingListAdapter<GC, AbstractDistinctValuesCollector.IGroupCount>(Groups);

#endregion
}

/// <summary>
/// LUCENENET specific class used to nest the <see cref="GroupCount{TGroupValue}"/>
/// class so it has similar syntax to that in Java Lucene
/// (AbstractDistinctValuesCollector.GroupCount{TGroupValue} rather than
/// (AbstractDistinctValuesCollector.GroupCount{TGroupValue} rather than
/// AbstractDistinctValuesCollector{GC}.GroupCount{TGroupValue}).
/// </summary>
public static class AbstractDistinctValuesCollector // LUCENENET specific: CA1052 Static holder types should be Static or NotInheritable
{
/// <summary>
/// Returned by <see cref="AbstractDistinctValuesCollector{GC}.Groups"/>,
/// Returned by <see cref="AbstractDistinctValuesCollector{GC, TGroupValue}.Groups"/>,
/// representing the value and set of distinct values for the group.
/// </summary>
/// <typeparam name="TGroupValue"></typeparam>
/// <remarks>
/// LUCENENET - removed this class from being a nested class of
/// <see cref="AbstractDistinctValuesCollector{GC}"/> and renamed
/// from GroupCount to AbstractGroupCount
/// LUCENENET - removed this class from being a nested class of
/// <see cref="AbstractDistinctValuesCollector{GC, TGroupValue}"/>
/// </remarks>
public abstract class GroupCount<TGroupValue> : IGroupCount<TGroupValue>
public abstract class GroupCount<TGroupValue> : IGroupCount
{
public TGroupValue GroupValue { get; protected set; }
public IEnumerable<TGroupValue> UniqueValues { get; protected set; }
public ISet<TGroupValue> UniqueValues { get; protected set; }

protected GroupCount(TGroupValue groupValue) // LUCENENET: CA1012: Abstract types should not have constructors (marked protected)
{
this.GroupValue = groupValue;
this.UniqueValues = new JCG.HashSet<TGroupValue>();
}

#region Explicit interface implementations

/// <summary>
/// LUCENENET specific method to provide an object-based implementation of <see cref="GroupValue"/>.
/// </summary>
object IGroupCount.GroupValue => GroupValue;

/// <summary>
/// LUCENENET specific method to provide an object-based implementation of <see cref="UniqueValues"/>.
/// </summary>
ISet<object> IGroupCount.UniqueValues => new CastingSetAdapter<TGroupValue, object>(UniqueValues);

#endregion
}

/// <summary>
/// LUCENENET specific interface used to apply covariance to TGroupValue
/// LUCENENET specific interface to provide a non-generic abstraction
/// for <see cref="GroupCount{TGroupValue}"/>.
/// </summary>
/// <typeparam name="TGroupValue"></typeparam>
public interface IGroupCount<out TGroupValue>
public interface IGroupCount
{
TGroupValue GroupValue { get; }
IEnumerable<TGroupValue> UniqueValues { get; }
object GroupValue { get; }

ISet<object> UniqueValues { get; }
}
}

/// <summary>
/// LUCENENET specific interface used to apply covariance to GC
/// LUCENENET specific interface to provide a non-generic abstraction
/// for <see cref="AbstractDistinctValuesCollector{GC, TGroupValue}"/>.
/// </summary>
/// <typeparam name="GC"></typeparam>
public interface IAbstractDistinctValuesCollector<out GC> : ICollector
public interface IAbstractDistinctValuesCollector : ICollector
{
/// <summary>
/// Returns all unique values for each top N group.
/// </summary>
/// <returns>all unique values for each top N group</returns>
IEnumerable<GC> Groups { get; }
IList<AbstractDistinctValuesCollector.IGroupCount> Groups { get; }
}
}
42 changes: 27 additions & 15 deletions src/Lucene.Net.Grouping/AbstractFirstPassGroupingCollector.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using Lucene.Net.Diagnostics;
using Lucene.Net.Index;
using Lucene.Net.Support;
using Lucene.Net.Support.Threading;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using JCG = J2N.Collections.Generic;
Expand Down Expand Up @@ -32,15 +32,15 @@ namespace Lucene.Net.Search.Grouping
/// to collect grouped hits. This pass gathers the top N sorted
/// groups. Concrete subclasses define what a group is and how it
/// is internally collected.
///
///
/// <para>
/// See <a href="https://github.com/apache/lucene-solr/blob/releases/lucene-solr/4.8.0/lucene/grouping/src/java/org/apache/lucene/search/grouping/package.html">org.apache.lucene.search.grouping</a> for more
/// details including a full code example.
/// </para>
/// @lucene.experimental
/// </summary>
/// <typeparam name="TGroupValue"></typeparam>
public abstract class AbstractFirstPassGroupingCollector<TGroupValue> : IAbstractFirstPassGroupingCollector<TGroupValue>
public abstract class AbstractFirstPassGroupingCollector<TGroupValue> : IAbstractFirstPassGroupingCollector
{
private readonly Sort groupSort;
private readonly FieldComparer[] comparers;
Expand Down Expand Up @@ -106,7 +106,7 @@ protected AbstractFirstPassGroupingCollector(Sort groupSort, int topNGroups) //
/// <param name="groupOffset">The offset in the collected groups</param>
/// <param name="fillFields">Whether to fill to <see cref="SearchGroup{TGroupValue}.SortValues"/></param>
/// <returns>top groups, starting from offset</returns>
public virtual IEnumerable<ISearchGroup<TGroupValue>> GetTopGroups(int groupOffset, bool fillFields)
public virtual ICollection<SearchGroup<TGroupValue>> GetTopGroups(int groupOffset, bool fillFields)
{

//System.out.println("FP.getTopGroups groupOffset=" + groupOffset + " fillFields=" + fillFields + " groupMap.size()=" + groupMap.size());
Expand All @@ -126,7 +126,7 @@ public virtual IEnumerable<ISearchGroup<TGroupValue>> GetTopGroups(int groupOffs
BuildSortedSet();
}

ICollection<ISearchGroup<TGroupValue>> result = new JCG.List<ISearchGroup<TGroupValue>>();
ICollection<SearchGroup<TGroupValue>> result = new JCG.List<SearchGroup<TGroupValue>>();
int upto = 0;
int sortFieldCount = groupSort.GetSort().Length;
foreach (CollectedSearchGroup<TGroupValue> group in m_orderedGroups)
Expand Down Expand Up @@ -421,27 +421,39 @@ public virtual void SetNextReader(AtomicReaderContext context)
/// <returns>a copy of the specified group value</returns>
protected abstract TGroupValue CopyDocGroupValue(TGroupValue groupValue, TGroupValue reuse);

#region Explicit interface implementations

/// <summary>
/// LUCENENET specific method to provide an <see cref="ISearchGroup"/>-based implementation of <see cref="GetTopGroups(int, bool)"/>.
/// </summary>
/// <param name="groupOffset">The offset in the collected groups</param>
/// <param name="fillFields">Whether to fill to <see cref="ISearchGroup.SortValues"/></param>
/// <returns>top groups, starting from offset</returns>
ICollection<ISearchGroup> IAbstractFirstPassGroupingCollector.GetTopGroups(int groupOffset, bool fillFields)
{
var topGroups = GetTopGroups(groupOffset, fillFields);
return topGroups != null
? new CastingCollectionAdapter<SearchGroup<TGroupValue>, ISearchGroup>(topGroups)
: null;
}

#endregion
}

/// <summary>
/// LUCENENET specific interface used to apply covariance to TGroupValue
/// to simulate Java's wildcard generics.
/// LUCENENET specific interface to provide a non-generic abstraction
/// for <see cref="AbstractFirstPassGroupingCollector{TGroupValue}"/>.
/// </summary>
/// <typeparam name="TGroupValue"></typeparam>
public interface IAbstractFirstPassGroupingCollector<out TGroupValue> : ICollector
public interface IAbstractFirstPassGroupingCollector : ICollector
{
/// <summary>
/// Returns top groups, starting from offset. This may
/// return null, if no groups were collected, or if the
/// number of unique groups collected is &lt;= offset.
/// </summary>
/// <param name="groupOffset">The offset in the collected groups</param>
/// <param name="fillFields">Whether to fill to <see cref="SearchGroup{TGroupValue}.SortValues"/></param>
/// <param name="fillFields">Whether to fill to <see cref="ISearchGroup.SortValues"/></param>
/// <returns>top groups, starting from offset</returns>
/// <remarks>
/// LUCENENET NOTE: We must use <see cref="IEnumerable{TGroupValue}"/> rather than
/// <see cref="ICollection{TGroupValue}"/> here because we need this to be covariant
/// </remarks>
IEnumerable<ISearchGroup<TGroupValue>> GetTopGroups(int groupOffset, bool fillFields);
ICollection<ISearchGroup> GetTopGroups(int groupOffset, bool fillFields);
}
}
Loading
Loading