Refactor results

This commit is contained in:
Andrea Cavalli 2021-10-28 23:48:25 +02:00
parent d861e26a57
commit 37de47fd6c
17 changed files with 223 additions and 381 deletions

View File

@ -43,7 +43,7 @@ jobs:
shell: bash shell: bash
run: | run: |
cd lucene cd lucene
./gradlew assemble -x test -x errorprone publishToMavenLocal ./gradlew assemble -x test -x errorprone publishToMavenLocal -x signJarsPublication
mvn deploy:deploy-file -DgroupId=org.lucene -DartifactId=lucene-core -Dversion=9.0.0-SNAPSHOT -DgeneratePom=true -Dpackaging=jar -DrepositoryId=mchv-release-distribution -Durl=https://mvn.mchv.eu/repository/mchv-snapshot -Dfile=lucene/core/build/libs/lucene-core-9.0.0-SNAPSHOT.jar -Djavadoc=lucene/core/build/libs/lucene-core-9.0.0-SNAPSHOT-javadoc.jar -Dsources=lucene/core/build/libs/lucene-core-9.0.0-SNAPSHOT-sources.jar mvn deploy:deploy-file -DgroupId=org.lucene -DartifactId=lucene-core -Dversion=9.0.0-SNAPSHOT -DgeneratePom=true -Dpackaging=jar -DrepositoryId=mchv-release-distribution -Durl=https://mvn.mchv.eu/repository/mchv-snapshot -Dfile=lucene/core/build/libs/lucene-core-9.0.0-SNAPSHOT.jar -Djavadoc=lucene/core/build/libs/lucene-core-9.0.0-SNAPSHOT-javadoc.jar -Dsources=lucene/core/build/libs/lucene-core-9.0.0-SNAPSHOT-sources.jar
mvn deploy:deploy-file -DgroupId=org.lucene -DartifactId=lucene-join -Dversion=9.0.0-SNAPSHOT -DgeneratePom=true -Dpackaging=jar -DrepositoryId=mchv-release-distribution -Durl=https://mvn.mchv.eu/repository/mchv-snapshot -Dfile=lucene/join/build/libs/lucene-join-9.0.0-SNAPSHOT.jar -Djavadoc=lucene/join/build/libs/lucene-join-9.0.0-SNAPSHOT-javadoc.jar -Dsources=lucene/join/build/libs/lucene-join-9.0.0-SNAPSHOT-sources.jar mvn deploy:deploy-file -DgroupId=org.lucene -DartifactId=lucene-join -Dversion=9.0.0-SNAPSHOT -DgeneratePom=true -Dpackaging=jar -DrepositoryId=mchv-release-distribution -Durl=https://mvn.mchv.eu/repository/mchv-snapshot -Dfile=lucene/join/build/libs/lucene-join-9.0.0-SNAPSHOT.jar -Djavadoc=lucene/join/build/libs/lucene-join-9.0.0-SNAPSHOT-javadoc.jar -Dsources=lucene/join/build/libs/lucene-join-9.0.0-SNAPSHOT-sources.jar
mvn deploy:deploy-file -DgroupId=org.lucene -DartifactId=lucene-analysis-common -Dversion=9.0.0-SNAPSHOT -DgeneratePom=true -Dpackaging=jar -DrepositoryId=mchv-release-distribution -Durl=https://mvn.mchv.eu/repository/mchv-snapshot -Dfile=lucene/analysis/common/build/libs/lucene-analysis-common-9.0.0-SNAPSHOT.jar -Djavadoc=lucene/analysis/common/build/libs/lucene-analysis-common-9.0.0-SNAPSHOT-javadoc.jar -Dsources=lucene/analysis/common/build/libs/lucene-analysis-common-9.0.0-SNAPSHOT-sources.jar mvn deploy:deploy-file -DgroupId=org.lucene -DartifactId=lucene-analysis-common -Dversion=9.0.0-SNAPSHOT -DgeneratePom=true -Dpackaging=jar -DrepositoryId=mchv-release-distribution -Durl=https://mvn.mchv.eu/repository/mchv-snapshot -Dfile=lucene/analysis/common/build/libs/lucene-analysis-common-9.0.0-SNAPSHOT.jar -Djavadoc=lucene/analysis/common/build/libs/lucene-analysis-common-9.0.0-SNAPSHOT-javadoc.jar -Dsources=lucene/analysis/common/build/libs/lucene-analysis-common-9.0.0-SNAPSHOT-sources.jar

View File

@ -522,7 +522,7 @@
<plugin> <plugin>
<groupId>it.cavallium</groupId> <groupId>it.cavallium</groupId>
<artifactId>data-generator</artifactId> <artifactId>data-generator</artifactId>
<version>0.9.69</version> <version>0.9.71</version>
<executions> <executions>
<execution> <execution>
<id>generate-lucene-query-sources</id> <id>generate-lucene-query-sources</id>

