Search in sources :

Example 26 with QueryComponent

use of com.apple.foundationdb.record.query.expressions.QueryComponent in project fdb-record-layer by FoundationDB.

the class FDBSortQueryIndexSelectionTest method testComplexQuery8x.

/**
 * Verify that a query with a filter on one field and a sort on another uses the index of the sort preferentially,
 * and falls back to filtering to implement the filter if an appropriate multi-field index is not available.
 */
@DualPlannerTest
public void testComplexQuery8x() throws Exception {
    RecordMetaDataHook hook = complexQuerySetupHook();
    complexQuerySetup(hook);
    final QueryComponent filter = Query.field("str_value_indexed").equalsValue("even");
    RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(filter).setSort(field("num_value_3_indexed")).build();
    RecordQueryPlan plan = planner.plan(query);
    assertThat(plan, filter(filter, indexScan(allOf(indexName("MySimpleRecord$num_value_3_indexed"), unbounded()))));
    if (planner instanceof RecordQueryPlanner) {
        assertEquals(-1429997503, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
    // TODO: Issue https://github.com/FoundationDB/fdb-record-layer/issues/1074
    // assertEquals(-1729416480, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    } else {
        assertEquals(952181942, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
    }
    try (FDBRecordContext context = openContext()) {
        openSimpleRecordStore(context, hook);
        int i = 0;
        try (RecordCursorIterator<FDBQueriedRecord<Message>> cursor = recordStore.executeQuery(plan).asIterator()) {
            while (cursor.hasNext()) {
                FDBQueriedRecord<Message> rec = cursor.next();
                TestRecords1Proto.MySimpleRecord.Builder myrec = TestRecords1Proto.MySimpleRecord.newBuilder();
                myrec.mergeFrom(Objects.requireNonNull(rec).getRecord());
                assertEquals("even", myrec.getStrValueIndexed());
                i++;
            }
        }
        assertEquals(50, i);
        assertDiscardedAtMost(50, context);
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) Message(com.google.protobuf.Message) FDBQueriedRecord(com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner) RecordQuery(com.apple.foundationdb.record.query.RecordQuery)

Example 27 with QueryComponent

use of com.apple.foundationdb.record.query.expressions.QueryComponent in project fdb-record-layer by FoundationDB.

the class FDBSortQueryIndexSelectionTest method sortWithNonScannableFilterOnIndex.

/**
 * Verify that if there is an index on the sorted field but it does not satisfy the comparison
 * of a filter (because that comparison cannot be accomplished with a scan) that the index
 * is still used solely to accomplish sorting.
 */
@ParameterizedTest
@MethodSource("hooks")
void sortWithNonScannableFilterOnIndex(RecordMetaDataHook hook, PlannableIndexTypes indexTypes) throws Exception {
    setupSimpleRecordStore(hook, (i, builder) -> builder.setRecNo(i).setNumValue2(i % 2).setNumValue3Indexed(i % 3));
    final QueryComponent filter = Query.field("num_value_3_indexed").notEquals(1);
    RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(filter).setSort(field("num_value_3_indexed")).build();
    setupPlanner(indexTypes);
    // Fetch(Covering(Index(MySimpleRecord$num_value_3_indexed <,>) -> [num_value_3_indexed: KEY[0], rec_no: KEY[1]]) | num_value_3_indexed NOT_EQUALS 1)
    RecordQueryPlan plan = planner.plan(query);
    assertThat(plan, fetch(filter(filter, coveringIndexScan(indexScan(allOf(indexName("MySimpleRecord$num_value_3_indexed"), unbounded()))))));
    assertEquals(-1303978120, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
    assertEquals(1548200279, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
    assertEquals(-856491930, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    AtomicInteger lastNumValue3 = new AtomicInteger(Integer.MIN_VALUE);
    int returned = querySimpleRecordStore(hook, plan, EvaluationContext::empty, builder -> {
        assertThat(builder.getNumValue3Indexed(), not(equalTo(1)));
        assertThat(builder.getNumValue3Indexed(), greaterThanOrEqualTo(lastNumValue3.get()));
        lastNumValue3.set(builder.getNumValue3Indexed());
    }, context -> assertDiscardedAtMost(33, context));
    assertEquals(67, returned);
    // reset planner
    setupPlanner(null);
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) EvaluationContext(com.apple.foundationdb.record.EvaluationContext) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MethodSource(org.junit.jupiter.params.provider.MethodSource)

Example 28 with QueryComponent

use of com.apple.foundationdb.record.query.expressions.QueryComponent in project fdb-record-layer by FoundationDB.

the class FilterVisitor method partitionFilters.

public static void partitionFilters(@Nonnull final List<QueryComponent> filters, @Nonnull final AvailableFields availableFields, @Nonnull final List<QueryComponent> indexFilters, @Nonnull final List<QueryComponent> residualFilters, @Nullable final Set<KeyExpression> allReferencedFields) {
    for (final QueryComponent filter : filters) {
        final Set<KeyExpression> referencedFields = new HashSet<>();
        if (findFilterReferencedFields(filter, referencedFields)) {
            if (availableFields.containsAll(referencedFields)) {
                indexFilters.add(filter);
                if (allReferencedFields != null) {
                    allReferencedFields.addAll(referencedFields);
                }
                continue;
            }
        }
        residualFilters.add(filter);
    }
}
Also used : QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) FunctionKeyExpression(com.apple.foundationdb.record.metadata.expressions.FunctionKeyExpression) LiteralKeyExpression(com.apple.foundationdb.record.metadata.expressions.LiteralKeyExpression) FieldKeyExpression(com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) QueryableKeyExpression(com.apple.foundationdb.record.metadata.expressions.QueryableKeyExpression) ThenKeyExpression(com.apple.foundationdb.record.metadata.expressions.ThenKeyExpression) HashSet(java.util.HashSet)

Example 29 with QueryComponent

use of com.apple.foundationdb.record.query.expressions.QueryComponent in project fdb-record-layer by FoundationDB.

the class UnionVisitor method postVisit.

@Nonnull
@Override
public RecordQueryPlan postVisit(@Nonnull final RecordQueryPlan recordQueryPlan) {
    if (recordQueryPlan instanceof RecordQueryUnionPlanBase) {
        RecordQueryUnionPlanBase unionPlan = (RecordQueryUnionPlanBase) recordQueryPlan;
        final Set<KeyExpression> requiredFields = unionPlan.getRequiredFields();
        boolean shouldPullOutFilter = false;
        QueryComponent filter = null;
        if (unionPlan.getChildren().stream().allMatch(child -> child instanceof RecordQueryFilterPlan)) {
            filter = ((RecordQueryFilterPlan) unionPlan.getChildren().get(0)).getConjunctedFilter();
            // needed for lambda expression
            final QueryComponent finalFilter = filter;
            shouldPullOutFilter = unionPlan.getChildren().stream().allMatch(plan -> ((RecordQueryFilterPlan) plan).getConjunctedFilter().equals(finalFilter));
        }
        List<ExpressionRef<RecordQueryPlan>> newChildren = new ArrayList<>(unionPlan.getChildren().size());
        for (RecordQueryPlan plan : unionPlan.getChildren()) {
            if (shouldPullOutFilter) {
                // Check if the plan under the filter can have its index fetch removed.
                if (!(plan instanceof RecordQueryFilterPlan)) {
                    throw new RecordCoreException("serious logic error: thought this was a filter plan but it wasn't");
                }
                plan = ((RecordQueryFilterPlan) plan).getChild();
            }
            @Nullable RecordQueryPlan newPlan = removeIndexFetch(plan, requiredFields);
            if (newPlan == null) {
                // can't remove index fetch, so give up
                return recordQueryPlan;
            }
            newChildren.add(GroupExpressionRef.of(newPlan));
        }
        RecordQueryPlan newUnionPlan = new RecordQueryFetchFromPartialRecordPlan(unionPlan.withChildrenReferences(newChildren), TranslateValueFunction.unableToTranslate());
        if (shouldPullOutFilter) {
            return new RecordQueryFilterPlan(newUnionPlan, filter);
        } else {
            return newUnionPlan;
        }
    }
    return recordQueryPlan;
}
Also used : TranslateValueFunction(com.apple.foundationdb.record.query.plan.plans.TranslateValueFunction) RecordMetaData(com.apple.foundationdb.record.RecordMetaData) RecordQueryFilterPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFilterPlan) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) RecordQueryFetchFromPartialRecordPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFetchFromPartialRecordPlan) Set(java.util.Set) PlannableIndexTypes(com.apple.foundationdb.record.query.plan.PlannableIndexTypes) GroupExpressionRef(com.apple.foundationdb.record.query.plan.temp.GroupExpressionRef) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) ArrayList(java.util.ArrayList) List(java.util.List) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) ExpressionRef(com.apple.foundationdb.record.query.plan.temp.ExpressionRef) Nonnull(javax.annotation.Nonnull) RecordQueryUnionPlanBase(com.apple.foundationdb.record.query.plan.plans.RecordQueryUnionPlanBase) Nullable(javax.annotation.Nullable) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) RecordQueryUnionPlanBase(com.apple.foundationdb.record.query.plan.plans.RecordQueryUnionPlanBase) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) ArrayList(java.util.ArrayList) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) RecordQueryFilterPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFilterPlan) RecordQueryFetchFromPartialRecordPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryFetchFromPartialRecordPlan) GroupExpressionRef(com.apple.foundationdb.record.query.plan.temp.GroupExpressionRef) ExpressionRef(com.apple.foundationdb.record.query.plan.temp.ExpressionRef) Nullable(javax.annotation.Nullable) Nonnull(javax.annotation.Nonnull)

