Search in sources :

Example 6 with RecordQueryFilterPlan

use of com.apple.foundationdb.record.query.plan.plans.RecordQueryFilterPlan in project fdb-record-layer by FoundationDB.

the class QueryPlanCursorTest method indexlessFilter.

@Test
public void indexlessFilter() throws Exception {
    final RecordQueryPlan plan = new RecordQueryFilterPlan(scanPlan(), Query.field("num_value_2").lessThan(50));
    compareSkipsAndCursors(plan);
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) RecordQueryFilterPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFilterPlan) Test(org.junit.jupiter.api.Test)

Example 7 with RecordQueryFilterPlan

use of com.apple.foundationdb.record.query.plan.plans.RecordQueryFilterPlan in project fdb-record-layer by FoundationDB.

the class FDBRecordStoreLimitTestBase method plans.

public Stream<Arguments> plans(boolean fail) {
    RecordQueryPlan scanPlan = new RecordQueryScanPlan(ScanComparisons.EMPTY, false);
    IndexScanParameters fullValueScan = IndexScanComparisons.byValue();
    RecordQueryPlan indexPlan = new RecordQueryIndexPlan("MySimpleRecord$str_value_indexed", fullValueScan, false);
    QueryComponent filter = Query.field("str_value_indexed").equalsValue("odd");
    QueryComponent middleFilter = Query.and(Query.field("rec_no").greaterThan(24L), Query.field("rec_no").lessThan(60L));
    RecordQueryPlan firstChild = indexPlanEquals("MySimpleRecord$str_value_indexed", "even");
    RecordQueryPlan secondChild = indexPlanEquals("MySimpleRecord$num_value_3_indexed", 0);
    return Stream.of(Arguments.of("full record scan", fail, scanPlan), Arguments.of("simple index scan", fail, indexPlan), Arguments.of("reverse index scan", fail, new RecordQueryIndexPlan("MySimpleRecord$str_value_indexed", fullValueScan, true)), Arguments.of("filter on scan plan", fail, new RecordQueryFilterPlan(scanPlan, filter)), Arguments.of("filter on index plan", fail, new RecordQueryFilterPlan(indexPlan, filter)), Arguments.of("type filter on scan plan", fail, new RecordQueryTypeFilterPlan(scanPlan, Collections.singletonList("MySimpleRecord"))), Arguments.of("type filter on index plan", fail, new RecordQueryTypeFilterPlan(indexPlan, Collections.singletonList("MySimpleRecord"))), Arguments.of("disjoint union", fail, RecordQueryUnionPlan.from(indexPlanEquals("MySimpleRecord$str_value_indexed", "odd"), indexPlanEquals("MySimpleRecord$str_value_indexed", "even"), primaryKey(), false)), Arguments.of("overlapping union", fail, RecordQueryUnionPlan.from(firstChild, secondChild, primaryKey(), false)), Arguments.of("overlapping union (swapped args)", fail, RecordQueryUnionPlan.from(secondChild, firstChild, primaryKey(), false)), Arguments.of("overlapping intersection", fail, RecordQueryIntersectionPlan.from(firstChild, secondChild, primaryKey())), Arguments.of("overlapping intersection", fail, RecordQueryIntersectionPlan.from(secondChild, firstChild, primaryKey())), Arguments.of("union with inner filter", fail, RecordQueryUnionPlan.from(new RecordQueryFilterPlan(firstChild, middleFilter), secondChild, primaryKey(), false)), Arguments.of("union with two inner filters", fail, RecordQueryUnionPlan.from(new RecordQueryFilterPlan(firstChild, middleFilter), new RecordQueryFilterPlan(secondChild, Query.field("rec_no").lessThan(55L)), primaryKey(), false)), Arguments.of("intersection with inner filter", fail, RecordQueryIntersectionPlan.from(new RecordQueryFilterPlan(firstChild, middleFilter), secondChild, primaryKey())), Arguments.of("intersection with two inner filters", fail, RecordQueryIntersectionPlan.from(new RecordQueryFilterPlan(firstChild, middleFilter), new RecordQueryFilterPlan(secondChild, Query.field("rec_no").lessThan(55L)), primaryKey())));
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) IndexScanParameters(com.apple.foundationdb.record.provider.foundationdb.IndexScanParameters) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) RecordQueryFilterPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFilterPlan) RecordQueryScanPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryScanPlan) RecordQueryIndexPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan) RecordQueryTypeFilterPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryTypeFilterPlan)