View File

@ -0,0 +1,13 @@
package it.cavallium.dbengine.client;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono;
public record HitEntry<T, U>(T key, U value, float score)
implements Comparable<HitEntry<T, U>> {
@Override
public int compareTo(@NotNull HitEntry<T, U> o) {
return Float.compare(o.score, this.score);
}
}

View File

@ -0,0 +1,18 @@
package it.cavallium.dbengine.client;
import java.util.Comparator;
import java.util.function.Function;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono;
public record HitKey<T>(T key, float score) implements Comparable<HitKey<T>> {
public <U> Mono<HitEntry<T, U>> withValue(Function<T, Mono<U>> valueGetter) {
return valueGetter.apply(key).map(value -> new HitEntry<>(key, value, score));
}
@Override
public int compareTo(@NotNull HitKey<T> o) {
return Float.compare(o.score, this.score);
}
}

View File

@ -0,0 +1,126 @@
package it.cavallium.dbengine.client;
import io.net5.buffer.api.Drop;
import io.net5.buffer.api.Owned;
import io.net5.buffer.api.Send;
import it.cavallium.dbengine.client.query.current.data.TotalHitsCount;
import io.net5.buffer.api.internal.ResourceSupport;
import it.cavallium.dbengine.database.collections.ValueGetter;
import it.cavallium.dbengine.database.collections.ValueTransformer;
import java.util.function.Function;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.function.Tuples;
public final class Hits<T> extends ResourceSupport<Hits<T>, Hits<T>> {
private static final Drop<Hits<?>> DROP = new Drop<>() {
@Override
public void drop(Hits<?> obj) {
if (obj.onClose != null) {
obj.onClose.run();
}
}
@Override
public Drop<Hits<?>> fork() {
return this;
}
@Override
public void attach(Hits<?> obj) {
}
};
private Flux<T> results;
private TotalHitsCount totalHitsCount;
private Runnable onClose;
@SuppressWarnings({"unchecked", "rawtypes"})
public Hits(Flux<T> results, TotalHitsCount totalHitsCount, Runnable onClose) {
super((Drop<Hits<T>>) (Drop) DROP);
this.results = results;
this.totalHitsCount = totalHitsCount;
this.onClose = onClose;
}
public static <T> Hits<T> empty() {
return new Hits<>(Flux.empty(), TotalHitsCount.of(0, true), null);
}
public static <K, V> Hits<LazyHitEntry<K, V>> withValuesLazy(Hits<LazyHitKey<K>> hits,
ValueGetter<K, V> valuesGetter) {
var hitsEntry = hits.results().map(hitKey -> hitKey.withValue(valuesGetter::get));
return new Hits<>(hitsEntry, hits.totalHitsCount, hits::close);
}
public static <K, V> Hits<HitEntry<K, V>> withValues(Hits<HitKey<K>> hits, ValueGetter<K, V> valuesGetter) {
var hitsEntry = hits.results().flatMap(hitKey -> hitKey.withValue(valuesGetter::get));
return new Hits<>(hitsEntry, hits.totalHitsCount, hits::close);
}
public static <T, U> Function<Send<Hits<HitKey<T>>>, Send<Hits<LazyHitEntry<T, U>>>> generateMapper(
ValueGetter<T, U> valueGetter) {
return resultToReceive -> {
var result = resultToReceive.receive();
var hitsToTransform = result.results()
.map(hit -> new LazyHitEntry<>(Mono.just(hit.key()), valueGetter.get(hit.key()), hit.score()));
return new Hits<>(hitsToTransform, result.totalHitsCount(), result::close).send();
};
}
public static <T, U> Function<Send<Hits<HitKey<T>>>, Send<Hits<LazyHitEntry<T, U>>>> generateMapper(
ValueTransformer<T, U> valueTransformer) {
return resultToReceive -> {
var result = resultToReceive.receive();
var hitsToTransform = result.results().map(hit -> Tuples.of(hit.score(), hit.key()));
var transformed = valueTransformer
.transform(hitsToTransform)
.filter(tuple3 -> tuple3.getT3().isPresent())
.map(tuple3 -> new LazyHitEntry<>(Mono.just(tuple3.getT2()),
Mono.just(tuple3.getT3().orElseThrow()),
tuple3.getT1()
));
return new Hits<>(transformed, result.totalHitsCount(), result::close).send();
};
}
public Flux<T> results() {
return results;
}
public TotalHitsCount totalHitsCount() {
return totalHitsCount;
}
@Override
public String toString() {
return "Hits[" + "results=" + results + ", " + "totalHitsCount=" + totalHitsCount + ']';
}
@Override
protected RuntimeException createResourceClosedException() {
return new IllegalStateException("Closed");
}
@Override
protected Owned<Hits<T>> prepareSend() {
var results = this.results;
var totalHitsCount = this.totalHitsCount;
var onClose = this.onClose;
return drop -> {
var instance = new Hits<>(results, totalHitsCount, onClose);
drop.attach(instance);
return instance;
};
}
protected void makeInaccessible() {
this.results = null;
this.totalHitsCount = null;
this.onClose = null;
}
}

