Search in sources :

Example 31 with RecordQueryPlanner

use of com.apple.foundationdb.record.query.plan.RecordQueryPlanner 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 32 with RecordQueryPlanner

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

the class FDBSortQueryIndexSelectionTest method sortUniqueNull.

/**
 * Verify that sort with filter works with different null interpretation on unique index.
 */
@DualPlannerTest
void sortUniqueNull() {
    try (FDBRecordContext context = openContext()) {
        openSimpleRecordStore(context, NULL_UNIQUE_HOOK);
        for (int i = 0; i < 100; i++) {
            TestRecords1Proto.MySimpleRecord.Builder recBuilder = TestRecords1Proto.MySimpleRecord.newBuilder();
            recBuilder.setRecNo((1096 * i + 722) % 1289);
            recBuilder.setNumValueUnique(i);
            recordStore.saveRecord(recBuilder.build());
        }
        commit(context);
    }
    RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("num_value_unique").greaterThanOrEquals(20)).setSort(field("num_value_unique")).build();
    // Index(MySimpleRecord$num_value_unique [[20],>)
    RecordQueryPlan plan = planner.plan(query);
    assertThat(plan, indexScan(allOf(indexName("MySimpleRecord$num_value_unique"), bounds(hasTupleString("[[20],>")))));
    if (planner instanceof RecordQueryPlanner) {
        assertEquals(-535398101, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(-1799532339, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(-1088253993, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    } else {
        assertEquals(-535398101, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(-1799532345, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(-1088253999, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    }
    try (FDBRecordContext context = openContext()) {
        openSimpleRecordStore(context, NULL_UNIQUE_HOOK);
        int i = 20;
        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(i++, myrec.getNumValueUnique());
            }
        }
        assertEquals(100, i);
        assertDiscardedNone(context);
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) FDBQueriedRecord(com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord) Message(com.google.protobuf.Message) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner) RecordQuery(com.apple.foundationdb.record.query.RecordQuery)

Example 33 with RecordQueryPlanner

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

the class FDBRecordStoreScanLimitTest method unorderedIntersectionWithScanLimit.

@ParameterizedTest(name = "unorderedIntersectionWithScanLimit [fail = {0}]")
@BooleanSource
public void unorderedIntersectionWithScanLimit(boolean fail) throws Exception {
    // TODO: When there is an UnorderedIntersectionPlan (or whatever) add that to the unordered plans stream
    RecordQueryPlanner planner = new RecordQueryPlanner(simpleMetaData(NO_HOOK), new RecordStoreState(null, null));
    RecordQueryPlan leftPlan = planner.plan(RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("str_value_indexed").startsWith("ev")).build());
    RecordQueryPlan rightPlan = planner.plan(RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("num_value_3_indexed").lessThanOrEquals(1)).build());
    int maximumToScan;
    try (FDBRecordContext context = openContext()) {
        openSimpleRecordStore(context);
        maximumToScan = recordStore.executeQuery(leftPlan).getCount().get() + recordStore.executeQuery(rightPlan).getCount().get();
    }
    for (int limit = 0; limit < 3 * maximumToScan; limit = 2 * limit + 1) {
        final int finalLimit = limit;
        Function<byte[], RecordCursor<FDBQueriedRecord<Message>>> cursorFunction = (continuation) -> {
            ExecuteProperties executeProperties = ExecuteProperties.newBuilder().setScannedRecordsLimit(finalLimit).setFailOnScanLimitReached(fail).build();
            return ProbableIntersectionCursor.create(record -> record.getPrimaryKey().getItems(), Arrays.asList(leftContinuation -> leftPlan.execute(recordStore, EvaluationContext.EMPTY, leftContinuation, executeProperties), rightContinuation -> rightPlan.execute(recordStore, EvaluationContext.EMPTY, rightContinuation, executeProperties)), continuation, recordStore.getTimer());
        };
        assertNumberOfRecordsScanned(limit, cursorFunction, fail, "should" + (limit >= maximumToScan ? "not " : "") + " be limited by record scan limit");
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) BeforeEach(org.junit.jupiter.api.BeforeEach) Arrays(java.util.Arrays) LogMessageKeys(com.apple.foundationdb.record.logging.LogMessageKeys) LoggerFactory(org.slf4j.LoggerFactory) Assertions.assertNotEquals(org.junit.jupiter.api.Assertions.assertNotEquals) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner) RecordCursorVisitor(com.apple.foundationdb.record.RecordCursorVisitor) Tuple(com.apple.foundationdb.tuple.Tuple) RecordCursorResult(com.apple.foundationdb.record.RecordCursorResult) KeyValueLogMessage(com.apple.foundationdb.record.logging.KeyValueLogMessage) QueryPlan(com.apple.foundationdb.record.query.plan.plans.QueryPlan) TestInstance(org.junit.jupiter.api.TestInstance) RecordCoreException(com.apple.foundationdb.record.RecordCoreException) BeforeAll(org.junit.jupiter.api.BeforeAll) Tag(org.junit.jupiter.api.Tag) MethodSource(org.junit.jupiter.params.provider.MethodSource) Query(com.apple.foundationdb.record.query.expressions.Query) TestRecords1Proto(com.apple.foundationdb.record.TestRecords1Proto) FDBStoreTimer(com.apple.foundationdb.record.provider.foundationdb.FDBStoreTimer) ScanLimitReachedException(com.apple.foundationdb.record.ScanLimitReachedException) Matchers.lessThanOrEqualTo(org.hamcrest.Matchers.lessThanOrEqualTo) Arguments(org.junit.jupiter.params.provider.Arguments) TupleRange(com.apple.foundationdb.record.TupleRange) Test(org.junit.jupiter.api.Test) List(java.util.List) Stream(java.util.stream.Stream) EvaluationContext(com.apple.foundationdb.record.EvaluationContext) RecordStoreState(com.apple.foundationdb.record.RecordStoreState) FDBQueriedRecord(com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord) Assertions.assertTrue(org.junit.jupiter.api.Assertions.assertTrue) Optional(java.util.Optional) Matchers.greaterThan(org.hamcrest.Matchers.greaterThan) ProbableIntersectionCursor(com.apple.foundationdb.record.provider.foundationdb.cursors.ProbableIntersectionCursor) Assertions.assertNotNull(org.junit.jupiter.api.Assertions.assertNotNull) RecordQueryPlanWithNoChildren(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlanWithNoChildren) IndexScanParameters(com.apple.foundationdb.record.provider.foundationdb.IndexScanParameters) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) Function(java.util.function.Function) Supplier(java.util.function.Supplier) ArrayList(java.util.ArrayList) Strings(com.google.common.base.Strings) ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) FDBRecordStore(com.apple.foundationdb.record.provider.foundationdb.FDBRecordStore) TestLogMessageKeys(com.apple.foundationdb.record.logging.TestLogMessageKeys) ScanProperties(com.apple.foundationdb.record.ScanProperties) RecordCursorIterator(com.apple.foundationdb.record.RecordCursorIterator) IndexScanComparisons(com.apple.foundationdb.record.provider.foundationdb.IndexScanComparisons) Matchers.lessThan(org.hamcrest.Matchers.lessThan) BooleanSource(com.apple.test.BooleanSource) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) Nonnull(javax.annotation.Nonnull) FDBStoredRecord(com.apple.foundationdb.record.provider.foundationdb.FDBStoredRecord) ValueSource(org.junit.jupiter.params.provider.ValueSource) RecordQueryIndexPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan) IsolationLevel(com.apple.foundationdb.record.IsolationLevel) Logger(org.slf4j.Logger) Tags(com.apple.test.Tags) BaseCursor(com.apple.foundationdb.record.cursors.BaseCursor) SplitHelper(com.apple.foundationdb.record.provider.foundationdb.SplitHelper) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) Message(com.google.protobuf.Message) RecordCursor(com.apple.foundationdb.record.RecordCursor) ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) RecordCursor(com.apple.foundationdb.record.RecordCursor) KeyValueLogMessage(com.apple.foundationdb.record.logging.KeyValueLogMessage) Message(com.google.protobuf.Message) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner) RecordStoreState(com.apple.foundationdb.record.RecordStoreState) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) BooleanSource(com.apple.test.BooleanSource)