Example 30 with QueryComponent

use of com.apple.foundationdb.record.query.expressions.QueryComponent in project fdb-record-layer by FoundationDB.

the class LuceneQueryIntegrationTest method selectsFromMultipleNestedIndexes.

@Test
void selectsFromMultipleNestedIndexes() throws Exception {
    useRewritePlanner = false;
    try (FDBRecordContext context = openContext()) {
        openRecordStore(context, metaData -> {
            metaData.addIndex(TextIndexTestUtils.COMPLEX_DOC, new Index(nestedDualIndex.toProto()));
            metaData.addIndex(TextIndexTestUtils.COMPLEX_DOC, new Index(nestedDualIndex2.toProto()));
        });
        setupPlanner(null);
        QueryComponent filter = new LuceneQueryComponent("text2:test", Arrays.asList("text2"));
        RecordQuery rq = RecordQuery.newBuilder().setRecordType(TextIndexTestUtils.COMPLEX_DOC).setFilter(filter).build();
        final RecordQueryPlan plan = planner.plan(rq);
        Set<String> appliedIndexNames = plan.getUsedIndexes();
        Assertions.assertEquals(1, appliedIndexNames.size(), "index selection is incorrect");
        Assertions.assertTrue(appliedIndexNames.contains(nestedDualIndex2.getName()), "Did not select the correct index");
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) LuceneQueryComponent(com.apple.foundationdb.record.query.expressions.LuceneQueryComponent) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) Index(com.apple.foundationdb.record.metadata.Index) LuceneQueryComponent(com.apple.foundationdb.record.query.expressions.LuceneQueryComponent) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) Test(org.junit.jupiter.api.Test)

Aggregations

QueryComponent (com.apple.foundationdb.record.query.expressions.QueryComponent)96 RecordQueryPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan)58 RecordQuery (com.apple.foundationdb.record.query.RecordQuery)44 Test (org.junit.jupiter.api.Test)41 FDBRecordContext (com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext)37 ArrayList (java.util.ArrayList)30 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)29 FDBQueriedRecord (com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord)25 Index (com.apple.foundationdb.record.metadata.Index)24 Nonnull (javax.annotation.Nonnull)23 Comparisons (com.apple.foundationdb.record.query.expressions.Comparisons)22 Message (com.google.protobuf.Message)22 Query (com.apple.foundationdb.record.query.expressions.Query)20 RecordQueryPlanner (com.apple.foundationdb.record.query.plan.RecordQueryPlanner)20 List (java.util.List)20 Collections (java.util.Collections)19 Nullable (javax.annotation.Nullable)18 Assertions.assertEquals (org.junit.jupiter.api.Assertions.assertEquals)18 PlanHashable (com.apple.foundationdb.record.PlanHashable)17 Expressions.field (com.apple.foundationdb.record.metadata.Key.Expressions.field)17