|
16 | 16 | import org.apache.lucene.queryparser.flexible.standard.config.PointsConfig; |
17 | 17 | import org.apache.lucene.search.BooleanClause; |
18 | 18 | import org.apache.lucene.search.BooleanQuery; |
| 19 | +import org.apache.lucene.search.ConstantScoreQuery; |
19 | 20 | import org.apache.lucene.search.IndexSearcher; |
20 | 21 | import org.apache.lucene.search.LRUQueryCache; |
21 | 22 | import org.apache.lucene.search.MatchAllDocsQuery; |
|
24 | 25 | import org.apache.lucene.search.ScoreDoc; |
25 | 26 | import org.apache.lucene.search.Sort; |
26 | 27 | import org.apache.lucene.search.SortField; |
| 28 | +import org.apache.lucene.search.TopDocs; |
27 | 29 | import org.apache.lucene.search.TopFieldDocs; |
28 | 30 | import org.apache.lucene.search.UsageTrackingQueryCachingPolicy; |
29 | 31 | import org.apache.lucene.store.Directory; |
|
65 | 67 | import java.util.Map; |
66 | 68 | import java.util.Set; |
67 | 69 | import java.util.StringTokenizer; |
| 70 | +import java.util.concurrent.ExecutorService; |
| 71 | +import java.util.concurrent.Executors; |
68 | 72 | import java.util.regex.Matcher; |
69 | 73 | import java.util.regex.Pattern; |
70 | 74 |
|
|
75 | 79 | public class JBrowseLuceneSearch |
76 | 80 | { |
77 | 81 | private static final Logger _log = LogHelper.getLogger(JBrowseLuceneSearch.class, "Logger related to JBrowse/Lucene indexing and queries"); |
| 82 | + private static final ExecutorService SEARCH_EXECUTOR = Executors.newFixedThreadPool(JBrowseServiceImpl.get().getCoresForLuceneSearches()); |
78 | 83 | private final JBrowseSession _session; |
79 | 84 | private final JsonFile _jsonFile; |
80 | 85 | private final User _user; |
@@ -116,7 +121,7 @@ private static synchronized CacheEntry getCacheEntryForSession(String trackObjec |
116 | 121 | Directory indexDirectory = FSDirectory.open(indexPath.toPath()); |
117 | 122 | LRUQueryCache queryCache = new LRUQueryCache(maxCachedQueries, maxRamBytesUsed); |
118 | 123 | IndexReader indexReader = DirectoryReader.open(indexDirectory); |
119 | | - IndexSearcher indexSearcher = new IndexSearcher(indexReader); |
| 124 | + IndexSearcher indexSearcher = new IndexSearcher(indexReader, SEARCH_EXECUTOR); |
120 | 125 | indexSearcher.setQueryCache(queryCache); |
121 | 126 | indexSearcher.setQueryCachingPolicy(new ForceMatchAllDocsCachingPolicy()); |
122 | 127 | cacheEntry = new CacheEntry(queryCache, indexSearcher, indexPath); |
@@ -252,7 +257,7 @@ private SearchConfig createSearchConfig(User u, String searchString, final int p |
252 | 257 |
|
253 | 258 | if (searchString.equals(ALL_DOCS)) |
254 | 259 | { |
255 | | - booleanQueryBuilder.add(new MatchAllDocsQuery(), BooleanClause.Occur.MUST); |
| 260 | + booleanQueryBuilder.add(new ConstantScoreQuery(new MatchAllDocsQuery()), BooleanClause.Occur.MUST); |
256 | 261 | } |
257 | 262 |
|
258 | 263 | // Split input into tokens, 1 token per query separated by & |
@@ -321,41 +326,46 @@ else if (numericQueryParserFields.containsKey(fieldName)) |
321 | 326 | } |
322 | 327 |
|
323 | 328 | private JSONObject paginateJSON(SearchConfig c) throws IOException, ParseException { |
324 | | - // Get chunks of size {pageSize}. Default to 1 chunk -- add to the offset to get more. |
325 | | - // We then iterate over the range of documents we want based on the offset. This does grow in memory |
326 | | - // linearly with the number of documents, but my understanding is that these are just score,id pairs |
327 | | - // rather than full documents, so mem usage *should* still be pretty low. |
328 | | - // Perform the search with sorting |
329 | | - TopFieldDocs topDocs = c.cacheEntry.indexSearcher.search(c.query, c.pageSize * (c.offset + 1), c.sort); |
| 329 | + IndexSearcher searcher = c.cacheEntry.indexSearcher; |
| 330 | + TopDocs topDocs; |
| 331 | + |
| 332 | + if (c.offset == 0) { |
| 333 | + topDocs = searcher.search(c.query, c.pageSize, c.sort); |
| 334 | + } else { |
| 335 | + TopFieldDocs prev = searcher.search(c.query, c.pageSize * c.offset, c.sort); |
| 336 | + long totalHits = prev.totalHits.value; |
| 337 | + ScoreDoc[] prevHits = prev.scoreDocs; |
| 338 | + |
| 339 | + if (prevHits.length < c.pageSize * c.offset) |
| 340 | + { |
| 341 | + JSONObject results = new JSONObject(); |
| 342 | + results.put("data", Collections.emptyList()); |
| 343 | + results.put("totalHits", totalHits); |
| 344 | + return results; |
| 345 | + } |
| 346 | + |
| 347 | + ScoreDoc lastDoc = prevHits[c.pageSize * c.offset - 1]; |
| 348 | + topDocs = searcher.searchAfter(lastDoc, c.query, c.pageSize, c.sort); |
| 349 | + } |
| 350 | + |
330 | 351 | JSONObject results = new JSONObject(); |
| 352 | + List<JSONObject> data = new ArrayList<>(topDocs.scoreDocs.length); |
331 | 353 |
|
332 | | - // Iterate over the doc list, (either to the total end or until the page ends) grab the requested docs, |
333 | | - // and add to returned results |
334 | | - List<JSONObject> data = new ArrayList<>(); |
335 | | - for (int i = c.pageSize * c.offset; i < Math.min(c.pageSize * (c.offset + 1), topDocs.scoreDocs.length); i++) |
| 354 | + for (ScoreDoc sd : topDocs.scoreDocs) |
336 | 355 | { |
| 356 | + Document doc = searcher.storedFields().document(sd.doc); |
337 | 357 | JSONObject elem = new JSONObject(); |
338 | | - Document doc = c.cacheEntry.indexSearcher.storedFields().document(topDocs.scoreDocs[i].doc); |
339 | | - |
340 | | - for (IndexableField field : doc.getFields()) |
| 358 | + for (IndexableField f : doc.getFields()) |
341 | 359 | { |
342 | | - String fieldName = field.name(); |
343 | | - String[] fieldValues = doc.getValues(fieldName); |
344 | | - if (fieldValues.length > 1) |
345 | | - { |
346 | | - elem.put(fieldName, fieldValues); |
347 | | - } |
348 | | - else |
349 | | - { |
350 | | - elem.put(fieldName, fieldValues[0]); |
351 | | - } |
| 360 | + String name = f.name(); |
| 361 | + String[] vals = doc.getValues(name); |
| 362 | + elem.put(name, vals.length > 1 ? Arrays.asList(vals) : vals[0]); |
352 | 363 | } |
353 | 364 | data.add(elem); |
354 | 365 | } |
355 | 366 |
|
356 | 367 | results.put("data", data); |
357 | 368 | results.put("totalHits", topDocs.totalHits.value); |
358 | | - |
359 | 369 | return results; |
360 | 370 | } |
361 | 371 |
|
|
0 commit comments