Example 34 with RecordQueryPlanner

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

the class FDBAndQueryToIntersectionTest method intersectionVersusRange.

/**
 * Verify that very complex AND clauses are implemented as combinations of range and index scans.
 * The possible plans are an index scan for one field or an intersection for the other, in each case with the other
 * condition as a filter. This checks that the intersection is only preferred when it accomplishes more.
 */
@DualPlannerTest
public void intersectionVersusRange() throws Exception {
    try (FDBRecordContext context = openContext()) {
        openSimpleRecordStore(context, metaData -> {
            metaData.addIndex("MySimpleRecord", "num_value_2");
            metaData.removeIndex("MySimpleRecord$num_value_3_indexed");
            metaData.addIndex("MySimpleRecord", new Index("index_2_3", "num_value_2", "num_value_3_indexed"));
        });
    }
    RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.and(Query.field("str_value_indexed").equalsValue("even"), Query.field("num_value_unique").equalsValue(0), Query.field("num_value_2").equalsValue(1), Query.field("num_value_3_indexed").greaterThanOrEquals(2), Query.field("num_value_3_indexed").lessThanOrEquals(3))).build();
    // Index(index_2_3 [[1, 2],[1, 3]]) | And([str_value_indexed EQUALS even, num_value_unique EQUALS 0])
    RecordQueryPlan plan = planner.plan(query);
    assertThat("should have range scan in " + plan, plan, descendant(indexScan("index_2_3")));
    assertFalse(plan.hasRecordScan(), "should not use record scan");
    if (planner instanceof RecordQueryPlanner) {
        assertMatchesExactly(plan, selfOrDescendantPlans(indexPlan().where(RecordQueryPlanMatchers.indexName("index_2_3"))));
        assertEquals(2140693065, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(-1517851081, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(1716318889, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    } else {
        assertMatchesExactly(plan, predicatesFilterPlan(indexPlan().where(RecordQueryPlanMatchers.indexName("index_2_3")).and(scanComparisons(range("[[1, 2],[1, 3]]")))).where(predicates(valuePredicate(fieldValue("str_value_indexed"), new Comparisons.SimpleComparison(Comparisons.Type.EQUALS, "even")), valuePredicate(fieldValue("num_value_unique"), new Comparisons.SimpleComparison(Comparisons.Type.EQUALS, 0)))));
        assertEquals(-476608798, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(-119924960, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(409745570, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) Index(com.apple.foundationdb.record.metadata.Index) RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner) RecordQuery(com.apple.foundationdb.record.query.RecordQuery)

Example 35 with RecordQueryPlanner

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

the class OnlineIndexerTest method openContext.

FDBRecordContext openContext(boolean checked) {
    FDBRecordContext context = fdb.openContext();
    FDBRecordStore.Builder builder = FDBRecordStore.newBuilder().setMetaDataProvider(metaData).setContext(context).setSubspace(subspace);
    if (checked) {
        recordStore = builder.createOrOpen(FDBRecordStoreBase.StoreExistenceCheck.NONE);
    } else {
        recordStore = builder.uncheckedOpen();
    }
    metaData = recordStore.getRecordMetaData();
    planner = new RecordQueryPlanner(metaData, recordStore.getRecordStoreState(), recordStore.getTimer());
    return context;
}
Also used : RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner)

Aggregations

RecordQueryPlanner (com.apple.foundationdb.record.query.plan.RecordQueryPlanner)71 RecordQuery (com.apple.foundationdb.record.query.RecordQuery)65 RecordQueryPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan)65 FDBRecordContext (com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext)58 FDBQueriedRecord (com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord)48 Message (com.google.protobuf.Message)47 Test (org.junit.jupiter.api.Test)37 Query (com.apple.foundationdb.record.query.expressions.Query)36 Tags (com.apple.test.Tags)36 MatcherAssert.assertThat (org.hamcrest.MatcherAssert.assertThat)36 Assertions.assertEquals (org.junit.jupiter.api.Assertions.assertEquals)36 Tag (org.junit.jupiter.api.Tag)36 PlanHashable (com.apple.foundationdb.record.PlanHashable)35 Index (com.apple.foundationdb.record.metadata.Index)35 Expressions.field (com.apple.foundationdb.record.metadata.Key.Expressions.field)35 Assertions.assertTrue (org.junit.jupiter.api.Assertions.assertTrue)35 QueryComponent (com.apple.foundationdb.record.query.expressions.QueryComponent)33 Collections (java.util.Collections)33 Assertions.assertFalse (org.junit.jupiter.api.Assertions.assertFalse)33 Key (com.apple.foundationdb.record.metadata.Key)32