Skip to content

Commit 7881476

Browse files
committed
Fix fluent API break due to base class; update docs and add tests
1 parent 98a913e commit 7881476

5 files changed

Lines changed: 481 additions & 37 deletions

File tree

src/Lucene.Net.Grouping/AbstractDistinctValuesCollector.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,23 @@ namespace Lucene.Net.Search.Grouping
3232
/// <remarks>
3333
/// The <typeparamref name="TGroupValue"/> type parameter is LUCENENET specific to allow for
3434
/// strongly-typed group values.
35+
/// <para/>
36+
/// <b>Migration from 4.8.0-beta00017 and earlier:</b> This class previously had a single type
37+
/// parameter <c>GC</c> with a constraint of
38+
/// <c>AbstractDistinctValuesCollector.IGroupCount&lt;object&gt;</c>. It now has two type
39+
/// parameters: <typeparamref name="GC"/> and <typeparamref name="TGroupValue"/>. When migrating,
40+
/// add the group value type (typically <c>BytesRef</c> or <c>MutableValue</c>) as the second
41+
/// type argument. For example:
42+
/// <code>
43+
/// // Before:
44+
/// AbstractDistinctValuesCollector&lt;MyGroupCount&gt;
45+
///
46+
/// // After:
47+
/// AbstractDistinctValuesCollector&lt;MyGroupCount, BytesRef&gt;
48+
/// </code>
49+
/// Additionally, the <c>GC</c> constraint changed from
50+
/// <c>AbstractDistinctValuesCollector.IGroupCount&lt;object&gt;</c> to
51+
/// <c>AbstractDistinctValuesCollector.GroupCount&lt;TGroupValue&gt;</c>.
3552
/// </remarks>
3653
public abstract class AbstractDistinctValuesCollector<GC, TGroupValue> : IAbstractDistinctValuesCollector
3754
where GC : AbstractDistinctValuesCollector.GroupCount<TGroupValue>

