From bb781d573830fb3d9c16c8f522d83a8ba598b5ce Mon Sep 17 00:00:00 2001
From: Paul Irwin
Date: Tue, 31 Dec 2024 16:06:26 -0700
Subject: [PATCH 1/3] Add CancellationToken parameter to IndexSearcher methods,
#922
---
.../Search/AssertingIndexSearcher.cs | 7 +-
.../Search/CheckHits.cs | 17 +--
.../Search/ShardSearchingTestBase.cs | 25 ++--
.../Search/TestBooleanQuery.cs | 5 +-
.../Search/TestCustomSearcherSort.cs | 9 +-
.../Search/CollectionTerminatedException.cs | 5 +-
src/Lucene.Net/Search/FieldComparator.cs | 22 ++--
src/Lucene.Net/Search/FieldDoc.cs | 5 +-
src/Lucene.Net/Search/FieldValueHitQueue.cs | 7 +-
src/Lucene.Net/Search/IndexSearcher.cs | 114 +++++++++---------
src/Lucene.Net/Search/Sort.cs | 5 +-
src/Lucene.Net/Search/TopDocs.cs | 5 +-
src/Lucene.Net/Search/TopFieldDocs.cs | 7 +-
13 files changed, 124 insertions(+), 109 deletions(-)
diff --git a/src/Lucene.Net.TestFramework/Search/AssertingIndexSearcher.cs b/src/Lucene.Net.TestFramework/Search/AssertingIndexSearcher.cs
index a6ab53113b..104e4df054 100644
--- a/src/Lucene.Net.TestFramework/Search/AssertingIndexSearcher.cs
+++ b/src/Lucene.Net.TestFramework/Search/AssertingIndexSearcher.cs
@@ -3,6 +3,7 @@
using RandomizedTesting.Generators;
using System;
using System.Collections.Generic;
+using System.Threading;
using System.Threading.Tasks;
namespace Lucene.Net.Search
@@ -100,10 +101,10 @@ protected override Query WrapFilter(Query query, Filter filter)
return (filter is null) ? query : new FilteredQuery(query, filter, TestUtil.RandomFilterStrategy(random));
}
- protected override void Search(IList leaves, Weight weight, ICollector collector)
+ protected override void Search(IList leaves, Weight weight, ICollector collector, CancellationToken cancellationToken = default)
{
// TODO: shouldn't we AssertingCollector.wrap(collector) here?
- base.Search(leaves, AssertingWeight.Wrap(random, weight), collector);
+ base.Search(leaves, AssertingWeight.Wrap(random, weight), collector, cancellationToken);
}
public override string ToString()
@@ -111,4 +112,4 @@ public override string ToString()
return "AssertingIndexSearcher(" + base.ToString() + ")";
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Lucene.Net.TestFramework/Search/CheckHits.cs b/src/Lucene.Net.TestFramework/Search/CheckHits.cs
index 51dcf60320..b4a047adfe 100644
--- a/src/Lucene.Net.TestFramework/Search/CheckHits.cs
+++ b/src/Lucene.Net.TestFramework/Search/CheckHits.cs
@@ -5,6 +5,7 @@
using System.Diagnostics;
using System.Globalization;
using System.Text;
+using System.Threading;
using JCG = J2N.Collections.Generic;
using Assert = Lucene.Net.TestFramework.Assert;
@@ -450,28 +451,28 @@ protected virtual void CheckExplanations(Query q)
base.Search(q, null, new ExplanationAsserter(q, null, this));
}
- public override TopFieldDocs Search(Query query, Filter filter, int n, Sort sort)
+ public override TopFieldDocs Search(Query query, Filter filter, int n, Sort sort, CancellationToken cancellationToken = default)
{
CheckExplanations(query);
- return base.Search(query, filter, n, sort);
+ return base.Search(query, filter, n, sort, cancellationToken);
}
- public override void Search(Query query, ICollector results)
+ public override void Search(Query query, ICollector results, CancellationToken cancellationToken = default)
{
CheckExplanations(query);
- base.Search(query, results);
+ base.Search(query, results, cancellationToken);
}
- public override void Search(Query query, Filter filter, ICollector results)
+ public override void Search(Query query, Filter filter, ICollector results, CancellationToken cancellationToken = default)
{
CheckExplanations(query);
- base.Search(query, filter, results);
+ base.Search(query, filter, results, cancellationToken);
}
- public override TopDocs Search(Query query, Filter filter, int n)
+ public override TopDocs Search(Query query, Filter filter, int n, CancellationToken cancellationToken = default)
{
CheckExplanations(query);
- return base.Search(query, filter, n);
+ return base.Search(query, filter, n, cancellationToken);
}
}
diff --git a/src/Lucene.Net.TestFramework/Search/ShardSearchingTestBase.cs b/src/Lucene.Net.TestFramework/Search/ShardSearchingTestBase.cs
index 72986281bd..4f1a008a6d 100644
--- a/src/Lucene.Net.TestFramework/Search/ShardSearchingTestBase.cs
+++ b/src/Lucene.Net.TestFramework/Search/ShardSearchingTestBase.cs
@@ -11,6 +11,7 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
+using System.Threading;
using JCG = J2N.Collections.Generic;
using Console = Lucene.Net.Util.SystemConsole;
#if FEATURE_SERIALIZABLE_EXCEPTIONS
@@ -453,7 +454,7 @@ public override CollectionStatistics CollectionStatistics(string field)
return new CollectionStatistics(field, maxDoc, docCount, sumTotalTermFreq, sumDocFreq);
}
- public override TopDocs Search(Query query, int numHits)
+ public override TopDocs Search(Query query, int numHits, CancellationToken cancellationToken = default)
{
TopDocs[] shardHits = new TopDocs[nodeVersions.Length];
for (int nodeID = 0; nodeID < nodeVersions.Length; nodeID++)
@@ -462,7 +463,7 @@ public override TopDocs Search(Query query, int numHits)
{
// My node; run using local shard searcher we
// already aquired:
- shardHits[nodeID] = LocalSearch(query, numHits);
+ shardHits[nodeID] = LocalSearch(query, numHits, cancellationToken);
}
else
{
@@ -474,12 +475,12 @@ public override TopDocs Search(Query query, int numHits)
return TopDocs.Merge(null, numHits, shardHits);
}
- public virtual TopDocs LocalSearch(Query query, int numHits)
+ public virtual TopDocs LocalSearch(Query query, int numHits, CancellationToken cancellationToken = default)
{
- return base.Search(query, numHits);
+ return base.Search(query, numHits, cancellationToken);
}
- public override TopDocs SearchAfter(ScoreDoc after, Query query, int numHits)
+ public override TopDocs SearchAfter(ScoreDoc after, Query query, int numHits, CancellationToken cancellationToken = default)
{
TopDocs[] shardHits = new TopDocs[nodeVersions.Length];
// results are merged in that order: score, shardIndex, doc. therefore we set
@@ -526,7 +527,7 @@ public override TopDocs SearchAfter(ScoreDoc after, Query query, int numHits)
{
// My node; run using local shard searcher we
// already aquired:
- shardHits[nodeID] = LocalSearchAfter(shardAfter, query, numHits);
+ shardHits[nodeID] = LocalSearchAfter(shardAfter, query, numHits, cancellationToken);
}
else
{
@@ -539,12 +540,12 @@ public override TopDocs SearchAfter(ScoreDoc after, Query query, int numHits)
return TopDocs.Merge(null, numHits, shardHits);
}
- public virtual TopDocs LocalSearchAfter(ScoreDoc after, Query query, int numHits)
+ public virtual TopDocs LocalSearchAfter(ScoreDoc after, Query query, int numHits, CancellationToken cancellationToken = default)
{
- return base.SearchAfter(after, query, numHits);
+ return base.SearchAfter(after, query, numHits, cancellationToken);
}
- public override TopFieldDocs Search(Query query, int numHits, Sort sort)
+ public override TopFieldDocs Search(Query query, int numHits, Sort sort, CancellationToken cancellationToken = default)
{
if (Debugging.AssertsEnabled) Debugging.Assert(sort != null);
TopDocs[] shardHits = new TopDocs[nodeVersions.Length];
@@ -554,7 +555,7 @@ public override TopFieldDocs Search(Query query, int numHits, Sort sort)
{
// My node; run using local shard searcher we
// already aquired:
- shardHits[nodeID] = LocalSearch(query, numHits, sort);
+ shardHits[nodeID] = LocalSearch(query, numHits, sort, cancellationToken);
}
else
{
@@ -566,9 +567,9 @@ public override TopFieldDocs Search(Query query, int numHits, Sort sort)
return (TopFieldDocs)TopDocs.Merge(sort, numHits, shardHits);
}
- public virtual TopFieldDocs LocalSearch(Query query, int numHits, Sort sort)
+ public virtual TopFieldDocs LocalSearch(Query query, int numHits, Sort sort, CancellationToken cancellationToken = default)
{
- return base.Search(query, numHits, sort);
+ return base.Search(query, numHits, sort, cancellationToken);
}
}
diff --git a/src/Lucene.Net.Tests/Search/TestBooleanQuery.cs b/src/Lucene.Net.Tests/Search/TestBooleanQuery.cs
index 1a06b59f76..580a15de6f 100644
--- a/src/Lucene.Net.Tests/Search/TestBooleanQuery.cs
+++ b/src/Lucene.Net.Tests/Search/TestBooleanQuery.cs
@@ -3,6 +3,7 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
+using System.Threading;
using System.Threading.Tasks;
using JCG = J2N.Collections.Generic;
using Assert = Lucene.Net.TestFramework.Assert;
@@ -396,10 +397,10 @@ public IndexSearcherAnonymousClass(IndexReader r)
{
}
- protected override void Search(IList leaves, Weight weight, ICollector collector)
+ protected override void Search(IList leaves, Weight weight, ICollector collector, CancellationToken cancellationToken = default)
{
Assert.AreEqual(-1, collector.GetType().Name.IndexOf("OutOfOrder", StringComparison.Ordinal));
- base.Search(leaves, weight, collector);
+ base.Search(leaves, weight, collector, cancellationToken);
}
}
}
diff --git a/src/Lucene.Net.Tests/Search/TestCustomSearcherSort.cs b/src/Lucene.Net.Tests/Search/TestCustomSearcherSort.cs
index c10f99745a..0acc7061be 100644
--- a/src/Lucene.Net.Tests/Search/TestCustomSearcherSort.cs
+++ b/src/Lucene.Net.Tests/Search/TestCustomSearcherSort.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Text;
+using System.Threading;
using Assert = Lucene.Net.TestFramework.Assert;
using Console = Lucene.Net.Util.SystemConsole;
using JCG = J2N.Collections.Generic;
@@ -213,20 +214,20 @@ public CustomSearcher(IndexReader r, int switcher)
this.switcher = switcher;
}
- public override TopFieldDocs Search(Query query, Filter filter, int nDocs, Sort sort)
+ public override TopFieldDocs Search(Query query, Filter filter, int nDocs, Sort sort, CancellationToken cancellationToken = default)
{
BooleanQuery bq = new BooleanQuery();
bq.Add(query, Occur.MUST);
bq.Add(new TermQuery(new Term("mandant", Convert.ToString(switcher))), Occur.MUST);
- return base.Search(bq, filter, nDocs, sort);
+ return base.Search(bq, filter, nDocs, sort, cancellationToken);
}
- public override TopDocs Search(Query query, Filter filter, int nDocs)
+ public override TopDocs Search(Query query, Filter filter, int nDocs, CancellationToken cancellationToken = default)
{
BooleanQuery bq = new BooleanQuery();
bq.Add(query, Occur.MUST);
bq.Add(new TermQuery(new Term("mandant", Convert.ToString(switcher))), Occur.MUST);
- return base.Search(bq, filter, nDocs);
+ return base.Search(bq, filter, nDocs, cancellationToken);
}
}
diff --git a/src/Lucene.Net/Search/CollectionTerminatedException.cs b/src/Lucene.Net/Search/CollectionTerminatedException.cs
index 1e212a179a..c169b3f524 100644
--- a/src/Lucene.Net/Search/CollectionTerminatedException.cs
+++ b/src/Lucene.Net/Search/CollectionTerminatedException.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading;
#if FEATURE_SERIALIZABLE_EXCEPTIONS
using System.ComponentModel;
@@ -29,10 +30,10 @@ namespace Lucene.Net.Search
/// terminate collection of the current leaf.
/// Note: swallows this exception and never re-throws it.
/// As a consequence, you should not catch it when calling any overload of
- /// as it is unnecessary and might hide misuse
+ /// as it is unnecessary and might hide misuse
/// of this exception.
///
- // LUCENENET: It is no longer good practice to use binary serialization.
+ // 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]
diff --git a/src/Lucene.Net/Search/FieldComparator.cs b/src/Lucene.Net/Search/FieldComparator.cs
index 847043a85b..1f2708e498 100644
--- a/src/Lucene.Net/Search/FieldComparator.cs
+++ b/src/Lucene.Net/Search/FieldComparator.cs
@@ -1,7 +1,9 @@
using Lucene.Net.Diagnostics;
+using Lucene.Net.Index;
using Lucene.Net.Support;
using System;
using System.IO;
+using System.Threading;
using JCG = J2N.Collections.Generic;
using Number = J2N.Numerics.Number;
@@ -403,7 +405,7 @@ public override FieldComparer SetNextReader(AtomicReaderContext context)
///
/// Parses field's values as (using
- /// and sorts by ascending value
+ /// and sorts by ascending value
///
[Obsolete, CLSCompliant(false)] // LUCENENET NOTE: marking non-CLS compliant because of sbyte - it is obsolete, anyway
public sealed class ByteComparer : NumericComparer
@@ -488,7 +490,7 @@ public override int CompareTop(int doc)
///
/// Parses field's values as (using
- /// and sorts by ascending value
+ /// and sorts by ascending value
///
public sealed class DoubleComparer : NumericComparer
{
@@ -581,7 +583,7 @@ public override int CompareTop(int doc)
///
/// Parses field's values as (using
- /// and sorts by ascending value
+ /// and sorts by ascending value
///
/// NOTE: This was FloatComparator in Lucene
///
@@ -677,7 +679,7 @@ public override int CompareTop(int doc)
///
/// Parses field's values as (using
- /// and sorts by ascending value
+ /// and sorts by ascending value
///
/// NOTE: This was ShortComparator in Lucene
///
@@ -765,7 +767,7 @@ public override int CompareTop(int doc)
///
/// Parses field's values as (using
- /// and sorts by ascending value
+ /// and sorts by ascending value
///
/// NOTE: This was IntComparator in Lucene
///
@@ -849,7 +851,7 @@ public override int CompareTop(int doc)
///
/// Parses field's values as (using
- /// and sorts by ascending value
+ /// and sorts by ascending value
///
/// NOTE: This was LongComparator in Lucene
///
@@ -941,7 +943,7 @@ public override int CompareTop(int doc)
/// sorting only by descending relevance and then
/// secondarily by ascending docID, performance is faster
/// using directly (which all overloads of
- /// use when no is
+ /// use when no is
/// specified).
///
public sealed class RelevanceComparer : FieldComparer
@@ -1105,11 +1107,11 @@ public override int CompareTop(int doc)
}
///
- /// Sorts by field's natural sort order, using
+ /// Sorts by field's natural sort order, using
/// ordinals. This is functionally equivalent to
/// , but it first resolves the string
/// to their relative ordinal positions (using the index
- /// returned by ), and
+ /// returned by ), and
/// does most comparisons using the ordinals. For medium
/// to large results, this comparer will be much faster
/// than . For very small
@@ -1447,7 +1449,7 @@ public override int CompareValues(BytesRef val1, BytesRef val2)
}
///
- /// Sorts by field's natural sort order. All
+ /// Sorts by field's natural sort order. All
/// comparisons are done using , which is
/// slow for medium to large result sets but possibly
/// very fast for very small results sets.
diff --git a/src/Lucene.Net/Search/FieldDoc.cs b/src/Lucene.Net/Search/FieldDoc.cs
index 431a2d557c..025c076f71 100644
--- a/src/Lucene.Net/Search/FieldDoc.cs
+++ b/src/Lucene.Net/Search/FieldDoc.cs
@@ -1,6 +1,7 @@
using Lucene.Net.Support;
using System.Diagnostics.CodeAnalysis;
using System.Text;
+using System.Threading;
namespace Lucene.Net.Search
{
@@ -48,7 +49,7 @@ public class FieldDoc : ScoreDoc
/// the method corresponding
/// FieldComparer used to sort this field.
///
- ///
+ ///
public object[] Fields;
///
@@ -87,4 +88,4 @@ public override string ToString()
return sb.ToString();
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Lucene.Net/Search/FieldValueHitQueue.cs b/src/Lucene.Net/Search/FieldValueHitQueue.cs
index 7d4e4737e4..0305b46eca 100644
--- a/src/Lucene.Net/Search/FieldValueHitQueue.cs
+++ b/src/Lucene.Net/Search/FieldValueHitQueue.cs
@@ -6,6 +6,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.IO;
+using System.Threading;
namespace Lucene.Net.Search
{
@@ -196,7 +197,7 @@ public static FieldValueHitQueue Create(SortField[] fields, int size)
///
/// @lucene.experimental
/// @since 2.9
- ///
+ ///
///
public abstract class FieldValueHitQueue : PriorityQueue
where T : FieldValueHitQueue.Entry
@@ -259,7 +260,7 @@ public virtual void SetComparer(int pos, FieldComparer comparer)
///
/// The used to create a
/// The newly created
- ///
+ ///
internal virtual FieldDoc FillFields(FieldValueHitQueue.Entry entry)
{
int n = m_comparers.Length;
@@ -278,4 +279,4 @@ internal virtual FieldDoc FillFields(FieldValueHitQueue.Entry entry)
[SuppressMessage("Microsoft.Performance", "CA1819", Justification = "Lucene's design requires some writable array properties")]
internal virtual SortField[] Fields => m_fields;
}
-}
\ No newline at end of file
+}
diff --git a/src/Lucene.Net/Search/IndexSearcher.cs b/src/Lucene.Net/Search/IndexSearcher.cs
index b7f0f13bdd..9b326d5e4d 100644
--- a/src/Lucene.Net/Search/IndexSearcher.cs
+++ b/src/Lucene.Net/Search/IndexSearcher.cs
@@ -1,5 +1,6 @@
#nullable enable
using Lucene.Net.Diagnostics;
+using Lucene.Net.Index;
using Lucene.Net.Support.Threading;
using Lucene.Net.Util;
using System;
@@ -7,6 +8,7 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
+using System.Threading;
using System.Threading.Tasks;
namespace Lucene.Net.Search
@@ -42,25 +44,25 @@ namespace Lucene.Net.Search
using Terms = Lucene.Net.Index.Terms;
///
- /// Implements search over a single .
+ /// Implements search over a single .
///
/// Applications usually need only call the inherited
- ///
- /// or methods. For
+ ///
+ /// or methods. For
/// performance reasons, if your index is unchanging, you
/// should share a single instance across
/// multiple searches instead of creating a new one
/// per-search. If your index has changed and you wish to
/// see the changes reflected in searching, you should
- /// use
+ /// use
/// to obtain a new reader and
/// then create a new from that. Also, for
/// low-latency turnaround it's best to use a near-real-time
- /// reader ().
- /// Once you have a new , it's relatively
+ /// reader ().
+ /// Once you have a new , it's relatively
/// cheap to create a new from it.
///
- /// NOTE:
+ ///
NOTE:
/// instances are completely
/// thread safe, meaning multiple threads can call any of its
/// methods, concurrently. If your application requires
@@ -132,7 +134,7 @@ public IndexSearcher(IndexReader r, TaskScheduler? executor)
/// will not shutdown/awaitTermination this on
/// close; you must do so, eventually, on your own.
///
- /// @lucene.experimental
+ /// @lucene.experimental
///
/// is null.
///
@@ -212,7 +214,7 @@ protected virtual LeafSlice[] GetSlices(IList leaves)
}
///
- /// Return the this searches.
+ /// Return the this searches.
public virtual IndexReader IndexReader => reader;
///
@@ -279,9 +281,9 @@ protected virtual Query WrapFilter(Query query, Filter? filter)
/// If a query would exceed
/// clauses.
/// is null.
- public virtual TopDocs SearchAfter(ScoreDoc? after, Query query, int n)
+ public virtual TopDocs SearchAfter(ScoreDoc? after, Query query, int n, CancellationToken cancellationToken = default)
{
- return Search(CreateNormalizedWeight(query), after, n);
+ return Search(CreateNormalizedWeight(query), after, n, cancellationToken);
}
///
@@ -296,9 +298,9 @@ public virtual TopDocs SearchAfter(ScoreDoc? after, Query query, int n)
/// If a query would exceed
/// clauses.
/// is null.
- public virtual TopDocs SearchAfter(ScoreDoc? after, Query query, Filter? filter, int n)
+ public virtual TopDocs SearchAfter(ScoreDoc? after, Query query, Filter? filter, int n, CancellationToken cancellationToken = default)
{
- return Search(CreateNormalizedWeight(WrapFilter(query, filter)), after, n);
+ return Search(CreateNormalizedWeight(WrapFilter(query, filter)), after, n, cancellationToken);
}
///
@@ -308,9 +310,9 @@ public virtual TopDocs SearchAfter(ScoreDoc? after, Query query, Filter? filter,
/// If a query would exceed
/// clauses.
/// is null.
- public virtual TopDocs Search(Query query, int n)
+ public virtual TopDocs Search(Query query, int n, CancellationToken cancellationToken = default)
{
- return Search(query, filter: null, n);
+ return Search(query, filter: null, n, cancellationToken);
}
///
@@ -319,9 +321,9 @@ public virtual TopDocs Search(Query query, int n)
///
/// If a query would exceed
/// clauses.
- public virtual TopDocs Search(Query query, Filter? filter, int n)
+ public virtual TopDocs Search(Query query, Filter? filter, int n, CancellationToken cancellationToken = default)
{
- return Search(CreateNormalizedWeight(WrapFilter(query, filter)), after: null, n);
+ return Search(CreateNormalizedWeight(WrapFilter(query, filter)), after: null, n, cancellationToken);
}
///
@@ -337,9 +339,9 @@ public virtual TopDocs Search(Query query, Filter? filter, int n)
/// clauses.
/// or
/// is null.
- public virtual void Search(Query query, Filter? filter, ICollector results)
+ public virtual void Search(Query query, Filter? filter, ICollector results, CancellationToken cancellationToken = default)
{
- Search(m_leafContexts, CreateNormalizedWeight(WrapFilter(query, filter)), results);
+ Search(m_leafContexts, CreateNormalizedWeight(WrapFilter(query, filter)), results, cancellationToken);
}
///
@@ -351,9 +353,9 @@ public virtual void Search(Query query, Filter? filter, ICollector results)
/// clauses.
/// or
/// is null.
- public virtual void Search(Query query, ICollector results)
+ public virtual void Search(Query query, ICollector results, CancellationToken cancellationToken = default)
{
- Search(m_leafContexts, CreateNormalizedWeight(query), results);
+ Search(m_leafContexts, CreateNormalizedWeight(query), results, cancellationToken);
}
///
@@ -363,16 +365,16 @@ public virtual void Search(Query query, ICollector results)
/// .
///
/// NOTE: this does not compute scores by default; use
- /// to
+ /// to
/// control scoring.
///
/// If a query would exceed
/// clauses.
/// or
/// is null.
- public virtual TopFieldDocs Search(Query query, Filter? filter, int n, Sort sort)
+ public virtual TopFieldDocs Search(Query query, Filter? filter, int n, Sort sort, CancellationToken cancellationToken = default)
{
- return Search(CreateNormalizedWeight(WrapFilter(query, filter)), n, sort, false, false);
+ return Search(CreateNormalizedWeight(WrapFilter(query, filter)), n, sort, false, false, cancellationToken);
}
///
@@ -391,9 +393,9 @@ public virtual TopFieldDocs Search(Query query, Filter? filter, int n, Sort sort
/// clauses.
/// or
/// is null.
- public virtual TopFieldDocs Search(Query query, Filter? filter, int n, Sort sort, bool doDocScores, bool doMaxScore)
+ public virtual TopFieldDocs Search(Query query, Filter? filter, int n, Sort sort, bool doDocScores, bool doMaxScore, CancellationToken cancellationToken = default)
{
- return Search(CreateNormalizedWeight(WrapFilter(query, filter)), n, sort, doDocScores, doMaxScore);
+ return Search(CreateNormalizedWeight(WrapFilter(query, filter)), n, sort, doDocScores, doMaxScore, cancellationToken);
}
///
@@ -409,11 +411,11 @@ public virtual TopFieldDocs Search(Query query, Filter? filter, int n, Sort sort
/// clauses.
/// or
/// is null.
- public virtual TopDocs SearchAfter(ScoreDoc? after, Query query, Filter? filter, int n, Sort sort)
+ public virtual TopDocs SearchAfter(ScoreDoc? after, Query query, Filter? filter, int n, Sort sort, CancellationToken cancellationToken = default)
{
FieldDoc? fieldDoc = GetScoreDocAsFieldDocIfNotNull(after);
- return Search(CreateNormalizedWeight(WrapFilter(query, filter)), fieldDoc, n, sort, true, false, false);
+ return Search(CreateNormalizedWeight(WrapFilter(query, filter)), fieldDoc, n, sort, true, false, false, cancellationToken);
}
private static FieldDoc? GetScoreDocAsFieldDocIfNotNull(ScoreDoc? after)
@@ -439,9 +441,9 @@ public virtual TopDocs SearchAfter(ScoreDoc? after, Query query, Filter? filter,
/// if there is a low-level I/O error
/// or
/// is null.
- public virtual TopFieldDocs Search(Query query, int n, Sort sort)
+ public virtual TopFieldDocs Search(Query query, int n, Sort sort, CancellationToken cancellationToken = default)
{
- return Search(CreateNormalizedWeight(query), n, sort, false, false);
+ return Search(CreateNormalizedWeight(query), n, sort, false, false, cancellationToken);
}
///
@@ -457,11 +459,11 @@ public virtual TopFieldDocs Search(Query query, int n, Sort sort)
/// clauses.
/// or
/// is null.
- public virtual TopDocs SearchAfter(ScoreDoc? after, Query query, int n, Sort sort)
+ public virtual TopDocs SearchAfter(ScoreDoc? after, Query query, int n, Sort sort, CancellationToken cancellationToken = default)
{
var fieldDoc = GetScoreDocAsFieldDocIfNotNull(after);
- return Search(CreateNormalizedWeight(query), fieldDoc, n, sort, true, false, false);
+ return Search(CreateNormalizedWeight(query), fieldDoc, n, sort, true, false, false, cancellationToken);
}
///
@@ -482,23 +484,23 @@ public virtual TopDocs SearchAfter(ScoreDoc? after, Query query, int n, Sort sor
/// clauses.
/// or
/// is null.
- public virtual TopDocs SearchAfter(ScoreDoc? after, Query query, Filter? filter, int n, Sort sort, bool doDocScores, bool doMaxScore)
+ public virtual TopDocs SearchAfter(ScoreDoc? after, Query query, Filter? filter, int n, Sort sort, bool doDocScores, bool doMaxScore, CancellationToken cancellationToken = default)
{
var fieldDoc = GetScoreDocAsFieldDocIfNotNull(after);
- return Search(CreateNormalizedWeight(WrapFilter(query, filter)), fieldDoc, n, sort, true, doDocScores, doMaxScore);
+ return Search(CreateNormalizedWeight(WrapFilter(query, filter)), fieldDoc, n, sort, true, doDocScores, doMaxScore, cancellationToken);
}
///
/// Expert: Low-level search implementation. Finds the top
/// hits for query, applying filter if non-null.
///
- /// Applications should usually call or
- /// instead.
+ /// Applications should usually call or
+ /// instead.
/// If a query would exceed
/// clauses.
/// is null.
- protected virtual TopDocs Search(Weight weight, ScoreDoc? after, int nDocs)
+ protected virtual TopDocs Search(Weight weight, ScoreDoc? after, int nDocs, CancellationToken cancellationToken = default)
{
int limit = reader.MaxDoc;
if (limit == 0)
@@ -513,7 +515,7 @@ protected virtual TopDocs Search(Weight weight, ScoreDoc? after, int nDocs)
if (executor is null)
{
- return Search(m_leafContexts, weight, after, nDocs);
+ return Search(m_leafContexts, weight, after, nDocs, cancellationToken);
}
else
{
@@ -557,13 +559,13 @@ protected virtual TopDocs Search(Weight weight, ScoreDoc? after, int nDocs)
/// Expert: Low-level search implementation. Finds the top n
/// hits for query.
///
- /// Applications should usually call or
- /// instead.
+ /// Applications should usually call or
+ /// instead.
/// If a query would exceed
/// clauses.
/// or
/// is null.
- protected virtual TopDocs Search(IList leaves, Weight weight, ScoreDoc? after, int nDocs)
+ protected virtual TopDocs Search(IList leaves, Weight weight, ScoreDoc? after, int nDocs, CancellationToken cancellationToken = default)
{
// LUCENENET: Added guard clause
if (weight is null)
@@ -577,7 +579,7 @@ protected virtual TopDocs Search(IList leaves, Weight weigh
}
nDocs = Math.Min(nDocs, limit);
TopScoreDocCollector collector = TopScoreDocCollector.Create(nDocs, after, !weight.ScoresDocsOutOfOrder);
- Search(leaves, weight, collector);
+ Search(leaves, weight, collector, cancellationToken);
return collector.GetTopDocs();
}
@@ -588,26 +590,26 @@ protected virtual TopDocs Search(IList leaves, Weight weigh
/// the top hits for query and sorting the hits
/// by the criteria in .
///
- /// Applications should usually call
- /// instead.
+ /// Applications should usually call
+ /// instead.
///
/// If a query would exceed
/// clauses.
/// or
/// is null.
- protected virtual TopFieldDocs Search(Weight weight, int nDocs, Sort sort, bool doDocScores, bool doMaxScore)
+ protected virtual TopFieldDocs Search(Weight weight, int nDocs, Sort sort, bool doDocScores, bool doMaxScore, CancellationToken cancellationToken = default)
{
- return Search(weight, after: null, nDocs, sort, true, doDocScores, doMaxScore);
+ return Search(weight, after: null, nDocs, sort, true, doDocScores, doMaxScore, cancellationToken);
}
///
- /// Just like , but you choose
+ /// Just like , but you choose
/// whether or not the fields in the returned instances should
/// be set by specifying .
///
/// or
/// is null.
- protected virtual TopFieldDocs Search(Weight weight, FieldDoc? after, int nDocs, Sort sort, bool fillFields, bool doDocScores, bool doMaxScore)
+ protected virtual TopFieldDocs Search(Weight weight, FieldDoc? after, int nDocs, Sort sort, bool fillFields, bool doDocScores, bool doMaxScore, CancellationToken cancellationToken = default)
{
if (sort is null)
throw new ArgumentNullException(nameof(sort), "Sort must not be null"); // LUCENENET specific - changed from IllegalArgumentException to ArgumentNullException (.NET convention)
@@ -622,7 +624,7 @@ protected virtual TopFieldDocs Search(Weight weight, FieldDoc? after, int nDocs,
if (executor is null)
{
// use all leaves here!
- return Search(m_leafContexts, weight, after, nDocs, sort, fillFields, doDocScores, doMaxScore);
+ return Search(m_leafContexts, weight, after, nDocs, sort, fillFields, doDocScores, doMaxScore, cancellationToken);
}
else
{
@@ -660,13 +662,13 @@ protected virtual TopFieldDocs Search(Weight weight, FieldDoc? after, int nDocs,
}
///
- /// Just like , but you choose
+ /// Just like , but you choose
/// whether or not the fields in the returned instances should
/// be set by specifying .
///
/// or
/// is null.
- protected virtual TopFieldDocs Search(IList leaves, Weight weight, FieldDoc? after, int nDocs, Sort sort, bool fillFields, bool doDocScores, bool doMaxScore)
+ protected virtual TopFieldDocs Search(IList leaves, Weight weight, FieldDoc? after, int nDocs, Sort sort, bool fillFields, bool doDocScores, bool doMaxScore, CancellationToken cancellationToken = default)
{
// LUCENENET: Added guard clause
if (weight is null)
@@ -681,7 +683,7 @@ protected virtual TopFieldDocs Search(IList leaves, Weight
nDocs = Math.Min(nDocs, limit);
TopFieldCollector collector = TopFieldCollector.Create(sort, nDocs, after, fillFields, doDocScores, doMaxScore, !weight.ScoresDocsOutOfOrder);
- Search(leaves, weight, collector);
+ Search(leaves, weight, collector, cancellationToken);
return (TopFieldDocs)collector.GetTopDocs();
}
@@ -689,7 +691,7 @@ protected virtual TopFieldDocs Search(IList leaves, Weight
/// Lower-level search API.
///
///
- /// is called for every document.
+ /// is called for every document.
///
///
/// NOTE: this method executes the searches on all given leaves exclusively.
@@ -705,7 +707,7 @@ protected virtual TopFieldDocs Search(IList leaves, Weight
/// clauses.
/// , ,
/// or is null.
- protected virtual void Search(IList leaves, Weight weight, ICollector collector)
+ protected virtual void Search(IList leaves, Weight weight, ICollector collector, CancellationToken cancellationToken = default)
{
// LUCENENET: Added guard clauses
if (leaves is null)
@@ -1029,7 +1031,7 @@ IEnumerator IEnumerable.GetEnumerator()
}
}
#nullable enable
-
+
///
/// A class holding a subset of the s leaf contexts to be
/// executed within a single thread.
@@ -1114,4 +1116,4 @@ public virtual CollectionStatistics CollectionStatistics(string field)
return new CollectionStatistics(field, reader.MaxDoc, docCount, sumTotalTermFreq, sumDocFreq);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Lucene.Net/Search/Sort.cs b/src/Lucene.Net/Search/Sort.cs
index 133bc18101..8823f06c54 100644
--- a/src/Lucene.Net/Search/Sort.cs
+++ b/src/Lucene.Net/Search/Sort.cs
@@ -1,6 +1,7 @@
using Lucene.Net.Support;
using System.IO;
using System.Text;
+using System.Threading;
namespace Lucene.Net.Search
{
@@ -102,7 +103,7 @@ public class Sort
///
/// Represents sorting by computed relevance. Using this sort criteria returns
/// the same results as calling
- /// without a sort criteria,
+ /// without a sort criteria,
/// only with slightly more overhead.
///
public static readonly Sort RELEVANCE = new Sort();
@@ -116,7 +117,7 @@ public class Sort
///
/// Sorts by computed relevance. This is the same sort criteria as calling
- /// without a sort criteria,
+ /// without a sort criteria,
/// only with slightly more overhead.
///
public Sort()
diff --git a/src/Lucene.Net/Search/TopDocs.cs b/src/Lucene.Net/Search/TopDocs.cs
index 26bcd34104..634e6e8f9d 100644
--- a/src/Lucene.Net/Search/TopDocs.cs
+++ b/src/Lucene.Net/Search/TopDocs.cs
@@ -7,6 +7,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Threading;
namespace Lucene.Net.Search
{
@@ -29,8 +30,8 @@ namespace Lucene.Net.Search
///
/// Represents hits returned by
- /// and
- /// .
+ /// and
+ /// .
///
public class TopDocs
{
diff --git a/src/Lucene.Net/Search/TopFieldDocs.cs b/src/Lucene.Net/Search/TopFieldDocs.cs
index d143e002dd..e55066a024 100644
--- a/src/Lucene.Net/Search/TopFieldDocs.cs
+++ b/src/Lucene.Net/Search/TopFieldDocs.cs
@@ -1,5 +1,6 @@
using Lucene.Net.Support;
using System.Diagnostics.CodeAnalysis;
+using System.Threading;
namespace Lucene.Net.Search
{
@@ -21,8 +22,8 @@ namespace Lucene.Net.Search
*/
///
- /// Represents hits returned by
- /// .
+ /// Represents hits returned by
+ /// .
///
public class TopFieldDocs : TopDocs
{
@@ -44,4 +45,4 @@ public TopFieldDocs(int totalHits, ScoreDoc[] scoreDocs, SortField[] fields, flo
this.Fields = fields;
}
}
-}
\ No newline at end of file
+}
From b137e199e14667e35e1b7f20cc1fbe21339ddd8f Mon Sep 17 00:00:00 2001
From: Paul Irwin
Date: Tue, 31 Dec 2024 16:47:54 -0700
Subject: [PATCH 2/3] Pass cancellation token and throw if requested, #922
---
.../Index/Sorter/BlockJoinComparatorSource.cs | 5 +++--
src/Lucene.Net/Search/IndexSearcher.cs | 20 +++++++++++++++----
2 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/src/Lucene.Net.Misc/Index/Sorter/BlockJoinComparatorSource.cs b/src/Lucene.Net.Misc/Index/Sorter/BlockJoinComparatorSource.cs
index c3f4d9dbaa..06b7b022da 100644
--- a/src/Lucene.Net.Misc/Index/Sorter/BlockJoinComparatorSource.cs
+++ b/src/Lucene.Net.Misc/Index/Sorter/BlockJoinComparatorSource.cs
@@ -2,6 +2,7 @@
using Lucene.Net.Util;
using System;
using System.IO;
+using System.Threading;
namespace Lucene.Net.Index.Sorter
{
@@ -28,7 +29,7 @@ namespace Lucene.Net.Index.Sorter
/// Note that this class is intended to used with ,
/// and for other purposes has some limitations:
///
- /// - Cannot yet be used with
+ ///
- Cannot yet be used with
/// IndexSearcher.SearchAfter
/// - Filling sort field values is not yet supported.
///
@@ -266,4 +267,4 @@ public override string ToString()
return "blockJoin(parentSort=" + parentSort + ",childSort=" + childSort + ")";
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Lucene.Net/Search/IndexSearcher.cs b/src/Lucene.Net/Search/IndexSearcher.cs
index 9b326d5e4d..ecba9fb8fa 100644
--- a/src/Lucene.Net/Search/IndexSearcher.cs
+++ b/src/Lucene.Net/Search/IndexSearcher.cs
@@ -70,6 +70,14 @@ namespace Lucene.Net.Search
/// synchronize on the instance;
/// use your own (non-Lucene) objects instead.
///
+ ///
+ /// LUCENENET Specific - Search methods have had an optional parameter added
+ /// to allow for cancellation of the search operation. For multithreaded search operations, the
+ /// passed to the constructor will be used to execute the search operations
+ /// and the will be passed to the awaited tasks. If the
+ /// is null, the search operations will be executed synchronously, and the
+ /// will throw if cancellation is requested upon entry to each leaf reader.
+ ///
public class IndexSearcher
{
internal readonly IndexReader reader; // package private for testing!
@@ -527,7 +535,7 @@ protected virtual TopDocs Search(Weight weight, ScoreDoc? after, int nDocs, Canc
HitQueue hq = new HitQueue(nDocs, prePopulate: false);
ReentrantLock @lock = new ReentrantLock();
- ExecutionHelper runner = new ExecutionHelper(executor);
+ ExecutionHelper runner = new ExecutionHelper(executor, cancellationToken);
for (int i = 0; i < m_leafSlices.Length; i++) // search each sub
{
@@ -637,7 +645,7 @@ protected virtual TopFieldDocs Search(Weight weight, FieldDoc? after, int nDocs,
TopFieldCollector topCollector = TopFieldCollector.Create(sort, nDocs, after, fillFields, doDocScores, doMaxScore, false);
ReentrantLock @lock = new ReentrantLock();
- ExecutionHelper runner = new ExecutionHelper(executor);
+ ExecutionHelper runner = new ExecutionHelper(executor, cancellationToken);
for (int i = 0; i < m_leafSlices.Length; i++) // search each leaf slice
{
@@ -722,6 +730,8 @@ protected virtual void Search(IList leaves, Weight weight,
// always use single thread:
foreach (AtomicReaderContext ctx in leaves) // search each subreader
{
+ cancellationToken.ThrowIfCancellationRequested(); // LUCENENET specific - cancellation support at leaf level
+
try
{
collector.SetNextReader(ctx);
@@ -960,12 +970,14 @@ public TopFieldDocs Call()
private sealed class ExecutionHelper : IEnumerator, IEnumerable
{
private readonly TaskSchedulerCompletionService service;
+ private readonly CancellationToken cancellationToken;
private int numTasks;
private T current;
- internal ExecutionHelper(TaskScheduler executor)
+ internal ExecutionHelper(TaskScheduler executor, CancellationToken cancellationToken)
{
this.service = new TaskSchedulerCompletionService(executor);
+ this.cancellationToken = cancellationToken;
}
public T Current => current;
@@ -995,7 +1007,7 @@ public bool MoveNext()
try
{
var awaitable = service.Take();
- awaitable.Wait();
+ awaitable.Wait(cancellationToken);
current = awaitable.Result;
return true;
From b2b8a48a3626420e9a8d214d741fc0812205d757 Mon Sep 17 00:00:00 2001
From: Paul Irwin
Date: Tue, 31 Dec 2024 17:05:16 -0700
Subject: [PATCH 3/3] Pass cancellation token further down in multithreaded
code, #922
---
src/Lucene.Net/Search/IndexSearcher.cs | 20 ++++++++++++-------
.../TaskSchedulerCompletionService.cs | 7 ++++---
2 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/src/Lucene.Net/Search/IndexSearcher.cs b/src/Lucene.Net/Search/IndexSearcher.cs
index ecba9fb8fa..8316d37adf 100644
--- a/src/Lucene.Net/Search/IndexSearcher.cs
+++ b/src/Lucene.Net/Search/IndexSearcher.cs
@@ -539,7 +539,7 @@ protected virtual TopDocs Search(Weight weight, ScoreDoc? after, int nDocs, Canc
for (int i = 0; i < m_leafSlices.Length; i++) // search each sub
{
- runner.Submit(new SearcherCallableNoSort(@lock, this, m_leafSlices[i], weight, after, nDocs, hq).Call);
+ runner.Submit(new SearcherCallableNoSort(@lock, this, m_leafSlices[i], weight, after, nDocs, hq, cancellationToken).Call);
}
int totalHits = 0;
@@ -649,7 +649,7 @@ protected virtual TopFieldDocs Search(Weight weight, FieldDoc? after, int nDocs,
for (int i = 0; i < m_leafSlices.Length; i++) // search each leaf slice
{
- runner.Submit(new SearcherCallableWithSort(@lock, this, m_leafSlices[i], weight, after, nDocs, topCollector, sort, doDocScores, doMaxScore).Call);
+ runner.Submit(new SearcherCallableWithSort(@lock, this, m_leafSlices[i], weight, after, nDocs, topCollector, sort, doDocScores, doMaxScore, cancellationToken).Call);
}
int totalHits = 0;
@@ -756,6 +756,8 @@ protected virtual void Search(IList leaves, Weight weight,
}
}
}
+
+ cancellationToken.ThrowIfCancellationRequested(); // LUCENENET specific - cancellation support
}
///
@@ -859,8 +861,9 @@ public virtual Weight CreateNormalizedWeight(Query query)
private readonly int nDocs;
private readonly HitQueue hq;
private readonly LeafSlice slice;
+ private readonly CancellationToken cancellationToken;
- public SearcherCallableNoSort(ReentrantLock @lock, IndexSearcher searcher, LeafSlice slice, Weight weight, ScoreDoc? after, int nDocs, HitQueue hq)
+ public SearcherCallableNoSort(ReentrantLock @lock, IndexSearcher searcher, LeafSlice slice, Weight weight, ScoreDoc? after, int nDocs, HitQueue hq, CancellationToken cancellationToken)
{
this.@lock = @lock;
this.searcher = searcher;
@@ -868,12 +871,13 @@ public SearcherCallableNoSort(ReentrantLock @lock, IndexSearcher searcher, LeafS
this.after = after;
this.nDocs = nDocs;
this.hq = hq;
+ this.cancellationToken = cancellationToken;
this.slice = slice;
}
public TopDocs Call()
{
- TopDocs docs = searcher.Search(slice.Leaves, weight, after, nDocs);
+ TopDocs docs = searcher.Search(slice.Leaves, weight, after, nDocs, cancellationToken);
ScoreDoc[] scoreDocs = docs.ScoreDocs;
//it would be so nice if we had a thread-safe insert
@lock.Lock();
@@ -911,8 +915,9 @@ public TopDocs Call()
private readonly FieldDoc? after;
private readonly bool doDocScores;
private readonly bool doMaxScore;
+ private readonly CancellationToken cancellationToken;
- public SearcherCallableWithSort(ReentrantLock @lock, IndexSearcher searcher, LeafSlice slice, Weight weight, FieldDoc? after, int nDocs, TopFieldCollector hq, Sort sort, bool doDocScores, bool doMaxScore)
+ public SearcherCallableWithSort(ReentrantLock @lock, IndexSearcher searcher, LeafSlice slice, Weight weight, FieldDoc? after, int nDocs, TopFieldCollector hq, Sort sort, bool doDocScores, bool doMaxScore, CancellationToken cancellationToken)
{
this.@lock = @lock;
this.searcher = searcher;
@@ -924,6 +929,7 @@ public SearcherCallableWithSort(ReentrantLock @lock, IndexSearcher searcher, Lea
this.after = after;
this.doDocScores = doDocScores;
this.doMaxScore = doMaxScore;
+ this.cancellationToken = cancellationToken;
}
private readonly FakeScorer fakeScorer = new FakeScorer();
@@ -931,7 +937,7 @@ public SearcherCallableWithSort(ReentrantLock @lock, IndexSearcher searcher, Lea
public TopFieldDocs Call()
{
if (Debugging.AssertsEnabled) Debugging.Assert(slice.Leaves.Length == 1);
- TopFieldDocs docs = searcher.Search(slice.Leaves, weight, after, nDocs, sort, true, doDocScores || sort.NeedsScores, doMaxScore);
+ TopFieldDocs docs = searcher.Search(slice.Leaves, weight, after, nDocs, sort, true, doDocScores || sort.NeedsScores, doMaxScore, cancellationToken);
@lock.Lock();
try
{
@@ -991,7 +997,7 @@ public void Dispose()
public void Submit(Func task)
{
- this.service.Submit(task);
+ this.service.Submit(task, cancellationToken);
++numTasks;
}
diff --git a/src/Lucene.Net/Support/Threading/TaskSchedulerCompletionService.cs b/src/Lucene.Net/Support/Threading/TaskSchedulerCompletionService.cs
index 4de73585d4..9f3ba465a1 100644
--- a/src/Lucene.Net/Support/Threading/TaskSchedulerCompletionService.cs
+++ b/src/Lucene.Net/Support/Threading/TaskSchedulerCompletionService.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Threading;
using System.Threading.Tasks;
namespace Lucene.Net.Support.Threading
@@ -31,9 +32,9 @@ public TaskSchedulerCompletionService(TaskScheduler scheduler)
this.factory = new TaskFactory(scheduler ?? TaskScheduler.Default);
}
- public Task Submit(Func task)
+ public Task Submit(Func task, CancellationToken cancellationToken = default)
{
- var t = factory.StartNew(task);
+ var t = factory.StartNew(task, cancellationToken);
taskQueue.Enqueue(t);
return t;
}
@@ -43,4 +44,4 @@ public Task Take()
return taskQueue.Dequeue();
}
}
-}
\ No newline at end of file
+}