From 0e21c72e0ae24279802d774d95e150513e19f377 Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Sun, 26 Feb 2023 21:41:20 +0100 Subject: [PATCH] Finalize and test the new implementation --- .../it/cavallium/dbengine/client/Hits.java | 80 +++--------------- .../dbengine/client/LuceneIndexImpl.java | 39 +++------ .../dbengine/database/LLLuceneIndex.java | 2 + .../database/LLSearchResultShard.java | 81 +------------------ .../cavallium/dbengine/database/LLUtils.java | 8 ++ .../DatabaseMapDictionaryHashed.java | 10 ++- .../database/disk/LLIndexSearchers.java | 10 ++- .../database/disk/LLLocalLuceneIndex.java | 28 ++++--- .../disk/LLLocalMultiLuceneIndex.java | 40 ++++++--- .../dbengine/lucene/LuceneUtils.java | 11 ++- .../searcher/AdaptiveLocalSearcher.java | 25 +++--- .../searcher/AdaptiveMultiSearcher.java | 26 +++--- .../lucene/searcher/CountMultiSearcher.java | 27 ++++--- .../lucene/searcher/LocalSearcher.java | 7 +- .../lucene/searcher/LuceneSearchResult.java | 16 ++-- .../lucene/searcher/MultiSearcher.java | 17 ++-- .../lucene/searcher/PagedLocalSearcher.java | 42 +++------- .../searcher/ScoredPagedMultiSearcher.java | 34 +++----- .../lucene/searcher/StandardSearcher.java | 48 ++++------- .../UnsortedStreamingMultiSearcher.java | 30 ++----- .../tests/SwappableLuceneSearcher.java | 15 ++-- .../dbengine/tests/TestDictionaryMapDeep.java | 5 +- .../tests/TestDictionaryMapDeepHashMap.java | 6 +- .../dbengine/tests/TestLuceneSearches.java | 17 ++-- .../UnsortedUnscoredSimpleMultiSearcher.java | 43 +++------- 25 files changed, 248 insertions(+), 419 deletions(-) diff --git a/src/main/java/it/cavallium/dbengine/client/Hits.java b/src/main/java/it/cavallium/dbengine/client/Hits.java index 1ecc5e6..aab76b1 100644 --- a/src/main/java/it/cavallium/dbengine/client/Hits.java +++ b/src/main/java/it/cavallium/dbengine/client/Hits.java @@ -1,29 +1,28 @@ package it.cavallium.dbengine.client; +import com.google.common.collect.Lists; import it.cavallium.dbengine.client.query.current.data.TotalHitsCount; import it.cavallium.dbengine.database.DiscardingCloseable; +import it.cavallium.dbengine.database.LLUtils; import it.cavallium.dbengine.database.SafeCloseable; import it.cavallium.dbengine.database.collections.ValueGetter; import it.cavallium.dbengine.lucene.LuceneCloseable; import it.cavallium.dbengine.utils.SimpleResource; +import java.util.ArrayList; +import java.util.List; import java.util.function.Function; import java.util.stream.Stream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -public class Hits extends SimpleResource implements DiscardingCloseable { +public class Hits { private static final Logger LOG = LogManager.getLogger(Hits.class); - private static final Hits EMPTY_HITS = new Hits<>(Stream.empty(), TotalHitsCount.of(0, true), false); - private final Stream results; + private static final Hits EMPTY_HITS = new Hits<>(List.of(), TotalHitsCount.of(0, true)); + private final List results; private final TotalHitsCount totalHitsCount; - public Hits(Stream results, TotalHitsCount totalHitsCount) { - this(results, totalHitsCount, true); - } - - private Hits(Stream results, TotalHitsCount totalHitsCount, boolean canClose) { - super(canClose); + public Hits(List results, TotalHitsCount totalHitsCount) { this.results = results; this.totalHitsCount = totalHitsCount; } @@ -36,27 +35,18 @@ public class Hits extends SimpleResource implements DiscardingCloseable { public static Function>, Hits>> generateMapper( ValueGetter valueGetter) { return result -> { - var hitsToTransform = result.results() - .map(hit -> new HitEntry<>(hit.key(), valueGetter.get(hit.key()), hit.score())); - return Hits.withResource(hitsToTransform, result.totalHitsCount(), result); + List> hitsToTransform = LLUtils.mapList(result.results, + hit -> new HitEntry<>(hit.key(), valueGetter.get(hit.key()), hit.score()) + ); + return new Hits<>(hitsToTransform, result.totalHitsCount()); }; } - public static Hits withResource(Stream hits, TotalHitsCount count, SafeCloseable resource) { - if (resource instanceof LuceneCloseable luceneCloseable) { - return new LuceneHits<>(hits, count, luceneCloseable); - } else { - return new CloseableHits<>(hits, count, resource); - } - } - - public Stream results() { - ensureOpen(); + public List results() { return results; } public TotalHitsCount totalHitsCount() { - ensureOpen(); return totalHitsCount; } @@ -64,48 +54,4 @@ public class Hits extends SimpleResource implements DiscardingCloseable { public String toString() { return "Hits[" + "results=" + results + ", " + "totalHitsCount=" + totalHitsCount + ']'; } - - @Override - protected void onClose() { - } - - public static final class LuceneHits extends Hits implements LuceneCloseable { - - private final LuceneCloseable resource; - - public LuceneHits(Stream hits, TotalHitsCount count, LuceneCloseable resource) { - super(hits, count); - this.resource = resource; - } - - @Override - protected void onClose() { - try { - resource.close(); - } catch (Throwable ex) { - LOG.error("Failed to close resource", ex); - } - super.onClose(); - } - } - - public static final class CloseableHits extends Hits { - - private final SafeCloseable resource; - - public CloseableHits(Stream hits, TotalHitsCount count, SafeCloseable resource) { - super(hits, count); - this.resource = resource; - } - - @Override - protected void onClose() { - try { - resource.close(); - } catch (Throwable ex) { - LOG.error("Failed to close resource", ex); - } - super.onClose(); - } - } } diff --git a/src/main/java/it/cavallium/dbengine/client/LuceneIndexImpl.java b/src/main/java/it/cavallium/dbengine/client/LuceneIndexImpl.java index 74236d2..dd5df85 100644 --- a/src/main/java/it/cavallium/dbengine/client/LuceneIndexImpl.java +++ b/src/main/java/it/cavallium/dbengine/client/LuceneIndexImpl.java @@ -1,28 +1,28 @@ package it.cavallium.dbengine.client; import static it.cavallium.dbengine.utils.StreamUtils.LUCENE_SCHEDULER; +import static it.cavallium.dbengine.utils.StreamUtils.collect; import static it.cavallium.dbengine.utils.StreamUtils.collectOn; +import static it.cavallium.dbengine.utils.StreamUtils.fastListing; import static it.cavallium.dbengine.utils.StreamUtils.toListOn; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toList; -import it.cavallium.dbengine.client.Hits.CloseableHits; -import it.cavallium.dbengine.client.Hits.LuceneHits; import it.cavallium.dbengine.client.query.ClientQueryParams; import it.cavallium.dbengine.client.query.current.data.Query; import it.cavallium.dbengine.client.query.current.data.TotalHitsCount; import it.cavallium.dbengine.database.LLKeyScore; import it.cavallium.dbengine.database.LLLuceneIndex; import it.cavallium.dbengine.database.LLSearchResultShard; -import it.cavallium.dbengine.database.LLSearchResultShard.LuceneLLSearchResultShard; -import it.cavallium.dbengine.database.LLSearchResultShard.ResourcesLLSearchResultShard; import it.cavallium.dbengine.database.LLSnapshot; import it.cavallium.dbengine.database.LLTerm; +import it.cavallium.dbengine.database.LLUtils; import it.cavallium.dbengine.database.SafeCloseable; import it.cavallium.dbengine.lucene.LuceneCloseable; import it.cavallium.dbengine.lucene.LuceneUtils; import it.cavallium.dbengine.lucene.collector.Buckets; import it.cavallium.dbengine.lucene.searcher.BucketParams; +import it.cavallium.dbengine.utils.StreamUtils; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.time.Duration; import java.util.List; @@ -39,7 +39,6 @@ import org.jetbrains.annotations.Nullable; public class LuceneIndexImpl implements LuceneIndex { private static final Duration MAX_COUNT_TIME = Duration.ofSeconds(30); - private static final Logger LOG = LogManager.getLogger(LuceneIndex.class); private final LLLuceneIndex luceneIndex; private final Indicizer indicizer; @@ -120,14 +119,10 @@ public class LuceneIndexImpl implements LuceneIndex { } private Hits> mapResults(LLSearchResultShard llSearchResult) { - Stream> scoresWithKeysFlux = llSearchResult.results() - .map(hit -> new HitKey<>(indicizer.getKey(hit.key()), hit.score())); - - if (llSearchResult instanceof LuceneCloseable luceneCloseable) { - return new LuceneHits<>(scoresWithKeysFlux, llSearchResult.totalHitsCount(), luceneCloseable); - } else { - return new CloseableHits<>(scoresWithKeysFlux, llSearchResult.totalHitsCount(), llSearchResult); - } + List> scoresWithKeys = LLUtils.mapList(llSearchResult.results(), + hit -> new HitKey<>(indicizer.getKey(hit.key()), hit.score()) + ); + return new Hits<>(scoresWithKeys, llSearchResult.totalHitsCount()); } @Override @@ -203,20 +198,14 @@ public class LuceneIndexImpl implements LuceneIndex { } TotalHitsCount count = null; ObjectArrayList> results = new ObjectArrayList<>(shards.size()); - ObjectArrayList resources = new ObjectArrayList(shards.size()); - boolean luceneResources = false; + var maxLimit = queryParams.offset() + queryParams.limit(); for (LLSearchResultShard shard : shards) { - if (!luceneResources && shard instanceof LuceneCloseable) { - luceneResources = true; - } if (count == null) { count = shard.totalHitsCount(); } else { count = LuceneUtils.sum(count, shard.totalHitsCount()); } - var maxLimit = queryParams.offset() + queryParams.limit(); - results.add(shard.results().limit(maxLimit)); - resources.add(shard); + results.add(shard.results().stream().limit(maxLimit)); } Objects.requireNonNull(count); Stream resultsFlux; @@ -225,13 +214,9 @@ public class LuceneIndexImpl implements LuceneIndex { } else if (results.size() == 1) { resultsFlux = results.get(0); } else { - resultsFlux = results.stream().flatMap(Function.identity()); - } - if (luceneResources) { - return new LuceneLLSearchResultShard(resultsFlux, count, (List) resources); - } else { - return new ResourcesLLSearchResultShard(resultsFlux, count, (List) resources); + resultsFlux = results.stream().flatMap(Function.identity()).limit(maxLimit); } + return new LLSearchResultShard(StreamUtils.toList(resultsFlux), count); } } diff --git a/src/main/java/it/cavallium/dbengine/database/LLLuceneIndex.java b/src/main/java/it/cavallium/dbengine/database/LLLuceneIndex.java index 1f9c61f..9dd4aa0 100644 --- a/src/main/java/it/cavallium/dbengine/database/LLLuceneIndex.java +++ b/src/main/java/it/cavallium/dbengine/database/LLLuceneIndex.java @@ -37,6 +37,7 @@ public interface LLLuceneIndex extends LLSnapshottable, IBackuppable, SafeClosea void deleteAll(); + // todo: add a filterer parameter? /** * @param queryParams the limit is valid for each lucene instance. If you have 15 instances, the number of elements * returned can be at most limit * 15. @@ -49,6 +50,7 @@ public interface LLLuceneIndex extends LLSnapshottable, IBackuppable, SafeClosea @Nullable String keyFieldName, Multimap mltDocumentFields); + // todo: add a filterer parameter? /** * @param queryParams the limit is valid for each lucene instance. If you have 15 instances, the number of elements * returned can be at most limit * 15 diff --git a/src/main/java/it/cavallium/dbengine/database/LLSearchResultShard.java b/src/main/java/it/cavallium/dbengine/database/LLSearchResultShard.java index 21a87b7..9bdbd81 100644 --- a/src/main/java/it/cavallium/dbengine/database/LLSearchResultShard.java +++ b/src/main/java/it/cavallium/dbengine/database/LLSearchResultShard.java @@ -9,35 +9,23 @@ import java.util.stream.Stream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -public class LLSearchResultShard extends SimpleResource implements DiscardingCloseable { +public class LLSearchResultShard { private static final Logger LOG = LogManager.getLogger(LLSearchResultShard.class); - private final Stream results; + private final List results; private final TotalHitsCount totalHitsCount; - public LLSearchResultShard(Stream results, TotalHitsCount totalHitsCount) { + public LLSearchResultShard(List results, TotalHitsCount totalHitsCount) { this.results = results; this.totalHitsCount = totalHitsCount; } - public static LLSearchResultShard withResource(Stream results, - TotalHitsCount totalHitsCount, - SafeCloseable closeableResource) { - if (closeableResource instanceof LuceneCloseable luceneCloseable) { - return new LuceneLLSearchResultShard(results, totalHitsCount, List.of(luceneCloseable)); - } else { - return new ResourcesLLSearchResultShard(results, totalHitsCount, List.of(closeableResource)); - } - } - - public Stream results() { - ensureOpen(); + public List results() { return results; } public TotalHitsCount totalHitsCount() { - ensureOpen(); return totalHitsCount; } @@ -60,65 +48,4 @@ public class LLSearchResultShard extends SimpleResource implements DiscardingClo public String toString() { return "LLSearchResultShard[" + "results=" + results + ", " + "totalHitsCount=" + totalHitsCount + ']'; } - - @Override - public void onClose() { - results.close(); - } - - public static class ResourcesLLSearchResultShard extends LLSearchResultShard { - - private final List resources; - - public ResourcesLLSearchResultShard(Stream resultsFlux, - TotalHitsCount count, - List resources) { - super(resultsFlux, count); - this.resources = resources; - } - - @Override - public void onClose() { - try { - for (SafeCloseable resource : resources) { - try { - resource.close(); - } catch (Throwable ex) { - LOG.error("Failed to close resource", ex); - } - } - } catch (Throwable ex) { - LOG.error("Failed to close resources", ex); - } - super.onClose(); - } - } - - public static class LuceneLLSearchResultShard extends LLSearchResultShard implements LuceneCloseable { - - private final List resources; - - public LuceneLLSearchResultShard(Stream resultsFlux, - TotalHitsCount count, - List resources) { - super(resultsFlux, count); - this.resources = resources; - } - - @Override - public void onClose() { - try { - for (LuceneCloseable resource : resources) { - try { - resource.close(); - } catch (Throwable ex) { - LOG.error("Failed to close resource", ex); - } - } - } catch (Throwable ex) { - LOG.error("Failed to close resources", ex); - } - super.onClose(); - } - } } diff --git a/src/main/java/it/cavallium/dbengine/database/LLUtils.java b/src/main/java/it/cavallium/dbengine/database/LLUtils.java index 12be464..fe825cc 100644 --- a/src/main/java/it/cavallium/dbengine/database/LLUtils.java +++ b/src/main/java/it/cavallium/dbengine/database/LLUtils.java @@ -6,6 +6,8 @@ import com.google.common.primitives.Ints; import com.google.common.primitives.Longs; import io.netty.util.IllegalReferenceCountException; import it.cavallium.dbengine.buffers.Buf; +import it.cavallium.dbengine.client.HitEntry; +import it.cavallium.dbengine.client.HitKey; import it.cavallium.dbengine.database.serialization.SerializationFunction; import it.cavallium.dbengine.lucene.LuceneCloseable; import it.cavallium.dbengine.lucene.LuceneUtils; @@ -24,6 +26,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; +import java.util.function.Function; import java.util.stream.Stream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -676,6 +679,11 @@ public class LLUtils { } } + public static List mapList(List input, Function mapper) { + //todo: optimize hits mapping + return input.stream().map(mapper).toList(); + } + private static class FakeBytesRefBuilder extends BytesRefBuilder { private final LLTerm term; diff --git a/src/main/java/it/cavallium/dbengine/database/collections/DatabaseMapDictionaryHashed.java b/src/main/java/it/cavallium/dbengine/database/collections/DatabaseMapDictionaryHashed.java index 5bb44eb..9cdc6a7 100644 --- a/src/main/java/it/cavallium/dbengine/database/collections/DatabaseMapDictionaryHashed.java +++ b/src/main/java/it/cavallium/dbengine/database/collections/DatabaseMapDictionaryHashed.java @@ -13,6 +13,7 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectSortedMap; import it.unimi.dsi.fastutil.objects.ObjectArraySet; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; @@ -188,12 +189,15 @@ public class DatabaseMapDictionaryHashed implements DatabaseStageMap> setAllValuesAndGetPrevious(Stream> entries) { - return entries.mapMulti((entry, sink) -> { + List> prevList = entries.map(entry -> { var prev = this.at(null, entry.getKey()).setAndGetPrevious(entry.getValue()); if (prev != null) { - sink.accept(Map.entry(entry.getKey(), prev)); + return Map.entry(entry.getKey(), prev); + } else { + return null; } - }); + }).filter(Objects::nonNull).toList(); + return prevList.stream(); } @Override diff --git a/src/main/java/it/cavallium/dbengine/database/disk/LLIndexSearchers.java b/src/main/java/it/cavallium/dbengine/database/disk/LLIndexSearchers.java index f1da746..4ea39ee 100644 --- a/src/main/java/it/cavallium/dbengine/database/disk/LLIndexSearchers.java +++ b/src/main/java/it/cavallium/dbengine/database/disk/LLIndexSearchers.java @@ -7,6 +7,7 @@ import it.cavallium.dbengine.utils.SimpleResource; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import org.apache.lucene.search.IndexSearcher; public interface LLIndexSearchers extends DiscardingCloseable { @@ -27,11 +28,12 @@ public interface LLIndexSearchers extends DiscardingCloseable { LLIndexSearcher llShard(int shardIndex); - class UnshardedIndexSearchers extends SimpleResource implements LLIndexSearchers, LuceneCloseable { + class UnshardedIndexSearchers implements LLIndexSearchers, LuceneCloseable { private final LLIndexSearcher indexSearcher; public UnshardedIndexSearchers(LLIndexSearcher indexSearcher) { + Objects.requireNonNull(indexSearcher); this.indexSearcher = indexSearcher; } @@ -70,12 +72,12 @@ public interface LLIndexSearchers extends DiscardingCloseable { } @Override - protected void onClose() { + public void close() { indexSearcher.close(); } } - class ShardedIndexSearchers extends SimpleResource implements LLIndexSearchers, LuceneCloseable { + class ShardedIndexSearchers implements LLIndexSearchers, LuceneCloseable { private final List indexSearchers; private final List indexSearchersVals; @@ -117,7 +119,7 @@ public interface LLIndexSearchers extends DiscardingCloseable { } @Override - protected void onClose() { + public void close() { for (LLIndexSearcher indexSearcher : indexSearchers) { indexSearcher.close(); } diff --git a/src/main/java/it/cavallium/dbengine/database/disk/LLLocalLuceneIndex.java b/src/main/java/it/cavallium/dbengine/database/disk/LLLocalLuceneIndex.java index 935b309..db505d2 100644 --- a/src/main/java/it/cavallium/dbengine/database/disk/LLLocalLuceneIndex.java +++ b/src/main/java/it/cavallium/dbengine/database/disk/LLLocalLuceneIndex.java @@ -4,6 +4,7 @@ import static it.cavallium.dbengine.database.LLUtils.MARKER_LUCENE; import static it.cavallium.dbengine.database.LLUtils.toDocument; import static it.cavallium.dbengine.database.LLUtils.toFields; import static it.cavallium.dbengine.lucene.searcher.GlobalQueryRewrite.NO_REWRITE; +import static it.cavallium.dbengine.lucene.searcher.LuceneSearchResult.EMPTY_COUNT; import static it.cavallium.dbengine.utils.StreamUtils.collect; import static it.cavallium.dbengine.utils.StreamUtils.fastListing; import static java.util.Objects.requireNonNull; @@ -60,6 +61,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.LongAdder; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Function; import java.util.function.Supplier; import java.util.logging.Level; import java.util.stream.Stream; @@ -494,33 +496,38 @@ public class LLLocalLuceneIndex extends SimpleResource implements IBackuppable, var searcher = this.searcherManager.retrieveSearcher(snapshot); var transformer = new MoreLikeThisTransformer(mltDocumentFieldsFlux, luceneAnalyzer, luceneSimilarity); - var result = localSearcher.collect(searcher, localQueryParams, keyFieldName, transformer); - return Stream.of(LLSearchResultShard.withResource(result.results(), result.totalHitsCount(), result)); + var result = localSearcher.collect(searcher, localQueryParams, keyFieldName, transformer, Function.identity()); + return Stream.of(new LLSearchResultShard(result.results(), result.totalHitsCount())); } @Override public Stream search(@Nullable LLSnapshot snapshot, QueryParams queryParams, @Nullable String keyFieldName) { var result = searchInternal(snapshot, queryParams, keyFieldName); - var shard = LLSearchResultShard.withResource(result.results(), result.totalHitsCount(), result); - return Stream.of(shard).onClose(shard::close); + var shard = new LLSearchResultShard(result.results(), result.totalHitsCount()); + return Stream.of(shard); } public LuceneSearchResult searchInternal(@Nullable LLSnapshot snapshot, QueryParams queryParams, @Nullable String keyFieldName) { LocalQueryParams localQueryParams = LuceneUtils.toLocalQueryParams(queryParams, luceneAnalyzer); try (var searcher = searcherManager.retrieveSearcher(snapshot)) { - - return localSearcher.collect(searcher, localQueryParams, keyFieldName, NO_REWRITE); + if (searcher != null) { + return localSearcher.collect(searcher, localQueryParams, keyFieldName, NO_REWRITE, Function.identity()); + } else { + return LuceneSearchResult.EMPTY; + } } } @Override public TotalHitsCount count(@Nullable LLSnapshot snapshot, Query query, @Nullable Duration timeout) { var params = LuceneUtils.getCountQueryParams(query); - try (var result = this.searchInternal(snapshot, params, null)) { - if (result == null) return TotalHitsCount.of(0, true); + var result = this.searchInternal(snapshot, params, null); + if (result != null) { return result.totalHitsCount(); + } else { + return EMPTY_COUNT; } } @@ -534,9 +541,10 @@ public class LLLocalLuceneIndex extends SimpleResource implements IBackuppable, localQueries.add(QueryParser.toQuery(query, luceneAnalyzer)); } var localNormalizationQuery = QueryParser.toQuery(normalizationQuery, luceneAnalyzer); - LLIndexSearchers searchers = LLIndexSearchers.unsharded(searcherManager.retrieveSearcher(snapshot)); + try (LLIndexSearchers searchers = LLIndexSearchers.unsharded(searcherManager.retrieveSearcher(snapshot))) { - return decimalBucketMultiSearcher.collectMulti(searchers, bucketParams, localQueries, localNormalizationQuery); + return decimalBucketMultiSearcher.collectMulti(searchers, bucketParams, localQueries, localNormalizationQuery); + } } public LLIndexSearcher retrieveSearcher(@Nullable LLSnapshot snapshot) { diff --git a/src/main/java/it/cavallium/dbengine/database/disk/LLLocalMultiLuceneIndex.java b/src/main/java/it/cavallium/dbengine/database/disk/LLLocalMultiLuceneIndex.java index b6e6d97..dac9d0d 100644 --- a/src/main/java/it/cavallium/dbengine/database/disk/LLLocalMultiLuceneIndex.java +++ b/src/main/java/it/cavallium/dbengine/database/disk/LLLocalMultiLuceneIndex.java @@ -58,6 +58,7 @@ import java.util.Objects; import java.util.concurrent.CompletionException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.logging.log4j.LogManager; @@ -210,14 +211,20 @@ public class LLLocalMultiLuceneIndex extends SimpleResource implements LLLuceneI String keyFieldName, Multimap mltDocumentFields) { LocalQueryParams localQueryParams = LuceneUtils.toLocalQueryParams(queryParams, luceneAnalyzer); - var searchers = this.getIndexSearchers(snapshot); - var transformer = new MoreLikeThisTransformer(mltDocumentFields, luceneAnalyzer, luceneSimilarity); + try (var searchers = this.getIndexSearchers(snapshot)) { + var transformer = new MoreLikeThisTransformer(mltDocumentFields, luceneAnalyzer, luceneSimilarity); - // Collect all the shards results into a single global result - LuceneSearchResult result = multiSearcher.collectMulti(searchers, localQueryParams, keyFieldName, transformer); + // Collect all the shards results into a single global result + LuceneSearchResult result = multiSearcher.collectMulti(searchers, + localQueryParams, + keyFieldName, + transformer, + Function.identity() + ); - // Transform the result type - return Stream.of(new LLSearchResultShard(result.results(), result.totalHitsCount())); + // Transform the result type + return Stream.of(new LLSearchResultShard(result.results(), result.totalHitsCount())); + } } @Override @@ -227,17 +234,23 @@ public class LLLocalMultiLuceneIndex extends SimpleResource implements LLLuceneI LuceneSearchResult result = searchInternal(snapshot, queryParams, keyFieldName); // Transform the result type var shard = new LLSearchResultShard(result.results(), result.totalHitsCount()); - return Stream.of(shard).onClose(shard::close); + return Stream.of(shard); } private LuceneSearchResult searchInternal(@Nullable LLSnapshot snapshot, QueryParams queryParams, @Nullable String keyFieldName) { LocalQueryParams localQueryParams = LuceneUtils.toLocalQueryParams(queryParams, luceneAnalyzer); - var searchers = getIndexSearchers(snapshot); + try (var searchers = getIndexSearchers(snapshot)) { - // Collect all the shards results into a single global result - return multiSearcher.collectMulti(searchers, localQueryParams, keyFieldName, GlobalQueryRewrite.NO_REWRITE); + // Collect all the shards results into a single global result + return multiSearcher.collectMulti(searchers, + localQueryParams, + keyFieldName, + GlobalQueryRewrite.NO_REWRITE, + Function.identity() + ); + } } @Override @@ -257,10 +270,11 @@ public class LLLocalMultiLuceneIndex extends SimpleResource implements LLLuceneI localQueries.add(QueryParser.toQuery(query, luceneAnalyzer)); } var localNormalizationQuery = QueryParser.toQuery(normalizationQuery, luceneAnalyzer); - var searchers = getIndexSearchers(snapshot); + try (var searchers = getIndexSearchers(snapshot)) { - // Collect all the shards results into a single global result - return decimalBucketMultiSearcher.collectMulti(searchers, bucketParams, localQueries, localNormalizationQuery); + // Collect all the shards results into a single global result + return decimalBucketMultiSearcher.collectMulti(searchers, bucketParams, localQueries, localNormalizationQuery); + } } @Override diff --git a/src/main/java/it/cavallium/dbengine/lucene/LuceneUtils.java b/src/main/java/it/cavallium/dbengine/lucene/LuceneUtils.java index 8968182..13a8c28 100644 --- a/src/main/java/it/cavallium/dbengine/lucene/LuceneUtils.java +++ b/src/main/java/it/cavallium/dbengine/lucene/LuceneUtils.java @@ -64,6 +64,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.Optional; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.logging.log4j.LogManager; @@ -722,10 +723,11 @@ public class LuceneUtils { LLIndexSearcher indexSearcher, LocalQueryParams queryParams, String keyFieldName, - GlobalQueryRewrite transformer) { + GlobalQueryRewrite transformer, + Function, Stream> filterer) { var indexSearchers = LLIndexSearchers.unsharded(indexSearcher); var queryParams2 = transformer.rewrite(indexSearchers, queryParams); - return localSearcher.collect(indexSearcher, queryParams2, keyFieldName, NO_REWRITE); + return localSearcher.collect(indexSearcher, queryParams2, keyFieldName, NO_REWRITE, filterer); } /** @@ -735,9 +737,10 @@ public class LuceneUtils { LLIndexSearchers indexSearchers, LocalQueryParams queryParams, String keyFieldName, - GlobalQueryRewrite transformer) { + GlobalQueryRewrite transformer, + Function, Stream> filterer) { var queryParams2 = transformer.rewrite(indexSearchers, queryParams); - return multiSearcher.collectMulti(indexSearchers, queryParams2, keyFieldName, NO_REWRITE); + return multiSearcher.collectMulti(indexSearchers, queryParams2, keyFieldName, NO_REWRITE, filterer); } public static void checkLuceneThread() { diff --git a/src/main/java/it/cavallium/dbengine/lucene/searcher/AdaptiveLocalSearcher.java b/src/main/java/it/cavallium/dbengine/lucene/searcher/AdaptiveLocalSearcher.java index 6d3dfc6..86478f7 100644 --- a/src/main/java/it/cavallium/dbengine/lucene/searcher/AdaptiveLocalSearcher.java +++ b/src/main/java/it/cavallium/dbengine/lucene/searcher/AdaptiveLocalSearcher.java @@ -2,9 +2,12 @@ package it.cavallium.dbengine.lucene.searcher; import static it.cavallium.dbengine.lucene.searcher.GlobalQueryRewrite.NO_REWRITE; +import it.cavallium.dbengine.database.LLKeyScore; import it.cavallium.dbengine.database.disk.LLIndexSearcher; import it.cavallium.dbengine.lucene.LuceneUtils; import java.io.IOException; +import java.util.function.Function; +import java.util.stream.Stream; import org.jetbrains.annotations.Nullable; public class AdaptiveLocalSearcher implements LocalSearcher { @@ -30,11 +33,12 @@ public class AdaptiveLocalSearcher implements LocalSearcher { public LuceneSearchResult collect(LLIndexSearcher indexSearcher, LocalQueryParams queryParams, @Nullable String keyFieldName, - GlobalQueryRewrite transformer) { + GlobalQueryRewrite transformer, + Function, Stream> filterer) { if (transformer != NO_REWRITE) { - return LuceneUtils.rewrite(this, indexSearcher, queryParams, keyFieldName, transformer); + return LuceneUtils.rewrite(this, indexSearcher, queryParams, keyFieldName, transformer, filterer); } - return transformedCollect(indexSearcher, queryParams, keyFieldName, transformer); + return transformedCollect(indexSearcher, queryParams, keyFieldName, transformer, filterer); } @Override @@ -46,35 +50,36 @@ public class AdaptiveLocalSearcher implements LocalSearcher { public LuceneSearchResult transformedCollect(LLIndexSearcher indexSearcher, LocalQueryParams queryParams, String keyFieldName, - GlobalQueryRewrite transformer) { + GlobalQueryRewrite transformer, + Function, Stream> filterer) { // offset + limit long realLimit = queryParams.offsetLong() + queryParams.limitLong(); long maxAllowedInMemoryLimit = Math.max(maxInMemoryResultEntries, (long) queryParams.pageLimits().getPageLimit(0)); if (queryParams.limitLong() == 0) { - return countSearcher.collect(indexSearcher, queryParams, keyFieldName, transformer); + return countSearcher.collect(indexSearcher, queryParams, keyFieldName, transformer, filterer); } else if (realLimit <= maxInMemoryResultEntries) { - return standardSearcher.collect(indexSearcher, queryParams, keyFieldName, transformer); + return standardSearcher.collect(indexSearcher, queryParams, keyFieldName, transformer, filterer); } else if (queryParams.isSorted()) { if (realLimit <= maxAllowedInMemoryLimit) { - return scoredPaged.collect(indexSearcher, queryParams, keyFieldName, transformer); + return scoredPaged.collect(indexSearcher, queryParams, keyFieldName, transformer, filterer); } else { if (queryParams.isSortedByScore()) { if (queryParams.limitLong() < maxInMemoryResultEntries) { throw new UnsupportedOperationException("Allowed limit is " + maxInMemoryResultEntries + " or greater"); } - return scoredPaged.collect(indexSearcher, queryParams, keyFieldName, transformer); + return scoredPaged.collect(indexSearcher, queryParams, keyFieldName, transformer, filterer); } else { if (queryParams.limitLong() < maxInMemoryResultEntries) { throw new UnsupportedOperationException("Allowed limit is " + maxInMemoryResultEntries + " or greater"); } - return scoredPaged.collect(indexSearcher, queryParams, keyFieldName, transformer); + return scoredPaged.collect(indexSearcher, queryParams, keyFieldName, transformer, filterer); } } } else { // Run large/unbounded searches using the continuous multi searcher - return unsortedUnscoredContinuous.collect(indexSearcher, queryParams, keyFieldName, transformer); + return unsortedUnscoredContinuous.collect(indexSearcher, queryParams, keyFieldName, transformer, filterer); } } } diff --git a/src/main/java/it/cavallium/dbengine/lucene/searcher/AdaptiveMultiSearcher.java b/src/main/java/it/cavallium/dbengine/lucene/searcher/AdaptiveMultiSearcher.java index 5e05b96..30c691f 100644 --- a/src/main/java/it/cavallium/dbengine/lucene/searcher/AdaptiveMultiSearcher.java +++ b/src/main/java/it/cavallium/dbengine/lucene/searcher/AdaptiveMultiSearcher.java @@ -2,9 +2,11 @@ package it.cavallium.dbengine.lucene.searcher; import static it.cavallium.dbengine.lucene.searcher.GlobalQueryRewrite.NO_REWRITE; +import it.cavallium.dbengine.database.LLKeyScore; import it.cavallium.dbengine.database.disk.LLIndexSearchers; import it.cavallium.dbengine.lucene.LuceneUtils; -import java.io.IOException; +import java.util.function.Function; +import java.util.stream.Stream; import org.jetbrains.annotations.Nullable; public class AdaptiveMultiSearcher implements MultiSearcher { @@ -30,46 +32,48 @@ public class AdaptiveMultiSearcher implements MultiSearcher { public LuceneSearchResult collectMulti(LLIndexSearchers indexSearchers, LocalQueryParams queryParams, @Nullable String keyFieldName, - GlobalQueryRewrite transformer) { + GlobalQueryRewrite transformer, + Function, Stream> filterer) { if (transformer != NO_REWRITE) { - return LuceneUtils.rewriteMulti(this, indexSearchers, queryParams, keyFieldName, transformer); + return LuceneUtils.rewriteMulti(this, indexSearchers, queryParams, keyFieldName, transformer, filterer); } - return transformedCollectMulti(indexSearchers, queryParams, keyFieldName, transformer); + return transformedCollectMulti(indexSearchers, queryParams, keyFieldName, transformer, filterer); } // Remember to change also AdaptiveLocalSearcher public LuceneSearchResult transformedCollectMulti(LLIndexSearchers indexSearchers, LocalQueryParams queryParams, @Nullable String keyFieldName, - GlobalQueryRewrite transformer) { + GlobalQueryRewrite transformer, + Function, Stream> filterer) { // offset + limit long realLimit = queryParams.offsetLong() + queryParams.limitLong(); long maxAllowedInMemoryLimit = Math.max(maxInMemoryResultEntries, (long) queryParams.pageLimits().getPageLimit(0)); if (queryParams.limitLong() == 0) { - return count.collectMulti(indexSearchers, queryParams, keyFieldName, transformer); + return count.collectMulti(indexSearchers, queryParams, keyFieldName, transformer, filterer); } else if (realLimit <= maxInMemoryResultEntries) { - return standardSearcher.collectMulti(indexSearchers, queryParams, keyFieldName, transformer); + return standardSearcher.collectMulti(indexSearchers, queryParams, keyFieldName, transformer, filterer); } else if (queryParams.isSorted()) { if (realLimit <= maxAllowedInMemoryLimit) { - return scoredPaged.collectMulti(indexSearchers, queryParams, keyFieldName, transformer); + return scoredPaged.collectMulti(indexSearchers, queryParams, keyFieldName, transformer, filterer); } else { if (queryParams.isSortedByScore()) { if (queryParams.limitLong() < maxInMemoryResultEntries) { throw new UnsupportedOperationException("Allowed limit is " + maxInMemoryResultEntries + " or greater"); } - return scoredPaged.collectMulti(indexSearchers, queryParams, keyFieldName, transformer); + return scoredPaged.collectMulti(indexSearchers, queryParams, keyFieldName, transformer, filterer); } else { if (queryParams.limitLong() < maxInMemoryResultEntries) { throw new UnsupportedOperationException("Allowed limit is " + maxInMemoryResultEntries + " or greater"); } - return scoredPaged.collectMulti(indexSearchers, queryParams, keyFieldName, transformer); + return scoredPaged.collectMulti(indexSearchers, queryParams, keyFieldName, transformer, filterer); } } } else { // Run large/unbounded searches using the continuous multi searcher - return unsortedUnscoredContinuous.collectMulti(indexSearchers, queryParams, keyFieldName, transformer); + return unsortedUnscoredContinuous.collectMulti(indexSearchers, queryParams, keyFieldName, transformer, filterer); } } diff --git a/src/main/java/it/cavallium/dbengine/lucene/searcher/CountMultiSearcher.java b/src/main/java/it/cavallium/dbengine/lucene/searcher/CountMultiSearcher.java index 5d997e3..95097f6 100644 --- a/src/main/java/it/cavallium/dbengine/lucene/searcher/CountMultiSearcher.java +++ b/src/main/java/it/cavallium/dbengine/lucene/searcher/CountMultiSearcher.java @@ -1,12 +1,15 @@ package it.cavallium.dbengine.lucene.searcher; import it.cavallium.dbengine.client.query.current.data.TotalHitsCount; +import it.cavallium.dbengine.database.LLKeyScore; import it.cavallium.dbengine.database.LLUtils; import it.cavallium.dbengine.database.disk.LLIndexSearcher; import it.cavallium.dbengine.database.disk.LLIndexSearchers; import it.cavallium.dbengine.lucene.LuceneUtils; import it.cavallium.dbengine.utils.DBException; import java.io.IOException; +import java.util.List; +import java.util.function.Function; import java.util.stream.Stream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -21,10 +24,11 @@ public class CountMultiSearcher implements MultiSearcher { @Override public LuceneSearchResult collectMulti(LLIndexSearchers indexSearchers, LocalQueryParams queryParams, - String keyFieldName, - GlobalQueryRewrite transformer) { + @Nullable String keyFieldName, + GlobalQueryRewrite transformer, + Function, Stream> filterer) { if (transformer != GlobalQueryRewrite.NO_REWRITE) { - return LuceneUtils.rewriteMulti(this, indexSearchers, queryParams, keyFieldName, transformer); + return LuceneUtils.rewriteMulti(this, indexSearchers, queryParams, keyFieldName, transformer, filterer); } if (queryParams.isSorted() && queryParams.limitLong() > 0) { throw new UnsupportedOperationException( @@ -38,34 +42,39 @@ public class CountMultiSearcher implements MultiSearcher { var results = indexSearchers .llShards() .stream() - .map(searcher -> this.collect(searcher, queryParams, keyFieldName, transformer)) + .map(searcher -> this.collect(searcher, + queryParams, + keyFieldName, + transformer, + f -> filterer.apply(f).limit(0) + )) .toList(); boolean exactTotalHitsCount = true; long totalHitsCountValue = 0; for (LuceneSearchResult result : results) { exactTotalHitsCount &= result.totalHitsCount().exact(); totalHitsCountValue += result.totalHitsCount().value(); - result.close(); } var totalHitsCount = new TotalHitsCount(totalHitsCountValue, exactTotalHitsCount); - return new LuceneSearchResult(totalHitsCount, Stream.empty()); + return new LuceneSearchResult(totalHitsCount, List.of()); } @Override public LuceneSearchResult collect(LLIndexSearcher indexSearcher, LocalQueryParams queryParams, @Nullable String keyFieldName, - GlobalQueryRewrite transformer) { + GlobalQueryRewrite transformer, + Function, Stream> filterer) { if (transformer != GlobalQueryRewrite.NO_REWRITE) { - return LuceneUtils.rewrite(this, indexSearcher, queryParams, keyFieldName, transformer); + return LuceneUtils.rewrite(this, indexSearcher, queryParams, keyFieldName, transformer, filterer); } try { var is = indexSearcher.getIndexSearcher(); is.setTimeout(new QueryTimeoutImpl(queryParams.timeout().toMillis())); var count = is.count(queryParams.query()); - return new LuceneSearchResult(TotalHitsCount.of(count, true), Stream.empty()); + return new LuceneSearchResult(TotalHitsCount.of(count, true), List.of()); } catch (IOException e) { throw new DBException(e); } diff --git a/src/main/java/it/cavallium/dbengine/lucene/searcher/LocalSearcher.java b/src/main/java/it/cavallium/dbengine/lucene/searcher/LocalSearcher.java index 0dcde76..9f2ae00 100644 --- a/src/main/java/it/cavallium/dbengine/lucene/searcher/LocalSearcher.java +++ b/src/main/java/it/cavallium/dbengine/lucene/searcher/LocalSearcher.java @@ -1,6 +1,9 @@ package it.cavallium.dbengine.lucene.searcher; +import it.cavallium.dbengine.database.LLKeyScore; import it.cavallium.dbengine.database.disk.LLIndexSearcher; +import java.util.function.Function; +import java.util.stream.Stream; import org.jetbrains.annotations.Nullable; public interface LocalSearcher { @@ -10,11 +13,13 @@ public interface LocalSearcher { * @param queryParams the query parameters * @param keyFieldName the name of the key field * @param transformer the search query transformer + * @param filterer the search result filterer */ LuceneSearchResult collect(LLIndexSearcher indexSearcher, LocalQueryParams queryParams, @Nullable String keyFieldName, - GlobalQueryRewrite transformer); + GlobalQueryRewrite transformer, + Function, Stream> filterer); /** * Get the name of this searcher type diff --git a/src/main/java/it/cavallium/dbengine/lucene/searcher/LuceneSearchResult.java b/src/main/java/it/cavallium/dbengine/lucene/searcher/LuceneSearchResult.java index bcbbc15..58737ee 100644 --- a/src/main/java/it/cavallium/dbengine/lucene/searcher/LuceneSearchResult.java +++ b/src/main/java/it/cavallium/dbengine/lucene/searcher/LuceneSearchResult.java @@ -4,19 +4,23 @@ import it.cavallium.dbengine.client.query.current.data.TotalHitsCount; import it.cavallium.dbengine.database.DiscardingCloseable; import it.cavallium.dbengine.database.LLKeyScore; import it.cavallium.dbengine.utils.SimpleResource; +import java.util.List; import java.util.Objects; import java.util.stream.Stream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -public class LuceneSearchResult extends SimpleResource implements DiscardingCloseable { +public class LuceneSearchResult { + public static final TotalHitsCount EMPTY_COUNT = new TotalHitsCount(0, true); + + public static final LuceneSearchResult EMPTY = new LuceneSearchResult(EMPTY_COUNT, List.of()); private static final Logger logger = LogManager.getLogger(LuceneSearchResult.class); private final TotalHitsCount totalHitsCount; - private final Stream results; + private final List results; - public LuceneSearchResult(TotalHitsCount totalHitsCount, Stream results) { + public LuceneSearchResult(TotalHitsCount totalHitsCount, List results) { this.totalHitsCount = totalHitsCount; this.results = results; } @@ -25,7 +29,7 @@ public class LuceneSearchResult extends SimpleResource implements DiscardingClos return totalHitsCount; } - public Stream results() { + public List results() { return results; } @@ -49,8 +53,4 @@ public class LuceneSearchResult extends SimpleResource implements DiscardingClos return "LuceneSearchResult[" + "totalHitsCount=" + totalHitsCount + ", " + "results=" + results + ']'; } - @Override - protected void onClose() { - results.close(); - } } diff --git a/src/main/java/it/cavallium/dbengine/lucene/searcher/MultiSearcher.java b/src/main/java/it/cavallium/dbengine/lucene/searcher/MultiSearcher.java index ecc72f6..d7f5c76 100644 --- a/src/main/java/it/cavallium/dbengine/lucene/searcher/MultiSearcher.java +++ b/src/main/java/it/cavallium/dbengine/lucene/searcher/MultiSearcher.java @@ -1,36 +1,43 @@ package it.cavallium.dbengine.lucene.searcher; +import it.cavallium.dbengine.database.LLKeyScore; import it.cavallium.dbengine.database.disk.LLIndexSearcher; import it.cavallium.dbengine.database.disk.LLIndexSearchers; import java.io.IOException; +import java.util.function.Function; +import java.util.stream.Stream; import org.jetbrains.annotations.Nullable; public interface MultiSearcher extends LocalSearcher { /** - * @param indexSearchersMono Lucene index searcher + * @param indexSearchers Lucene index searcher * @param queryParams the query parameters * @param keyFieldName the name of the key field * @param transformer the search query transformer + * @param filterer the search result filterer */ - LuceneSearchResult collectMulti(LLIndexSearchers indexSearchersMono, + LuceneSearchResult collectMulti(LLIndexSearchers indexSearchers, LocalQueryParams queryParams, @Nullable String keyFieldName, - GlobalQueryRewrite transformer); + GlobalQueryRewrite transformer, + Function, Stream> filterer); /** * @param indexSearcher Lucene index searcher * @param queryParams the query parameters * @param keyFieldName the name of the key field * @param transformer the search query transformer + * @param filterer the search result filterer */ @Override default LuceneSearchResult collect(LLIndexSearcher indexSearcher, LocalQueryParams queryParams, @Nullable String keyFieldName, - GlobalQueryRewrite transformer) { + GlobalQueryRewrite transformer, + Function, Stream> filterer) { LLIndexSearchers searchers = LLIndexSearchers.unsharded(indexSearcher); - return this.collectMulti(searchers, queryParams, keyFieldName, transformer); + return this.collectMulti(searchers, queryParams, keyFieldName, transformer, filterer); } } diff --git a/src/main/java/it/cavallium/dbengine/lucene/searcher/PagedLocalSearcher.java b/src/main/java/it/cavallium/dbengine/lucene/searcher/PagedLocalSearcher.java index 3b3b01f..c5ad863 100644 --- a/src/main/java/it/cavallium/dbengine/lucene/searcher/PagedLocalSearcher.java +++ b/src/main/java/it/cavallium/dbengine/lucene/searcher/PagedLocalSearcher.java @@ -2,21 +2,21 @@ package it.cavallium.dbengine.lucene.searcher; import static it.cavallium.dbengine.lucene.searcher.CurrentPageInfo.EMPTY_STATUS; import static it.cavallium.dbengine.lucene.searcher.PaginationInfo.MAX_SINGLE_SEARCH_LIMIT; +import static it.cavallium.dbengine.utils.StreamUtils.fastListing; import static it.cavallium.dbengine.utils.StreamUtils.streamWhileNonNull; -import it.cavallium.dbengine.client.query.current.data.TotalHitsCount; import it.cavallium.dbengine.database.LLKeyScore; import it.cavallium.dbengine.database.LLUtils; import it.cavallium.dbengine.database.disk.LLIndexSearcher; import it.cavallium.dbengine.database.disk.LLIndexSearchers; -import it.cavallium.dbengine.lucene.LuceneCloseable; import it.cavallium.dbengine.lucene.LuceneUtils; import it.cavallium.dbengine.lucene.collector.TopDocsCollectorMultiManager; import it.cavallium.dbengine.utils.DBException; +import it.cavallium.dbengine.utils.StreamUtils; import java.io.IOException; import java.util.List; -import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; import java.util.stream.Stream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -35,9 +35,10 @@ public class PagedLocalSearcher implements LocalSearcher { public LuceneSearchResult collect(LLIndexSearcher indexSearcher, LocalQueryParams queryParams, @Nullable String keyFieldName, - GlobalQueryRewrite transformer) { + GlobalQueryRewrite transformer, + Function, Stream> filterer) { if (transformer != GlobalQueryRewrite.NO_REWRITE) { - return LuceneUtils.rewrite(this, indexSearcher, queryParams, keyFieldName, transformer); + return LuceneUtils.rewrite(this, indexSearcher, queryParams, keyFieldName, transformer, filterer); } PaginationInfo paginationInfo = getPaginationInfo(queryParams); @@ -51,12 +52,7 @@ public class PagedLocalSearcher implements LocalSearcher { keyFieldName, queryParams ); - return this.computeOtherResults(firstResult, - indexSearchers.shards(), - queryParams, - keyFieldName, - () -> indexSearchers.close() - ); + return this.computeOtherResults(firstResult, indexSearchers.shards(), queryParams, keyFieldName, filterer); } @Override @@ -113,7 +109,7 @@ public class PagedLocalSearcher implements LocalSearcher { List indexSearchers, LocalQueryParams queryParams, String keyFieldName, - Runnable onClose) { + Function, Stream> filterer) { var totalHitsCount = firstResult.totalHitsCount(); var firstPageHitsStream = firstResult.firstPageHitsStream(); var secondPageInfo = firstResult.nextPageInfo(); @@ -121,7 +117,7 @@ public class PagedLocalSearcher implements LocalSearcher { Stream nextHitsFlux = searchOtherPages(indexSearchers, queryParams, keyFieldName, secondPageInfo); Stream combinedFlux = Stream.concat(firstPageHitsStream, nextHitsFlux); - return new MyLuceneSearchResult(totalHitsCount, combinedFlux, onClose); + return new LuceneSearchResult(totalHitsCount, StreamUtils.collect(filterer.apply(combinedFlux), fastListing())); } /** @@ -193,24 +189,4 @@ public class PagedLocalSearcher implements LocalSearcher { return new PageIterationStepResult(EMPTY_STATUS, null); } } - - private static class MyLuceneSearchResult extends LuceneSearchResult implements LuceneCloseable { - - private final Runnable onClose; - - public MyLuceneSearchResult(TotalHitsCount totalHitsCount, Stream combinedStream, Runnable onClose) { - super(totalHitsCount, combinedStream); - this.onClose = onClose; - } - - @Override - protected void onClose() { - try { - onClose.run(); - } catch (Throwable ex) { - LOG.error("Failed to close the search result", ex); - } - super.onClose(); - } - } } diff --git a/src/main/java/it/cavallium/dbengine/lucene/searcher/ScoredPagedMultiSearcher.java b/src/main/java/it/cavallium/dbengine/lucene/searcher/ScoredPagedMultiSearcher.java index d9a2d7e..12c3485 100644 --- a/src/main/java/it/cavallium/dbengine/lucene/searcher/ScoredPagedMultiSearcher.java +++ b/src/main/java/it/cavallium/dbengine/lucene/searcher/ScoredPagedMultiSearcher.java @@ -2,6 +2,7 @@ package it.cavallium.dbengine.lucene.searcher; import static it.cavallium.dbengine.lucene.searcher.PaginationInfo.MAX_SINGLE_SEARCH_LIMIT; import static it.cavallium.dbengine.utils.StreamUtils.LUCENE_SCHEDULER; +import static it.cavallium.dbengine.utils.StreamUtils.fastListing; import static it.cavallium.dbengine.utils.StreamUtils.streamWhileNonNull; import static it.cavallium.dbengine.utils.StreamUtils.toListOn; @@ -15,12 +16,14 @@ import it.cavallium.dbengine.lucene.LuceneUtils; import it.cavallium.dbengine.lucene.PageLimits; import it.cavallium.dbengine.lucene.collector.ScoringShardsCollectorMultiManager; import it.cavallium.dbengine.utils.DBException; +import it.cavallium.dbengine.utils.StreamUtils; import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; import java.util.stream.Stream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -42,9 +45,10 @@ public class ScoredPagedMultiSearcher implements MultiSearcher { public LuceneSearchResult collectMulti(LLIndexSearchers indexSearchers, LocalQueryParams queryParams, @Nullable String keyFieldName, - GlobalQueryRewrite transformer) { + GlobalQueryRewrite transformer, + Function, Stream> filterer) { if (transformer != GlobalQueryRewrite.NO_REWRITE) { - return LuceneUtils.rewriteMulti(this, indexSearchers, queryParams, keyFieldName, transformer); + return LuceneUtils.rewriteMulti(this, indexSearchers, queryParams, keyFieldName, transformer, filterer); } PaginationInfo paginationInfo = getPaginationInfo(queryParams); @@ -57,7 +61,7 @@ public class ScoredPagedMultiSearcher implements MultiSearcher { indexSearchers.shards(), queryParams, keyFieldName, - () -> indexSearchers.close() + filterer ); } @@ -119,7 +123,7 @@ public class ScoredPagedMultiSearcher implements MultiSearcher { List indexSearchers, LocalQueryParams queryParams, String keyFieldName, - Runnable onClose) { + Function, Stream> filterer) { var totalHitsCount = firstResult.totalHitsCount(); var firstPageHitsStream = firstResult.firstPageHitsStream(); var secondPageInfo = firstResult.nextPageInfo(); @@ -127,7 +131,7 @@ public class ScoredPagedMultiSearcher implements MultiSearcher { Stream nextHitsFlux = searchOtherPages(indexSearchers, queryParams, keyFieldName, secondPageInfo); Stream combinedStream = Stream.concat(firstPageHitsStream, nextHitsFlux); - return new MyLuceneSearchResult(totalHitsCount, combinedStream, onClose); + return new LuceneSearchResult(totalHitsCount, StreamUtils.collect(filterer.apply(combinedStream), fastListing())); } /** @@ -214,24 +218,4 @@ public class ScoredPagedMultiSearcher implements MultiSearcher { return "scored paged multi"; } - - private static class MyLuceneSearchResult extends LuceneSearchResult implements LuceneCloseable { - - private final Runnable onClose; - - public MyLuceneSearchResult(TotalHitsCount totalHitsCount, Stream combinedFlux, Runnable onClose) { - super(totalHitsCount, combinedFlux); - this.onClose = onClose; - } - - @Override - protected void onClose() { - try { - onClose.run(); - } catch (Throwable ex) { - LOG.error("Failed to close the search result", ex); - } - super.onClose(); - } - } } diff --git a/src/main/java/it/cavallium/dbengine/lucene/searcher/StandardSearcher.java b/src/main/java/it/cavallium/dbengine/lucene/searcher/StandardSearcher.java index de9058c..d1a6313 100644 --- a/src/main/java/it/cavallium/dbengine/lucene/searcher/StandardSearcher.java +++ b/src/main/java/it/cavallium/dbengine/lucene/searcher/StandardSearcher.java @@ -1,17 +1,19 @@ package it.cavallium.dbengine.lucene.searcher; +import static it.cavallium.dbengine.utils.StreamUtils.toList; import static java.util.Objects.requireNonNull; import it.cavallium.dbengine.client.query.current.data.TotalHitsCount; import it.cavallium.dbengine.database.LLKeyScore; -import it.cavallium.dbengine.database.LLUtils; import it.cavallium.dbengine.database.disk.LLIndexSearchers; import it.cavallium.dbengine.lucene.LuceneCloseable; import it.cavallium.dbengine.lucene.LuceneUtils; import it.cavallium.dbengine.utils.DBException; +import it.cavallium.dbengine.utils.StreamUtils; import java.io.IOException; import java.util.Collection; import java.util.List; +import java.util.function.Function; import java.util.stream.Stream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -36,14 +38,15 @@ public class StandardSearcher implements MultiSearcher { public LuceneSearchResult collectMulti(LLIndexSearchers indexSearchers, LocalQueryParams queryParams, @Nullable String keyFieldName, - GlobalQueryRewrite transformer) { + GlobalQueryRewrite transformer, + Function, Stream> filterer) { if (transformer != GlobalQueryRewrite.NO_REWRITE) { - return LuceneUtils.rewriteMulti(this, indexSearchers, queryParams, keyFieldName, transformer); + return LuceneUtils.rewriteMulti(this, indexSearchers, queryParams, keyFieldName, transformer, filterer); } // Search results var fullDocs = this.search(indexSearchers.shards(), queryParams); // Compute the results - return this.computeResults(fullDocs, indexSearchers, keyFieldName, queryParams); + return this.computeResults(fullDocs, indexSearchers, keyFieldName, queryParams, filterer); } /** @@ -55,10 +58,12 @@ public class StandardSearcher implements MultiSearcher { CollectorManager, ? extends TopDocs> sharedManager; if (queryParams.isSorted() && !queryParams.isSortedByScore()) { sharedManager = TopFieldCollector.createSharedManager(queryParams.sort(), - queryParams.limitInt(), null, totalHitsThreshold); + queryParams.limitInt(), null, totalHitsThreshold + ); } else { sharedManager = TopScoreDocCollector.createSharedManager(queryParams.limitInt(), null, totalHitsThreshold); - }; + } + ; var collectors = indexSearchers.stream().map(shard -> { try { TopDocsCollector collector; @@ -112,43 +117,20 @@ public class StandardSearcher implements MultiSearcher { private LuceneSearchResult computeResults(TopDocs data, LLIndexSearchers indexSearchers, String keyFieldName, - LocalQueryParams queryParams) { + LocalQueryParams queryParams, + Function, Stream> filterer) { var totalHitsCount = LuceneUtils.convertTotalHitsCount(data.totalHits); Stream hitsStream = LuceneUtils - .convertHits(Stream.of(data.scoreDocs), - indexSearchers.shards(), keyFieldName - ) + .convertHits(Stream.of(data.scoreDocs), indexSearchers.shards(), keyFieldName) .skip(queryParams.offsetLong()) .limit(queryParams.limitLong()); - return new MyLuceneSearchResult(totalHitsCount, hitsStream, indexSearchers); + return new LuceneSearchResult(totalHitsCount, toList(filterer.apply(hitsStream))); } @Override public String getName() { return "standard"; } - - private static class MyLuceneSearchResult extends LuceneSearchResult implements LuceneCloseable { - - private final LLIndexSearchers indexSearchers; - - public MyLuceneSearchResult(TotalHitsCount totalHitsCount, - Stream hitsStream, - LLIndexSearchers indexSearchers) { - super(totalHitsCount, hitsStream); - this.indexSearchers = indexSearchers; - } - - @Override - protected void onClose() { - try { - indexSearchers.close(); - } catch (Throwable e) { - LOG.error("Can't close index searchers", e); - } - super.onClose(); - } - } } diff --git a/src/main/java/it/cavallium/dbengine/lucene/searcher/UnsortedStreamingMultiSearcher.java b/src/main/java/it/cavallium/dbengine/lucene/searcher/UnsortedStreamingMultiSearcher.java index 00a6329..dc170b7 100644 --- a/src/main/java/it/cavallium/dbengine/lucene/searcher/UnsortedStreamingMultiSearcher.java +++ b/src/main/java/it/cavallium/dbengine/lucene/searcher/UnsortedStreamingMultiSearcher.java @@ -1,6 +1,7 @@ package it.cavallium.dbengine.lucene.searcher; import static com.google.common.collect.Streams.mapWithIndex; +import static it.cavallium.dbengine.utils.StreamUtils.toList; import it.cavallium.dbengine.client.query.current.data.TotalHitsCount; import it.cavallium.dbengine.database.LLKeyScore; @@ -26,9 +27,10 @@ public class UnsortedStreamingMultiSearcher implements MultiSearcher { public LuceneSearchResult collectMulti(LLIndexSearchers indexSearchers, LocalQueryParams queryParams, @Nullable String keyFieldName, - GlobalQueryRewrite transformer) { + GlobalQueryRewrite transformer, + Function, Stream> filterer) { if (transformer != GlobalQueryRewrite.NO_REWRITE) { - return LuceneUtils.rewriteMulti(this, indexSearchers, queryParams, keyFieldName, transformer); + return LuceneUtils.rewriteMulti(this, indexSearchers, queryParams, keyFieldName, transformer, filterer); } if (queryParams.isSorted() && queryParams.limitLong() > 0) { throw new UnsupportedOperationException("Sorted queries are not supported" + " by UnsortedContinuousLuceneMultiSearcher"); @@ -44,7 +46,7 @@ public class UnsortedStreamingMultiSearcher implements MultiSearcher { var totalHitsCount = new TotalHitsCount(0, false); Stream mergedFluxes = resultsFlux.skip(queryParams.offsetLong()).limit(queryParams.limitLong()); - return new MyLuceneSearchResult(totalHitsCount, mergedFluxes, indexSearchers); + return new LuceneSearchResult(totalHitsCount, toList(filterer.apply(mergedFluxes))); } private Stream getScoreDocs(LocalQueryParams localQueryParams, List shards) { @@ -68,26 +70,4 @@ public class UnsortedStreamingMultiSearcher implements MultiSearcher { public String getName() { return "unsorted streaming multi"; } - - private static class MyLuceneSearchResult extends LuceneSearchResult implements LuceneCloseable { - - private final LLIndexSearchers indexSearchers; - - public MyLuceneSearchResult(TotalHitsCount totalHitsCount, - Stream hitsFlux, - LLIndexSearchers indexSearchers) { - super(totalHitsCount, hitsFlux); - this.indexSearchers = indexSearchers; - } - - @Override - protected void onClose() { - try { - indexSearchers.close(); - } catch (Throwable e) { - LOG.error("Can't close index searchers", e); - } - super.onClose(); - } - } } diff --git a/src/test/java/it/cavallium/dbengine/tests/SwappableLuceneSearcher.java b/src/test/java/it/cavallium/dbengine/tests/SwappableLuceneSearcher.java index de92142..e4d5deb 100644 --- a/src/test/java/it/cavallium/dbengine/tests/SwappableLuceneSearcher.java +++ b/src/test/java/it/cavallium/dbengine/tests/SwappableLuceneSearcher.java @@ -3,6 +3,7 @@ package it.cavallium.dbengine.tests; import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNullElseGet; +import it.cavallium.dbengine.database.LLKeyScore; import it.cavallium.dbengine.database.disk.LLIndexSearcher; import it.cavallium.dbengine.database.disk.LLIndexSearchers; import it.cavallium.dbengine.lucene.searcher.GlobalQueryRewrite; @@ -13,6 +14,8 @@ import it.cavallium.dbengine.lucene.searcher.LuceneSearchResult; import java.io.Closeable; import java.io.IOException; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.stream.Stream; import org.jetbrains.annotations.Nullable; public class SwappableLuceneSearcher implements LocalSearcher, MultiSearcher, Closeable { @@ -28,13 +31,14 @@ public class SwappableLuceneSearcher implements LocalSearcher, MultiSearcher, Cl public LuceneSearchResult collect(LLIndexSearcher indexSearcher, LocalQueryParams queryParams, @Nullable String keyFieldName, - GlobalQueryRewrite transformer) { + GlobalQueryRewrite transformer, + Function, Stream> filterer) { var single = this.single.get(); if (single == null) { single = this.multi.get(); } requireNonNull(single, "LuceneLocalSearcher not set"); - return single.collect(indexSearcher, queryParams, keyFieldName, transformer); + return single.collect(indexSearcher, queryParams, keyFieldName, transformer, filterer); } @Override @@ -55,10 +59,11 @@ public class SwappableLuceneSearcher implements LocalSearcher, MultiSearcher, Cl @Override public LuceneSearchResult collectMulti(LLIndexSearchers indexSearchers, LocalQueryParams queryParams, - String keyFieldName, - GlobalQueryRewrite transformer) { + @Nullable String keyFieldName, + GlobalQueryRewrite transformer, + Function, Stream> filterer) { var multi = requireNonNull(this.multi.get(), "LuceneMultiSearcher not set"); - return multi.collectMulti(indexSearchers, queryParams, keyFieldName, transformer); + return multi.collectMulti(indexSearchers, queryParams, keyFieldName, transformer, filterer); } public void setSingle(LocalSearcher single) { diff --git a/src/test/java/it/cavallium/dbengine/tests/TestDictionaryMapDeep.java b/src/test/java/it/cavallium/dbengine/tests/TestDictionaryMapDeep.java index 2591bdd..40a5970 100644 --- a/src/test/java/it/cavallium/dbengine/tests/TestDictionaryMapDeep.java +++ b/src/test/java/it/cavallium/dbengine/tests/TestDictionaryMapDeep.java @@ -8,6 +8,7 @@ import static it.cavallium.dbengine.tests.DbTestUtils.runVoid; import static it.cavallium.dbengine.tests.DbTestUtils.tempDatabaseMapDictionaryDeepMap; import static it.cavallium.dbengine.tests.DbTestUtils.tempDb; import static it.cavallium.dbengine.tests.DbTestUtils.tempDictionary; +import static it.cavallium.dbengine.utils.StreamUtils.toList; import com.google.common.collect.Streams; import it.cavallium.dbengine.database.UpdateMode; @@ -805,11 +806,11 @@ public abstract class TestDictionaryMapDeep { var stpVer = run(shouldFail, () -> tempDb(getTempDbGenerator(), db -> { var map = tempDatabaseMapDictionaryDeepMap(tempDictionary(db, updateMode), 5, 6); map.putMulti(entries.entrySet().stream()); - return map.getAllStages(null, false).map(stage -> { + return toList(map.getAllStages(null, false).map(stage -> { var v = stage.getValue().get(null); if (v == null) return null; return Map.entry(stage.getKey(), v); - }).filter(Objects::nonNull).toList(); + }).filter(Objects::nonNull)); })); if (shouldFail) { this.checkLeaks = false; diff --git a/src/test/java/it/cavallium/dbengine/tests/TestDictionaryMapDeepHashMap.java b/src/test/java/it/cavallium/dbengine/tests/TestDictionaryMapDeepHashMap.java index e699f16..5ddd055 100644 --- a/src/test/java/it/cavallium/dbengine/tests/TestDictionaryMapDeepHashMap.java +++ b/src/test/java/it/cavallium/dbengine/tests/TestDictionaryMapDeepHashMap.java @@ -7,6 +7,7 @@ import static it.cavallium.dbengine.tests.DbTestUtils.run; import static it.cavallium.dbengine.tests.DbTestUtils.tempDatabaseMapDictionaryDeepMapHashMap; import static it.cavallium.dbengine.tests.DbTestUtils.tempDb; import static it.cavallium.dbengine.tests.DbTestUtils.tempDictionary; +import static it.cavallium.dbengine.utils.StreamUtils.toList; import com.google.common.collect.Streams; import it.cavallium.dbengine.database.UpdateMode; @@ -103,12 +104,11 @@ public abstract class TestDictionaryMapDeepHashMap { var stpVer = run(shouldFail, () -> tempDb(getTempDbGenerator(), db -> { var map = tempDatabaseMapDictionaryDeepMapHashMap(tempDictionary(db, updateMode), 5); map.at(null, key1).putValue(key2, value); - return map + return toList(map .getAllValues(null, false) .map(Entry::getValue) .flatMap(maps -> maps.entrySet().stream()) - .map(Entry::getValue) - .toList(); + .map(Entry::getValue)); })); if (shouldFail) { this.checkLeaks = false; diff --git a/src/test/java/it/cavallium/dbengine/tests/TestLuceneSearches.java b/src/test/java/it/cavallium/dbengine/tests/TestLuceneSearches.java index 990e60d..effc959 100644 --- a/src/test/java/it/cavallium/dbengine/tests/TestLuceneSearches.java +++ b/src/test/java/it/cavallium/dbengine/tests/TestLuceneSearches.java @@ -237,9 +237,9 @@ public class TestLuceneSearches { ExpectedQueryType expectedQueryType) throws Throwable { runSearchers(expectedQueryType, searcher -> { - var luceneIndex = getLuceneIndex(expectedQueryType.shard(), searcher); - var query = queryParamsBuilder.build(); - try (var results = luceneIndex.search(query)) { + try (var luceneIndex1 = getLuceneIndex(expectedQueryType.shard(), searcher)) { + var query = queryParamsBuilder.build(); + var results = luceneIndex1.search(query); var hits = results.totalHitsCount(); var keys = getResults(results); if (hits.exact()) { @@ -249,9 +249,9 @@ public class TestLuceneSearches { } var standardSearcher = new StandardSearcher(); - luceneIndex = getLuceneIndex(expectedQueryType.shard(), standardSearcher); - var officialQuery = queryParamsBuilder.limit(ELEMENTS.size() * 2L).build(); - try (var officialResults = luceneIndex.search(officialQuery)) { + try (var luceneIndex2 = getLuceneIndex(expectedQueryType.shard(), standardSearcher)) { + var officialQuery = queryParamsBuilder.limit(ELEMENTS.size() * 2L).build(); + var officialResults = luceneIndex2.search(officialQuery); var officialHits = officialResults.totalHitsCount(); var officialKeys = getResults(officialResults); if (officialHits.exact()) { @@ -343,10 +343,7 @@ public class TestLuceneSearches { } private List getResults(Hits> results) { - return results - .results() - .map(key -> new Scored(key.key(), key.score())) - .toList(); + return results.results().stream().map(key -> new Scored(key.key(), key.score())).toList(); } } diff --git a/src/test/java/it/cavallium/dbengine/tests/UnsortedUnscoredSimpleMultiSearcher.java b/src/test/java/it/cavallium/dbengine/tests/UnsortedUnscoredSimpleMultiSearcher.java index 41711b5..95242cc 100644 --- a/src/test/java/it/cavallium/dbengine/tests/UnsortedUnscoredSimpleMultiSearcher.java +++ b/src/test/java/it/cavallium/dbengine/tests/UnsortedUnscoredSimpleMultiSearcher.java @@ -17,9 +17,11 @@ import it.cavallium.dbengine.utils.SimpleResource; import java.io.UncheckedIOException; import java.util.ArrayList; import java.util.List; +import java.util.function.Function; import java.util.stream.Stream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.Nullable; public class UnsortedUnscoredSimpleMultiSearcher implements MultiSearcher { @@ -34,10 +36,11 @@ public class UnsortedUnscoredSimpleMultiSearcher implements MultiSearcher { @Override public LuceneSearchResult collectMulti(LLIndexSearchers indexSearchers, LocalQueryParams queryParams, - String keyFieldName, - GlobalQueryRewrite transformer) { + @Nullable String keyFieldName, + GlobalQueryRewrite transformer, + Function, Stream> filterer) { if (transformer != NO_REWRITE) { - return LuceneUtils.rewriteMulti(this, indexSearchers, queryParams, keyFieldName, transformer); + return LuceneUtils.rewriteMulti(this, indexSearchers, queryParams, keyFieldName, transformer, filterer); } if (queryParams.isSorted() && queryParams.limitLong() > 0) { throw new UnsupportedOperationException( @@ -50,15 +53,13 @@ public class UnsortedUnscoredSimpleMultiSearcher implements MultiSearcher { var localQueryParams = getLocalQueryParams(queryParams); var results = indexSearchers.llShards().stream() - .map(searcher -> localSearcher.collect(searcher, localQueryParams, keyFieldName, transformer)) + .map(searcher -> localSearcher.collect(searcher, localQueryParams, keyFieldName, transformer, filterer)) .toList(); - List resultsToDrop = new ArrayList<>(results.size()); List> resultsFluxes = new ArrayList<>(results.size()); boolean exactTotalHitsCount = true; long totalHitsCountValue = 0; for (LuceneSearchResult result : results) { - resultsToDrop.add(result); - resultsFluxes.add(result.results()); + resultsFluxes.add(result.results().stream()); exactTotalHitsCount &= result.totalHitsCount().exact(); totalHitsCountValue += result.totalHitsCount().value(); } @@ -69,7 +70,7 @@ public class UnsortedUnscoredSimpleMultiSearcher implements MultiSearcher { .skip(queryParams.offsetLong()) .limit(queryParams.limitLong()); - return new MyLuceneSearchResult(totalHitsCount, mergedFluxes, resultsToDrop, indexSearchers); + return new LuceneSearchResult(totalHitsCount, mergedFluxes.toList()); } private LocalQueryParams getLocalQueryParams(LocalQueryParams queryParams) { @@ -87,30 +88,4 @@ public class UnsortedUnscoredSimpleMultiSearcher implements MultiSearcher { public String getName() { return "unsorted unscored simple multi"; } - - private static class MyLuceneSearchResult extends LuceneSearchResult implements LuceneCloseable { - - private final List resultsToDrop; - private final LLIndexSearchers indexSearchers; - - public MyLuceneSearchResult(TotalHitsCount totalHitsCount, - Stream mergedFluxes, - List resultsToDrop, - LLIndexSearchers indexSearchers) { - super(totalHitsCount, mergedFluxes); - this.resultsToDrop = resultsToDrop; - this.indexSearchers = indexSearchers; - } - - @Override - protected void onClose() { - resultsToDrop.forEach(SimpleResource::close); - try { - indexSearchers.close(); - } catch (UncheckedIOException e) { - LOG.error("Can't close index searchers", e); - } - super.onClose(); - } - } }