From 8f3911b147c53cfe72a9b1af441d24262c9bc392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Novotn=C3=BD?= Date: Fri, 13 Sep 2024 10:33:09 +0200 Subject: [PATCH] fix(#668): Filter was not yet called on selling price bitmap filter, this is not expected! --- .../user/en/operate/reference/metrics.md | 4 +- .../FlattenedFormulaWithFilteredPrices.java | 19 +++- ...thFilteredPricesAndFilteredOutRecords.java | 19 +++- .../prefetch/EntityFilteringFormula.java | 10 +- .../algebra/prefetch/SelectionFormula.java | 18 ++-- .../price/FilteredPriceRecordAccessor.java | 5 +- .../FilteredPriceRecords.java | 20 ++-- .../priceIndex/PriceIdContainerFormula.java | 5 +- .../PriceIndexContainerFormula.java | 7 +- .../PriceListCombinationFormula.java | 2 +- .../FirstVariantPriceTerminationFormula.java | 23 +++-- ...riceTerminationFormulaWithPriceFilter.java | 23 +++-- .../SumPriceTerminationFormula.java | 15 +-- .../PriceIdToEntityIdTranslateFormula.java | 14 ++- .../AttributeHistogramTranslator.java | 1 - .../producer/AttributeHistogramProducer.java | 7 -- .../producer/PriceHistogramComputer.java | 8 +- .../producer/PriceHistogramProducer.java | 1 + .../alternative/AttributeBitmapFilter.java | 63 +++++++------ .../LocaleEntityToBitmapFilter.java | 30 ++++-- .../SellingPriceAvailableBitmapFilter.java | 94 ++++++++++--------- .../core/query/sort/OrderByVisitor.java | 1 + .../price/FilteredPriceRecordsCollector.java | 32 +++++-- .../sort/price/FilteredPricesSorter.java | 8 +- .../FilteredPriceRecordsCollectorTest.java | 9 +- .../evitadb/spike/FormulaCostMeasurement.java | 6 +- .../spike/mock/MockEntityIdsFormula.java | 7 +- .../spike/mock/MockInnerRecordIdsFormula.java | 5 +- ...PricesAndFilteredOutRecordsSerializer.java | 4 +- ...edFormulaWithFilteredPricesSerializer.java | 4 +- 30 files changed, 281 insertions(+), 183 deletions(-) diff --git a/documentation/user/en/operate/reference/metrics.md b/documentation/user/en/operate/reference/metrics.md index 68c22e6bf..06793c9e5 100644 --- a/documentation/user/en/operate/reference/metrics.md +++ b/documentation/user/en/operate/reference/metrics.md @@ -8,9 +8,9 @@
catalogName
Catalog: N/A
entityType
-
Entity type: N/A
-
entityType
Collection: N/A
+
entityType
+
Entity type: N/A
fileType
File type: N/A
httpMethod
diff --git a/evita_engine/src/main/java/io/evitadb/core/cache/payload/FlattenedFormulaWithFilteredPrices.java b/evita_engine/src/main/java/io/evitadb/core/cache/payload/FlattenedFormulaWithFilteredPrices.java index a176bca7b..491a3d871 100644 --- a/evita_engine/src/main/java/io/evitadb/core/cache/payload/FlattenedFormulaWithFilteredPrices.java +++ b/evita_engine/src/main/java/io/evitadb/core/cache/payload/FlattenedFormulaWithFilteredPrices.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. @@ -23,12 +23,14 @@ package io.evitadb.core.cache.payload; +import io.evitadb.core.query.QueryExecutionContext; import io.evitadb.core.query.algebra.Formula; import io.evitadb.core.query.algebra.price.FilteredPriceRecordAccessor; import io.evitadb.core.query.algebra.price.filteredPriceRecords.FilteredPriceRecords; import io.evitadb.core.query.algebra.price.termination.PriceEvaluationContext; import io.evitadb.core.query.algebra.price.termination.PriceWrappingFormula; import io.evitadb.index.bitmap.Bitmap; +import io.evitadb.utils.Assert; import io.evitadb.utils.MemoryMeasuringConstants; import lombok.Getter; @@ -47,9 +49,9 @@ public class FlattenedFormulaWithFilteredPrices extends FlattenedFormula impleme @Serial private static final long serialVersionUID = 29711505428272096L; /** * Contains information about price records leading to a computed result. - * Copies {@link FilteredPriceRecordAccessor#getFilteredPriceRecords()}. + * Copies {@link FilteredPriceRecordAccessor#getFilteredPriceRecords(QueryExecutionContext)} . */ - @Getter private final FilteredPriceRecords filteredPriceRecords; + private final FilteredPriceRecords filteredPriceRecords; /** * Price evaluation context. Copies {@link PriceWrappingFormula#getPriceEvaluationContext()}. */ @@ -73,4 +75,15 @@ public FlattenedFormulaWithFilteredPrices(long formulaHash, long transactionalId this.filteredPriceRecords.prepareForFlattening(); } + @Nonnull + @Override + public FilteredPriceRecords getFilteredPriceRecords(@Nonnull QueryExecutionContext context) { + return this.filteredPriceRecords; + } + + @Nonnull + public FilteredPriceRecords getFilteredPriceRecordsOrThrowException() { + Assert.isPremiseValid(this.filteredPriceRecords != null, "Filtered price records are not available."); + return this.filteredPriceRecords; + } } diff --git a/evita_engine/src/main/java/io/evitadb/core/cache/payload/FlattenedFormulaWithFilteredPricesAndFilteredOutRecords.java b/evita_engine/src/main/java/io/evitadb/core/cache/payload/FlattenedFormulaWithFilteredPricesAndFilteredOutRecords.java index d8256a31e..73c4951ed 100644 --- a/evita_engine/src/main/java/io/evitadb/core/cache/payload/FlattenedFormulaWithFilteredPricesAndFilteredOutRecords.java +++ b/evita_engine/src/main/java/io/evitadb/core/cache/payload/FlattenedFormulaWithFilteredPricesAndFilteredOutRecords.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. @@ -24,6 +24,7 @@ package io.evitadb.core.cache.payload; import io.evitadb.api.query.require.QueryPriceMode; +import io.evitadb.core.query.QueryExecutionContext; import io.evitadb.core.query.algebra.Formula; import io.evitadb.core.query.algebra.price.FilteredOutPriceRecordAccessor; import io.evitadb.core.query.algebra.price.FilteredPriceRecordAccessor; @@ -34,6 +35,7 @@ import io.evitadb.core.query.algebra.price.termination.PriceWrappingFormula; import io.evitadb.index.bitmap.Bitmap; import io.evitadb.index.bitmap.RoaringBitmapBackedBitmap; +import io.evitadb.utils.Assert; import io.evitadb.utils.MemoryMeasuringConstants; import io.evitadb.utils.NumberUtils; import lombok.Getter; @@ -55,9 +57,9 @@ public class FlattenedFormulaWithFilteredPricesAndFilteredOutRecords extends Fla @Serial private static final long serialVersionUID = -6052882250380556441L; /** * Contains information about price records leading to a computed result. - * Copies {@link FilteredPriceRecordAccessor#getFilteredPriceRecords()}. + * Copies {@link FilteredPriceRecordAccessor#getFilteredPriceRecords(QueryExecutionContext)}. */ - @Getter @Nonnull private final FilteredPriceRecords filteredPriceRecords; + @Nonnull private final FilteredPriceRecords filteredPriceRecords; /** * Records that has been filtered out by the original formula. * Copies {@link FilteredOutPriceRecordAccessor#getCloneWithPricePredicateFilteredOutResults()}. @@ -167,4 +169,15 @@ public Formula getCloneWithPricePredicateFilteredOutResults() { return this.memoizedClone; } + @Nonnull + @Override + public FilteredPriceRecords getFilteredPriceRecords(@Nonnull QueryExecutionContext context) { + return this.filteredPriceRecords; + } + + @Nonnull + public FilteredPriceRecords getFilteredPriceRecordsOrThrowException() { + Assert.isPremiseValid(this.filteredPriceRecords != null, "Filtered price records must not be null."); + return this.filteredPriceRecords; + } } diff --git a/evita_engine/src/main/java/io/evitadb/core/query/algebra/prefetch/EntityFilteringFormula.java b/evita_engine/src/main/java/io/evitadb/core/query/algebra/prefetch/EntityFilteringFormula.java index 35c1872ff..fc71deed5 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/algebra/prefetch/EntityFilteringFormula.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/algebra/prefetch/EntityFilteringFormula.java @@ -27,6 +27,7 @@ import io.evitadb.api.query.require.EntityRequire; import io.evitadb.api.requestResponse.EvitaRequest; import io.evitadb.api.requestResponse.schema.dto.GlobalAttributeSchema; +import io.evitadb.core.query.QueryExecutionContext; import io.evitadb.core.query.algebra.AbstractFormula; import io.evitadb.core.query.algebra.Formula; import io.evitadb.core.query.algebra.price.FilteredPriceRecordAccessor; @@ -90,11 +91,10 @@ protected Bitmap computeInternal() { @Nonnull @Override - public FilteredPriceRecords getFilteredPriceRecords() { - Assert.isPremiseValid(this.executionContext != null, "The formula hasn't been initialized!"); - Assert.isTrue(this.executionContext.getPrefetchedEntities() != null, () -> new EntityCollectionRequiredException("matching entities")); - return alternative instanceof FilteredPriceRecordAccessor ? - ((FilteredPriceRecordAccessor) alternative).getFilteredPriceRecords() : + public FilteredPriceRecords getFilteredPriceRecords(@Nonnull QueryExecutionContext context) { + Assert.isTrue(context.getPrefetchedEntities() != null, () -> new EntityCollectionRequiredException("matching entities")); + return this.alternative instanceof FilteredPriceRecordAccessor fpra ? + fpra.getFilteredPriceRecords(context) : new ResolvedFilteredPriceRecords(); } diff --git a/evita_engine/src/main/java/io/evitadb/core/query/algebra/prefetch/SelectionFormula.java b/evita_engine/src/main/java/io/evitadb/core/query/algebra/prefetch/SelectionFormula.java index 165cef90f..1f3eca339 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/algebra/prefetch/SelectionFormula.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/algebra/prefetch/SelectionFormula.java @@ -219,18 +219,20 @@ public Formula getCloneWithPricePredicateFilteredOutResults() { @Nonnull @Override - public FilteredPriceRecords getFilteredPriceRecords() { - Assert.isPremiseValid(this.executionContext != null, "The formula hasn't been initialized!"); + public FilteredPriceRecords getFilteredPriceRecords(@Nonnull QueryExecutionContext context) { // if the entities were prefetched we passed the "is it worthwhile" check - return Optional.ofNullable(executionContext.getPrefetchedEntities()) + return Optional.ofNullable(this.executionContext.getPrefetchedEntities()) // ask the alternative solution for filtered price records - .map(it -> - alternative instanceof FilteredPriceRecordAccessor ? - ((FilteredPriceRecordAccessor) alternative).getFilteredPriceRecords() : - new ResolvedFilteredPriceRecords() + .map(it -> { + if (this.alternative instanceof FilteredPriceRecordAccessor fpra) { + return fpra.getFilteredPriceRecords(context); + } else { + return new ResolvedFilteredPriceRecords(); + } + } ) // otherwise collect the filtered records from the delegate - .orElseGet(() -> FilteredPriceRecords.createFromFormulas(this, this.compute())); + .orElseGet(() -> FilteredPriceRecords.createFromFormulas(this, this.compute(), this.executionContext)); } @Override diff --git a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/FilteredPriceRecordAccessor.java b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/FilteredPriceRecordAccessor.java index 356d702af..332ea81fe 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/FilteredPriceRecordAccessor.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/FilteredPriceRecordAccessor.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. @@ -23,6 +23,7 @@ package io.evitadb.core.query.algebra.price; +import io.evitadb.core.query.QueryExecutionContext; import io.evitadb.core.query.algebra.Formula; import io.evitadb.core.query.algebra.price.filteredPriceRecords.FilteredPriceRecords; import io.evitadb.index.price.PriceListAndCurrencyPriceIndex; @@ -46,6 +47,6 @@ public interface FilteredPriceRecordAccessor { * additional logic that needs to work with the prices (mainly sorting) could perform quickly. */ @Nonnull - FilteredPriceRecords getFilteredPriceRecords(); + FilteredPriceRecords getFilteredPriceRecords(@Nonnull QueryExecutionContext context); } diff --git a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/filteredPriceRecords/FilteredPriceRecords.java b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/filteredPriceRecords/FilteredPriceRecords.java index 4fa1e9be8..65fd257a1 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/filteredPriceRecords/FilteredPriceRecords.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/filteredPriceRecords/FilteredPriceRecords.java @@ -23,6 +23,7 @@ package io.evitadb.core.query.algebra.price.filteredPriceRecords; +import io.evitadb.core.query.QueryExecutionContext; import io.evitadb.core.query.SharedBufferPool; import io.evitadb.core.query.algebra.Formula; import io.evitadb.core.query.algebra.price.FilteredPriceRecordAccessor; @@ -83,7 +84,8 @@ public interface FilteredPriceRecords extends Serializable { @Nonnull static FilteredPriceRecords createFromFormulas( @Nonnull Formula parentFormula, - @Nullable Bitmap narrowToEntityIds + @Nullable Bitmap narrowToEntityIds, + @Nonnull QueryExecutionContext context ) { // collect all FilteredPriceRecordAccessor that were involved in computing delegate result final Collection filteredPriceRecordAccessors = FormulaFinder.findAmongChildren( @@ -92,7 +94,7 @@ static FilteredPriceRecords createFromFormulas( final List filteredPriceRecords = filteredPriceRecordAccessors .stream() - .map(FilteredPriceRecordAccessor::getFilteredPriceRecords) + .map(it -> it.getFilteredPriceRecords(context)) .map(it -> it instanceof NonResolvedFilteredPriceRecords ? ((NonResolvedFilteredPriceRecords) it).toResolvedFilteredPriceRecords() : it) .toList(); @@ -104,7 +106,7 @@ static FilteredPriceRecords createFromFormulas( return filteredPriceRecords.get(0); // all price records are resolved } else { - final Optional lazyEvaluatedEntityPriceRecords = getLazyEvaluatedEntityPriceRecords(filteredPriceRecordAccessors); + final Optional lazyEvaluatedEntityPriceRecords = getLazyEvaluatedEntityPriceRecords(filteredPriceRecordAccessors, context); final Optional resolvedFilteredPriceRecords; if (narrowToEntityIds == null) { // and no filtering is known (all contents combined should be returned) @@ -133,10 +135,11 @@ static FilteredPriceRecords createFromFormulas( @Nonnull private static Optional getLazyEvaluatedEntityPriceRecords( - @Nonnull Collection filteredPriceRecordAccessors + @Nonnull Collection filteredPriceRecordAccessors, + @Nonnull QueryExecutionContext context ) { - final PriceListAndCurrencyPriceIndex[] priceIndexes = filteredPriceRecordAccessors.stream() - .map(FilteredPriceRecordAccessor::getFilteredPriceRecords) + final PriceListAndCurrencyPriceIndex[] priceIndexes = filteredPriceRecordAccessors.stream() + .map(it -> it.getFilteredPriceRecords(context)) .filter(LazyEvaluatedEntityPriceRecords.class::isInstance) .map(LazyEvaluatedEntityPriceRecords.class::cast) .flatMap(it -> Arrays.stream(it.getPriceIndexes())) @@ -234,12 +237,13 @@ private static Optional getResolvedFilteredPriceRe @Nonnull static FilteredPriceRecordsLookupResult collectFilteredPriceRecordsFromPriceRecordAccessors( @Nonnull Collection filteredPriceRecordAccessors, - @Nonnull RoaringBitmap filterTo + @Nonnull RoaringBitmap filterTo, + @Nonnull QueryExecutionContext context ) { final CompositeObjectArray collectedPriceRecords = new CompositeObjectArray<>(PriceRecordContract.class, false); final List priceRecordIterators = filteredPriceRecordAccessors .stream() - .map(it -> it.getFilteredPriceRecords().getPriceRecordsLookup()) + .map(it -> it.getFilteredPriceRecords(context).getPriceRecordsLookup()) .toList(); final int[] buffer = SharedBufferPool.INSTANCE.obtain(); diff --git a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/priceIndex/PriceIdContainerFormula.java b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/priceIndex/PriceIdContainerFormula.java index 18f8ddc3e..439cc991a 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/priceIndex/PriceIdContainerFormula.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/priceIndex/PriceIdContainerFormula.java @@ -23,6 +23,7 @@ package io.evitadb.core.query.algebra.price.priceIndex; +import io.evitadb.core.query.QueryExecutionContext; import io.evitadb.core.query.algebra.AbstractFormula; import io.evitadb.core.query.algebra.Formula; import io.evitadb.core.query.algebra.price.filteredPriceRecords.FilteredPriceRecords; @@ -69,9 +70,9 @@ public Formula getDelegate() { @Nonnull @Override - public FilteredPriceRecords getFilteredPriceRecords() { + public FilteredPriceRecords getFilteredPriceRecords(@Nonnull QueryExecutionContext context) { return new ResolvedFilteredPriceRecords( - priceIndex.getPriceRecords(compute()), + this.priceIndex.getPriceRecords(compute()), SortingForm.NOT_SORTED ); } diff --git a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/priceIndex/PriceIndexContainerFormula.java b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/priceIndex/PriceIndexContainerFormula.java index b37c88cb1..5e4132ea3 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/priceIndex/PriceIndexContainerFormula.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/priceIndex/PriceIndexContainerFormula.java @@ -23,6 +23,7 @@ package io.evitadb.core.query.algebra.price.priceIndex; +import io.evitadb.core.query.QueryExecutionContext; import io.evitadb.core.query.algebra.AbstractCacheableFormula; import io.evitadb.core.query.algebra.CacheableFormula; import io.evitadb.core.query.algebra.Formula; @@ -99,13 +100,13 @@ public Formula getDelegate() { @Nonnull @Override - public FilteredPriceRecords getFilteredPriceRecords() { - return new LazyEvaluatedEntityPriceRecords(priceIndex); + public FilteredPriceRecords getFilteredPriceRecords(@Nonnull QueryExecutionContext context) { + return new LazyEvaluatedEntityPriceRecords(this.priceIndex); } @Override public String toString() { - return "DO WITH PRICE INDEX: " + priceIndex.getPriceIndexKey(); + return "DO WITH PRICE INDEX: " + this.priceIndex.getPriceIndexKey(); } @Nonnull diff --git a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/priceIndex/PriceListCombinationFormula.java b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/priceIndex/PriceListCombinationFormula.java index 9c81d6a48..0201ad780 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/priceIndex/PriceListCombinationFormula.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/priceIndex/PriceListCombinationFormula.java @@ -103,7 +103,7 @@ public FlattenedFormula toSerializableFormula(long formulaHash, @Nonnull LongHas .sorted() .toArray(), computationalResult, - FilteredPriceRecords.createFromFormulas(this, computationalResult), + FilteredPriceRecords.createFromFormulas(this, computationalResult, this.executionContext), priceEvaluationContext ); } diff --git a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/termination/FirstVariantPriceTerminationFormula.java b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/termination/FirstVariantPriceTerminationFormula.java index c0f52cd52..d30ecfced 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/termination/FirstVariantPriceTerminationFormula.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/termination/FirstVariantPriceTerminationFormula.java @@ -74,7 +74,7 @@ * It may also filter out entity ids which don't pass {@link #pricePredicate} predicate test. * * This formula consumes and produces {@link Formula} of {@link PriceRecord#entityPrimaryKey() entity ids}. It uses - * information from underlying formulas that implement {@link FilteredPriceRecordAccessor#getFilteredPriceRecords()} + * information from underlying formulas that implement {@link FilteredPriceRecordAccessor#getFilteredPriceRecords(QueryExecutionContext)} * to access the lowest price of each entity/inner record id combination for filtering purposes. * * @author Jan Novotný (novotny@fg.cz), FG Forrest a.s. (c) 2021 @@ -222,14 +222,17 @@ public CacheableFormula getCloneWithComputationCallback(@Nonnull Consumer it.getFilteredPriceRecords(this.executionContext)) .map(FilteredPriceRecords::getPriceRecordsLookup) .toArray(PriceRecordLookup[]::new); // create array for the lowest prices by entity diff --git a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/termination/PlainPriceTerminationFormulaWithPriceFilter.java b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/termination/PlainPriceTerminationFormulaWithPriceFilter.java index af64ed6d3..ebb085a9f 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/termination/PlainPriceTerminationFormulaWithPriceFilter.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/termination/PlainPriceTerminationFormulaWithPriceFilter.java @@ -70,7 +70,7 @@ * * This formula consumes and produces {@link Formula} of reduced {@link PriceRecord#entityPrimaryKey() entity ids} * which price passes the {@link #pricePredicate} predicate. It uses information from underlying formulas that implement - * {@link FilteredPriceRecordAccessor#getFilteredPriceRecords()} to access the appropriate price for filtering purposes. + * {@link FilteredPriceRecordAccessor#getFilteredPriceRecords(QueryExecutionContext)} to access the appropriate price for filtering purposes. * * @author Jan Novotný (novotny@fg.cz), FG Forrest a.s. (c) 2021 */ @@ -195,9 +195,12 @@ public CacheableFormula getCloneWithComputationCallback(@Nonnull Consumer it.getFilteredPriceRecords(this.executionContext)) .map(FilteredPriceRecords::getPriceRecordsLookup) .toArray(PriceRecordLookup[]::new); diff --git a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/termination/SumPriceTerminationFormula.java b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/termination/SumPriceTerminationFormula.java index d0d114e4c..2a5667d47 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/termination/SumPriceTerminationFormula.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/termination/SumPriceTerminationFormula.java @@ -76,7 +76,7 @@ * out entity ids which don't pass {@link #pricePredicate} predicate test. * * This formula consumes and produces {@link Formula} of {@link PriceRecord#entityPrimaryKey() entity ids}. It uses - * information from underlying formulas that implement {@link FilteredPriceRecordAccessor#getFilteredPriceRecords()} + * information from underlying formulas that implement {@link FilteredPriceRecordAccessor#getFilteredPriceRecords(QueryExecutionContext)} * to compute virtual (sum of) prices of entity ids across all of their inner records. * * @author Jan Novotný (novotny@fg.cz), FG Forrest a.s. (c) 2021 @@ -231,9 +231,12 @@ public CacheableFormula getCloneWithComputationCallback(@Nonnull Consumer it.getFilteredPriceRecords(this.executionContext)) .map(FilteredPriceRecords::getPriceRecordsLookup) .toArray(PriceRecordLookup[]::new); // create helper associative index for looking up index of the appropriate price by entity id in the priceRecordsFunnel diff --git a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/translate/PriceIdToEntityIdTranslateFormula.java b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/translate/PriceIdToEntityIdTranslateFormula.java index 7fd2a4661..fe5247ae7 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/translate/PriceIdToEntityIdTranslateFormula.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/algebra/price/translate/PriceIdToEntityIdTranslateFormula.java @@ -25,6 +25,7 @@ import io.evitadb.core.cache.payload.FlattenedFormula; import io.evitadb.core.cache.payload.FlattenedFormulaWithFilteredPrices; +import io.evitadb.core.query.QueryExecutionContext; import io.evitadb.core.query.algebra.AbstractCacheableFormula; import io.evitadb.core.query.algebra.CacheableFormula; import io.evitadb.core.query.algebra.Formula; @@ -128,7 +129,7 @@ public FlattenedFormula toSerializableFormula(long formulaHash, @Nonnull LongHas .sorted() .toArray(), compute(), - getFilteredPriceRecords(), + getFilteredPriceRecords(this.executionContext), getPriceEvaluationContext() ); } @@ -166,9 +167,12 @@ public CacheableFormula getCloneWithComputationCallback(@Nonnull Consumer formula.getEstimatedCardinality()).sum(); + return Arrays.stream(this.innerFormulas).mapToInt(Formula::getEstimatedCardinality).sum(); } @Override diff --git a/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/histogram/AttributeHistogramTranslator.java b/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/histogram/AttributeHistogramTranslator.java index 680d9eda5..dfa335f6f 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/histogram/AttributeHistogramTranslator.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/histogram/AttributeHistogramTranslator.java @@ -85,7 +85,6 @@ public ExtraResultProducer apply(AttributeHistogram attributeHistogram, ExtraRes // if there was no producer ready, create new one if (attributeHistogramProducer == null) { attributeHistogramProducer = new AttributeHistogramProducer( - schema.getName(), bucketCount, behavior, extraResultPlanner.getFilteringFormula() diff --git a/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/histogram/producer/AttributeHistogramProducer.java b/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/histogram/producer/AttributeHistogramProducer.java index 4127e884f..4300cb546 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/histogram/producer/AttributeHistogramProducer.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/histogram/producer/AttributeHistogramProducer.java @@ -29,7 +29,6 @@ import io.evitadb.api.requestResponse.extraResult.Histogram; import io.evitadb.api.requestResponse.extraResult.HistogramContract; import io.evitadb.api.requestResponse.schema.AttributeSchemaContract; -import io.evitadb.api.requestResponse.schema.dto.EntitySchema; import io.evitadb.core.query.QueryExecutionContext; import io.evitadb.core.query.algebra.Formula; import io.evitadb.core.query.algebra.attribute.AttributeFormula; @@ -76,10 +75,6 @@ * @author Jan Novotný (novotny@fg.cz), FG Forrest a.s. (c) 2022 */ public class AttributeHistogramProducer implements ExtraResultProducer { - /** - * Type of the queried entity - {@link EntitySchema#getName()}. - */ - private final String entityType; /** * Bucket count contains desired count of histogram columns=buckets. Output histogram bucket count must never exceed * this value, but might be optimized to lower count when there are big gaps between columns. @@ -101,12 +96,10 @@ public class AttributeHistogramProducer implements ExtraResultProducer { private final Map histogramRequests; public AttributeHistogramProducer( - @Nonnull String entityType, int bucketCount, @Nonnull HistogramBehavior behavior, @Nonnull Formula filterFormula ) { - this.entityType = entityType; this.bucketCount = bucketCount; this.behavior = behavior; this.filterFormula = filterFormula; diff --git a/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/histogram/producer/PriceHistogramComputer.java b/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/histogram/producer/PriceHistogramComputer.java index 0c5bc01c4..ef8938589 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/histogram/producer/PriceHistogramComputer.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/histogram/producer/PriceHistogramComputer.java @@ -361,12 +361,14 @@ private PriceRecordContract[] getPriceRecords() { // create price records collector reusing existing data or computing them from scratch final FilteredPriceRecordsCollector priceRecordsCollector = this.priceRecordsLookupResult == null ? new FilteredPriceRecordsCollector( - RoaringBitmapBackedBitmap.getRoaringBitmap(filteringFormula.compute()), - filteredPriceRecordAccessors + RoaringBitmapBackedBitmap.getRoaringBitmap(this.filteringFormula.compute()), + this.filteredPriceRecordAccessors, + this.context ) : new FilteredPriceRecordsCollector( this.priceRecordsLookupResult, - filteredPriceRecordAccessors + this.filteredPriceRecordAccessors, + this.context ); // collect all price records that match filtering formula computation (ignoring price between query) diff --git a/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/histogram/producer/PriceHistogramProducer.java b/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/histogram/producer/PriceHistogramProducer.java index b8b9a343b..b8bfb4978 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/histogram/producer/PriceHistogramProducer.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/extraResult/translator/histogram/producer/PriceHistogramProducer.java @@ -107,6 +107,7 @@ public EvitaResponseExtraResult fabricate(@Nonnull Quer filteredRecordsFound.get() ? formulaWithFilteredOutResults : null, filteredPriceRecordAccessors, priceRecordsLookupResult ); + computer.initialize(context); final CacheableHistogramContract optimalHistogram = context.analyse(computer).compute(); if (optimalHistogram == CacheableHistogramContract.EMPTY) { return null; diff --git a/evita_engine/src/main/java/io/evitadb/core/query/filter/translator/attribute/alternative/AttributeBitmapFilter.java b/evita_engine/src/main/java/io/evitadb/core/query/filter/translator/attribute/alternative/AttributeBitmapFilter.java index e851748aa..48a8a3052 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/filter/translator/attribute/alternative/AttributeBitmapFilter.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/filter/translator/attribute/alternative/AttributeBitmapFilter.java @@ -82,6 +82,10 @@ public class AttributeBitmapFilter implements EntityToBitmapFilter { * Contains array of all attribute required traits. */ private final AttributeTrait[] requiredAttributeTraits; + /** + * Contains the Bitmap result that has been memoized for efficiency. + */ + private Bitmap memoizedResult; public AttributeBitmapFilter( @Nonnull String attributeName, @@ -108,38 +112,41 @@ public EntityFetch getEntityRequire() { @Nonnull @Override public Bitmap filter(@Nonnull QueryExecutionContext context) { - final List prefetchedEntities = context.getPrefetchedEntities(); - if (prefetchedEntities == null) { - return EmptyBitmap.INSTANCE; - } else { - String entityType = null; - Predicate>> filter = null; - final BaseBitmap result = new BaseBitmap(); - // iterate over all entities - for (SealedEntity entity : prefetchedEntities) { - /* we can be sure entities are sorted by type because: - 1. all entities share the same type - 2. or entities are fetched via {@link QueryPlanningContext#prefetchEntities(EntityReference[], EntityContentRequire[])} - that fetches them by entity type in bulk - */ - final EntitySchemaContract entitySchema = entity.getSchema(); - if (!Objects.equals(entityType, entitySchema.getName())) { - entityType = entitySchema.getName(); - final AttributeSchemaContract attributeSchema = attributeSchemaAccessor.apply( - entitySchema, attributeName, requiredAttributeTraits - ); - filter = filterFactory.apply(attributeSchema); - } - // and filter by predicate - if (filter != null) { - final Stream> valueStream = attributeValueAccessor.apply(entity, attributeName); - if (valueStream != null && filter.test(valueStream)) { - result.add(context.translateEntity(entity)); + if (this.memoizedResult == null) { + final List prefetchedEntities = context.getPrefetchedEntities(); + if (prefetchedEntities == null) { + this.memoizedResult = EmptyBitmap.INSTANCE; + } else { + String entityType = null; + Predicate>> filter = null; + final BaseBitmap result = new BaseBitmap(); + // iterate over all entities + for (SealedEntity entity : prefetchedEntities) { + /* we can be sure entities are sorted by type because: + 1. all entities share the same type + 2. or entities are fetched via {@link QueryPlanningContext#prefetchEntities(EntityReference[], EntityContentRequire[])} + that fetches them by entity type in bulk + */ + final EntitySchemaContract entitySchema = entity.getSchema(); + if (!Objects.equals(entityType, entitySchema.getName())) { + entityType = entitySchema.getName(); + final AttributeSchemaContract attributeSchema = attributeSchemaAccessor.apply( + entitySchema, attributeName, requiredAttributeTraits + ); + filter = filterFactory.apply(attributeSchema); + } + // and filter by predicate + if (filter != null) { + final Stream> valueStream = attributeValueAccessor.apply(entity, attributeName); + if (valueStream != null && filter.test(valueStream)) { + result.add(context.translateEntity(entity)); + } } } + this.memoizedResult = result; } - return result; } + return this.memoizedResult; } } diff --git a/evita_engine/src/main/java/io/evitadb/core/query/filter/translator/entity/alternative/LocaleEntityToBitmapFilter.java b/evita_engine/src/main/java/io/evitadb/core/query/filter/translator/entity/alternative/LocaleEntityToBitmapFilter.java index bdc4ef8e5..913b92558 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/filter/translator/entity/alternative/LocaleEntityToBitmapFilter.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/filter/translator/entity/alternative/LocaleEntityToBitmapFilter.java @@ -45,22 +45,32 @@ */ @RequiredArgsConstructor public class LocaleEntityToBitmapFilter implements EntityToBitmapFilter { + /** + * The locale to be used for filtering entities. + */ private final Locale locale; + /** + * The memoized result of the filter. + */ + private Bitmap memoizedResult; @Nonnull @Override public Bitmap filter(@Nonnull QueryExecutionContext context) { - final List entities = context.getPrefetchedEntities(); - if (entities == null) { - return EmptyBitmap.INSTANCE; - } else { - return new BaseBitmap( - entities.stream() - .filter(it -> it.getLocales().contains(locale)) - .mapToInt(context::translateEntity) - .toArray() - ); + if (this.memoizedResult == null) { + final List entities = context.getPrefetchedEntities(); + if (entities == null) { + this.memoizedResult = EmptyBitmap.INSTANCE; + } else { + this.memoizedResult = new BaseBitmap( + entities.stream() + .filter(it -> it.getLocales().contains(locale)) + .mapToInt(context::translateEntity) + .toArray() + ); + } } + return this.memoizedResult; } @Nonnull diff --git a/evita_engine/src/main/java/io/evitadb/core/query/filter/translator/price/alternative/SellingPriceAvailableBitmapFilter.java b/evita_engine/src/main/java/io/evitadb/core/query/filter/translator/price/alternative/SellingPriceAvailableBitmapFilter.java index 3404dabee..175b587e7 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/filter/translator/price/alternative/SellingPriceAvailableBitmapFilter.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/filter/translator/price/alternative/SellingPriceAvailableBitmapFilter.java @@ -95,6 +95,10 @@ public class SellingPriceAvailableBitmapFilter implements EntityToBitmapFilter, * Contains result containing all entities that were filtered out by {@link #filter} predicate. */ private Formula filteredOutRecords; + /** + * Memoized result of the filter. + */ + private Bitmap memoizedResult; public SellingPriceAvailableBitmapFilter( @Nullable String[] additionalPriceLists, @@ -136,63 +140,69 @@ public Formula getCloneWithPricePredicateFilteredOutResults() { @Nonnull @Override - public FilteredPriceRecords getFilteredPriceRecords() { - Assert.isPremiseValid(filteredOutRecords != null, "Filter was not yet called on selling price bitmap filter, this is not expected!"); - return filteredPriceRecords; + public FilteredPriceRecords getFilteredPriceRecords(@Nonnull QueryExecutionContext context) { + if (this.filteredPriceRecords == null) { + // init the records first + filter(context); + } + return this.filteredPriceRecords; } @Nonnull @Override public Bitmap filter(@Nonnull QueryExecutionContext context) { - final CompositeObjectArray theFilteredPriceRecords = new CompositeObjectArray<>(PriceRecordContract.class); - final QueryPriceMode queryPriceMode = context.getQueryPriceMode(); - final BaseBitmap result = new BaseBitmap(); - final BaseBitmap filterOutResult = new BaseBitmap(); - final AtomicInteger indexedPricePlaces = new AtomicInteger(); - String entityType = null; - final List entities = context.getPrefetchedEntities(); - if (entities == null) { - return EmptyBitmap.INSTANCE; - } else { - // iterate over all entities - for (EntityDecorator entity : entities) { + if (this.memoizedResult == null) { + final CompositeObjectArray theFilteredPriceRecords = new CompositeObjectArray<>(PriceRecordContract.class); + final QueryPriceMode queryPriceMode = context.getQueryPriceMode(); + final BaseBitmap result = new BaseBitmap(); + final BaseBitmap filterOutResult = new BaseBitmap(); + final AtomicInteger indexedPricePlaces = new AtomicInteger(); + String entityType = null; + final List entities = context.getPrefetchedEntities(); + if (entities == null) { + this.memoizedResult = EmptyBitmap.INSTANCE; + } else { + // iterate over all entities + for (EntityDecorator entity : entities) { /* we can be sure entities are sorted by type because: 1. all entities share the same type 2. or entities are fetched via {@link QueryPlanningContext#prefetchEntities(EntityReference[], EntityContentRequire[])} that fetches them by entity type in bulk */ - final EntitySchemaContract entitySchema = entity.getSchema(); - if (!Objects.equals(entityType, entitySchema.getName())) { - entityType = entitySchema.getName(); - indexedPricePlaces.set(entitySchema.getIndexedPricePlaces()); - } - final int primaryKey = context.translateEntity(entity); - if (entity.isPriceForSaleContextAvailable()) { - // check whether they have valid selling price (applying filter on price lists and currency) - entity.getPriceForSale(filter) - // and if there is still selling price add it to the output result - .ifPresentOrElse( - it -> { - theFilteredPriceRecords.add(converter.apply(primaryKey, indexedPricePlaces.get(), queryPriceMode, it)); - result.add(primaryKey); - }, - () -> filterOutResult.add(primaryKey) - ); - } else { - if (entity.getPrices().stream().filter(PriceContract::sellable).anyMatch(filter)) { - result.add(primaryKey); + final EntitySchemaContract entitySchema = entity.getSchema(); + if (!Objects.equals(entityType, entitySchema.getName())) { + entityType = entitySchema.getName(); + indexedPricePlaces.set(entitySchema.getIndexedPricePlaces()); + } + final int primaryKey = context.translateEntity(entity); + if (entity.isPriceForSaleContextAvailable()) { + // check whether they have valid selling price (applying filter on price lists and currency) + entity.getPriceForSale(filter) + // and if there is still selling price add it to the output result + .ifPresentOrElse( + it -> { + theFilteredPriceRecords.add(converter.apply(primaryKey, indexedPricePlaces.get(), queryPriceMode, it)); + result.add(primaryKey); + }, + () -> filterOutResult.add(primaryKey) + ); } else { - filterOutResult.add(primaryKey); + if (entity.getPrices().stream().filter(PriceContract::sellable).anyMatch(filter)) { + result.add(primaryKey); + } else { + filterOutResult.add(primaryKey); + } } - } + } + // memoize valid selling prices for sorting purposes + this.filteredPriceRecords = new ResolvedFilteredPriceRecords(theFilteredPriceRecords.toArray(), SortingForm.NOT_SORTED); + this.filteredOutRecords = filterOutResult.isEmpty() ? EmptyFormula.INSTANCE : new ConstantFormula(filterOutResult); + // return entity ids having selling prices + this.memoizedResult = result; } - // memoize valid selling prices for sorting purposes - this.filteredPriceRecords = new ResolvedFilteredPriceRecords(theFilteredPriceRecords.toArray(), SortingForm.NOT_SORTED); - this.filteredOutRecords = filterOutResult.isEmpty() ? EmptyFormula.INSTANCE : new ConstantFormula(filterOutResult); - // return entity ids having selling prices - return result; } + return this.memoizedResult; } } diff --git a/evita_engine/src/main/java/io/evitadb/core/query/sort/OrderByVisitor.java b/evita_engine/src/main/java/io/evitadb/core/query/sort/OrderByVisitor.java index 9b6b55f79..f4f71c24d 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/sort/OrderByVisitor.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/sort/OrderByVisitor.java @@ -271,6 +271,7 @@ public ProcessingScope getProcessingScope() { /** * Returns index which is best suited for supplying {@link SortIndex}. */ + @Nonnull public EntityIndex[] getIndexesForSort() { final ProcessingScope theScope = this.scope.peek(); isPremiseValid(theScope != null, "Scope is unexpectedly empty!"); diff --git a/evita_engine/src/main/java/io/evitadb/core/query/sort/price/FilteredPriceRecordsCollector.java b/evita_engine/src/main/java/io/evitadb/core/query/sort/price/FilteredPriceRecordsCollector.java index ebcba6df8..a4468733a 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/sort/price/FilteredPriceRecordsCollector.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/sort/price/FilteredPriceRecordsCollector.java @@ -23,6 +23,7 @@ package io.evitadb.core.query.sort.price; +import io.evitadb.core.query.QueryExecutionContext; import io.evitadb.core.query.algebra.Formula; import io.evitadb.core.query.algebra.price.FilteredPriceRecordAccessor; import io.evitadb.core.query.algebra.price.FilteredPriceRecordsLookupResult; @@ -57,13 +58,27 @@ public class FilteredPriceRecordsCollector { * formula result. */ @Nonnull @Getter private final FilteredPriceRecordsLookupResult result; + /** + * The execution context for running query operations in the {@link FilteredPriceRecordsCollector} class. + */ + @Nonnull private final QueryExecutionContext context; - public FilteredPriceRecordsCollector(@Nonnull RoaringBitmap filteredResults, @Nonnull Collection filteredPriceRecordAccessors) { + public FilteredPriceRecordsCollector( + @Nonnull RoaringBitmap filteredResults, + @Nonnull Collection filteredPriceRecordAccessors, + @Nonnull QueryExecutionContext context + ) { + this.context = context; this.filteredPriceRecordAccessors = filteredPriceRecordAccessors; - this.result = computeResult(filteredResults, filteredPriceRecordAccessors); + this.result = computeResult(filteredResults, filteredPriceRecordAccessors, context); } - public FilteredPriceRecordsCollector(@Nonnull FilteredPriceRecordsLookupResult result, @Nonnull Collection filteredPriceRecordAccessors) { + public FilteredPriceRecordsCollector( + @Nonnull FilteredPriceRecordsLookupResult result, + @Nonnull Collection filteredPriceRecordAccessors, + @Nonnull QueryExecutionContext context + ) { + this.context = context; this.filteredPriceRecordAccessors = filteredPriceRecordAccessors; this.result = result; } @@ -76,7 +91,7 @@ public FilteredPriceRecordsCollector(@Nonnull FilteredPriceRecordsLookupResult r */ public PriceRecordContract[] combineResultWithAndReturnPriceRecords(@Nonnull RoaringBitmap filteredResults) { // compute new lookup result for passed entity primary keys - final FilteredPriceRecordsLookupResult subResult = computeResult(filteredResults, filteredPriceRecordAccessors); + final FilteredPriceRecordsLookupResult subResult = computeResult(filteredResults, this.filteredPriceRecordAccessors, this.context); // these two arrays will be merged together final PriceRecordContract[] originalRecords = this.result.getPriceRecords(); final PriceRecordContract[] addedRecords = subResult.getPriceRecords(); @@ -115,10 +130,15 @@ public PriceRecordContract[] combineResultWithAndReturnPriceRecords(@Nonnull Roa * array of entity ids for which the price records were not found. */ @Nonnull - protected FilteredPriceRecordsLookupResult computeResult(@Nonnull RoaringBitmap filteredResults, @Nonnull Collection filteredPriceRecordAccessors) { + protected FilteredPriceRecordsLookupResult computeResult( + @Nonnull RoaringBitmap filteredResults, + @Nonnull Collection filteredPriceRecordAccessors, + @Nonnull QueryExecutionContext context + ) { return FilteredPriceRecords.collectFilteredPriceRecordsFromPriceRecordAccessors( filteredPriceRecordAccessors, - filteredResults + filteredResults, + context ); } diff --git a/evita_engine/src/main/java/io/evitadb/core/query/sort/price/FilteredPricesSorter.java b/evita_engine/src/main/java/io/evitadb/core/query/sort/price/FilteredPricesSorter.java index c0a2b3b53..a5e7af069 100644 --- a/evita_engine/src/main/java/io/evitadb/core/query/sort/price/FilteredPricesSorter.java +++ b/evita_engine/src/main/java/io/evitadb/core/query/sort/price/FilteredPricesSorter.java @@ -143,12 +143,12 @@ public int sortAndSlice(@Nonnull QueryExecutionContext queryContext, @Nonnull Fo final Bitmap computeResult = input.compute(); final RoaringBitmap computeResultBitmap = RoaringBitmapBackedBitmap.getRoaringBitmap(computeResult); // collect price records from the filtering formulas - priceRecordsLookupResult = new FilteredPriceRecordsCollector( - computeResultBitmap, filteredPriceRecordAccessors + this.priceRecordsLookupResult = new FilteredPriceRecordsCollector( + computeResultBitmap, this.filteredPriceRecordAccessors, queryContext ).getResult(); // now sort filtered prices by passed comparator - final PriceRecordContract[] translatedResult = priceRecordsLookupResult.getPriceRecords(); + final PriceRecordContract[] translatedResult = this.priceRecordsLookupResult.getPriceRecords(); Arrays.sort(translatedResult, getPriceRecordComparator()); // slice the output and cut appropriate page from it @@ -159,7 +159,7 @@ public int sortAndSlice(@Nonnull QueryExecutionContext queryContext, @Nonnull Fo } // if the output is not complete, and we have not found entity PKs - final int[] notFoundEntities = priceRecordsLookupResult.getNotFoundEntities(); + final int[] notFoundEntities = this.priceRecordsLookupResult.getNotFoundEntities(); if (translatedResult.length < endIndex && (notFoundEntities != null && notFoundEntities.length > 0)) { // pass them to another sorter final int recomputedStartIndex = Math.max(0, startIndex - written); diff --git a/evita_functional_tests/src/test/java/io/evitadb/core/query/sort/price/FilteredPriceRecordsCollectorTest.java b/evita_functional_tests/src/test/java/io/evitadb/core/query/sort/price/FilteredPriceRecordsCollectorTest.java index d84d97f93..4824dd0fd 100644 --- a/evita_functional_tests/src/test/java/io/evitadb/core/query/sort/price/FilteredPriceRecordsCollectorTest.java +++ b/evita_functional_tests/src/test/java/io/evitadb/core/query/sort/price/FilteredPriceRecordsCollectorTest.java @@ -23,6 +23,7 @@ package io.evitadb.core.query.sort.price; +import io.evitadb.core.query.QueryExecutionContext; import io.evitadb.core.query.algebra.price.FilteredPriceRecordAccessor; import io.evitadb.core.query.algebra.price.FilteredPriceRecordsLookupResult; import io.evitadb.index.price.model.priceRecord.PriceRecord; @@ -122,13 +123,17 @@ private static class MockedPriceRecordsCollector extends FilteredPriceRecordsCol private final PriceRecord[] addedRecords; public MockedPriceRecordsCollector(@Nonnull PriceRecord[] originalRecords, @Nonnull PriceRecord[] addedRecords) { - super(new FilteredPriceRecordsLookupResult(originalRecords), Collections.emptyList()); + super(new FilteredPriceRecordsLookupResult(originalRecords), Collections.emptyList(), null); this.addedRecords = addedRecords; } @Nonnull @Override - protected FilteredPriceRecordsLookupResult computeResult(@Nonnull RoaringBitmap filteredResults, @Nonnull Collection filteredPriceRecordAccessors) { + protected FilteredPriceRecordsLookupResult computeResult( + @Nonnull RoaringBitmap filteredResults, + @Nonnull Collection filteredPriceRecordAccessors, + @Nonnull QueryExecutionContext context + ) { return new FilteredPriceRecordsLookupResult(addedRecords); } diff --git a/evita_performance_tests/src/main/java/io/evitadb/spike/FormulaCostMeasurement.java b/evita_performance_tests/src/main/java/io/evitadb/spike/FormulaCostMeasurement.java index bd4b7e718..d5d882c88 100644 --- a/evita_performance_tests/src/main/java/io/evitadb/spike/FormulaCostMeasurement.java +++ b/evita_performance_tests/src/main/java/io/evitadb/spike/FormulaCostMeasurement.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. @@ -164,14 +164,14 @@ public void priceIdContainer(PriceIdsWithPriceRecordsRecordState priceDataSet, B priceDataSet.getPriceIdsFormula() ); blackhole.consume(testedFormula.compute()); - blackhole.consume(testedFormula.getFilteredPriceRecords()); + blackhole.consume(testedFormula.getFilteredPriceRecords(null)); } @Benchmark public void priceIdToEntityIdTranslate(PriceIdsWithPriceRecordsRecordState priceDataSet, Blackhole blackhole) { final PriceIdToEntityIdTranslateFormula testedFormula = new PriceIdToEntityIdTranslateFormula(priceDataSet.getPriceIdsFormula()); blackhole.consume(testedFormula.compute()); - blackhole.consume(testedFormula.getFilteredPriceRecords()); + blackhole.consume(testedFormula.getFilteredPriceRecords(null)); } @Benchmark diff --git a/evita_performance_tests/src/main/java/io/evitadb/spike/mock/MockEntityIdsFormula.java b/evita_performance_tests/src/main/java/io/evitadb/spike/mock/MockEntityIdsFormula.java index dd5b30920..967dd0d41 100644 --- a/evita_performance_tests/src/main/java/io/evitadb/spike/mock/MockEntityIdsFormula.java +++ b/evita_performance_tests/src/main/java/io/evitadb/spike/mock/MockEntityIdsFormula.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. @@ -23,6 +23,7 @@ package io.evitadb.spike.mock; +import io.evitadb.core.query.QueryExecutionContext; import io.evitadb.core.query.algebra.AbstractFormula; import io.evitadb.core.query.algebra.Formula; import io.evitadb.core.query.algebra.price.FilteredPriceRecordAccessor; @@ -58,8 +59,8 @@ public long getOperationCost() { @Nonnull @Override - public FilteredPriceRecords getFilteredPriceRecords() { - return priceRecords; + public FilteredPriceRecords getFilteredPriceRecords(@Nonnull QueryExecutionContext context) { + return this.priceRecords; } @Nonnull diff --git a/evita_performance_tests/src/main/java/io/evitadb/spike/mock/MockInnerRecordIdsFormula.java b/evita_performance_tests/src/main/java/io/evitadb/spike/mock/MockInnerRecordIdsFormula.java index 1c9182486..c8d7f7365 100644 --- a/evita_performance_tests/src/main/java/io/evitadb/spike/mock/MockInnerRecordIdsFormula.java +++ b/evita_performance_tests/src/main/java/io/evitadb/spike/mock/MockInnerRecordIdsFormula.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. @@ -23,6 +23,7 @@ package io.evitadb.spike.mock; +import io.evitadb.core.query.QueryExecutionContext; import io.evitadb.core.query.algebra.AbstractFormula; import io.evitadb.core.query.algebra.Formula; import io.evitadb.core.query.algebra.price.FilteredPriceRecordAccessor; @@ -72,7 +73,7 @@ public Formula getDelegate() { @Nonnull @Override - public FilteredPriceRecords getFilteredPriceRecords() { + public FilteredPriceRecords getFilteredPriceRecords(@Nonnull QueryExecutionContext context) { return allPriceRecords; } diff --git a/evita_store/evita_store_server/src/main/java/io/evitadb/store/cache/serializer/FlattenedFormulaWithFilteredPricesAndFilteredOutRecordsSerializer.java b/evita_store/evita_store_server/src/main/java/io/evitadb/store/cache/serializer/FlattenedFormulaWithFilteredPricesAndFilteredOutRecordsSerializer.java index 2924107a3..ccbdf1846 100644 --- a/evita_store/evita_store_server/src/main/java/io/evitadb/store/cache/serializer/FlattenedFormulaWithFilteredPricesAndFilteredOutRecordsSerializer.java +++ b/evita_store/evita_store_server/src/main/java/io/evitadb/store/cache/serializer/FlattenedFormulaWithFilteredPricesAndFilteredOutRecordsSerializer.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. @@ -58,7 +58,7 @@ public void write(Kryo kryo, Output output, FlattenedFormulaWithFilteredPricesAn writeBitmapIds(output, object.getTransactionalDataIds()); writeIntegerBitmap(output, object.compute()); writePriceEvaluationContext(kryo, output, object.getPriceEvaluationContext()); - writeFilteredPriceRecords(kryo, output, object.getFilteredPriceRecords()); + writeFilteredPriceRecords(kryo, output, object.getFilteredPriceRecordsOrThrowException()); writeIntegerBitmap(output, object.getRecordsFilteredOutByPredicate()); } diff --git a/evita_store/evita_store_server/src/main/java/io/evitadb/store/cache/serializer/FlattenedFormulaWithFilteredPricesSerializer.java b/evita_store/evita_store_server/src/main/java/io/evitadb/store/cache/serializer/FlattenedFormulaWithFilteredPricesSerializer.java index 0d43fc8a7..bd6a3bc32 100644 --- a/evita_store/evita_store_server/src/main/java/io/evitadb/store/cache/serializer/FlattenedFormulaWithFilteredPricesSerializer.java +++ b/evita_store/evita_store_server/src/main/java/io/evitadb/store/cache/serializer/FlattenedFormulaWithFilteredPricesSerializer.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. @@ -52,7 +52,7 @@ public void write(Kryo kryo, Output output, FlattenedFormulaWithFilteredPrices o writeBitmapIds(output, object.getTransactionalDataIds()); writeIntegerBitmap(output, object.compute()); writePriceEvaluationContext(kryo, output, object.getPriceEvaluationContext()); - writeFilteredPriceRecords(kryo, output, object.getFilteredPriceRecords()); + writeFilteredPriceRecords(kryo, output, object.getFilteredPriceRecordsOrThrowException()); } @Override