Example 8 with RecordQueryFilterPlan

use of com.apple.foundationdb.record.query.plan.plans.RecordQueryFilterPlan in project fdb-record-layer by FoundationDB.

the class RecordQueryPlanner method planText.

@Nullable
private ScoredPlan planText(@Nonnull CandidateScan candidateScan, @Nonnull Index index, @Nonnull QueryComponent filter, @Nullable KeyExpression sort) {
    if (sort != null) {
        // TODO: Full Text: Sorts are not supported with full text queries (https://github.com/FoundationDB/fdb-record-layer/issues/55)
        return null;
    }
    FilterSatisfiedMask filterMask = FilterSatisfiedMask.of(filter);
    final TextScan scan = TextScanPlanner.getScanForQuery(index, filter, false, filterMask);
    if (scan == null) {
        return null;
    }
    // TODO: Check the rest of the fields of the text index expression to see if the sort and unsatisfied filters can be helped.
    RecordQueryPlan plan = new RecordQueryTextIndexPlan(index.getName(), scan, candidateScan.reverse);
    // Add a type filter if the index is over more types than those the query specifies
    Set<String> possibleTypes = getPossibleTypes(index);
    plan = addTypeFilterIfNeeded(candidateScan, plan, possibleTypes);
    // is "strict", it must be surrounded be a filter plan.
    if (scan.getTextComparison() instanceof Comparisons.TextContainsAllPrefixesComparison) {
        Comparisons.TextContainsAllPrefixesComparison textComparison = (Comparisons.TextContainsAllPrefixesComparison) scan.getTextComparison();
        if (textComparison.isStrict()) {
            plan = new RecordQueryFilterPlan(plan, filter);
            filterMask.setSatisfied(true);
        }
    }
    // than other indexes.
    return new ScoredPlan(plan, filterMask.getUnsatisfiedFilters(), Collections.emptyList(), 10, scan.createsDuplicates(), null);
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) RecordQueryFilterPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFilterPlan) TimeWindowScanComparisons(com.apple.foundationdb.record.provider.foundationdb.leaderboard.TimeWindowScanComparisons) IndexScanComparisons(com.apple.foundationdb.record.provider.foundationdb.IndexScanComparisons) RankComparisons(com.apple.foundationdb.record.query.plan.planning.RankComparisons) Comparisons(com.apple.foundationdb.record.query.expressions.Comparisons) FilterSatisfiedMask(com.apple.foundationdb.record.query.plan.planning.FilterSatisfiedMask) RecordQueryTextIndexPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryTextIndexPlan) Nullable(javax.annotation.Nullable)

Example 9 with RecordQueryFilterPlan

use of com.apple.foundationdb.record.query.plan.plans.RecordQueryFilterPlan in project fdb-record-layer by FoundationDB.

the class RecordQueryPlanner method planOr.