src/Lucene.Net.Grouping/GroupingSearch.cs

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public static DocBlockGroupingSearch<TGroupValue> ByDocBlock<TGroupValue>(Filter
117117
/// The group field can only have one token per document. This means that the field must not be analysed.
118118
/// </summary>
119119
/// <seealso cref="GroupingSearch.ByField(string)"/>
120-
public class FieldGroupingSearch : AbstractFieldOrFunctionGroupingSearch<BytesRef>
120+
public class FieldGroupingSearch : AbstractFieldOrFunctionGroupingSearch<BytesRef, FieldGroupingSearch>
121121
{
122122
private readonly string groupField;
123123
private int initialSize = 128;
@@ -131,7 +131,7 @@ public FieldGroupingSearch(string groupField)
131131
this.groupField = groupField;
132132
}
133133

134-
/// <inheritdoc cref="AbstractGroupingSearch{T}.Search(IndexSearcher,Filter,Query,int,int)"/>
134+
/// <inheritdoc cref="AbstractGroupingSearch{T, TSelf}.Search(IndexSearcher,Filter,Query,int,int)"/>
135135
public override TopGroups<BytesRef> Search(IndexSearcher searcher, Filter filter, Query query, int groupOffset, int groupLimit)
136136
{
137137
int topN = groupOffset + groupLimit;
@@ -255,8 +255,8 @@ public override TopGroups<BytesRef> Search(IndexSearcher searcher, Filter filter
255255
/// This prevents growing data structures many times. This can improve the performance of the grouping at the cost of
256256
/// more initial RAM.
257257
/// <para>
258-
/// The <see cref="AbstractFieldOrFunctionGroupingSearch{T}.SetAllGroups(bool)"/> and
259-
/// <see cref="AbstractFieldOrFunctionGroupingSearch{T}.SetAllGroupHeads(bool)"/> features use this option.
258+
/// The <see cref="AbstractFieldOrFunctionGroupingSearch{T, TSelf}.SetAllGroups(bool)"/> and
259+
/// <see cref="AbstractFieldOrFunctionGroupingSearch{T, TSelf}.SetAllGroupHeads(bool)"/> features use this option.
260260
/// Defaults to 128.
261261
/// </para>
262262
/// </summary>
@@ -274,7 +274,7 @@ public virtual FieldGroupingSearch SetInitialSize(int initialSize)
274274
/// </summary>
275275
/// <typeparam name="T">The type of the mutable value</typeparam>
276276
/// <seealso cref="GroupingSearch.ByFunction{TMutableValue}(ValueSource, IDictionary)"/>
277-
public class FunctionGroupingSearch<T> : AbstractFieldOrFunctionGroupingSearch<T>
277+
public class FunctionGroupingSearch<T> : AbstractFieldOrFunctionGroupingSearch<T, FunctionGroupingSearch<T>>
278278
where T : MutableValue
279279
{
280280
private readonly ValueSource groupFunction;
@@ -291,7 +291,7 @@ public FunctionGroupingSearch(ValueSource groupFunction, IDictionary /* Map<?, ?
291291
this.valueSourceContext = valueSourceContext;
292292
}
293293

294-
/// <inheritdoc cref="AbstractGroupingSearch{T}.Search(IndexSearcher,Filter,Query,int,int)"/>
294+
/// <inheritdoc cref="AbstractGroupingSearch{T, TSelf}.Search(IndexSearcher,Filter,Query,int,int)"/>
295295
public override TopGroups<T> Search(IndexSearcher searcher, Filter filter, Query query, int groupOffset, int groupLimit)
296296
{
297297
int topN = groupOffset + groupLimit;
@@ -418,7 +418,7 @@ public override TopGroups<T> Search(IndexSearcher searcher, Filter filter, Query
418418
/// This class can only be used when documents belonging in a group are indexed in one block.
419419
/// </summary>
420420
/// <typeparam name="T">The type of the group value</typeparam>
421-
public class DocBlockGroupingSearch<T> : AbstractGroupingSearch<T>
421+
public class DocBlockGroupingSearch<T> : AbstractGroupingSearch<T, DocBlockGroupingSearch<T>>
422422
{
423423
private readonly Filter groupEndDocs;
424424

@@ -432,7 +432,7 @@ public DocBlockGroupingSearch(Filter groupEndDocs)
432432
this.groupEndDocs = groupEndDocs;
433433
}
434434

435-
/// <inheritdoc cref="AbstractGroupingSearch{T}.Search(IndexSearcher,Filter,Query,int,int)"/>
435+
/// <inheritdoc cref="AbstractGroupingSearch{T, TSelf}.Search(IndexSearcher,Filter,Query,int,int)"/>
436436
public override TopGroups<T> Search(IndexSearcher searcher, Filter filter, Query query, int groupOffset, int groupLimit)
437437
{
438438
int topN = groupOffset + groupLimit;
@@ -447,11 +447,13 @@ public override TopGroups<T> Search(IndexSearcher searcher, Filter filter, Query
447447
/// Abstract base class for grouping search implementations that groups documents by index terms or function.
448448
/// </summary>
449449
/// <typeparam name="T">The type of the group value</typeparam>
450+
/// <typeparam name="TSelf">The type of the concrete grouping search implementation, used for fluent method chaining</typeparam>
450451
/// <remarks>
451452
/// LUCENENET specific
452453
/// </remarks>
453454
/// <seealso cref="GroupingSearch"/>
454-
public abstract class AbstractFieldOrFunctionGroupingSearch<T> : AbstractGroupingSearch<T>
455+
public abstract class AbstractFieldOrFunctionGroupingSearch<T, TSelf> : AbstractGroupingSearch<T, TSelf>
456+
where TSelf : AbstractFieldOrFunctionGroupingSearch<T, TSelf>
455457
{
456458
// LUCENENET: Converted to protected properties
457459
protected bool IncludeMaxScore { get; private set; } = true;
@@ -473,12 +475,12 @@ public abstract class AbstractFieldOrFunctionGroupingSearch<T> : AbstractGroupin
473475
/// <param name="maxCacheRAMMB">The maximum amount in MB the cache is allowed to hold</param>
474476
/// <param name="cacheScores">Whether to cache the scores</param>
475477
/// <returns><c>this</c></returns>
476-
public virtual AbstractGroupingSearch<T> SetCachingInMB(double maxCacheRAMMB, bool cacheScores)
478+
public virtual TSelf SetCachingInMB(double maxCacheRAMMB, bool cacheScores)
477479
{
478480
this.MaxCacheRAMMB = maxCacheRAMMB;
479481
this.MaxDocsToCache = null;
480482
this.CacheScores = cacheScores;
481-
return this;
483+
return (TSelf)this;
482484
}
483485

484486
/// <summary>
@@ -489,34 +491,34 @@ public virtual AbstractGroupingSearch<T> SetCachingInMB(double maxCacheRAMMB, bo
489491
/// <param name="maxDocsToCache">The maximum number of documents the cache is allowed to hold</param>
490492
/// <param name="cacheScores">Whether to cache the scores</param>
491493
/// <returns><c>this</c></returns>
492-
public virtual AbstractGroupingSearch<T> SetCaching(int maxDocsToCache, bool cacheScores)
494+
public virtual TSelf SetCaching(int maxDocsToCache, bool cacheScores)
493495
{
494496
this.MaxDocsToCache = maxDocsToCache;
495497
this.MaxCacheRAMMB = null;
496498
this.CacheScores = cacheScores;
497-
return this;
499+
return (TSelf)this;
498500
}
499501

500502
/// <summary>
501503
/// Disables any enabled cache.
502504
/// </summary>
503505
/// <returns><c>this</c></returns>
504-
public virtual AbstractGroupingSearch<T> DisableCaching()
506+
public virtual TSelf DisableCaching()
505507
{
506508
this.MaxCacheRAMMB = null;
507509
this.MaxDocsToCache = null;
508-
return this;
510+
return (TSelf)this;
509511
}
510512

511513
/// <summary>
512514
/// Whether to include the score of the most relevant document per group.
513515
/// </summary>
514516
/// <param name="includeMaxScore">Whether to include the score of the most relevant document per group</param>
515517
/// <returns><c>this</c></returns>
516-
public virtual AbstractGroupingSearch<T> SetIncludeMaxScore(bool includeMaxScore)
518+
public virtual TSelf SetIncludeMaxScore(bool includeMaxScore)
517519
{
518520
this.IncludeMaxScore = includeMaxScore;
519-
return this;
521+
return (TSelf)this;
520522
}
521523

522524
/// <summary>
@@ -529,10 +531,10 @@ public virtual AbstractGroupingSearch<T> SetIncludeMaxScore(bool includeMaxScore
529531
/// </summary>
530532
/// <param name="allGroups">to also compute all groups matching the query</param>
531533
/// <returns><c>this</c></returns>
532-
public virtual AbstractGroupingSearch<T> SetAllGroups(bool allGroups)
534+
public virtual TSelf SetAllGroups(bool allGroups)
533535
{
534536
this.AllGroups = allGroups;
535-
return this;
537+
return (TSelf)this;
536538
}
537539

538540
/// <summary>
@@ -553,10 +555,10 @@ public virtual ICollection<T> GetAllMatchingGroups()
553555
/// </summary>
554556
/// <param name="allGroupHeads">Whether to compute all group heads (most relevant document per group) matching the query</param>
555557
/// <returns><c>this</c></returns>
556-
public virtual AbstractGroupingSearch<T> SetAllGroupHeads(bool allGroupHeads)
558+
public virtual TSelf SetAllGroupHeads(bool allGroupHeads)
557559
{
558560
this.AllGroupHeads = allGroupHeads;
559-
return this;
561+
return (TSelf)this;
560562
}
561563

562564
/// <summary>
@@ -573,11 +575,13 @@ public virtual IBits GetAllGroupHeads()
573575
/// Abstract base class for grouping search implementations.
574576
/// </summary>
575577
/// <typeparam name="T">The type of the group value</typeparam>
578+
/// <typeparam name="TSelf">The type of the concrete grouping search implementation, used for fluent method chaining</typeparam>
576579
/// <remarks>
577580
/// LUCENENET specific
578581
/// </remarks>
579582
/// <seealso cref="GroupingSearch"/>
580-
public abstract class AbstractGroupingSearch<T> : IAbstractGroupingSearch
583+
public abstract class AbstractGroupingSearch<T, TSelf> : IAbstractGroupingSearch
584+
where TSelf : AbstractGroupingSearch<T, TSelf>
581585
{
582586
// LUCENENET: Converted to protected properties
583587
protected Sort GroupSort { get; private set; } = Sort.RELEVANCE;
@@ -618,10 +622,10 @@ public TopGroups<T> Search(IndexSearcher searcher, Query query, int groupOffset,
618622
/// </summary>
619623
/// <param name="groupSort">The sort for the groups.</param>
620624
/// <returns><c>this</c></returns>
621-
public virtual AbstractGroupingSearch<T> SetGroupSort(Sort groupSort)
625+
public virtual TSelf SetGroupSort(Sort groupSort)
622626
{
623627
this.GroupSort = groupSort;
624-
return this;
628+
return (TSelf)this;
625629
}
626630

627631
/// <summary>
@@ -630,54 +634,54 @@ public virtual AbstractGroupingSearch<T> SetGroupSort(Sort groupSort)
630634
/// </summary>
631635
/// <param name="sortWithinGroup">The sort for documents inside a group</param>
632636
/// <returns><c>this</c></returns>
633-
public virtual AbstractGroupingSearch<T> SetSortWithinGroup(Sort sortWithinGroup)
637+
public virtual TSelf SetSortWithinGroup(Sort sortWithinGroup)
634638
{
635639
this.SortWithinGroup = sortWithinGroup;
636-
return this;
640+
return (TSelf)this;
637641
}
638642

639643
/// <summary>
640644
/// Specifies the offset for documents inside a group.
641645
/// </summary>
642646
/// <param name="groupDocsOffset">The offset for documents inside a</param>
643647
/// <returns><c>this</c></returns>
644-
public virtual AbstractGroupingSearch<T> SetGroupDocsOffset(int groupDocsOffset)
648+
public virtual TSelf SetGroupDocsOffset(int groupDocsOffset)
645649
{
646650
this.GroupDocsOffset = groupDocsOffset;
647-
return this;
651+
return (TSelf)this;
648652
}
649653

650654
/// <summary>
651655
/// Specifies the number of documents to return inside a group from the specified groupDocsOffset.
652656
/// </summary>
653657
/// <param name="groupDocsLimit">The number of documents to return inside a group</param>
654658
/// <returns><c>this</c></returns>
655-
public virtual AbstractGroupingSearch<T> SetGroupDocsLimit(int groupDocsLimit)
659+
public virtual TSelf SetGroupDocsLimit(int groupDocsLimit)
656660
{
657661
this.GroupDocsLimit = groupDocsLimit;
658-
return this;
662+
return (TSelf)this;
659663
}
660664

661665
/// <summary>
662666
/// Whether to also fill the sort fields per returned group and groups docs.
663667
/// </summary>
664668
/// <param name="fillSortFields">Whether to also fill the sort fields per returned group and groups docs</param>
665669
/// <returns><c>this</c></returns>
666-
public virtual AbstractGroupingSearch<T> SetFillSortFields(bool fillSortFields)
670+
public virtual TSelf SetFillSortFields(bool fillSortFields)
667671
{
668672
this.FillSortFields = fillSortFields;
669-
return this;
673+
return (TSelf)this;
670674
}
671675

672676
/// <summary>
673677
/// Whether to include the scores per doc inside a group.
674678
/// </summary>
675679
/// <param name="includeScores">Whether to include the scores per doc inside a group</param>
676680
/// <returns><c>this</c></returns>
677-
public virtual AbstractGroupingSearch<T> SetIncludeScores(bool includeScores)
681+
public virtual TSelf SetIncludeScores(bool includeScores)
678682
{
679683
this.IncludeScores = includeScores;
680-
return this;
684+
return (TSelf)this;
681685
}
682686

683687
#region Explicit interface implementations
@@ -694,7 +698,7 @@ ITopGroups IAbstractGroupingSearch.Search(IndexSearcher searcher, Filter filter,
694698
}
695699

696700
/// <summary>
697-
/// LUCENENET specific interface for non-generic access to <see cref="AbstractGroupingSearch{T}"/>.
701+
/// LUCENENET specific interface for non-generic access to <see cref="AbstractGroupingSearch{T, TSelf}"/>.
698702
/// </summary>
699703
public interface IAbstractGroupingSearch
700704
{

src/Lucene.Net.Grouping/package.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Known limitations:
7676
Typical usage for the generic two-pass grouping search looks like this using the grouping convenience utility (optionally using caching for the second pass search):
7777

7878
```cs
79-
GroupingSearch groupingSearch = new GroupingSearch("author");
79+
FieldGroupingSearch groupingSearch = GroupingSearch.ByField("author");
8080
groupingSearch.SetGroupSort(groupSort);
8181
groupingSearch.SetFillSortFields(fillFields);
8282

@@ -140,7 +140,7 @@ Or alternatively use the `GroupingSearch` convenience utility:
140140

141141
```cs
142142
// Per search:
143-
GroupingSearch groupingSearch = new GroupingSearch(groupEndDocs);
143+
DocBlockGroupingSearch<object> groupingSearch = GroupingSearch.ByDocBlock<object>(groupEndDocs);
144144
groupingSearch.SetGroupSort(groupSort);
145145
groupingSearch.SetIncludeScores(needsScores);
146146
TermQuery query = new TermQuery(new Term("content", searchTerm));

0 commit comments

Comments
 (0)