View File

@ -0,0 +1,11 @@
package it.cavallium.dbengine.client;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono;
public record LazyHitEntry<T, U>(Mono<T> key, Mono<U> value, float score) {
public Mono<HitEntry<T, U>> resolve() {
return Mono.zip(key, value, (k, v) -> new HitEntry<>(k, v, score));
}
}

View File

@ -0,0 +1,19 @@
package it.cavallium.dbengine.client;
import java.util.function.Function;
import reactor.core.publisher.Mono;
public record LazyHitKey<T>(Mono<T> key, float score) {
public <U> LazyHitEntry<T, U> withValue(Function<T, Mono<U>> valueGetter) {
return new LazyHitEntry<>(key, key.flatMap(valueGetter), score);
}
public Mono<HitKey<T>> resolve() {
return key.map(k -> new HitKey<>(k, score));
}
public <U> Mono<HitEntry<T, U>> resolveWithValue(Function<T, Mono<U>> valueGetter) {
return resolve().flatMap(key -> key.withValue(valueGetter));
}
}

View File

@ -9,16 +9,11 @@ import it.cavallium.dbengine.database.LLSnapshottable;
import it.cavallium.dbengine.database.collections.ValueGetter; import it.cavallium.dbengine.database.collections.ValueGetter;
import it.cavallium.dbengine.database.collections.ValueTransformer; import it.cavallium.dbengine.database.collections.ValueTransformer;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Optional;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuple3;
import reactor.util.function.Tuples;
@SuppressWarnings("unused")
public interface LuceneIndex<T, U> extends LLSnapshottable { public interface LuceneIndex<T, U> extends LLSnapshottable {
Mono<Void> addDocument(T key, U value); Mono<Void> addDocument(T key, U value);
@ -53,32 +48,10 @@ public interface LuceneIndex<T, U> extends LLSnapshottable {
Mono<Void> deleteAll(); Mono<Void> deleteAll();
Mono<Send<SearchResultKeys<T>>> moreLikeThis(ClientQueryParams<SearchResultKey<T>> queryParams, T key, U mltDocumentValue); Mono<Send<Hits<HitKey<T>>>> moreLikeThis(ClientQueryParams queryParams, T key,
U mltDocumentValue);
default Mono<Send<SearchResult<T, U>>> moreLikeThisWithValues(ClientQueryParams<SearchResultItem<T, U>> queryParams, Mono<Send<Hits<HitKey<T>>>> search(ClientQueryParams queryParams);
T key,
U mltDocumentValue,
ValueGetter<T, U> valueGetter) {
return this.moreLikeThisWithTransformer(queryParams,
key,
mltDocumentValue,
getValueGetterTransformer(valueGetter));
}
Mono<Send<SearchResult<T, U>>> moreLikeThisWithTransformer(ClientQueryParams<SearchResultItem<T, U>> queryParams,
T key,
U mltDocumentValue,
ValueTransformer<T, U> valueTransformer);
Mono<Send<SearchResultKeys<T>>> search(ClientQueryParams<SearchResultKey<T>> queryParams);
default Mono<Send<SearchResult<T, U>>> searchWithValues(ClientQueryParams<SearchResultItem<T, U>> queryParams,
ValueGetter<T, U> valueGetter) {
return this.searchWithTransformer(queryParams, getValueGetterTransformer(valueGetter));
}
Mono<Send<SearchResult<T, U>>> searchWithTransformer(ClientQueryParams<SearchResultItem<T, U>> queryParams,
ValueTransformer<T, U> valueTransformer);
Mono<TotalHitsCount> count(@Nullable CompositeSnapshot snapshot, Query query); Mono<TotalHitsCount> count(@Nullable CompositeSnapshot snapshot, Query query);
@ -89,17 +62,4 @@ public interface LuceneIndex<T, U> extends LLSnapshottable {
Mono<Void> flush(); Mono<Void> flush();
Mono<Void> refresh(boolean force); Mono<Void> refresh(boolean force);
private static <T, U> ValueTransformer<T, U> getValueGetterTransformer(ValueGetter<T, U> valueGetter) {
return new ValueTransformer<T, U>() {
@Override
public <X> Flux<Tuple3<X, T, Optional<U>>> transform(Flux<Tuple2<X, T>> keys) {
return keys.flatMapSequential(key -> valueGetter
.get(key.getT2())
.map(result -> Tuples.of(key.getT1(), key.getT2(), Optional.of(result)))
.switchIfEmpty(Mono.fromSupplier(() -> Tuples.of(key.getT1(), key.getT2(), Optional.empty())))
);
}
};
}
} }

View File

@ -19,7 +19,6 @@ import it.cavallium.dbengine.database.LLLuceneIndex;
import it.cavallium.dbengine.database.LLSearchResultShard; import it.cavallium.dbengine.database.LLSearchResultShard;
import it.cavallium.dbengine.database.LLSnapshot; import it.cavallium.dbengine.database.LLSnapshot;
import it.cavallium.dbengine.database.LLTerm; import it.cavallium.dbengine.database.LLTerm;
import it.cavallium.dbengine.database.collections.ValueGetter;
import it.cavallium.dbengine.database.collections.ValueTransformer; import it.cavallium.dbengine.database.collections.ValueTransformer;
import java.lang.ref.Cleaner; import java.lang.ref.Cleaner;
import java.util.Map; import java.util.Map;
@ -36,11 +35,9 @@ import reactor.core.publisher.Sinks;
import reactor.core.publisher.Sinks.EmitResult; import reactor.core.publisher.Sinks.EmitResult;
import reactor.core.publisher.Sinks.Empty; import reactor.core.publisher.Sinks.Empty;
import reactor.core.publisher.Sinks.Many; import reactor.core.publisher.Sinks.Many;
import reactor.core.publisher.Sinks.One;
import reactor.core.scheduler.Schedulers; import reactor.core.scheduler.Schedulers;
import reactor.util.concurrent.Queues; import reactor.util.concurrent.Queues;
import reactor.util.function.Tuple2; import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;
public class LuceneIndexImpl<T, U> implements LuceneIndex<T, U> { public class LuceneIndexImpl<T, U> implements LuceneIndex<T, U> {
@ -202,140 +199,47 @@ public class LuceneIndexImpl<T, U> implements LuceneIndex<T, U> {
return Mono.create(sink -> emitActionOptimistically(new IndexAction.DeleteAll(sink))); return Mono.create(sink -> emitActionOptimistically(new IndexAction.DeleteAll(sink)));
} }
private Mono<Send<SearchResultKeys<T>>> transformLuceneResultWithTransformer(
Mono<Send<LLSearchResultShard>> llSearchResultMono) {
return llSearchResultMono.map(llSearchResultToReceive -> {
var llSearchResult = llSearchResultToReceive.receive();
return new SearchResultKeys<>(llSearchResult.results()
.map(signal -> new SearchResultKey<>(Mono
.fromCallable(signal::key)
.map(indicizer::getKey), signal.score())),
llSearchResult.totalHitsCount(),
llSearchResult::close
).send();
});
}
private Mono<Send<SearchResult<T, U>>> transformLuceneResultWithValues(
Mono<Send<LLSearchResultShard>> llSearchResultMono,
ValueGetter<T, U> valueGetter) {
return llSearchResultMono.map(llSearchResultToReceive -> {
var llSearchResult = llSearchResultToReceive.receive();
return 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::close).send();
});
}
private Mono<Send<SearchResult<T, U>>> transformLuceneResultWithTransformer(
Mono<Send<LLSearchResultShard>> llSearchResultMono,
ValueTransformer<T, U> valueTransformer) {
return llSearchResultMono
.map(llSearchResultToReceive -> {
var llSearchResult = llSearchResultToReceive.receive();
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 new SearchResult<>(resultItemsFlux, llSearchResult.totalHitsCount(), llSearchResult::close).send();
});
}
@Override @Override
public Mono<Send<SearchResultKeys<T>>> moreLikeThis(ClientQueryParams<SearchResultKey<T>> queryParams, public Mono<Send<Hits<HitKey<T>>>> moreLikeThis(ClientQueryParams queryParams,
T key, T key,
U mltDocumentValue) { U mltDocumentValue) {
Flux<Tuple2<String, Set<String>>> mltDocumentFields Flux<Tuple2<String, Set<String>>> mltDocumentFields
= indicizer.getMoreLikeThisDocumentFields(key, mltDocumentValue); = indicizer.getMoreLikeThisDocumentFields(key, mltDocumentValue);
return luceneIndex
.moreLikeThis(resolveSnapshot(queryParams.snapshot()), queryParams.toQueryParams(), indicizer.getKeyFieldName(), mltDocumentFields)
.transform(this::transformLuceneResultWithTransformer);
}
@Override
public Mono<Send<SearchResult<T, U>>> moreLikeThisWithValues(ClientQueryParams<SearchResultItem<T, U>> queryParams,
T key,
U mltDocumentValue,
ValueGetter<T, U> valueGetter) {
Flux<Tuple2<String, Set<String>>> mltDocumentFields
= indicizer.getMoreLikeThisDocumentFields(key, mltDocumentValue);
return luceneIndex return luceneIndex
.moreLikeThis(resolveSnapshot(queryParams.snapshot()), .moreLikeThis(resolveSnapshot(queryParams.snapshot()),
queryParams.toQueryParams(), queryParams.toQueryParams(),
indicizer.getKeyFieldName(), indicizer.getKeyFieldName(),
mltDocumentFields mltDocumentFields
) )
.transform(llSearchResult -> this.transformLuceneResultWithValues(llSearchResult, .map(this::mapResults)
valueGetter)); .single();
} }
@Override @Override
public Mono<Send<SearchResult<T, U>>> moreLikeThisWithTransformer(ClientQueryParams<SearchResultItem<T, U>> queryParams, public Mono<Send<Hits<HitKey<T>>>> search(ClientQueryParams queryParams) {
T key,
U mltDocumentValue,
ValueTransformer<T, U> valueTransformer) {
Flux<Tuple2<String, Set<String>>> mltDocumentFields
= indicizer.getMoreLikeThisDocumentFields(key, mltDocumentValue);
return luceneIndex
.moreLikeThis(resolveSnapshot(queryParams.snapshot()),
queryParams.toQueryParams(),
indicizer.getKeyFieldName(),
mltDocumentFields
)
.transform(llSearchResult -> this.transformLuceneResultWithTransformer(llSearchResult,
valueTransformer));
}
@Override
public Mono<Send<SearchResultKeys<T>>> search(ClientQueryParams<SearchResultKey<T>> queryParams) {
return luceneIndex return luceneIndex
.search(resolveSnapshot(queryParams.snapshot()), .search(resolveSnapshot(queryParams.snapshot()),
queryParams.toQueryParams(), queryParams.toQueryParams(),
indicizer.getKeyFieldName() indicizer.getKeyFieldName()
) )
.single() .map(this::mapResults)
.transform(this::transformLuceneResultWithTransformer)
.single(); .single();
} }
@Override private Send<Hits<HitKey<T>>> mapResults(Send<LLSearchResultShard> llSearchResultToReceive) {
public Mono<Send<SearchResult<T, U>>> searchWithValues( var llSearchResult = llSearchResultToReceive.receive();
ClientQueryParams<SearchResultItem<T, U>> queryParams, var scoresWithKeysFlux = llSearchResult
ValueGetter<T, U> valueGetter) { .results()
return luceneIndex .map(hit -> new HitKey<>(indicizer.getKey(hit.key()), hit.score()));
.search(resolveSnapshot(queryParams.snapshot()), queryParams.toQueryParams(),
indicizer.getKeyFieldName())
.transform(llSearchResult -> this.transformLuceneResultWithValues(llSearchResult,
valueGetter));
}
@Override return new Hits<>(scoresWithKeysFlux, llSearchResult.totalHitsCount(), llSearchResult::close).send();
public Mono<Send<SearchResult<T, U>>> searchWithTransformer(
ClientQueryParams<SearchResultItem<T, U>> queryParams,
ValueTransformer<T, U> valueTransformer) {
return luceneIndex
.search(resolveSnapshot(queryParams.snapshot()), queryParams.toQueryParams(),
indicizer.getKeyFieldName())
.transform(llSearchResult -> this.transformLuceneResultWithTransformer(llSearchResult,
valueTransformer));
} }
@Override @Override
public Mono<TotalHitsCount> count(@Nullable CompositeSnapshot snapshot, Query query) { public Mono<TotalHitsCount> count(@Nullable CompositeSnapshot snapshot, Query query) {
return this return this
.search(ClientQueryParams.<SearchResultKey<T>>builder().snapshot(snapshot).query(query).limit(0).build()) .search(ClientQueryParams.<LazyHitKey<T>>builder().snapshot(snapshot).query(query).limit(0).build())
.single() .single()
.map(searchResultKeysSend -> { .map(searchResultKeysSend -> {
try (var searchResultKeys = searchResultKeysSend.receive()) { try (var searchResultKeys = searchResultKeysSend.receive()) {

View File

@ -1,81 +0,0 @@
package it.cavallium.dbengine.client;
import io.net5.buffer.api.Drop;
import io.net5.buffer.api.Owned;
import it.cavallium.dbengine.client.query.current.data.TotalHitsCount;
import io.net5.buffer.api.internal.ResourceSupport;
import reactor.core.publisher.Flux;
public final class SearchResult<T, U> extends ResourceSupport<SearchResult<T, U>, SearchResult<T, U>> {
private static final Drop<SearchResult<?, ?>> DROP = new Drop<>() {
@Override
public void drop(SearchResult<?, ?> obj) {
if (obj.onClose != null) {
obj.onClose.run();
}
}
@Override
public Drop<SearchResult<?, ?>> fork() {
return this;
}
@Override
public void attach(SearchResult<?, ?> obj) {
}
};
private Flux<SearchResultItem<T, U>> results;
private TotalHitsCount totalHitsCount;
private Runnable onClose;
@SuppressWarnings({"unchecked", "rawtypes"})
public SearchResult(Flux<SearchResultItem<T, U>> results, TotalHitsCount totalHitsCount, Runnable onClose) {
super((Drop<SearchResult<T,U>>) (Drop) DROP);
this.results = results;
this.totalHitsCount = totalHitsCount;
this.onClose = onClose;
}
public static <T, U> SearchResult<T, U> empty() {
return new SearchResult<T, U>(Flux.empty(), TotalHitsCount.of(0, true), null);
}
public Flux<SearchResultItem<T, U>> results() {
return results;
}
public TotalHitsCount totalHitsCount() {
return totalHitsCount;
}
@Override
public String toString() {
return "SearchResult[" + "results=" + results + ", " + "totalHitsCount=" + totalHitsCount + ']';
}
@Override
protected RuntimeException createResourceClosedException() {
return new IllegalStateException("Closed");
}
@Override
protected Owned<SearchResult<T, U>> prepareSend() {
var results = this.results;
var totalHitsCount = this.totalHitsCount;
var onClose = this.onClose;
return drop -> {
var instance = new SearchResult<>(results, totalHitsCount, onClose);
drop.attach(instance);
return instance;
};
}
protected void makeInaccessible() {
this.results = null;
this.totalHitsCount = null;
this.onClose = null;
}
}

View File

@ -1,13 +0,0 @@
package it.cavallium.dbengine.client;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono;
public record SearchResultItem<T, U>(Mono<T> key, Mono<U> value, float score)
implements Comparable<SearchResultItem<T, U>> {
@Override
public int compareTo(@NotNull SearchResultItem<T, U> o) {
return Float.compare(o.score, this.score);
}
}

View File

@ -1,7 +0,0 @@
package it.cavallium.dbengine.client;
import java.util.Objects;
import java.util.StringJoiner;
import reactor.core.publisher.Mono;
public record SearchResultKey<T>(Mono<T> key, float score) {}

View File

@ -1,96 +0,0 @@
package it.cavallium.dbengine.client;
import io.net5.buffer.api.Drop;
import io.net5.buffer.api.Owned;
import it.cavallium.dbengine.client.query.current.data.TotalHitsCount;
import io.net5.buffer.api.internal.ResourceSupport;
import it.cavallium.dbengine.database.collections.ValueGetter;
import org.warp.commonutils.log.Logger;
import org.warp.commonutils.log.LoggerFactory;
import reactor.core.publisher.Flux;
@SuppressWarnings("unused")
public final class SearchResultKeys<T> extends ResourceSupport<SearchResultKeys<T>, SearchResultKeys<T>> {
private static final Logger logger = LoggerFactory.getLogger(SearchResultKeys.class);
private static final Drop<SearchResultKeys<?>> DROP = new Drop<>() {
@Override
public void drop(SearchResultKeys<?> obj) {
if (obj.onClose != null) {
obj.onClose.run();
}
}
@Override
public Drop<SearchResultKeys<?>> fork() {
return this;
}
@Override
public void attach(SearchResultKeys<?> obj) {
}
};
private Flux<SearchResultKey<T>> results;
private TotalHitsCount totalHitsCount;
private Runnable onClose;
@SuppressWarnings({"unchecked", "rawtypes"})
public SearchResultKeys(Flux<SearchResultKey<T>> results, TotalHitsCount totalHitsCount, Runnable onClose) {
super((Drop<SearchResultKeys<T>>) (Drop) DROP);
this.results = results;
this.totalHitsCount = totalHitsCount;
this.onClose = onClose;
}
public static <T> SearchResultKeys<T> empty() {
return new SearchResultKeys<>(Flux.empty(), TotalHitsCount.of(0, true), null);
}
public <U> SearchResult<T, U> withValues(ValueGetter<T, U> valuesGetter) {
return new SearchResult<>(results.map(item -> new SearchResultItem<>(item.key(),
item.key().flatMap(valuesGetter::get),
item.score()
)), totalHitsCount, this::close);
}
public Flux<SearchResultKey<T>> results() {
return results;
}
public TotalHitsCount totalHitsCount() {
return totalHitsCount;
}
@Override
public String toString() {
return "SearchResultKeys[" + "results=" + results + ", " + "totalHitsCount=" + totalHitsCount + ']';
}
@Override
protected RuntimeException createResourceClosedException() {
return new IllegalStateException("Closed");
}
@Override
protected Owned<SearchResultKeys<T>> prepareSend() {
var results = this.results;
var totalHitsCount = this.totalHitsCount;
var onClose = this.onClose;
makeInaccessible();
return drop -> {
var instance = new SearchResultKeys<>(results, totalHitsCount, onClose);
drop.attach(instance);
return instance;
};
}
protected void makeInaccessible() {
this.results = null;
this.totalHitsCount = null;
this.onClose = null;
}
}

View File

@ -12,17 +12,17 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@RecordBuilder @RecordBuilder
public final record ClientQueryParams<T>(@Nullable CompositeSnapshot snapshot, public final record ClientQueryParams(@Nullable CompositeSnapshot snapshot,
@NotNull Query query, @NotNull Query query,
long offset, long offset,
long limit, long limit,
@Nullable Float minCompetitiveScore, @Nullable Float minCompetitiveScore,
@Nullable Sort sort, @Nullable Sort sort,
boolean complete) { boolean complete) {
public static <T> ClientQueryParamsBuilder<T> builder() { public static ClientQueryParamsBuilder builder() {
return ClientQueryParamsBuilder return ClientQueryParamsBuilder
.<T>builder() .builder()
.snapshot(null) .snapshot(null)
.offset(0) .offset(0)
.limit(Long.MAX_VALUE) .limit(Long.MAX_VALUE)

View File

@ -7,7 +7,6 @@ import io.net5.buffer.api.Send;
import io.net5.buffer.api.internal.ResourceSupport; import io.net5.buffer.api.internal.ResourceSupport;
import it.cavallium.dbengine.client.BadBlock; import it.cavallium.dbengine.client.BadBlock;
import it.cavallium.dbengine.client.CompositeSnapshot; import it.cavallium.dbengine.client.CompositeSnapshot;
import it.cavallium.dbengine.client.SearchResultKeys;
import it.cavallium.dbengine.database.Delta; import it.cavallium.dbengine.database.Delta;
import it.cavallium.dbengine.database.LLDictionary; import it.cavallium.dbengine.database.LLDictionary;
import it.cavallium.dbengine.database.LLDictionaryResultType; import it.cavallium.dbengine.database.LLDictionaryResultType;

View File

@ -4,22 +4,14 @@ import static it.cavallium.dbengine.database.LLUtils.MARKER_ROCKSDB;
import static it.cavallium.dbengine.database.disk.LLLocalDictionary.getRocksIterator; import static it.cavallium.dbengine.database.disk.LLLocalDictionary.getRocksIterator;
import io.net5.buffer.api.Buffer; import io.net5.buffer.api.Buffer;
import io.net5.buffer.api.BufferAllocator;
import io.net5.buffer.api.Drop; import io.net5.buffer.api.Drop;
import io.net5.buffer.api.Owned; import io.net5.buffer.api.Owned;
import io.net5.buffer.api.Resource;
import io.net5.buffer.api.Send; import io.net5.buffer.api.Send;
import io.net5.buffer.api.internal.ResourceSupport; import io.net5.buffer.api.internal.ResourceSupport;
import io.net5.util.IllegalReferenceCountException;
import it.cavallium.dbengine.client.SearchResult;
import it.cavallium.dbengine.database.LLRange; import it.cavallium.dbengine.database.LLRange;
import it.cavallium.dbengine.database.LLUtils; import it.cavallium.dbengine.database.LLUtils;
import it.cavallium.dbengine.netty.NullableBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.rocksdb.ColumnFamilyHandle;
import org.rocksdb.ReadOptions; import org.rocksdb.ReadOptions;
import org.rocksdb.RocksDB;
import org.rocksdb.RocksDBException; import org.rocksdb.RocksDBException;
import org.warp.commonutils.log.Logger; import org.warp.commonutils.log.Logger;
import org.warp.commonutils.log.LoggerFactory; import org.warp.commonutils.log.LoggerFactory;

View File

@ -10,10 +10,11 @@ import static org.junit.jupiter.api.Assertions.fail;
import io.net5.buffer.PooledByteBufAllocator; import io.net5.buffer.PooledByteBufAllocator;
import it.cavallium.dbengine.DbTestUtils.TempDb; import it.cavallium.dbengine.DbTestUtils.TempDb;
import it.cavallium.dbengine.DbTestUtils.TestAllocator; import it.cavallium.dbengine.DbTestUtils.TestAllocator;
import it.cavallium.dbengine.client.HitKey;
import it.cavallium.dbengine.client.Hits;
import it.cavallium.dbengine.client.LuceneIndex; import it.cavallium.dbengine.client.LuceneIndex;
import it.cavallium.dbengine.client.Sort; import it.cavallium.dbengine.client.Sort;
import it.cavallium.dbengine.client.SearchResultKey; import it.cavallium.dbengine.client.LazyHitKey;
import it.cavallium.dbengine.client.SearchResultKeys;
import it.cavallium.dbengine.client.query.ClientQueryParams; import it.cavallium.dbengine.client.query.ClientQueryParams;
import it.cavallium.dbengine.client.query.ClientQueryParamsBuilder; import it.cavallium.dbengine.client.query.ClientQueryParamsBuilder;
import it.cavallium.dbengine.client.query.current.data.BooleanQuery; import it.cavallium.dbengine.client.query.current.data.BooleanQuery;
@ -237,7 +238,7 @@ public class TestLuceneSearches {
} }
private boolean supportsPreciseHitsCount(LocalSearcher searcher, private boolean supportsPreciseHitsCount(LocalSearcher searcher,
ClientQueryParams<SearchResultKey<String>> query) { ClientQueryParams query) {
var sorted = query.isSorted(); var sorted = query.isSorted();
if (searcher instanceof UnsortedUnscoredStreamingMultiSearcher) { if (searcher instanceof UnsortedUnscoredStreamingMultiSearcher) {
return false; return false;
@ -248,7 +249,7 @@ public class TestLuceneSearches {
} }
} }
public void testSearch(ClientQueryParamsBuilder<SearchResultKey<String>> queryParamsBuilder, public void testSearch(ClientQueryParamsBuilder queryParamsBuilder,
ExpectedQueryType expectedQueryType) throws Throwable { ExpectedQueryType expectedQueryType) throws Throwable {
runSearchers(expectedQueryType, searcher -> { runSearchers(expectedQueryType, searcher -> {
@ -291,7 +292,7 @@ public class TestLuceneSearches {
@MethodSource("provideQueryArgumentsScoreModeAndSort") @MethodSource("provideQueryArgumentsScoreModeAndSort")
public void testSearchNoDocs(boolean shards, Sort multiSort) throws Throwable { public void testSearchNoDocs(boolean shards, Sort multiSort) throws Throwable {
var queryBuilder = ClientQueryParams var queryBuilder = ClientQueryParams
.<SearchResultKey<String>>builder() .<LazyHitKey<String>>builder()
.query(new MatchNoDocsQuery()) .query(new MatchNoDocsQuery())
.snapshot(null) .snapshot(null)
.complete(true) .complete(true)
@ -305,7 +306,7 @@ public class TestLuceneSearches {
@MethodSource("provideQueryArgumentsScoreModeAndSort") @MethodSource("provideQueryArgumentsScoreModeAndSort")
public void testSearchAllDocs(boolean shards, Sort multiSort) throws Throwable { public void testSearchAllDocs(boolean shards, Sort multiSort) throws Throwable {
var queryBuilder = ClientQueryParams var queryBuilder = ClientQueryParams
.<SearchResultKey<String>>builder() .<LazyHitKey<String>>builder()
.query(new MatchAllDocsQuery()) .query(new MatchAllDocsQuery())
.snapshot(null) .snapshot(null)
.complete(true) .complete(true)
@ -319,7 +320,7 @@ public class TestLuceneSearches {
@MethodSource("provideQueryArgumentsScoreModeAndSort") @MethodSource("provideQueryArgumentsScoreModeAndSort")
public void testSearchAdvancedText(boolean shards, Sort multiSort) throws Throwable { public void testSearchAdvancedText(boolean shards, Sort multiSort) throws Throwable {
var queryBuilder = ClientQueryParams var queryBuilder = ClientQueryParams
.<SearchResultKey<String>>builder() .<LazyHitKey<String>>builder()
.query(new BooleanQuery(List.of( .query(new BooleanQuery(List.of(
new BooleanQueryPart(new BoostQuery(new TermQuery(new Term("text", "hello")), 3), new OccurShould()), new BooleanQueryPart(new BoostQuery(new TermQuery(new Term("text", "hello")), 3), new OccurShould()),
new BooleanQueryPart(new TermQuery(new Term("text", "world")), new OccurShould()), new BooleanQueryPart(new TermQuery(new Term("text", "world")), new OccurShould()),
@ -357,14 +358,10 @@ public class TestLuceneSearches {
assertEquals(new TotalHitsCount(expectedCount, true), hits); assertEquals(new TotalHitsCount(expectedCount, true), hits);
} }
private List<Scored> getResults(SearchResultKeys<String> results) { private List<Scored> getResults(Hits<HitKey<String>> results) {
return run(results return run(results
.results() .results()
.flatMapSequential(searchResultKey -> searchResultKey .map(key -> new Scored(key.key(), key.score()))
.key()
.single()
.map(key -> new Scored(key, searchResultKey.score()))
)
.collectList()); .collectList());
} }