@Nullable
private ScoredPlan planOr(@Nonnull PlanContext planContext, @Nonnull OrComponent filter) {
    if (filter.getChildren().isEmpty()) {
        return null;
    }
    List<ScoredPlan> subplans = new ArrayList<>(filter.getChildren().size());
    boolean allHaveOrderingKey = true;
    RecordQueryPlan commonFilteredBasePlan = null;
    boolean allHaveSameBasePlan = true;
    for (QueryComponent subfilter : filter.getChildren()) {
        ScoredPlan subplan = planFilter(planContext, subfilter, true);
        if (subplan == null) {
            return null;
        }
        if (subplan.planOrderingKey == null) {
            allHaveOrderingKey = false;
        }
        RecordQueryPlan filteredBasePlan;
        if (subplan.plan instanceof RecordQueryFilterPlan) {
            filteredBasePlan = ((RecordQueryFilterPlan) subplan.plan).getInnerPlan();
        } else {
            filteredBasePlan = null;
        }
        if (subplans.isEmpty()) {
            commonFilteredBasePlan = filteredBasePlan;
            allHaveSameBasePlan = filteredBasePlan != null;
        } else if (allHaveSameBasePlan && !Objects.equals(filteredBasePlan, commonFilteredBasePlan)) {
            allHaveSameBasePlan = false;
        }
        subplans.add(subplan);
    }
    // out there over the equivalent OR(EQUALS) filters.
    if (allHaveSameBasePlan) {
        final RecordQueryPlan combinedOrFilter = new RecordQueryFilterPlan(commonFilteredBasePlan, new OrComponent(subplans.stream().map(subplan -> ((RecordQueryFilterPlan) subplan.plan).getConjunctedFilter()).collect(Collectors.toList())));
        ScoredPlan firstSubPlan = subplans.get(0);
        return new ScoredPlan(combinedOrFilter, Collections.emptyList(), Collections.emptyList(), firstSubPlan.score, firstSubPlan.createsDuplicates, firstSubPlan.includedRankComparisons);
    }
    // neither removes duplicates nor requires the children be in order.
    if (allHaveOrderingKey) {
        final ScoredPlan orderedUnionPlan = planOrderedUnion(planContext, subplans);
        if (orderedUnionPlan != null) {
            return orderedUnionPlan;
        }
    }
    final ScoredPlan unorderedUnionPlan = planUnorderedUnion(planContext, subplans);
    if (unorderedUnionPlan != null) {
        return planRemoveDuplicates(planContext, unorderedUnionPlan);
    }
    return null;
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) RecordQueryFilterPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFilterPlan) RecordQueryIntersectionPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryIntersectionPlan) StoreTimer(com.apple.foundationdb.record.provider.common.StoreTimer) RecordTypeKeyExpression(com.apple.foundationdb.record.metadata.expressions.RecordTypeKeyExpression) LoggerFactory(org.slf4j.LoggerFactory) IndexScanType(com.apple.foundationdb.record.IndexScanType) KeyValueLogMessage(com.apple.foundationdb.record.logging.KeyValueLogMessage) QueryRecordFunctionWithComparison(com.apple.foundationdb.record.query.expressions.QueryRecordFunctionWithComparison) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) VersionKeyExpression(com.apple.foundationdb.record.metadata.expressions.VersionKeyExpression) RecordQueryScanPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryScanPlan) GroupingKeyExpression(com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression) FieldWithComparisonCountProperty(com.apple.foundationdb.record.query.plan.temp.properties.FieldWithComparisonCountProperty) RecordQueryUnionPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryUnionPlan) RecordQueryUnorderedUnionPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryUnorderedUnionPlan) Query(com.apple.foundationdb.record.query.expressions.Query) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) TimeWindowScanComparisons(com.apple.foundationdb.record.provider.foundationdb.leaderboard.TimeWindowScanComparisons) Collection(java.util.Collection) PlannerGraphProperty(com.apple.foundationdb.record.query.plan.temp.explain.PlannerGraphProperty) Set(java.util.Set) FanType(com.apple.foundationdb.record.metadata.expressions.KeyExpression.FanType) AndComponent(com.apple.foundationdb.record.query.expressions.AndComponent) TextScanPlanner(com.apple.foundationdb.record.query.plan.planning.TextScanPlanner) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) RecordQueryCoveringIndexPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryCoveringIndexPlan) List(java.util.List) OneOfThemWithComponent(com.apple.foundationdb.record.query.expressions.OneOfThemWithComponent) RecordQueryInUnionPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryInUnionPlan) RecordQueryUnorderedPrimaryKeyDistinctPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryUnorderedPrimaryKeyDistinctPlan) RecordStoreState(com.apple.foundationdb.record.RecordStoreState) RecordTypeKeyComparison(com.apple.foundationdb.record.query.expressions.RecordTypeKeyComparison) API(com.apple.foundationdb.annotation.API) RecordQueryTypeFilterPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryTypeFilterPlan) FunctionNames(com.apple.foundationdb.record.FunctionNames) RecordMetaData(com.apple.foundationdb.record.RecordMetaData) RecordQueryPlannerSubstitutionVisitor(com.apple.foundationdb.record.query.plan.visitor.RecordQueryPlannerSubstitutionVisitor) Iterables(com.google.common.collect.Iterables) SpotBugsSuppressWarnings(com.apple.foundationdb.annotation.SpotBugsSuppressWarnings) IndexScanParameters(com.apple.foundationdb.record.provider.foundationdb.IndexScanParameters) RecordQueryPlannerSortConfiguration(com.apple.foundationdb.record.query.plan.sorting.RecordQueryPlannerSortConfiguration) InExtractor(com.apple.foundationdb.record.query.plan.planning.InExtractor) KeyWithValueExpression(com.apple.foundationdb.record.metadata.expressions.KeyWithValueExpression) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) BooleanNormalizer(com.apple.foundationdb.record.query.plan.planning.BooleanNormalizer) ArrayList(java.util.ArrayList) Key(com.apple.foundationdb.record.metadata.Key) FieldKeyExpression(com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression) HashSet(java.util.HashSet) UnorderedPrimaryKeyDistinctVisitor(com.apple.foundationdb.record.query.plan.visitor.UnorderedPrimaryKeyDistinctVisitor) FilterVisitor(com.apple.foundationdb.record.query.plan.visitor.FilterVisitor) Lists(com.google.common.collect.Lists) ImmutableList(com.google.common.collect.ImmutableList) NestingKeyExpression(com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression) ParameterRelationshipGraph(com.apple.foundationdb.record.query.ParameterRelationshipGraph) IndexScanComparisons(com.apple.foundationdb.record.provider.foundationdb.IndexScanComparisons) TimeWindowRecordFunction(com.apple.foundationdb.record.provider.foundationdb.leaderboard.TimeWindowRecordFunction) InSource(com.apple.foundationdb.record.query.plan.plans.InSource) Nonnull(javax.annotation.Nonnull) EmptyKeyExpression(com.apple.foundationdb.record.metadata.expressions.EmptyKeyExpression) Nullable(javax.annotation.Nullable) QueryKeyExpressionWithComparison(com.apple.foundationdb.record.query.expressions.QueryKeyExpressionWithComparison) FieldWithComparison(com.apple.foundationdb.record.query.expressions.FieldWithComparison) RecordQueryIndexPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan) RecordQueryPlanWithIndex(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlanWithIndex) Logger(org.slf4j.Logger) FilterSatisfiedMask(com.apple.foundationdb.record.query.plan.planning.FilterSatisfiedMask) Iterator(java.util.Iterator) RecordQueryTextIndexPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryTextIndexPlan) RankComparisons(com.apple.foundationdb.record.query.plan.planning.RankComparisons) OrComponent(com.apple.foundationdb.record.query.expressions.OrComponent) Comparisons(com.apple.foundationdb.record.query.expressions.Comparisons) RecordType(com.apple.foundationdb.record.metadata.RecordType) NestedField(com.apple.foundationdb.record.query.expressions.NestedField) Index(com.apple.foundationdb.record.metadata.Index) RecordQuerySortPlan(com.apple.foundationdb.record.query.plan.sorting.RecordQuerySortPlan) QueryKeyExpressionWithOneOfComparison(com.apple.foundationdb.record.query.expressions.QueryKeyExpressionWithOneOfComparison) OneOfThemWithComparison(com.apple.foundationdb.record.query.expressions.OneOfThemWithComparison) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) VisibleForTesting(com.google.common.annotations.VisibleForTesting) Comparator(java.util.Comparator) ThenKeyExpression(com.apple.foundationdb.record.metadata.expressions.ThenKeyExpression) Collections(java.util.Collections) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) RecordQueryFilterPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFilterPlan) OrComponent(com.apple.foundationdb.record.query.expressions.OrComponent) ArrayList(java.util.ArrayList) Nullable(javax.annotation.Nullable)

