diff --git a/evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/FacetSummary.java b/evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/FacetSummary.java index 62a289d3c..d43793150 100644 --- a/evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/FacetSummary.java +++ b/evita_api/src/main/java/io/evitadb/api/requestResponse/extraResult/FacetSummary.java @@ -292,7 +292,7 @@ public String prettyPrint( statistics .getFacetStatistics() .stream() - .map(facet -> "\t\t[" + (facet.isRequested() ? "X" : " ") + "] " + + .map(facet -> "\t\t[" + (facet.isRequested() ? "X" : (ofNullable(facet.getImpact()).map(RequestImpact::hasSense).orElse(true) ? " " : "-")) + "] " + ofNullable(facetRenderer.apply(facet)).filter(it -> !it.isBlank()).orElseGet(() -> String.valueOf(facet.getFacetEntity().getPrimaryKey())) + " (" + facet.getCount() + ")" + ofNullable(facet.getImpact()).map(RequestImpact::toString).map(it -> " " + it).orElse("")) @@ -361,8 +361,12 @@ public int hashCode() { * @param difference Projected number of entities that are added or removed from result if the query is altered by adding this * facet to filtering query in comparison to current result. * @param matchCount Projected number of filtered entities if the query is altered by adding this facet to filtering query. + * @param hasSense Selection has sense - TRUE if there is at least one entity still present in the result if + * the query is altered by adding this facet to filtering query. In case of OR relation between + * facets it's also true only if there is at least one entity present in the result when all other + * facets in the same group are removed and only this facet is requested. */ - public record RequestImpact(int difference, int matchCount) implements Serializable { + public record RequestImpact(int difference, int matchCount, boolean hasSense) implements Serializable { @Serial private static final long serialVersionUID = 8332603848272953977L; /** @@ -373,24 +377,16 @@ public int difference() { return difference; } - /** - * Selection has sense - TRUE if there is at least one entity still present in the result if the query is - * altered by adding this facet to filtering query. - */ - public boolean hasSense() { - return matchCount > 0; - } - @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof RequestImpact that)) return false; - return difference() == that.difference() && matchCount() == that.matchCount(); + return difference() == that.difference() && this.matchCount() == that.matchCount() && this.hasSense() == that.hasSense(); } @Override public int hashCode() { - return Objects.hash(difference(), matchCount()); + return Objects.hash(difference(), matchCount(), hasSense()); } @Override diff --git a/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/facet/producer/AbstractFacetFormulaGenerator.java b/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/facet/producer/AbstractFacetFormulaGenerator.java index f21454f89..f9dda823b 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/facet/producer/AbstractFacetFormulaGenerator.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/facet/producer/AbstractFacetFormulaGenerator.java @@ -512,7 +512,7 @@ public void visit(@Nonnull Formula formula) { * @return The base entity IDs as a Bitmap. */ @Nonnull - protected Bitmap getBaseEntityIds(@Nonnull Bitmap[] facetEntityIds) { + protected static Bitmap getBaseEntityIds(@Nonnull Bitmap[] facetEntityIds) { if (facetEntityIds.length == 0) { return EmptyBitmap.INSTANCE; } else if (facetEntityIds.length == 1) { @@ -677,18 +677,27 @@ protected static class MutableFormulaFinderAndReplacer implements FormulaVisitor */ private final Deque formulaStack = new ArrayDeque<>(16); /** - * Flag that is set to true if the visitor found the target {@link MutableFormula}. + * Reference to {@link MutableFormula} found. */ - @Getter private boolean targetFound; + @Getter + private MutableFormula target; + + /** + * Returns true if the target {@link MutableFormula} has been found. + * @return True if the target {@link MutableFormula} has been found. + */ + public boolean isTargetFound() { + return target != null; + } @Override public void visit(@Nonnull Formula formula) { - if (!targetFound) { + if (target == null) { if (formula instanceof MutableFormula mutableFormula) { - if (targetFound) { + if (target != null) { throw new GenericEvitaInternalError("Expected single MutableFormula in the formula tree!"); } else { - targetFound = true; + target = mutableFormula; mutableFormula.setDelegate(formulaToReplaceSupplier.get()); for (Formula parentFormula : formulaStack) { parentFormula.clearMemory(); diff --git a/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/facet/producer/ImpactFormulaGenerator.java b/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/facet/producer/ImpactFormulaGenerator.java index 8424b099c..017c78a76 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/facet/producer/ImpactFormulaGenerator.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/facet/producer/ImpactFormulaGenerator.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023 + * Copyright (c) 2023-2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ import io.evitadb.core.query.algebra.facet.FacetGroupOrFormula; import io.evitadb.index.bitmap.BaseBitmap; import io.evitadb.index.bitmap.Bitmap; +import io.evitadb.utils.Assert; import io.evitadb.utils.CollectionUtils; import javax.annotation.Nonnull; @@ -170,6 +171,39 @@ protected boolean handleUserFilter(@Nonnull Formula formula, @Nonnull Formula[] } } + /** + * We need to calculate whether the `facetId` returns any results when other facets in the same group are removed. + * + * @param hypotheticalFormula the current formula including this facet and all other facets + * @param referenceSchema the reference schema of the facet group + * @param facetGroupId the facet group id + * @param facetId the examined facet id + * @param facetEntityIds the examined facet entity ids + * @return true when there is at least one result when the formula is altered in a way, that the `facetId` is requested + * on its own in the facet group OR formula + */ + public boolean hasSenseAlone( + @Nonnull Formula hypotheticalFormula, + @Nonnull ReferenceSchemaContract referenceSchema, + @Nullable Integer facetGroupId, + int facetId, + @Nonnull Bitmap[] facetEntityIds + ) { + if (this.isFacetGroupConjunction.test(referenceSchema, facetGroupId)) { + return !hypotheticalFormula.compute().isEmpty(); + } else { + final Bitmap facetEntityIdsBitmap = getBaseEntityIds(facetEntityIds); + final MutableFormulaFinderAndReplacer mutableFormulaFinderAndReplacer = new MutableFormulaFinderAndReplacer( + () -> new FacetGroupOrFormula(referenceSchema.getName(), facetGroupId, new BaseBitmap(facetId), facetEntityIdsBitmap) + ); + hypotheticalFormula.accept(mutableFormulaFinderAndReplacer); + Assert.isPremiseValid(mutableFormulaFinderAndReplacer.isTargetFound(), "Expected single MutableFormula in the formula tree!"); + return mutableFormulaFinderAndReplacer.getTarget().suppressPivot( + () -> !hypotheticalFormula.compute().isEmpty() + ); + } + } + /** * Represents a cache key used for caching formula generation results. The cache key contains all key information * needed to distinguish the situation when we need to analyze and create new formula composition and we can reuse diff --git a/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/facet/producer/MemoizingFacetCalculator.java b/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/facet/producer/MemoizingFacetCalculator.java index d7c3cb014..2634d0bee 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/facet/producer/MemoizingFacetCalculator.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/facet/producer/MemoizingFacetCalculator.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023 + * Copyright (c) 2023-2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -60,9 +60,9 @@ public class MemoizingFacetCalculator implements FacetCalculator, ImpactCalculat */ private final Formula baseFormulaWithoutUserFilter; /** - * Contains "no-impact" result for all facets that are already selected in {@link EvitaRequest}. + * Contains current match count (the base-line). */ - private final RequestImpact base; + private final int baseMatchCount; /** * Contains instance of {@link FacetFormulaGenerator} that is reused for all calls. Visitors instances are usually * created for single use and then thrown away but here we expect a lot of repeated computations for facets and @@ -86,7 +86,7 @@ public MemoizingFacetCalculator( // now replace common parts of the formula with cached counterparts this.baseFormula = queryContext.analyse(optimizedFormula); this.baseFormulaWithoutUserFilter = baseFormulaWithoutUserFilter; - this.base = new RequestImpact(0, baseFormula.compute().size()); + this.baseMatchCount = baseFormula.compute().size(); this.facetFormulaGenerator = new FacetFormulaGenerator( queryContext::isFacetGroupConjunction, queryContext::isFacetGroupDisjunction, @@ -102,32 +102,29 @@ public MemoizingFacetCalculator( @Nullable @Override public RequestImpact calculateImpact(@Nonnull ReferenceSchemaContract referenceSchema, int facetId, @Nullable Integer facetGroupId, boolean required, @Nonnull Bitmap[] facetEntityIds) { - if (required) { - // facet is already selected in request - return "no impact" result quickly - return base; - } else { - // create formula that would capture the requested facet selected - final Formula hypotheticalFormula = impactFormulaGenerator.generateFormula( - baseFormula, baseFormulaWithoutUserFilter, referenceSchema, facetGroupId, facetId, facetEntityIds - ); - // compute the hypothetical result - final int hypotheticalCount = hypotheticalFormula.compute().size(); - // and return computed impact - return new RequestImpact( - hypotheticalCount - base.matchCount(), - hypotheticalCount - ); - } + // create formula that would capture the requested facet selected + final Formula hypotheticalFormula = impactFormulaGenerator.generateFormula( + baseFormula, baseFormulaWithoutUserFilter, referenceSchema, facetGroupId, facetId, facetEntityIds + ); + // compute the hypothetical result + final int hypotheticalCount = hypotheticalFormula.compute().size(); + // and return computed impact + final int difference = hypotheticalCount - this.baseMatchCount; + return new RequestImpact( + difference, + hypotheticalCount, + hypotheticalCount > 0 && + (difference != 0 || impactFormulaGenerator.hasSenseAlone(hypotheticalFormula, referenceSchema, facetGroupId, facetId, facetEntityIds)) + ); } @Nonnull @Override public Formula createCountFormula(@Nonnull ReferenceSchemaContract referenceSchema, int facetId, @Nullable Integer facetGroupId, @Nonnull Bitmap[] facetEntityIds) { // create formula that would capture all mandatory filtering constraints plus this single facet selected - final Formula formula = facetFormulaGenerator.generateFormula( + return facetFormulaGenerator.generateFormula( baseFormula, baseFormulaWithoutUserFilter, referenceSchema, facetGroupId, facetId, facetEntityIds ); - return formula; } @Nonnull diff --git a/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/facet/producer/MutableFormula.java b/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/facet/producer/MutableFormula.java index 75ca86408..e5dbc3927 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/facet/producer/MutableFormula.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/facet/producer/MutableFormula.java @@ -27,9 +27,11 @@ import io.evitadb.core.query.algebra.FormulaVisitor; import io.evitadb.core.query.algebra.facet.FacetGroupFormula; import io.evitadb.index.bitmap.Bitmap; +import io.evitadb.utils.Assert; import javax.annotation.Nonnull; import java.util.Objects; +import java.util.function.BooleanSupplier; /** * This formula is a HACK and don't use it!!! @@ -46,6 +48,7 @@ * @author Jan Novotný (novotny@fg.cz), FG Forrest a.s. (c) 2024 */ class MutableFormula implements Formula { + private boolean suppressPivot; private FacetGroupFormula pivot; private FacetGroupFormula delegate; private FacetGroupFormula result; @@ -188,6 +191,23 @@ public String toStringVerbose() { return getInnerFormula().toStringVerbose(); } + /** + * Method allows to calculate {@link #compute()} result based only on {@link #delegate}, suppressing combination + * with {@link #pivot} formula even if this is set. + * + * @param lambda the lambda to be executed + * @return the result of the lambda + */ + public boolean suppressPivot(@Nonnull BooleanSupplier lambda) { + try { + Assert.isPremiseValid(this.result == null, "Cannot suppress pivot when the result is already computed!"); + this.suppressPivot = true; + return lambda.getAsBoolean(); + } finally { + this.suppressPivot = false; + } + } + /** * Returns the inner formula. If the pivot is set, the result is merged with the pivot. * @return the inner formula @@ -195,7 +215,7 @@ public String toStringVerbose() { @Nonnull private FacetGroupFormula getInnerFormula() { if (this.result == null) { - if (this.pivot != null) { + if (this.pivot != null && !this.suppressPivot) { this.result = this.pivot.mergeWith(this.delegate); } else { this.result = this.delegate; diff --git a/evita_external_api/evita_external_api_grpc/server/src/main/java/io/evitadb/externalApi/grpc/builders/query/extraResults/GrpcFacetSummaryBuilder.java b/evita_external_api/evita_external_api_grpc/server/src/main/java/io/evitadb/externalApi/grpc/builders/query/extraResults/GrpcFacetSummaryBuilder.java index 71a884a18..5beb7c220 100644 --- a/evita_external_api/evita_external_api_grpc/server/src/main/java/io/evitadb/externalApi/grpc/builders/query/extraResults/GrpcFacetSummaryBuilder.java +++ b/evita_external_api/evita_external_api_grpc/server/src/main/java/io/evitadb/externalApi/grpc/builders/query/extraResults/GrpcFacetSummaryBuilder.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023 + * Copyright (c) 2023-2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,7 @@ import io.evitadb.api.requestResponse.data.structure.EntityReference; import io.evitadb.api.requestResponse.extraResult.FacetSummary; import io.evitadb.api.requestResponse.extraResult.FacetSummary.FacetGroupStatistics; +import io.evitadb.api.requestResponse.extraResult.FacetSummary.RequestImpact; import io.evitadb.externalApi.grpc.generated.GrpcEntityReference; import io.evitadb.externalApi.grpc.generated.GrpcExtraResults.Builder; import io.evitadb.externalApi.grpc.generated.GrpcFacetGroupStatistics; @@ -75,9 +76,12 @@ public static void buildFacetSummary(@Nonnull Builder extraResults, @Nonnull Fac statisticsBuilder.setFacetEntity(EntityConverter.toGrpcSealedEntity(entity)); } - if (facetStatistic.getImpact() != null) { - statisticsBuilder.setImpact(Int32Value.newBuilder().setValue(facetStatistic.getImpact().difference()).build()); - statisticsBuilder.setMatchCount(Int32Value.newBuilder().setValue(facetStatistic.getImpact().matchCount()).build()); + final RequestImpact impact = facetStatistic.getImpact(); + if (impact != null) { + statisticsBuilder. + setImpact(Int32Value.newBuilder().setValue(impact.difference()).build()) + .setMatchCount(Int32Value.newBuilder().setValue(impact.matchCount()).build()) + .setHasSense(impact.hasSense()); } final GrpcFacetStatistics statistics = statisticsBuilder.build(); diff --git a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcExtraResultsOuterClass.java b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcExtraResultsOuterClass.java index bd08cedba..1d8827bdc 100644 --- a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcExtraResultsOuterClass.java +++ b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcExtraResultsOuterClass.java @@ -127,7 +127,7 @@ public static void registerAllExtensions( "xternalApi.grpc.generated.GrpcSealedEnti" + "ty\022\r\n\005count\030\004 \001(\005\022S\n\017facetStatistics\030\005 \003" + "(\0132:.io.evitadb.externalApi.grpc.generat" + - "ed.GrpcFacetStatistics\"\275\002\n\023GrpcFacetStat" + + "ed.GrpcFacetStatistics\"\317\002\n\023GrpcFacetStat" + "istics\022X\n\024facetEntityReference\030\001 \001(\0132:.i" + "o.evitadb.externalApi.grpc.generated.Grp" + "cEntityReference\022L\n\013facetEntity\030\002 \001(\01327." + @@ -135,49 +135,50 @@ public static void registerAllExtensions( "pcSealedEntity\022\021\n\trequested\030\003 \001(\010\022\r\n\005cou" + "nt\030\004 \001(\005\022+\n\006impact\030\005 \001(\0132\033.google.protob" + "uf.Int32Value\022/\n\nmatchCount\030\006 \001(\0132\033.goog" + - "le.protobuf.Int32Value\"\320\001\n\rGrpcHierarchy" + - "\022V\n\thierarchy\030\001 \003(\0132C.io.evitadb.externa" + - "lApi.grpc.generated.GrpcHierarchy.Hierar" + - "chyEntry\032g\n\016HierarchyEntry\022\013\n\003key\030\001 \001(\t\022" + - "D\n\005value\030\002 \001(\01325.io.evitadb.externalApi." + - "grpc.generated.GrpcLevelInfos:\0028\001\"Z\n\016Grp" + - "cLevelInfos\022H\n\nlevelInfos\030\001 \003(\01324.io.evi" + - "tadb.externalApi.grpc.generated.GrpcLeve" + - "lInfo\"\362\002\n\rGrpcLevelInfo\022S\n\017entityReferen" + - "ce\030\001 \001(\0132:.io.evitadb.externalApi.grpc.g" + - "enerated.GrpcEntityReference\022G\n\006entity\030\002" + - " \001(\01327.io.evitadb.externalApi.grpc.gener" + - "ated.GrpcSealedEntity\0227\n\022queriedEntityCo" + - "unt\030\003 \001(\0132\033.google.protobuf.Int32Value\0222" + - "\n\rchildrenCount\030\004 \001(\0132\033.google.protobuf." + - "Int32Value\022C\n\005items\030\005 \003(\01324.io.evitadb.e" + - "xternalApi.grpc.generated.GrpcLevelInfo\022" + - "\021\n\trequested\030\006 \001(\010\"\335\001\n\022GrpcQueryTelemetr" + - "y\022H\n\toperation\030\001 \001(\01625.io.evitadb.extern" + - "alApi.grpc.generated.GrpcQueryPhase\022\r\n\005s" + - "tart\030\002 \001(\003\022H\n\005steps\030\003 \003(\01329.io.evitadb.e" + - "xternalApi.grpc.generated.GrpcQueryTelem" + - "etry\022\021\n\targuments\030\004 \003(\t\022\021\n\tspentTime\030\005 \001" + - "(\003\"\200\006\n\020GrpcExtraResults\022k\n\022attributeHist" + - "ogram\030\001 \003(\0132O.io.evitadb.externalApi.grp" + - "c.generated.GrpcExtraResults.AttributeHi" + - "stogramEntry\022L\n\016priceHistogram\030\002 \001(\01324.i" + - "o.evitadb.externalApi.grpc.generated.Grp" + - "cHistogram\022]\n\024facetGroupStatistics\030\003 \003(\013" + - "2?.io.evitadb.externalApi.grpc.generated" + - ".GrpcFacetGroupStatistics\022K\n\rselfHierarc" + - "hy\030\004 \001(\01324.io.evitadb.externalApi.grpc.g" + - "enerated.GrpcHierarchy\022Y\n\thierarchy\030\005 \003(" + - "\0132F.io.evitadb.externalApi.grpc.generate" + - "d.GrpcExtraResults.HierarchyEntry\022Q\n\016que" + - "ryTelemetry\030\006 \001(\01329.io.evitadb.externalA" + - "pi.grpc.generated.GrpcQueryTelemetry\032o\n\027" + - "AttributeHistogramEntry\022\013\n\003key\030\001 \001(\t\022C\n\005" + - "value\030\002 \001(\01324.io.evitadb.externalApi.grp" + - "c.generated.GrpcHistogram:\0028\001\032f\n\016Hierarc" + - "hyEntry\022\013\n\003key\030\001 \001(\t\022C\n\005value\030\002 \001(\01324.io" + + "le.protobuf.Int32Value\022\020\n\010hasSense\030\007 \001(\010" + + "\"\320\001\n\rGrpcHierarchy\022V\n\thierarchy\030\001 \003(\0132C." + + "io.evitadb.externalApi.grpc.generated.Gr" + + "pcHierarchy.HierarchyEntry\032g\n\016HierarchyE" + + "ntry\022\013\n\003key\030\001 \001(\t\022D\n\005value\030\002 \001(\01325.io.ev" + + "itadb.externalApi.grpc.generated.GrpcLev" + + "elInfos:\0028\001\"Z\n\016GrpcLevelInfos\022H\n\nlevelIn" + + "fos\030\001 \003(\01324.io.evitadb.externalApi.grpc." + + "generated.GrpcLevelInfo\"\362\002\n\rGrpcLevelInf" + + "o\022S\n\017entityReference\030\001 \001(\0132:.io.evitadb." + + "externalApi.grpc.generated.GrpcEntityRef" + + "erence\022G\n\006entity\030\002 \001(\01327.io.evitadb.exte" + + "rnalApi.grpc.generated.GrpcSealedEntity\022" + + "7\n\022queriedEntityCount\030\003 \001(\0132\033.google.pro" + + "tobuf.Int32Value\0222\n\rchildrenCount\030\004 \001(\0132" + + "\033.google.protobuf.Int32Value\022C\n\005items\030\005 " + + "\003(\01324.io.evitadb.externalApi.grpc.genera" + + "ted.GrpcLevelInfo\022\021\n\trequested\030\006 \001(\010\"\335\001\n" + + "\022GrpcQueryTelemetry\022H\n\toperation\030\001 \001(\01625" + + ".io.evitadb.externalApi.grpc.generated.G" + + "rpcQueryPhase\022\r\n\005start\030\002 \001(\003\022H\n\005steps\030\003 " + + "\003(\01329.io.evitadb.externalApi.grpc.genera" + + "ted.GrpcQueryTelemetry\022\021\n\targuments\030\004 \003(" + + "\t\022\021\n\tspentTime\030\005 \001(\003\"\200\006\n\020GrpcExtraResult" + + "s\022k\n\022attributeHistogram\030\001 \003(\0132O.io.evita" + + "db.externalApi.grpc.generated.GrpcExtraR" + + "esults.AttributeHistogramEntry\022L\n\016priceH" + + "istogram\030\002 \001(\01324.io.evitadb.externalApi." + + "grpc.generated.GrpcHistogram\022]\n\024facetGro" + + "upStatistics\030\003 \003(\0132?.io.evitadb.external" + + "Api.grpc.generated.GrpcFacetGroupStatist" + + "ics\022K\n\rselfHierarchy\030\004 \001(\01324.io.evitadb." + + "externalApi.grpc.generated.GrpcHierarchy" + + "\022Y\n\thierarchy\030\005 \003(\0132F.io.evitadb.externa" + + "lApi.grpc.generated.GrpcExtraResults.Hie" + + "rarchyEntry\022Q\n\016queryTelemetry\030\006 \001(\01329.io" + ".evitadb.externalApi.grpc.generated.Grpc" + - "Hierarchy:\0028\001B\014P\001\252\002\007EvitaDBb\006proto3" + "QueryTelemetry\032o\n\027AttributeHistogramEntr" + + "y\022\013\n\003key\030\001 \001(\t\022C\n\005value\030\002 \001(\01324.io.evita" + + "db.externalApi.grpc.generated.GrpcHistog" + + "ram:\0028\001\032f\n\016HierarchyEntry\022\013\n\003key\030\001 \001(\t\022C" + + "\n\005value\030\002 \001(\01324.io.evitadb.externalApi.g" + + "rpc.generated.GrpcHierarchy:\0028\001B\014P\001\252\002\007Ev" + + "itaDBb\006proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor .internalBuildGeneratedFileFrom(descriptorData, @@ -210,7 +211,7 @@ public static void registerAllExtensions( internal_static_io_evitadb_externalApi_grpc_generated_GrpcFacetStatistics_fieldAccessorTable = new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( internal_static_io_evitadb_externalApi_grpc_generated_GrpcFacetStatistics_descriptor, - new java.lang.String[] { "FacetEntityReference", "FacetEntity", "Requested", "Count", "Impact", "MatchCount", }); + new java.lang.String[] { "FacetEntityReference", "FacetEntity", "Requested", "Count", "Impact", "MatchCount", "HasSense", }); internal_static_io_evitadb_externalApi_grpc_generated_GrpcHierarchy_descriptor = getDescriptor().getMessageTypes().get(3); internal_static_io_evitadb_externalApi_grpc_generated_GrpcHierarchy_fieldAccessorTable = new diff --git a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcFacetStatistics.java b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcFacetStatistics.java index 8a5f3ebe5..11132e20c 100644 --- a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcFacetStatistics.java +++ b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcFacetStatistics.java @@ -137,6 +137,11 @@ private GrpcFacetStatistics( break; } + case 56: { + + hasSense_ = input.readBool(); + break; + } default: { if (!parseUnknownField( input, unknownFields, extensionRegistry, tag)) { @@ -354,6 +359,24 @@ public com.google.protobuf.Int32ValueOrBuilder getMatchCountOrBuilder() { return getMatchCount(); } + public static final int HASSENSE_FIELD_NUMBER = 7; + private boolean hasSense_; + /** + *
+   * Selection has sense - TRUE if there is at least one entity still present in the result if
+   * the query is altered by adding this facet to filtering query. In case of OR relation between
+   * facets it's also true only if there is at least one entity present in the result when all other
+   * facets in the same group are removed and only this facet is requested.
+   * 
+ * + * bool hasSense = 7; + * @return The hasSense. + */ + @java.lang.Override + public boolean getHasSense() { + return hasSense_; + } + private byte memoizedIsInitialized = -1; @java.lang.Override public final boolean isInitialized() { @@ -386,6 +409,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) if (matchCount_ != null) { output.writeMessage(6, getMatchCount()); } + if (hasSense_ != false) { + output.writeBool(7, hasSense_); + } unknownFields.writeTo(output); } @@ -419,6 +445,10 @@ public int getSerializedSize() { size += com.google.protobuf.CodedOutputStream .computeMessageSize(6, getMatchCount()); } + if (hasSense_ != false) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(7, hasSense_); + } size += unknownFields.getSerializedSize(); memoizedSize = size; return size; @@ -458,6 +488,8 @@ public boolean equals(final java.lang.Object obj) { if (!getMatchCount() .equals(other.getMatchCount())) return false; } + if (getHasSense() + != other.getHasSense()) return false; if (!unknownFields.equals(other.unknownFields)) return false; return true; } @@ -490,6 +522,9 @@ public int hashCode() { hash = (37 * hash) + MATCHCOUNT_FIELD_NUMBER; hash = (53 * hash) + getMatchCount().hashCode(); } + hash = (37 * hash) + HASSENSE_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getHasSense()); hash = (29 * hash) + unknownFields.hashCode(); memoizedHashCode = hash; return hash; @@ -655,6 +690,8 @@ public Builder clear() { matchCount_ = null; matchCountBuilder_ = null; } + hasSense_ = false; + return this; } @@ -703,6 +740,7 @@ public io.evitadb.externalApi.grpc.generated.GrpcFacetStatistics buildPartial() } else { result.matchCount_ = matchCountBuilder_.build(); } + result.hasSense_ = hasSense_; onBuilt(); return result; } @@ -769,6 +807,9 @@ public Builder mergeFrom(io.evitadb.externalApi.grpc.generated.GrpcFacetStatisti if (other.hasMatchCount()) { mergeMatchCount(other.getMatchCount()); } + if (other.getHasSense() != false) { + setHasSense(other.getHasSense()); + } this.mergeUnknownFields(other.unknownFields); onChanged(); return this; @@ -1512,6 +1553,58 @@ public com.google.protobuf.Int32ValueOrBuilder getMatchCountOrBuilder() { } return matchCountBuilder_; } + + private boolean hasSense_ ; + /** + *
+     * Selection has sense - TRUE if there is at least one entity still present in the result if
+     * the query is altered by adding this facet to filtering query. In case of OR relation between
+     * facets it's also true only if there is at least one entity present in the result when all other
+     * facets in the same group are removed and only this facet is requested.
+     * 
+ * + * bool hasSense = 7; + * @return The hasSense. + */ + @java.lang.Override + public boolean getHasSense() { + return hasSense_; + } + /** + *
+     * Selection has sense - TRUE if there is at least one entity still present in the result if
+     * the query is altered by adding this facet to filtering query. In case of OR relation between
+     * facets it's also true only if there is at least one entity present in the result when all other
+     * facets in the same group are removed and only this facet is requested.
+     * 
+ * + * bool hasSense = 7; + * @param value The hasSense to set. + * @return This builder for chaining. + */ + public Builder setHasSense(boolean value) { + + hasSense_ = value; + onChanged(); + return this; + } + /** + *
+     * Selection has sense - TRUE if there is at least one entity still present in the result if
+     * the query is altered by adding this facet to filtering query. In case of OR relation between
+     * facets it's also true only if there is at least one entity present in the result when all other
+     * facets in the same group are removed and only this facet is requested.
+     * 
+ * + * bool hasSense = 7; + * @return This builder for chaining. + */ + public Builder clearHasSense() { + + hasSense_ = false; + onChanged(); + return this; + } @java.lang.Override public final Builder setUnknownFields( final com.google.protobuf.UnknownFieldSet unknownFields) { diff --git a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcFacetStatisticsOrBuilder.java b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcFacetStatisticsOrBuilder.java index 0f18347db..d237ec16e 100644 --- a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcFacetStatisticsOrBuilder.java +++ b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/generated/GrpcFacetStatisticsOrBuilder.java @@ -160,4 +160,17 @@ public interface GrpcFacetStatisticsOrBuilder extends * .google.protobuf.Int32Value matchCount = 6; */ com.google.protobuf.Int32ValueOrBuilder getMatchCountOrBuilder(); + + /** + *
+   * Selection has sense - TRUE if there is at least one entity still present in the result if
+   * the query is altered by adding this facet to filtering query. In case of OR relation between
+   * facets it's also true only if there is at least one entity present in the result when all other
+   * facets in the same group are removed and only this facet is requested.
+   * 
+ * + * bool hasSense = 7; + * @return The hasSense. + */ + boolean getHasSense(); } diff --git a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/requestResponse/ResponseConverter.java b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/requestResponse/ResponseConverter.java index baac5ef2b..253ab381b 100644 --- a/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/requestResponse/ResponseConverter.java +++ b/evita_external_api/evita_external_api_grpc/shared/src/main/java/io/evitadb/externalApi/grpc/requestResponse/ResponseConverter.java @@ -309,7 +309,8 @@ private static FacetStatistics toFacetStatistics( grpcFacetStatistics.hasImpact() && grpcFacetStatistics.hasMatchCount() ? new RequestImpact( grpcFacetStatistics.getImpact().getValue(), - grpcFacetStatistics.getMatchCount().getValue() + grpcFacetStatistics.getMatchCount().getValue(), + grpcFacetStatistics.getHasSense() ) : null ); diff --git a/evita_external_api/evita_external_api_grpc/shared/src/main/resources/META-INF/io/evitadb/externalApi/grpc/GrpcExtraResults.proto b/evita_external_api/evita_external_api_grpc/shared/src/main/resources/META-INF/io/evitadb/externalApi/grpc/GrpcExtraResults.proto index 24416427c..a9781e62e 100644 --- a/evita_external_api/evita_external_api_grpc/shared/src/main/resources/META-INF/io/evitadb/externalApi/grpc/GrpcExtraResults.proto +++ b/evita_external_api/evita_external_api_grpc/shared/src/main/resources/META-INF/io/evitadb/externalApi/grpc/GrpcExtraResults.proto @@ -74,6 +74,11 @@ message GrpcFacetStatistics { google.protobuf.Int32Value impact = 5; // Projected number of filtered entities if the query is altered by adding this facet to filtering constraint. google.protobuf.Int32Value matchCount = 6; + // Selection has sense - TRUE if there is at least one entity still present in the result if + // the query is altered by adding this facet to filtering query. In case of OR relation between + // facets it's also true only if there is at least one entity present in the result when all other + // facets in the same group are removed and only this facet is requested. + bool hasSense = 7; } // Contains list of statistics for the single level (probably root or whatever is filtered by the query) of @@ -163,4 +168,4 @@ message GrpcExtraResults { map hierarchy = 5; // This DTO contains detailed information about query processing time and its decomposition to single operations. GrpcQueryTelemetry queryTelemetry = 6; -} \ No newline at end of file +} diff --git a/evita_functional_tests/src/test/java/io/evitadb/api/EntityByFacetFilteringFunctionalTest.java b/evita_functional_tests/src/test/java/io/evitadb/api/EntityByFacetFilteringFunctionalTest.java index 556e2f01f..8798c5b53 100644 --- a/evita_functional_tests/src/test/java/io/evitadb/api/EntityByFacetFilteringFunctionalTest.java +++ b/evita_functional_tests/src/test/java/io/evitadb/api/EntityByFacetFilteringFunctionalTest.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023 + * Copyright (c) 2023-2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -247,7 +247,7 @@ private static FacetSummaryWithResultCount computeFacetSummary( final List filteredEntities = ofNullable(entityFilter) .map(it -> entities.stream().filter(it)) .orElseGet(entities::stream) - .collect(toList()); + .toList(); // collect set of faceted reference types final Set facetedEntities = schema.getReferences() @@ -311,9 +311,9 @@ private static FacetSummaryWithResultCount computeFacetSummary( // filter entities by facets in input query (even if part of user filter) - use AND for different entity types, and OR for facet ids final List filteredEntitiesIncludingUserFilter = - selectedEntitiesPredicate == null ? - filteredEntities.stream().toList() : - filteredEntities.stream().filter(selectedEntitiesPredicate).toList(); + selectedEntitiesPredicate == null ? + filteredEntities.stream().toList() : + filteredEntities.stream().filter(selectedEntitiesPredicate).toList(); final Set facetFilteredEntityIds = filteredEntitiesIncludingUserFilter .stream() .filter(fcc.createBaseFacetPredicate()) @@ -448,21 +448,38 @@ private static int compareFacetGroup( } } - private static RequestImpact computeImpact(@Nonnull List filteredEntities, @Nonnull Set filteredEntityIds, @Nonnull ReferenceKey facet, @Nonnull FacetComputationalContext fcc) { + @Nonnull + private static RequestImpact computeImpact( + @Nonnull List filteredEntities, + @Nonnull Set filteredEntityIds, + @Nonnull ReferenceKey facet, + @Nonnull FacetComputationalContext fcc + ) { // on already filtered entities + final Predicate newPredicate = fcc.createTestFacetPredicate(facet); final Set newResult = filteredEntities.stream() // apply newly created predicate with added current facet query - .filter(fcc.createTestFacetPredicate(facet)) + .filter(newPredicate) // we need only primary keys .map(EntityContract::getPrimaryKey) // in set .collect(Collectors.toSet()); + final int difference = newResult.size() - filteredEntityIds.size(); return new RequestImpact( // compute difference with base result - newResult.size() - filteredEntityIds.size(), + difference, // pass new result count - newResult.size() + newResult.size(), + // calculate has sense + !newResult.isEmpty() && ( + // if there is difference + ( + difference != 0 || + filteredEntities.stream() + .anyMatch(fcc.createBaseFacetPredicateWithoutGroupOfFacet(facet)) + ) + ) ); } @@ -1590,15 +1607,15 @@ void shouldReturnFacetSummaryForHierarchyTreeWithStatistics(Evita evita, EntityS @DisplayName("Should return facet summary with parameter selection for hierarchy with statistics") @UseDataSet(THOUSAND_PRODUCTS_WITH_FACETS) @Test - void shouldReturnFacetSummaryForHierarchyTreeAndParameterFacetWithStatistics(Evita evita, EntitySchemaContract productSchema, List originalProductEntities, Hierarchy categoryHierarchy, Map parameterGroupMapping) { + void shouldReturnFacetSummaryForHierarchyTreeAndParameterFacetWithStatistics(Evita evita, EntitySchemaContract productSchema, List originalProductEntities, Map parameterGroupMapping) { evita.queryCatalog( TEST_CATALOG, session -> { final int allParametersWithinOneGroupResult = queryParameterFacets( - productSchema, originalProductEntities, categoryHierarchy, parameterGroupMapping, session, null, 3, 11 + productSchema, originalProductEntities, parameterGroupMapping, session, null, 3, 11 ); final int parametersInDifferentGroupsResult = queryParameterFacets( - productSchema, originalProductEntities, categoryHierarchy, parameterGroupMapping, session, null, 2, 3, 11 + productSchema, originalProductEntities, parameterGroupMapping, session, null, 2, 3, 11 ); assertTrue( parametersInDifferentGroupsResult < allParametersWithinOneGroupResult, @@ -1661,7 +1678,7 @@ void shouldReturnFacetSummaryForHierarchyTreeWithStatisticsAndInvertedInterFacet @DisplayName("Should return facet summary with parameter selection for hierarchy with statistics with inverted inter facet relation") @UseDataSet(THOUSAND_PRODUCTS_WITH_FACETS) @Test - void shouldReturnFacetSummaryForHierarchyTreeAndParameterFacetWithStatisticsAndInvertedInterFacetRelation(Evita evita, EntitySchemaContract productSchema, List originalProductEntities, Hierarchy categoryHierarchy, Map parameterGroupMapping) { + void shouldReturnFacetSummaryForHierarchyTreeAndParameterFacetWithStatisticsAndInvertedInterFacetRelation(Evita evita, EntitySchemaContract productSchema, List originalProductEntities, Map parameterGroupMapping) { evita.queryCatalog( TEST_CATALOG, session -> { @@ -1672,10 +1689,10 @@ void shouldReturnFacetSummaryForHierarchyTreeAndParameterFacetWithStatisticsAndI assertTrue(facets.length > 1, "There should be at least two facets."); final int singleParameterSelectedResult = queryParameterFacets( - productSchema, originalProductEntities, categoryHierarchy, parameterGroupMapping, session, null, facets[0] + productSchema, originalProductEntities, parameterGroupMapping, session, null, facets[0] ); final int twoParametersFromSameGroupResult = queryParameterFacets( - productSchema, originalProductEntities, categoryHierarchy, parameterGroupMapping, session, null, facets[0], facets[1] + productSchema, originalProductEntities, parameterGroupMapping, session, null, facets[0], facets[1] ); assertTrue( twoParametersFromSameGroupResult > singleParameterSelectedResult, @@ -1683,10 +1700,10 @@ void shouldReturnFacetSummaryForHierarchyTreeAndParameterFacetWithStatisticsAndI ); final Integer groupId = groups.iterator().next(); final int singleParameterSelectedResultInverted = queryParameterFacets( - productSchema, originalProductEntities, categoryHierarchy, parameterGroupMapping, session, facetGroupsConjunction(Entities.PARAMETER, filterBy(entityPrimaryKeyInSet(groupId))), facets[0] + productSchema, originalProductEntities, parameterGroupMapping, session, facetGroupsConjunction(Entities.PARAMETER, filterBy(entityPrimaryKeyInSet(groupId))), facets[0] ); final int twoParametersFromSameGroupResultInverted = queryParameterFacets( - productSchema, originalProductEntities, categoryHierarchy, parameterGroupMapping, session, facetGroupsConjunction(Entities.PARAMETER, filterBy(entityPrimaryKeyInSet(groupId))), facets[0], facets[1] + productSchema, originalProductEntities, parameterGroupMapping, session, facetGroupsConjunction(Entities.PARAMETER, filterBy(entityPrimaryKeyInSet(groupId))), facets[0], facets[1] ); assertTrue( twoParametersFromSameGroupResultInverted < singleParameterSelectedResultInverted, @@ -1700,7 +1717,7 @@ productSchema, originalProductEntities, categoryHierarchy, parameterGroupMapping @DisplayName("Should return facet summary with parameter selection for hierarchy with statistics with inverted facet group relation") @UseDataSet(THOUSAND_PRODUCTS_WITH_FACETS) @Test - void shouldReturnFacetSummaryForHierarchyTreeAndParameterFacetWithStatisticsAndInvertedFacetGroupRelation(Evita evita, EntitySchemaContract productSchema, List originalProductEntities, Hierarchy categoryHierarchy, Map parameterGroupMapping) { + void shouldReturnFacetSummaryForHierarchyTreeAndParameterFacetWithStatisticsAndInvertedFacetGroupRelation(Evita evita, EntitySchemaContract productSchema, List originalProductEntities, Map parameterGroupMapping) { evita.queryCatalog( TEST_CATALOG, session -> { @@ -1716,20 +1733,20 @@ void shouldReturnFacetSummaryForHierarchyTreeAndParameterFacetWithStatisticsAndI assertEquals(facets.length, groups.length, "Number of facets and groups must be equal."); final int singleParameterSelectedResult = queryParameterFacets( - productSchema, originalProductEntities, categoryHierarchy, parameterGroupMapping, session, null, facets[0] + productSchema, originalProductEntities, parameterGroupMapping, session, null, facets[0] ); final int twoParametersFromDifferentGroupResult = queryParameterFacets( - productSchema, originalProductEntities, categoryHierarchy, parameterGroupMapping, session, null, facets + productSchema, originalProductEntities, parameterGroupMapping, session, null, facets ); assertTrue( twoParametersFromDifferentGroupResult < singleParameterSelectedResult, "When selecting multiple facets from their groups should decrease the result" ); final int singleParameterSelectedResultWithOr = queryParameterFacets( - productSchema, originalProductEntities, categoryHierarchy, parameterGroupMapping, session, facetGroupsDisjunction(Entities.PARAMETER, filterBy(entityPrimaryKeyInSet(groups[1]))), facets[0] + productSchema, originalProductEntities, parameterGroupMapping, session, facetGroupsDisjunction(Entities.PARAMETER, filterBy(entityPrimaryKeyInSet(groups[1]))), facets[0] ); final int twoParametersFromDifferentGroupResultWithOr = queryParameterFacets( - productSchema, originalProductEntities, categoryHierarchy, parameterGroupMapping, session, facetGroupsDisjunction(Entities.PARAMETER, filterBy(entityPrimaryKeyInSet(groups[1]))), facets + productSchema, originalProductEntities, parameterGroupMapping, session, facetGroupsDisjunction(Entities.PARAMETER, filterBy(entityPrimaryKeyInSet(groups[1]))), facets ); assertTrue( twoParametersFromDifferentGroupResultWithOr > singleParameterSelectedResultWithOr, @@ -1743,16 +1760,16 @@ productSchema, originalProductEntities, categoryHierarchy, parameterGroupMapping @DisplayName("Should return facet summary with parameter selection for hierarchy with statistics with negated meaning of group") @UseDataSet(THOUSAND_PRODUCTS_WITH_FACETS) @Test - void shouldReturnFacetSummaryForHierarchyTreeAndParameterFacetWithStatisticsAndNegatedGroupImpact(Evita evita, EntitySchemaContract productSchema, List originalProductEntities, Hierarchy categoryHierarchy, Map parameterGroupMapping) { + void shouldReturnFacetSummaryForHierarchyTreeAndParameterFacetWithStatisticsAndNegatedGroupImpact(Evita evita, EntitySchemaContract productSchema, List originalProductEntities, Map parameterGroupMapping) { evita.queryCatalog( TEST_CATALOG, session -> { final int facetId = 3; final int singleParameterSelectedResult = queryParameterFacets( - productSchema, originalProductEntities, categoryHierarchy, parameterGroupMapping, session, null, facetId + productSchema, originalProductEntities, parameterGroupMapping, session, null, facetId ); final int twoParametersFromSameGroupResult = queryParameterFacets( - productSchema, originalProductEntities, categoryHierarchy, parameterGroupMapping, session, + productSchema, originalProductEntities, parameterGroupMapping, session, facetGroupsNegation(Entities.PARAMETER, filterBy(entityPrimaryKeyInSet(parameterGroupMapping.get(facetId)))), facetId ); @@ -2376,7 +2393,14 @@ private void assertFacetSummaryEntities( * Simplification method that executes query with facet computation and returns how many record matches the query * that filters over input parameter facet ids. */ - private int queryParameterFacets(EntitySchemaContract productSchema, List originalProductEntities, Hierarchy categoryHierarchy, Map parameterGroupMapping, EvitaSessionContract session, RequireConstraint additionalRequirement, Integer... facetIds) { + private int queryParameterFacets( + EntitySchemaContract productSchema, + List originalProductEntities, + Map parameterGroupMapping, + EvitaSessionContract session, + RequireConstraint additionalRequirement, + Integer... facetIds + ) { final Query query = query( collection(Entities.PRODUCT), filterBy( @@ -2740,9 +2764,30 @@ public Predicate createBaseFacetPredicate() { return combineFacetsIntoPredicate(existingFacetPredicates); } + public Predicate createBaseFacetPredicateWithoutGroupOfFacet(ReferenceKey facet) { + final Predicate matchTypeAndGroup = it -> Objects.equals(facet.referenceName(), it.referenceSchema().getName()) && + Objects.equals(getGroup(facet), it.facetGroupId()); + + return combineFacetsIntoPredicate( + Stream.concat( + Stream.of( + // create brand new predicate + createFacetGroupPredicate( + entitySchema.getReferenceOrThrowException(facet.referenceName()), + getGroup(facet), + facet.primaryKey() + ) + ), + // use all previous facet predicates that doesn't match this facet type and group + existingFacetPredicates + .stream() + .filter(matchTypeAndGroup.negate()) + ).toList() + ); + } + @Nonnull public Predicate createTestFacetPredicate(@Nonnull ReferenceKey facet) { - // create brand new predicate final Predicate matchTypeAndGroup = it -> Objects.equals(facet.referenceName(), it.referenceSchema().getName()) && Objects.equals(getGroup(facet), it.facetGroupId()); diff --git a/evita_functional_tests/src/test/java/io/evitadb/api/requestResponse/extraResult/FacetSummaryTest.java b/evita_functional_tests/src/test/java/io/evitadb/api/requestResponse/extraResult/FacetSummaryTest.java index c02616657..c61acbd82 100644 --- a/evita_functional_tests/src/test/java/io/evitadb/api/requestResponse/extraResult/FacetSummaryTest.java +++ b/evita_functional_tests/src/test/java/io/evitadb/api/requestResponse/extraResult/FacetSummaryTest.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023 + * Copyright (c) 2023-2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -54,7 +54,7 @@ void shouldBeEqual() { } @Nonnull - private FacetSummary createFacetSummary() { + private static FacetSummary createFacetSummary() { final ReferenceSchema parameter = ReferenceSchema._internalBuild( "parameter", "parameter", false, Cardinality.ZERO_OR_MORE, "parameterGroup", false, true, true ); @@ -66,8 +66,8 @@ private FacetSummary createFacetSummary() { 14, Arrays.asList( new FacetStatistics(new EntityReference("parameter", 1), true, 5, null), - new FacetStatistics(new EntityReference("parameter", 2), false, 6, new RequestImpact(6, 11)), - new FacetStatistics(new EntityReference("parameter", 3), false, 3, new RequestImpact(3, 8)) + new FacetStatistics(new EntityReference("parameter", 2), false, 6, new RequestImpact(6, 11, true)), + new FacetStatistics(new EntityReference("parameter", 3), false, 3, new RequestImpact(3, 8, true)) ) ), new FacetGroupStatistics( @@ -76,8 +76,8 @@ private FacetSummary createFacetSummary() { 14, Arrays.asList( new FacetStatistics(new EntityReference("parameter", 4), true, 5, null), - new FacetStatistics(new EntityReference("parameter", 5), false, 6, new RequestImpact(6, 11)), - new FacetStatistics(new EntityReference("parameter", 6), false, 3, new RequestImpact(3, 8)) + new FacetStatistics(new EntityReference("parameter", 5), false, 6, new RequestImpact(6, 11, true)), + new FacetStatistics(new EntityReference("parameter", 6), false, 3, new RequestImpact(3, 8, true)) ) ) ) diff --git a/evita_functional_tests/src/test/java/io/evitadb/externalApi/grpc/builders/query/extraResults/GrpcFacetSummaryBuilderTest.java b/evita_functional_tests/src/test/java/io/evitadb/externalApi/grpc/builders/query/extraResults/GrpcFacetSummaryBuilderTest.java index 10f4d01e8..8b6bef222 100644 --- a/evita_functional_tests/src/test/java/io/evitadb/externalApi/grpc/builders/query/extraResults/GrpcFacetSummaryBuilderTest.java +++ b/evita_functional_tests/src/test/java/io/evitadb/externalApi/grpc/builders/query/extraResults/GrpcFacetSummaryBuilderTest.java @@ -6,7 +6,7 @@ * | __/\ V /| | || (_| | |_| | |_) | * \___| \_/ |_|\__\__,_|____/|____/ * - * Copyright (c) 2023 + * Copyright (c) 2023-2024 * * Licensed under the Business Source License, Version 1.1 (the "License"); * you may not use this file except in compliance with the License. @@ -77,10 +77,10 @@ void buildFacetSummary() { new EntityReference(Objects.requireNonNull(types[0].getReferencedGroupType()), 1), 15, List.of( - new FacetStatistics(new EntityReference(types[0].getReferencedEntityType(), 1), true, 5, new RequestImpact(1, 7)), - new FacetStatistics(new EntityReference(types[0].getReferencedEntityType(), 2), false, 4, new RequestImpact(5, 6)), - new FacetStatistics(new EntityReference(types[0].getReferencedEntityType(), 3), false, 5, new RequestImpact(6, 6)), - new FacetStatistics(new EntityReference(types[0].getReferencedEntityType(), 4), false, 1, new RequestImpact(4, 58)) + new FacetStatistics(new EntityReference(types[0].getReferencedEntityType(), 1), true, 5, new RequestImpact(1, 7, true)), + new FacetStatistics(new EntityReference(types[0].getReferencedEntityType(), 2), false, 4, new RequestImpact(5, 6, true)), + new FacetStatistics(new EntityReference(types[0].getReferencedEntityType(), 3), false, 5, new RequestImpact(6, 6, true)), + new FacetStatistics(new EntityReference(types[0].getReferencedEntityType(), 4), false, 1, new RequestImpact(4, 58, true)) ) ), new FacetGroupStatistics( @@ -88,10 +88,10 @@ void buildFacetSummary() { createGroupEntity("testGroup2"), 15, List.of( - new FacetStatistics(createFacetEntity(types[1].getReferencedEntityType(), 1, "phone1"), true, 5, new RequestImpact(55, 7)), - new FacetStatistics(createFacetEntity(types[1].getReferencedEntityType(), 2, "phone2"), false, 4, new RequestImpact(7, 8)), - new FacetStatistics(createFacetEntity(types[1].getReferencedEntityType(), 3, "phone3"), false, 5, new RequestImpact(6, 6)), - new FacetStatistics(createFacetEntity(types[1].getReferencedEntityType(), 4, "phone4"), false, 1, new RequestImpact(7, 4)) + new FacetStatistics(createFacetEntity(types[1].getReferencedEntityType(), 1, "phone1"), true, 5, new RequestImpact(55, 7, true)), + new FacetStatistics(createFacetEntity(types[1].getReferencedEntityType(), 2, "phone2"), false, 4, new RequestImpact(7, 8, true)), + new FacetStatistics(createFacetEntity(types[1].getReferencedEntityType(), 3, "phone3"), false, 5, new RequestImpact(6, 6, true)), + new FacetStatistics(createFacetEntity(types[1].getReferencedEntityType(), 4, "phone4"), false, 1, new RequestImpact(7, 4, true)) ) ), new FacetGroupStatistics( @@ -99,10 +99,10 @@ void buildFacetSummary() { null, 29, List.of( - new FacetStatistics(new EntityReference(types[2].getReferencedEntityType(), 1), true, 8, new RequestImpact(1, 5)), - new FacetStatistics(new EntityReference(types[2].getReferencedEntityType(), 2), false, 9, new RequestImpact(2, 66)), - new FacetStatistics(new EntityReference(types[2].getReferencedEntityType(), 3), false, 7, new RequestImpact(3, 76)), - new FacetStatistics(new EntityReference(types[2].getReferencedEntityType(), 4), false, 5, new RequestImpact(4, 8)) + new FacetStatistics(new EntityReference(types[2].getReferencedEntityType(), 1), true, 8, new RequestImpact(1, 5, true)), + new FacetStatistics(new EntityReference(types[2].getReferencedEntityType(), 2), false, 9, new RequestImpact(2, 66, true)), + new FacetStatistics(new EntityReference(types[2].getReferencedEntityType(), 3), false, 7, new RequestImpact(3, 76, true)), + new FacetStatistics(new EntityReference(types[2].getReferencedEntityType(), 4), false, 5, new RequestImpact(4, 8, true)) ) ) )