Search in sources :

Example 6 with BooleanSource

use of com.apple.test.BooleanSource in project fdb-record-layer by FoundationDB.

the class FDBAndQueryToIntersectionTest method sortedIntersectionBounded.

/**
 * Verify that a query with a sort by primary key and AND clause (with complex limits) is implemented as an
 * intersection of index scans, when the primary key is bounded.
 */
@ParameterizedTest
@BooleanSource
public void sortedIntersectionBounded(boolean shouldDeferFetch) throws Exception {
    RecordMetaDataHook hook = sortingShapesHook();
    setupEnumShapes(hook);
    RecordQuery query = RecordQuery.newBuilder().setRecordType("MyShapeRecord").setFilter(Query.and(Query.field("shape").equalsValue(TestRecordsEnumProto.MyShapeRecord.Shape.CIRCLE), Query.field("color").equalsValue(TestRecordsEnumProto.MyShapeRecord.Color.RED), Query.field("rec_no").greaterThanOrEquals(2), Query.field("rec_no").lessThanOrEquals(11))).setSort(field("rec_no")).build();
    setDeferFetchAfterUnionAndIntersection(shouldDeferFetch);
    // Fetch(Covering(Index(color [[10, 2],[10, 11]]) -> [color: KEY[0], rec_name: KEY[2], rec_no: KEY[1]]) ∩ Covering(Index(shape [[200, 2],[200, 11]]) -> [rec_name: KEY[2], rec_no: KEY[1], shape: KEY[0]]))
    // Fetch(Covering(Index(color [[10, 2],[10, 11]]) -> [color: KEY[0], rec_name: KEY[2], rec_no: KEY[1]]) ∩ Covering(Index(shape [[200, 2],[200, 11]]) -> [rec_name: KEY[2], rec_no: KEY[1], shape: KEY[0]]))
    RecordQueryPlan plan = planner.plan(query);
    if (shouldDeferFetch) {
        assertThat(plan, fetch(intersection(coveringIndexScan(indexScan(allOf(indexName("color"), bounds(hasTupleString("[[10, 2],[10, 11]]"))))), coveringIndexScan(indexScan(allOf(indexName("shape"), bounds(hasTupleString("[[200, 2],[200, 11]]"))))))));
        assertEquals(1992249868, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(625673791, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(-1309396162, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    } else {
        assertThat(plan, intersection(indexScan(allOf(indexName("color"), bounds(hasTupleString("[[10, 2],[10, 11]]")))), indexScan(allOf(indexName("shape"), bounds(hasTupleString("[[200, 2],[200, 11]]"))))));
        assertEquals(-942526391, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(-1527867032, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(832030311, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    }
    try (FDBRecordContext context = openContext()) {
        openEnumRecordStore(context, hook);
        int i = 0;
        try (RecordCursorIterator<FDBQueriedRecord<Message>> cursor = recordStore.executeQuery(plan).asIterator()) {
            while (cursor.hasNext()) {
                FDBQueriedRecord<Message> rec = cursor.next();
                TestRecordsEnumProto.MyShapeRecord.Builder shapeRec = TestRecordsEnumProto.MyShapeRecord.newBuilder();
                shapeRec.mergeFrom(rec.getRecord());
                assertThat(shapeRec.getRecName(), anyOf(is("SMALL-RED-CIRCLE"), is("MEDIUM-RED-CIRCLE")));
                assertThat(shapeRec.getShape(), equalTo(TestRecordsEnumProto.MyShapeRecord.Shape.CIRCLE));
                assertThat(shapeRec.getColor(), equalTo(TestRecordsEnumProto.MyShapeRecord.Color.RED));
                assertThat(shapeRec.getRecNo(), allOf(greaterThanOrEqualTo(2), lessThanOrEqualTo(11)));
                i++;
            }
        }
        assertEquals(2, i);
        assertDiscardedAtMost(4, context);
        if (shouldDeferFetch) {
            assertLoadRecord(2, 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) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) BooleanSource(com.apple.test.BooleanSource)

Example 7 with BooleanSource

use of com.apple.test.BooleanSource in project fdb-record-layer by FoundationDB.

the class FDBAndQueryToIntersectionTest method sortedIntersectionUnbounded.

/**
 * Verify that a query with a sort by primary key and AND clause is implemented as an intersection of index scans,
 * when the primary key is unbounded.
 */
@ParameterizedTest
@BooleanSource
public void sortedIntersectionUnbounded(boolean shouldDeferFetch) throws Exception {
    RecordMetaDataHook hook = sortingShapesHook();
    setupEnumShapes(hook);
    RecordQuery query = RecordQuery.newBuilder().setRecordType("MyShapeRecord").setFilter(Query.and(Query.field("shape").equalsValue(TestRecordsEnumProto.MyShapeRecord.Shape.CIRCLE), Query.field("color").equalsValue(TestRecordsEnumProto.MyShapeRecord.Color.RED))).setSort(field("rec_no")).build();
    setDeferFetchAfterUnionAndIntersection(shouldDeferFetch);
    // Fetch(Covering(Index(color [[10],[10]]) -> [color: KEY[0], rec_name: KEY[2], rec_no: KEY[1]]) ∩ Covering(Index(shape [[200],[200]]) -> [rec_name: KEY[2], rec_no: KEY[1], shape: KEY[0]]))
    RecordQueryPlan plan = planner.plan(query);
    if (shouldDeferFetch) {
        assertThat(plan, fetch(intersection(coveringIndexScan(indexScan(allOf(indexName("color"), bounds(hasTupleString("[[10],[10]]"))))), coveringIndexScan(indexScan(allOf(indexName("shape"), bounds(hasTupleString("[[200],[200]]"))))))));
        assertEquals(-2072158516, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(-1707812033, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(1828796254, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    } else {
        assertThat(plan, intersection(indexScan(allOf(indexName("color"), bounds(hasTupleString("[[10],[10]]")))), indexScan(allOf(indexName("shape"), bounds(hasTupleString("[[200],[200]]"))))));
        assertEquals(-296022647, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(433614440, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(-324744569, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    }
    try (FDBRecordContext context = openContext()) {
        openEnumRecordStore(context, hook);
        int i = 0;
        try (RecordCursorIterator<FDBQueriedRecord<Message>> cursor = recordStore.executeQuery(plan).asIterator()) {
            while (cursor.hasNext()) {
                FDBQueriedRecord<Message> rec = cursor.next();
                TestRecordsEnumProto.MyShapeRecord.Builder shapeRec = TestRecordsEnumProto.MyShapeRecord.newBuilder();
                shapeRec.mergeFrom(rec.getRecord());
                assertThat(shapeRec.getRecName(), endsWith("-RED-CIRCLE"));
                assertThat(shapeRec.getShape(), equalTo(TestRecordsEnumProto.MyShapeRecord.Shape.CIRCLE));
                assertThat(shapeRec.getColor(), equalTo(TestRecordsEnumProto.MyShapeRecord.Color.RED));
                i++;
            }
        }
        assertEquals(3, i);
        assertDiscardedAtMost(10, context);
        if (shouldDeferFetch) {
            assertLoadRecord(3, 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) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) BooleanSource(com.apple.test.BooleanSource)

Example 8 with BooleanSource

use of com.apple.test.BooleanSource in project fdb-record-layer by FoundationDB.

the class FDBOrQueryToUnionTest method testOrQueryPlanEquals.

/**
 * Verify that queries with an OR of equality predicates on the same field are implemented using a union of indexes.
 */
@DualPlannerTest
@ParameterizedTest
@BooleanSource
void testOrQueryPlanEquals(boolean shouldDeferFetch) throws Exception {
    RecordMetaDataHook hook = complexQuerySetupHook();
    complexQuerySetup(hook);
    RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.or(Query.field("num_value_3_indexed").equalsValue(1), Query.field("num_value_3_indexed").equalsValue(2), Query.field("num_value_3_indexed").equalsValue(4))).build();
    setDeferFetchAfterUnionAndIntersection(shouldDeferFetch);
    RecordQueryPlan plan = planner.plan(query);
    RecordQuery query2 = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.or(Query.field("num_value_3_indexed").equalsValue(4), Query.field("num_value_3_indexed").equalsValue(2), Query.field("num_value_3_indexed").equalsValue(1))).build();
    setDeferFetchAfterUnionAndIntersection(shouldDeferFetch);
    RecordQueryPlan plan2 = planner.plan(query2);
    // plan is physically different but returns the same result
    assertThat(plan.hashCode(), not(equalTo(plan2.hashCode())));
    assertThat(plan, not(equalTo(plan2)));
    assertTrue(plan.semanticEquals(plan2));
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) BooleanSource(com.apple.test.BooleanSource)

Example 9 with BooleanSource

use of com.apple.test.BooleanSource in project fdb-record-layer by FoundationDB.

the class FDBOrQueryToUnionTest method testOrQueryChildReordering.

@DualPlannerTest
@ParameterizedTest
@BooleanSource
void testOrQueryChildReordering(boolean shouldPushFetchAboveUnionToIntersection) throws Exception {
    RecordMetaDataHook hook = complexQuerySetupHook();
    complexQuerySetup(hook);
    RecordQuery query1 = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.or(Query.field("str_value_indexed").equalsValue("odd"), Query.field("num_value_3_indexed").equalsValue(0))).setSort(null, true).setRemoveDuplicates(true).build();
    setDeferFetchAfterUnionAndIntersection(shouldPushFetchAboveUnionToIntersection);
    // Index(MySimpleRecord$str_value_indexed [[odd],[odd]] REVERSE) ∪ Index(MySimpleRecord$num_value_3_indexed [[0],[0]] REVERSE)
    // Fetch(Covering(Index(MySimpleRecord$str_value_indexed [[odd],[odd]] REVERSE) -> [rec_no: KEY[1], str_value_indexed: KEY[0]]) ∪ Covering(Index(MySimpleRecord$num_value_3_indexed [[0],[0]] REVERSE) -> [num_value_3_indexed: KEY[0], rec_no: KEY[1]]))
    RecordQueryPlan plan1 = planner.plan(query1);
    RecordQuery query2 = query1.toBuilder().setFilter(Query.or(Query.field("num_value_3_indexed").equalsValue(0), Query.field("str_value_indexed").equalsValue("odd"))).build();
    // Index(MySimpleRecord$num_value_3_indexed [[0],[0]] REVERSE) ∪ Index(MySimpleRecord$str_value_indexed [[odd],[odd]] REVERSE)
    // Fetch(Covering(Index(MySimpleRecord$num_value_3_indexed [[0],[0]] REVERSE) -> [num_value_3_indexed: KEY[0], rec_no: KEY[1]]) ∪ Covering(Index(MySimpleRecord$str_value_indexed [[odd],[odd]] REVERSE) -> [rec_no: KEY[1], str_value_indexed: KEY[0]]))
    RecordQueryPlan plan2 = planner.plan(query2);
    assertNotEquals(plan1.hashCode(), plan2.hashCode());
    assertNotEquals(plan1, plan2);
    assertEquals(plan1.semanticHashCode(), plan2.semanticHashCode());
    assertTrue(plan1.semanticEquals(plan2));
    if (shouldPushFetchAboveUnionToIntersection || planner instanceof CascadesPlanner) {
        assertEquals(-1584186103, plan1.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(-357068519, plan1.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(964023338, plan1.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        assertEquals(-91575587, plan2.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(-1919956247, plan2.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(78160824, plan2.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    } else {
        assertEquals(-2067012572, plan1.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(1784357954, plan1.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(-1189517485, plan1.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        assertEquals(600484528, plan2.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(221470226, plan2.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(-2075379999, plan2.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    }
    Set<Long> seen = new HashSet<>();
    try (FDBRecordContext context = openContext()) {
        openSimpleRecordStore(context, hook);
        int i = 0;
        try (RecordCursorIterator<FDBQueriedRecord<Message>> cursor1 = recordStore.executeQuery(plan1).asIterator();
            RecordCursorIterator<FDBQueriedRecord<Message>> cursor2 = recordStore.executeQuery(plan2).asIterator()) {
            while (cursor1.hasNext()) {
                assertThat(cursor2.hasNext(), is(true));
                FDBQueriedRecord<Message> rec1 = cursor1.next();
                FDBQueriedRecord<Message> rec2 = cursor2.next();
                assertEquals(Objects.requireNonNull(rec1).getRecord(), Objects.requireNonNull(rec2).getRecord());
                TestRecords1Proto.MySimpleRecord.Builder myrec = TestRecords1Proto.MySimpleRecord.newBuilder();
                myrec.mergeFrom(rec1.getRecord());
                assertTrue(myrec.getStrValueIndexed().equals("odd") || myrec.getNumValue3Indexed() == 0, "condition on record not met");
                assertFalse(seen.contains(myrec.getRecNo()), "Already saw a record!");
                seen.add(myrec.getRecNo());
                i++;
            }
            assertThat(cursor2.hasNext(), is(false));
        }
        assertEquals(60, i);
        assertDiscardedAtMost(20, context);
        if (shouldPushFetchAboveUnionToIntersection) {
            assertLoadRecord(120, context);
        }
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) Message(com.google.protobuf.Message) FDBQueriedRecord(com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) CascadesPlanner(com.apple.foundationdb.record.query.plan.temp.CascadesPlanner) HashSet(java.util.HashSet) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) BooleanSource(com.apple.test.BooleanSource)

Example 10 with BooleanSource

use of com.apple.test.BooleanSource in project fdb-record-layer by FoundationDB.

the class FDBOrQueryToUnionTest method testComplexQuery6.

/**
 * Verify that an OR of compatibly-ordered (up to reversal) indexed fields can be implemented as a union.
 */
@DualPlannerTest
@ParameterizedTest
@BooleanSource
void testComplexQuery6(boolean shouldDeferFetch) throws Exception {
    RecordMetaDataHook hook = complexQuerySetupHook();
    complexQuerySetup(hook);
    RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.or(Query.field("str_value_indexed").equalsValue("odd"), Query.field("num_value_3_indexed").equalsValue(0))).setSort(null, true).setRemoveDuplicates(true).build();
    setDeferFetchAfterUnionAndIntersection(shouldDeferFetch);
    // Index(MySimpleRecord$str_value_indexed [[odd],[odd]] REVERSE) ∪ Index(MySimpleRecord$num_value_3_indexed [[0],[0]] REVERSE)
    // Fetch(Covering(Index(MySimpleRecord$str_value_indexed [[odd],[odd]] REVERSE) -> [rec_no: KEY[1], str_value_indexed: KEY[0]]) ∪ Covering(Index(MySimpleRecord$num_value_3_indexed [[0],[0]] REVERSE) -> [num_value_3_indexed: KEY[0], rec_no: KEY[1]]))
    RecordQueryPlan plan = planner.plan(query);
    if (shouldDeferFetch || planner instanceof CascadesPlanner) {
        final BindingMatcher<? extends RecordQueryPlan> planMatcher = fetchFromPartialRecordPlan(unionPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$str_value_indexed")).and(scanComparisons(range("[[odd],[odd]]"))))), coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$num_value_3_indexed")).and(scanComparisons(range("[[0],[0]]")))))));
        assertMatchesExactly(plan, planMatcher);
        assertTrue(plan.getQueryPlanChildren().stream().allMatch(QueryPlan::isReverse));
        assertEquals(-1584186103, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(-357068519, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(964023338, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    } else {
        final BindingMatcher<? extends RecordQueryPlan> planMatcher = unionPlan(indexPlan().where(indexName("MySimpleRecord$str_value_indexed")).and(scanComparisons(range("[[odd],[odd]]"))), indexPlan().where(indexName("MySimpleRecord$num_value_3_indexed")).and(scanComparisons(range("[[0],[0]]"))));
        assertMatchesExactly(plan, planMatcher);
        assertTrue(plan.getQueryPlanChildren().stream().allMatch(QueryPlan::isReverse));
        assertEquals(-2067012572, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(1784357954, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(-1189517485, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    }
    Set<Long> seen = new HashSet<>();
    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());
                assertTrue(myrec.getStrValueIndexed().equals("odd") || myrec.getNumValue3Indexed() == 0, "condition on record not met");
                assertFalse(seen.contains(myrec.getRecNo()), "Already saw a record!");
                seen.add(myrec.getRecNo());
                i++;
            }
        }
        assertEquals(60, i);
        assertDiscardedAtMost(10, context);
        if (shouldDeferFetch) {
            assertLoadRecord(60, context);
        }
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) Message(com.google.protobuf.Message) FDBQueriedRecord(com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) CascadesPlanner(com.apple.foundationdb.record.query.plan.temp.CascadesPlanner) HashSet(java.util.HashSet) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) BooleanSource(com.apple.test.BooleanSource)

Aggregations

BooleanSource (com.apple.test.BooleanSource)57 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)57 RecordQuery (com.apple.foundationdb.record.query.RecordQuery)37 RecordQueryPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan)37 FDBRecordContext (com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext)36 FDBQueriedRecord (com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord)24 Message (com.google.protobuf.Message)23 QueryComponent (com.apple.foundationdb.record.query.expressions.QueryComponent)14 RecordMetaDataBuilder (com.apple.foundationdb.record.RecordMetaDataBuilder)10 LuceneQueryComponent (com.apple.foundationdb.record.query.expressions.LuceneQueryComponent)10 RecordMetaData (com.apple.foundationdb.record.RecordMetaData)9 CascadesPlanner (com.apple.foundationdb.record.query.plan.temp.CascadesPlanner)9 MatcherAssert.assertThat (org.hamcrest.MatcherAssert.assertThat)9 Assertions.assertEquals (org.junit.jupiter.api.Assertions.assertEquals)9 Assertions.assertTrue (org.junit.jupiter.api.Assertions.assertTrue)9 Test (org.junit.jupiter.api.Test)9 TestRecords1Proto (com.apple.foundationdb.record.TestRecords1Proto)7 RecordCursorIterator (com.apple.foundationdb.record.RecordCursorIterator)6 Index (com.apple.foundationdb.record.metadata.Index)6 Tuple (com.apple.foundationdb.tuple.Tuple)6