Example 10 with RecordQueryFilterPlan

use of com.apple.foundationdb.record.query.plan.plans.RecordQueryFilterPlan in project fdb-record-layer by FoundationDB.

the class PlanOrderingKey method forPlan.

@Nullable
public static PlanOrderingKey forPlan(@Nonnull RecordMetaData metaData, @Nonnull RecordQueryPlan queryPlan, @Nullable KeyExpression primaryKey) {
    if (primaryKey == null) {
        return null;
    }
    while (queryPlan instanceof RecordQueryFilterPlan) {
        queryPlan = ((RecordQueryFilterPlan) queryPlan).getInnerPlan();
    }
    if (queryPlan instanceof RecordQueryPlanWithIndex) {
        final RecordQueryPlanWithIndex indexPlan = (RecordQueryPlanWithIndex) queryPlan;
        final Index index = metaData.getIndex(indexPlan.getIndexName());
        final List<KeyExpression> keys = new ArrayList<>(index.getRootExpression().normalizeKeyForPositions());
        int pkeyStart = keys.size();
        int pKeyTail = pkeyStart;
        // Primary keys come after index value keys, unless they were already part of it.
        for (KeyExpression pkey : primaryKey.normalizeKeyForPositions()) {
            int pos = keys.indexOf(pkey);
            if (pos < 0) {
                keys.add(pkey);
            } else if (pkeyStart > pos) {
                pkeyStart = pos;
            }
        }
        final int prefixSize;
        if (indexPlan instanceof RecordQueryIndexPlan) {
            prefixSize = ((RecordQueryIndexPlan) indexPlan).getComparisons().getEqualitySize();
        } else if (indexPlan instanceof RecordQueryTextIndexPlan) {
            final TextScan textScan = ((RecordQueryTextIndexPlan) indexPlan).getTextScan();
            int groupingSize = textScan.getGroupingComparisons() != null ? textScan.getGroupingComparisons().getEqualitySize() : 0;
            int suffixSize = textScan.getSuffixComparisons() != null ? textScan.getSuffixComparisons().getEqualitySize() : 0;
            if (textScan.getTextComparison().getType().isEquality()) {
                // Can use the equality comparisons in the grouping columns and any columns after the text index
                // plus the text column itself.
                prefixSize = groupingSize + suffixSize + 1;
            } else {
                // by the token that the prefix scan just so happened to hit.
                return null;
            }
        } else {
            // Some unknown index plan. Maybe this should throw an error?
            return null;
        }
        return new PlanOrderingKey(keys, prefixSize, pkeyStart, pKeyTail);
    } else if (queryPlan instanceof RecordQueryScanPlan) {
        final RecordQueryScanPlan scanPlan = (RecordQueryScanPlan) queryPlan;
        return new PlanOrderingKey(primaryKey.normalizeKeyForPositions(), scanPlan.getComparisons().getEqualitySize(), 0, 0);
    } else if (queryPlan instanceof RecordQueryIntersectionPlan) {
        return forComparisonKey(((RecordQueryIntersectionPlan) queryPlan).getComparisonKey(), primaryKey);
    } else if (queryPlan instanceof RecordQueryUnionPlan) {
        return forComparisonKey(((RecordQueryUnionPlan) queryPlan).getComparisonKey(), primaryKey);
    } else {
        return null;
    }
}
Also used : RecordQueryUnionPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryUnionPlan) RecordQueryScanPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryScanPlan) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) ThenKeyExpression(com.apple.foundationdb.record.metadata.expressions.ThenKeyExpression) ArrayList(java.util.ArrayList) RecordQueryIndexPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan) RecordQueryPlanWithIndex(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlanWithIndex) Index(com.apple.foundationdb.record.metadata.Index) RecordQueryTextIndexPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryTextIndexPlan) RecordQueryIntersectionPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryIntersectionPlan) RecordQueryFilterPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFilterPlan) RecordQueryPlanWithIndex(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlanWithIndex) Nullable(javax.annotation.Nullable)

