19
19
import static org .apache .lucene .search .DocIdSetIterator .NO_MORE_DOCS ;
20
20
21
21
import java .io .IOException ;
22
+ import java .util .ArrayList ;
22
23
import java .util .Arrays ;
23
24
import java .util .Comparator ;
24
25
import java .util .List ;
25
26
import java .util .Objects ;
26
27
import java .util .concurrent .ExecutionException ;
27
- import java .util .concurrent .Executor ;
28
28
import java .util .concurrent .FutureTask ;
29
- import java .util .stream .Collectors ;
30
29
import org .apache .lucene .codecs .KnnVectorsReader ;
31
30
import org .apache .lucene .index .FieldInfo ;
32
31
import org .apache .lucene .index .IndexReader ;
@@ -82,11 +81,12 @@ public Query rewrite(IndexSearcher indexSearcher) throws IOException {
82
81
filterWeight = null ;
83
82
}
84
83
85
- Executor executor = indexSearcher .getExecutor ();
84
+ SliceExecutor sliceExecutor = indexSearcher .getSliceExecutor ();
85
+ // in case of parallel execution, the leaf results are not ordered by leaf context's ordinal
86
86
TopDocs [] perLeafResults =
87
- (executor == null )
87
+ (sliceExecutor == null )
88
88
? sequentialSearch (reader .leaves (), filterWeight )
89
- : parallelSearch (reader . leaves (), filterWeight , executor );
89
+ : parallelSearch (indexSearcher . getSlices (), filterWeight , sliceExecutor );
90
90
91
91
// Merge sort the results
92
92
TopDocs topK = TopDocs .merge (k , perLeafResults );
@@ -110,27 +110,40 @@ private TopDocs[] sequentialSearch(
110
110
}
111
111
112
112
private TopDocs [] parallelSearch (
113
- List <LeafReaderContext > leafReaderContexts , Weight filterWeight , Executor executor ) {
114
- List <FutureTask <TopDocs >> tasks =
115
- leafReaderContexts .stream ()
116
- .map (ctx -> new FutureTask <>(() -> searchLeaf (ctx , filterWeight )))
117
- .collect (Collectors .toList ());
113
+ IndexSearcher .LeafSlice [] slices , Weight filterWeight , SliceExecutor sliceExecutor ) {
114
+
115
+ List <FutureTask <TopDocs []>> tasks = new ArrayList <>(slices .length );
116
+ int segmentsCount = 0 ;
117
+ for (IndexSearcher .LeafSlice slice : slices ) {
118
+ segmentsCount += slice .leaves .length ;
119
+ tasks .add (
120
+ new FutureTask <>(
121
+ () -> {
122
+ TopDocs [] results = new TopDocs [slice .leaves .length ];
123
+ int i = 0 ;
124
+ for (LeafReaderContext context : slice .leaves ) {
125
+ results [i ++] = searchLeaf (context , filterWeight );
126
+ }
127
+ return results ;
128
+ }));
129
+ }
118
130
119
- SliceExecutor sliceExecutor = new SliceExecutor (executor );
120
131
sliceExecutor .invokeAll (tasks );
121
132
122
- return tasks .stream ()
123
- .map (
124
- task -> {
125
- try {
126
- return task .get ();
127
- } catch (ExecutionException e ) {
128
- throw new RuntimeException (e .getCause ());
129
- } catch (InterruptedException e ) {
130
- throw new ThreadInterruptedException (e );
131
- }
132
- })
133
- .toArray (TopDocs []::new );
133
+ TopDocs [] topDocs = new TopDocs [segmentsCount ];
134
+ int i = 0 ;
135
+ for (FutureTask <TopDocs []> task : tasks ) {
136
+ try {
137
+ for (TopDocs docs : task .get ()) {
138
+ topDocs [i ++] = docs ;
139
+ }
140
+ } catch (ExecutionException e ) {
141
+ throw new RuntimeException (e .getCause ());
142
+ } catch (InterruptedException e ) {
143
+ throw new ThreadInterruptedException (e );
144
+ }
145
+ }
146
+ return topDocs ;
134
147
}
135
148
136
149
private TopDocs searchLeaf (LeafReaderContext ctx , Weight filterWeight ) throws IOException {
0 commit comments