|
19 | 19 | import java.io.IOException;
|
20 | 20 | import java.nio.file.Path;
|
21 | 21 | import java.util.ArrayList;
|
| 22 | +import java.util.Collection; |
22 | 23 | import java.util.Collections;
|
23 | 24 | import java.util.List;
|
24 | 25 | import java.util.concurrent.TimeUnit;
|
|
29 | 30 | import org.apache.lucene.queryparser.classic.QueryParser;
|
30 | 31 | import org.apache.lucene.search.BooleanClause.Occur;
|
31 | 32 | import org.apache.lucene.search.BooleanQuery.Builder;
|
32 |
| -import org.apache.lucene.search.Collector; |
| 33 | +import org.apache.lucene.search.CollectorManager; |
33 | 34 | import org.apache.lucene.search.IndexSearcher;
|
34 |
| -import org.apache.lucene.search.MultiCollector; |
| 35 | +import org.apache.lucene.search.MultiCollectorManager; |
35 | 36 | import org.apache.lucene.search.Query;
|
36 | 37 | import org.apache.lucene.search.ScoreDoc;
|
37 | 38 | import org.apache.lucene.search.SearcherManager;
|
38 | 39 | import org.apache.lucene.search.Sort;
|
39 | 40 | import org.apache.lucene.search.SortField;
|
40 | 41 | import org.apache.lucene.search.SortField.Type;
|
41 | 42 | import org.apache.lucene.search.TopFieldCollector;
|
| 43 | +import org.apache.lucene.search.TopFieldDocs; |
42 | 44 | import org.apache.lucene.store.MMapDirectory;
|
43 | 45 | import org.slf4j.Logger;
|
44 | 46 | import org.slf4j.LoggerFactory;
|
@@ -111,30 +113,41 @@ public SearchResult<LogMessage> search(
|
111 | 113 | // This is a useful optimization for indexes that are static.
|
112 | 114 | IndexSearcher searcher = searcherManager.acquire();
|
113 | 115 | try {
|
114 |
| - TopFieldCollector topFieldCollector = buildTopFieldCollector(howMany); |
115 |
| - StatsCollector statsCollector = |
| 116 | + List<LogMessage> results; |
| 117 | + Histogram histogram = new NoOpHistogramImpl(); |
| 118 | + |
| 119 | + CollectorManager<StatsCollector, Histogram> statsCollector = |
116 | 120 | buildStatsCollector(bucketCount, startTimeMsEpoch, endTimeMsEpoch);
|
117 |
| - Collector collectorChain = MultiCollector.wrap(topFieldCollector, statsCollector); |
118 | 121 |
|
119 |
| - searcher.search(query, collectorChain); |
120 |
| - List<LogMessage> results; |
121 | 122 | if (howMany > 0) {
|
122 |
| - ScoreDoc[] hits = topFieldCollector.topDocs().scoreDocs; |
| 123 | + CollectorManager<TopFieldCollector, TopFieldDocs> topFieldCollector = |
| 124 | + buildTopFieldCollector(howMany, bucketCount > 0 ? Integer.MAX_VALUE : howMany); |
| 125 | + MultiCollectorManager collectorManager; |
| 126 | + if (bucketCount > 0) { |
| 127 | + collectorManager = new MultiCollectorManager(topFieldCollector, statsCollector); |
| 128 | + } else { |
| 129 | + collectorManager = new MultiCollectorManager(topFieldCollector); |
| 130 | + } |
| 131 | + Object[] collector = searcher.search(query, collectorManager); |
| 132 | + |
| 133 | + ScoreDoc[] hits = ((TopFieldDocs) collector[0]).scoreDocs; |
123 | 134 | results = new ArrayList<>(hits.length);
|
124 | 135 | for (ScoreDoc hit : hits) {
|
125 | 136 | results.add(buildLogMessage(searcher, hit));
|
126 | 137 | }
|
| 138 | + if (bucketCount > 0) { |
| 139 | + histogram = ((Histogram) collector[1]); |
| 140 | + } |
127 | 141 | } else {
|
128 | 142 | results = Collections.emptyList();
|
| 143 | + histogram = searcher.search(query, statsCollector); |
129 | 144 | }
|
130 | 145 |
|
131 |
| - Histogram histogram = statsCollector.histogram; |
132 |
| - |
133 | 146 | elapsedTime.stop();
|
134 | 147 | return new SearchResult<>(
|
135 | 148 | results,
|
136 | 149 | elapsedTime.elapsed(TimeUnit.MICROSECONDS),
|
137 |
| - histogram.count(), |
| 150 | + bucketCount > 0 ? histogram.count() : results.size(), |
138 | 151 | histogram.getBuckets(),
|
139 | 152 | 0,
|
140 | 153 | 0,
|
@@ -167,22 +180,50 @@ private LogMessage buildLogMessage(IndexSearcher searcher, ScoreDoc hit) {
|
167 | 180 | }
|
168 | 181 | }
|
169 | 182 |
|
170 |
| - private TopFieldCollector buildTopFieldCollector(int howMany) { |
| 183 | + /** |
| 184 | + * Builds a top field collector for the requested amount of results, with the option to set the |
| 185 | + * totalHitsThreshold. If the totalHitsThreshold is set to Integer.MAX_VALUE it will force a |
| 186 | + * ScoreMode.COMPLETE, iterating over all documents at the expense of a longer query time. This |
| 187 | + * value can be set to equal howMany to allow early exiting (ScoreMode.TOP_SCORES), but should |
| 188 | + * only be done when all collectors are tolerant of an early exit. |
| 189 | + */ |
| 190 | + private CollectorManager<TopFieldCollector, TopFieldDocs> buildTopFieldCollector( |
| 191 | + int howMany, int totalHitsThreshold) { |
171 | 192 | if (howMany > 0) {
|
172 | 193 | SortField sortField = new SortField(SystemField.TIME_SINCE_EPOCH.fieldName, Type.LONG, true);
|
173 |
| - return TopFieldCollector.create(new Sort(sortField), howMany, howMany); |
| 194 | + return TopFieldCollector.createSharedManager( |
| 195 | + new Sort(sortField), howMany, null, totalHitsThreshold); |
174 | 196 | } else {
|
175 | 197 | return null;
|
176 | 198 | }
|
177 | 199 | }
|
178 | 200 |
|
179 |
| - private StatsCollector buildStatsCollector( |
| 201 | + private CollectorManager<StatsCollector, Histogram> buildStatsCollector( |
180 | 202 | int bucketCount, long startTimeMsEpoch, long endTimeMsEpoch) {
|
181 | 203 | Histogram histogram =
|
182 | 204 | bucketCount > 0
|
183 | 205 | ? new FixedIntervalHistogramImpl(startTimeMsEpoch, endTimeMsEpoch, bucketCount)
|
184 | 206 | : new NoOpHistogramImpl();
|
185 |
| - return new StatsCollector(histogram); |
| 207 | + |
| 208 | + return new CollectorManager<>() { |
| 209 | + @Override |
| 210 | + public StatsCollector newCollector() { |
| 211 | + return new StatsCollector(histogram); |
| 212 | + } |
| 213 | + |
| 214 | + @Override |
| 215 | + public Histogram reduce(Collection<StatsCollector> collectors) { |
| 216 | + Histogram histogram = null; |
| 217 | + for (StatsCollector collector : collectors) { |
| 218 | + if (histogram == null) { |
| 219 | + histogram = collector.getHistogram(); |
| 220 | + } else { |
| 221 | + histogram.mergeHistogram(collector.getHistogram().getBuckets()); |
| 222 | + } |
| 223 | + } |
| 224 | + return histogram; |
| 225 | + } |
| 226 | + }; |
186 | 227 | }
|
187 | 228 |
|
188 | 229 | private Query buildQuery(
|
|
0 commit comments