Aggregations

RecordQueryFilterPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryFilterPlan)10 RecordQueryPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan)8 KeyExpression (com.apple.foundationdb.record.metadata.expressions.KeyExpression)5 QueryComponent (com.apple.foundationdb.record.query.expressions.QueryComponent)5 Nonnull (javax.annotation.Nonnull)5 Nullable (javax.annotation.Nullable)5 ThenKeyExpression (com.apple.foundationdb.record.metadata.expressions.ThenKeyExpression)4 FieldKeyExpression (com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression)3 RecordQueryIndexPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan)3 RecordQueryScanPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryScanPlan)3 RecordQueryTextIndexPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryTextIndexPlan)3 ArrayList (java.util.ArrayList)3 RecordCoreException (com.apple.foundationdb.record.RecordCoreException)2 RecordMetaData (com.apple.foundationdb.record.RecordMetaData)2 Index (com.apple.foundationdb.record.metadata.Index)2 EmptyKeyExpression (com.apple.foundationdb.record.metadata.expressions.EmptyKeyExpression)2 GroupingKeyExpression (com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression)2 IndexScanComparisons (com.apple.foundationdb.record.provider.foundationdb.IndexScanComparisons)2 IndexScanParameters (com.apple.foundationdb.record.provider.foundationdb.IndexScanParameters)2 TimeWindowScanComparisons (com.apple.foundationdb.record.provider.foundationdb.leaderboard.TimeWindowScanComparisons)2