package it.cavallium.dbengine.client; 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.LLSnapshot; import it.cavallium.dbengine.database.LLTerm; import it.cavallium.dbengine.database.collections.ValueGetter; import it.cavallium.dbengine.database.collections.ValueTransformer; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.util.function.Tuple2; import reactor.util.function.Tuples; public class LuceneIndexImpl implements LuceneIndex { private final LLLuceneIndex luceneIndex; private final Indicizer indicizer; public LuceneIndexImpl(LLLuceneIndex luceneIndex, Indicizer indicizer) { this.luceneIndex = luceneIndex; this.indicizer = indicizer; } private LLSnapshot resolveSnapshot(CompositeSnapshot snapshot) { if (snapshot == null) { return null; } else { return snapshot.getSnapshot(luceneIndex); } } @Override public Mono addDocument(T key, U value) { return indicizer .toDocument(key, value) .flatMap(doc -> luceneIndex.addDocument(indicizer.toIndex(key), doc)); } @Override public Mono addDocuments(Flux> entries) { return luceneIndex .addDocuments(entries .flatMap(entry -> indicizer .toDocument(entry.getKey(), entry.getValue()) .map(doc -> Map.entry(indicizer.toIndex(entry.getKey()), doc))) ); } @Override public Mono deleteDocument(T key) { LLTerm id = indicizer.toIndex(key); return luceneIndex.deleteDocument(id); } @Override public Mono updateDocument(T key, @NotNull U value) { return indicizer .toDocument(key, value) .flatMap(doc -> luceneIndex.updateDocument(indicizer.toIndex(key), doc)); } @Override public Mono updateDocuments(Flux> entries) { return luceneIndex .updateDocuments(entries .flatMap(entry -> indicizer .toDocument(entry.getKey(), entry.getValue()) .map(doc -> Map.entry(indicizer.toIndex(entry.getKey()), doc))) .collectMap(Entry::getKey, Entry::getValue) ); } @Override public Mono deleteAll() { return luceneIndex.deleteAll(); } private Mono> transformLuceneResultWithTransformer(LLSearchResultShard llSearchResult) { return Mono.just(new SearchResultKeys<>(llSearchResult.results() .map(signal -> new SearchResultKey<>(Mono.fromCallable(signal::key).map(indicizer::getKey), signal.score())), llSearchResult.totalHitsCount(), llSearchResult.release() )); } private Mono> transformLuceneResultWithValues(LLSearchResultShard llSearchResult, ValueGetter valueGetter) { return Mono.fromCallable(() -> new SearchResult<>(llSearchResult.results().map(signal -> { var key = Mono.fromCallable(signal::key).map(indicizer::getKey); return new SearchResultItem<>(key, key.flatMap(valueGetter::get), signal.score()); }), llSearchResult.totalHitsCount(), llSearchResult.release())); } private Mono> transformLuceneResultWithTransformer(LLSearchResultShard llSearchResult, ValueTransformer valueTransformer) { var scoresWithKeysFlux = llSearchResult .results() .flatMapSequential(signal -> Mono .fromCallable(signal::key) .map(indicizer::getKey) .map(key -> Tuples.of(signal.score(), key)) ); var resultItemsFlux = valueTransformer .transform(scoresWithKeysFlux) .filter(tuple3 -> tuple3.getT3().isPresent()) .map(tuple3 -> new SearchResultItem<>(Mono.just(tuple3.getT2()), Mono.just(tuple3.getT3().orElseThrow()), tuple3.getT1() )); return Mono.fromCallable(() -> new SearchResult<>(resultItemsFlux, llSearchResult.totalHitsCount(), llSearchResult.release() )); } @Override public Mono> moreLikeThis(ClientQueryParams> queryParams, T key, U mltDocumentValue) { Flux>> mltDocumentFields = indicizer.getMoreLikeThisDocumentFields(key, mltDocumentValue); return luceneIndex .moreLikeThis(resolveSnapshot(queryParams.snapshot()), queryParams.toQueryParams(), indicizer.getKeyFieldName(), mltDocumentFields) .flatMap(this::transformLuceneResultWithTransformer); } @Override public Mono> moreLikeThisWithValues(ClientQueryParams> queryParams, T key, U mltDocumentValue, ValueGetter valueGetter) { Flux>> mltDocumentFields = indicizer.getMoreLikeThisDocumentFields(key, mltDocumentValue); return luceneIndex .moreLikeThis(resolveSnapshot(queryParams.snapshot()), queryParams.toQueryParams(), indicizer.getKeyFieldName(), mltDocumentFields ) .flatMap(llSearchResult -> this.transformLuceneResultWithValues(llSearchResult, valueGetter )); } @Override public Mono> moreLikeThisWithTransformer(ClientQueryParams> queryParams, T key, U mltDocumentValue, ValueTransformer valueTransformer) { Flux>> mltDocumentFields = indicizer.getMoreLikeThisDocumentFields(key, mltDocumentValue); return luceneIndex .moreLikeThis(resolveSnapshot(queryParams.snapshot()), queryParams.toQueryParams(), indicizer.getKeyFieldName(), mltDocumentFields ) .flatMap(llSearchResult -> this.transformLuceneResultWithTransformer(llSearchResult, valueTransformer)); } @Override public Mono> search(ClientQueryParams> queryParams) { return luceneIndex .search(resolveSnapshot(queryParams.snapshot()), queryParams.toQueryParams(), indicizer.getKeyFieldName() ) .flatMap(this::transformLuceneResultWithTransformer); } @Override public Mono> searchWithValues(ClientQueryParams> queryParams, ValueGetter valueGetter) { return luceneIndex .search(resolveSnapshot(queryParams.snapshot()), queryParams.toQueryParams(), indicizer.getKeyFieldName()) .flatMap(llSearchResult -> this.transformLuceneResultWithValues(llSearchResult, valueGetter)); } @Override public Mono> searchWithTransformer(ClientQueryParams> queryParams, ValueTransformer valueTransformer) { return luceneIndex .search(resolveSnapshot(queryParams.snapshot()), queryParams.toQueryParams(), indicizer.getKeyFieldName()) .flatMap(llSearchResult -> this.transformLuceneResultWithTransformer(llSearchResult, valueTransformer)); } @Override public Mono count(@Nullable CompositeSnapshot snapshot, Query query) { return this .search(ClientQueryParams.>builder().snapshot(snapshot).query(query).limit(0).build()) .flatMap(tSearchResultKeys -> tSearchResultKeys.release().thenReturn(tSearchResultKeys.totalHitsCount())); } @Override public boolean isLowMemoryMode() { return luceneIndex.isLowMemoryMode(); } @Override public Mono close() { return luceneIndex.close(); } /** * Flush writes to disk */ @Override public Mono flush() { return luceneIndex.flush(); } /** * Refresh index searcher */ @Override public Mono refresh(boolean force) { return luceneIndex.refresh(force); } @Override public Mono takeSnapshot() { return luceneIndex.takeSnapshot(); } @Override public Mono releaseSnapshot(LLSnapshot snapshot) { return luceneIndex.releaseSnapshot(snapshot); } }