Search in sources :

Example 51 with BooleanSource

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

the class FDBAndQueryToIntersectionTest method testComplexQueryAndWithMultipleChildren.

/**
 * Verify that a complex query with an AND of more than two fields with compatibly ordered indexes generates an intersection plan.
 */
@ParameterizedTest
@BooleanSource
public void testComplexQueryAndWithMultipleChildren(boolean shouldDeferFetch) throws Exception {
    // Add an additional index to use for additional filtering
    RecordMetaDataHook hook = (metaDataBuilder) -> {
        complexQuerySetupHook().apply(metaDataBuilder);
        metaDataBuilder.removeIndex("multi_index");
        metaDataBuilder.addIndex("MySimpleRecord", "MySimpleRecord$num_value_2", field("num_value_2"));
    };
    complexQuerySetup(hook);
    RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.and(Query.field("str_value_indexed").equalsValue("odd"), Query.field("num_value_3_indexed").equalsValue(2), Query.field("num_value_2").equalsValue(1))).build();
    setDeferFetchAfterUnionAndIntersection(shouldDeferFetch);
    // Index(MySimpleRecord$str_value_indexed [[odd],[odd]]) ∩ Index(MySimpleRecord$num_value_3_indexed [[2],[2]]) ∩ Index(MySimpleRecord$num_value_2 [[1],[1]])
    // Fetch(Covering(Index(MySimpleRecord$str_value_indexed [[odd],[odd]]) -> [rec_no: KEY[1], str_value_indexed: KEY[0]]) ∩ Covering(Index(MySimpleRecord$num_value_3_indexed [[2],[2]]) -> [num_value_3_indexed: KEY[0], rec_no: KEY[1]]) ∩ Covering(Index(MySimpleRecord$num_value_2 [[1],[1]]) -> [num_value_2: KEY[0], rec_no: KEY[1]]))
    RecordQueryPlan plan = planner.plan(query);
    if (shouldDeferFetch) {
        assertThat(plan, fetch(intersection(Arrays.asList(coveringIndexScan(indexScan(allOf(indexName("MySimpleRecord$str_value_indexed"), bounds(hasTupleString("[[odd],[odd]]"))))), coveringIndexScan(indexScan(allOf(indexName("MySimpleRecord$num_value_3_indexed"), bounds(hasTupleString("[[2],[2]]"))))), coveringIndexScan(indexScan(allOf(indexName("MySimpleRecord$num_value_2"), bounds(hasTupleString("[[1],[1]]")))))), equalTo(field("rec_no")))));
        assertEquals(946461036, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(-625341018, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(116741660, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    } else {
        assertThat(plan, intersection(Arrays.asList(indexScan(allOf(indexName("MySimpleRecord$str_value_indexed"), bounds(hasTupleString("[[odd],[odd]]")))), indexScan(allOf(indexName("MySimpleRecord$num_value_3_indexed"), bounds(hasTupleString("[[2],[2]]")))), indexScan(allOf(indexName("MySimpleRecord$num_value_2"), bounds(hasTupleString("[[1],[1]]"))))), equalTo(field("rec_no"))));
        assertEquals(-478358039, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(1448156435, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(-2104728183, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    }
    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(rec.getRecord());
                assertEquals("odd", myrec.getStrValueIndexed());
                assertEquals(2, myrec.getNumValue3Indexed());
                assertEquals(1, myrec.getNumValue2());
                i++;
            }
        }
        assertEquals(4, i);
        assertDiscardedAtMost(90, context);
        if (shouldDeferFetch) {
            assertLoadRecord(4, context);
        }
    }
}
Also used : Arrays(java.util.Arrays) RecordQueryIntersectionPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryIntersectionPlan) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordQueryPlanMatchers.predicates(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.predicates) PlanMatchers.bounds(com.apple.foundationdb.record.query.plan.match.PlanMatchers.bounds) RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner) Assertions.assertFalse(org.junit.jupiter.api.Assertions.assertFalse) Expressions.concatenateFields(com.apple.foundationdb.record.metadata.Key.Expressions.concatenateFields) Expressions.concat(com.apple.foundationdb.record.metadata.Key.Expressions.concat) Tag(org.junit.jupiter.api.Tag) PlanMatchers.coveringIndexScan(com.apple.foundationdb.record.query.plan.match.PlanMatchers.coveringIndexScan) RecordQueryPlanMatchers.selfOrDescendantPlans(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.selfOrDescendantPlans) Query(com.apple.foundationdb.record.query.expressions.Query) TestRecords1Proto(com.apple.foundationdb.record.TestRecords1Proto) PlanMatchers.intersection(com.apple.foundationdb.record.query.plan.match.PlanMatchers.intersection) Matchers.allOf(org.hamcrest.Matchers.allOf) Matchers.lessThanOrEqualTo(org.hamcrest.Matchers.lessThanOrEqualTo) Test(org.junit.jupiter.api.Test) PlanMatchers.hasTupleString(com.apple.foundationdb.record.query.plan.match.PlanMatchers.hasTupleString) ScanComparisons.range(com.apple.foundationdb.record.query.plan.ScanComparisons.range) PlanMatchers.indexName(com.apple.foundationdb.record.query.plan.match.PlanMatchers.indexName) FDBQueriedRecord(com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord) PlanMatchers.hasNoDescendant(com.apple.foundationdb.record.query.plan.match.PlanMatchers.hasNoDescendant) Matchers.equalTo(org.hamcrest.Matchers.equalTo) Assertions.assertTrue(org.junit.jupiter.api.Assertions.assertTrue) TestRecordsEnumProto(com.apple.foundationdb.record.TestRecordsEnumProto) IndexTypes(com.apple.foundationdb.record.metadata.IndexTypes) Matchers.is(org.hamcrest.Matchers.is) Matchers.anyOf(org.hamcrest.Matchers.anyOf) RecordQueryPlanMatchers(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers) RecordQueryPlanMatchers.predicatesFilterPlan(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.predicatesFilterPlan) Matchers.endsWith(org.hamcrest.Matchers.endsWith) RecordQueryPlannerSubstitutionVisitor(com.apple.foundationdb.record.query.plan.visitor.RecordQueryPlannerSubstitutionVisitor) PlanMatchers.fetch(com.apple.foundationdb.record.query.plan.match.PlanMatchers.fetch) IndexScanParameters(com.apple.foundationdb.record.provider.foundationdb.IndexScanParameters) PlanMatchers.indexScan(com.apple.foundationdb.record.query.plan.match.PlanMatchers.indexScan) QueryPlanner(com.apple.foundationdb.record.query.plan.QueryPlanner) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) ExecuteProperties.newBuilder(com.apple.foundationdb.record.ExecuteProperties.newBuilder) PlanHashable(com.apple.foundationdb.record.PlanHashable) PlanMatchers.filter(com.apple.foundationdb.record.query.plan.match.PlanMatchers.filter) TestHelpers.assertDiscardedExactly(com.apple.foundationdb.record.TestHelpers.assertDiscardedExactly) ImmutableList(com.google.common.collect.ImmutableList) RecordCursorIterator(com.apple.foundationdb.record.RecordCursorIterator) IndexScanComparisons(com.apple.foundationdb.record.provider.foundationdb.IndexScanComparisons) BooleanSource(com.apple.test.BooleanSource) RecordQueryPlanMatchers.scanComparisons(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.scanComparisons) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) Expressions.field(com.apple.foundationdb.record.metadata.Key.Expressions.field) RecordQueryIndexPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryIndexPlan) Matchers.greaterThanOrEqualTo(org.hamcrest.Matchers.greaterThanOrEqualTo) RecordTypeBuilder(com.apple.foundationdb.record.metadata.RecordTypeBuilder) Tags(com.apple.test.Tags) TestHelpers.assertLoadRecord(com.apple.foundationdb.record.TestHelpers.assertLoadRecord) QueryPredicateMatchers.valuePredicate(com.apple.foundationdb.record.query.plan.temp.matchers.QueryPredicateMatchers.valuePredicate) PlannableIndexTypes(com.apple.foundationdb.record.query.plan.PlannableIndexTypes) Comparisons(com.apple.foundationdb.record.query.expressions.Comparisons) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) Index(com.apple.foundationdb.record.metadata.Index) RecordQueryPlanMatchers.indexPlan(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.indexPlan) TestHelpers.assertDiscardedAtMost(com.apple.foundationdb.record.TestHelpers.assertDiscardedAtMost) Message(com.google.protobuf.Message) PlanMatchers.descendant(com.apple.foundationdb.record.query.plan.match.PlanMatchers.descendant) RealAnythingMatcher.anything(com.apple.foundationdb.record.TestHelpers.RealAnythingMatcher.anything) ValueMatchers.fieldValue(com.apple.foundationdb.record.query.plan.temp.matchers.ValueMatchers.fieldValue) 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 52 with BooleanSource

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

the class FDBRepeatedFieldQueryTest method sortRepeated.

/**
 * Verify that sorts on repeated fields are implemented with fanout indexes.
 * Verify that they include distinctness filters and value filters where necessary.
 */
@ParameterizedTest
@BooleanSource
public void sortRepeated(final boolean shouldOptimizeForIndexFilters) throws Exception {
    try (FDBRecordContext context = openContext()) {
        openNestedRecordStore(context);
        TestRecords4Proto.RestaurantReviewer reviewer = TestRecords4Proto.RestaurantReviewer.newBuilder().setId(1L).setName("Javert").setEmail("inspecteur@policier.fr").setStats(TestRecords4Proto.ReviewerStats.newBuilder().setStartDate(100L).setHometown("Toulon")).build();
        recordStore.saveRecord(reviewer);
        reviewer = TestRecords4Proto.RestaurantReviewer.newBuilder().setId(2L).setName("M. le Maire").setStats(TestRecords4Proto.ReviewerStats.newBuilder().setStartDate(120L).setHometown("Montreuil-sur-mer")).build();
        recordStore.saveRecord(reviewer);
        TestRecords4Proto.RestaurantRecord restaurant = TestRecords4Proto.RestaurantRecord.newBuilder().setRestNo(1000L).setName("Chez Thénardier").addReviews(TestRecords4Proto.RestaurantReview.newBuilder().setReviewer(1L).setRating(100)).addReviews(TestRecords4Proto.RestaurantReview.newBuilder().setReviewer(2L).setRating(0)).addTags(TestRecords4Proto.RestaurantTag.newBuilder().setValue("l'atmosphère").setWeight(10)).addTags(TestRecords4Proto.RestaurantTag.newBuilder().setValue("les aliments").setWeight(70)).addCustomer("jean").addCustomer("fantine").addCustomer("cosette").addCustomer("éponine").build();
        recordStore.saveRecord(restaurant);
        restaurant = TestRecords4Proto.RestaurantRecord.newBuilder().setRestNo(1001L).setName("ABC").addReviews(TestRecords4Proto.RestaurantReview.newBuilder().setReviewer(1L).setRating(34)).addReviews(TestRecords4Proto.RestaurantReview.newBuilder().setReviewer(2L).setRating(110)).addTags(TestRecords4Proto.RestaurantTag.newBuilder().setValue("l'atmosphère").setWeight(40)).addTags(TestRecords4Proto.RestaurantTag.newBuilder().setValue("les aliments").setWeight(20)).addCustomer("gavroche").addCustomer("enjolras").addCustomer("éponine").build();
        recordStore.saveRecord(restaurant);
        commit(context);
    }
    {
        RecordQuery.Builder builder = RecordQuery.newBuilder().setRecordType("RestaurantRecord").setSort(field("reviews", FanType.FanOut).nest("rating"));
        RecordQuery query = builder.setRemoveDuplicates(false).build();
        // Index(review_rating <,>)
        RecordQueryPlan plan = planner.plan(query);
        assertThat(plan, indexScan(allOf(indexName("review_rating"), unbounded())));
        assertEquals(406416366, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(1919610161, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(1919610161, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        assertEquals(Arrays.asList(1000L, 1001L, 1000L, 1001L), fetchResultValues(plan, TestRecords4Proto.RestaurantRecord.REST_NO_FIELD_NUMBER, this::openNestedRecordStore, TestHelpers::assertDiscardedNone));
        query = builder.setRemoveDuplicates(true).build();
        // Index(review_rating <,>) | UnorderedPrimaryKeyDistinct()
        plan = planner.plan(query);
        assertThat(plan, primaryKeyDistinct(indexScan(allOf(indexName("review_rating"), unbounded()))));
        assertEquals(406416367, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(1124430507, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(1124430507, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        assertEquals(Arrays.asList(1000L, 1001L), fetchResultValues(plan, TestRecords4Proto.RestaurantRecord.REST_NO_FIELD_NUMBER, this::openNestedRecordStore, context -> assertDiscardedAtMost(2, context)));
    }
    {
        RecordQuery.Builder builder = RecordQuery.newBuilder().setRecordType("RestaurantRecord").setSort(field("reviews", FanType.FanOut).nest("rating"), true);
        RecordQuery query = builder.setRemoveDuplicates(false).build();
        // Index(review_rating <,> REVERSE)
        RecordQueryPlan plan = planner.plan(query);
        assertThat(plan, indexScan(allOf(indexName("review_rating"), unbounded())));
        assertTrue(plan.isReverse());
        assertEquals(406416367, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(1919609975, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(1919609975, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        assertEquals(Arrays.asList(1001L, 1000L, 1001L, 1000L), fetchResultValues(plan, TestRecords4Proto.RestaurantRecord.REST_NO_FIELD_NUMBER, this::openNestedRecordStore, TestHelpers::assertDiscardedNone));
        query = builder.setRemoveDuplicates(true).build();
        // Index(review_rating <,> REVERSE) | UnorderedPrimaryKeyDistinct()
        plan = planner.plan(query);
        assertThat(plan, primaryKeyDistinct(indexScan(allOf(indexName("review_rating"), unbounded()))));
        assertTrue(plan.isReverse());
        assertEquals(406416368, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(1124430321, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(1124430321, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        assertEquals(Arrays.asList(1001L, 1000L), fetchResultValues(plan, TestRecords4Proto.RestaurantRecord.REST_NO_FIELD_NUMBER, this::openNestedRecordStore, context -> assertDiscardedAtMost(2, context)));
    }
    {
        RecordQuery.Builder builder = RecordQuery.newBuilder().setRecordType("RestaurantRecord").setSort(field("reviews", FanType.FanOut).nest("rating")).setFilter(Query.field("name").greaterThan("A"));
        RecordQuery query = builder.setRemoveDuplicates(false).build();
        // Index(review_rating <,>) | name GREATER_THAN A
        RecordQueryPlan plan = planner.plan(query);
        assertThat(plan, filter(query.getFilter(), indexScan(allOf(indexName("review_rating"), unbounded()))));
        assertEquals(1381942688, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(-2104094855, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(-1943284962, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        assertEquals(Arrays.asList(1000L, 1001L, 1000L, 1001L), fetchResultValues(plan, TestRecords4Proto.RestaurantRecord.REST_NO_FIELD_NUMBER, this::openNestedRecordStore, TestHelpers::assertDiscardedNone));
        query = builder.setRemoveDuplicates(true).build();
        // Index(review_rating <,>) | UnorderedPrimaryKeyDistinct() | name GREATER_THAN A
        plan = planner.plan(query);
        assertThat(plan, filter(query.getFilter(), primaryKeyDistinct(indexScan(allOf(indexName("review_rating"), unbounded())))));
        assertEquals(1381942689, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(-984860353, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(-824050460, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        assertEquals(Arrays.asList(1000L, 1001L), fetchResultValues(plan, TestRecords4Proto.RestaurantRecord.REST_NO_FIELD_NUMBER, this::openNestedRecordStore, context -> assertDiscardedAtMost(2, context)));
    }
    {
        setOptimizeForIndexFilters(shouldOptimizeForIndexFilters);
        RecordQuery.Builder builder = RecordQuery.newBuilder().setRecordType("RestaurantRecord").setSort(field("customer", FanType.FanOut)).setFilter(Query.field("name").greaterThan("A"));
        RecordQuery query = builder.setRemoveDuplicates(false).build();
        // Index(customers <,>) | name GREATER_THAN A
        // Fetch(Covering(Index(customers-name <,>) -> [name: KEY[1], rest_no: KEY[2]]) | name GREATER_THAN A)
        RecordQueryPlan plan = planner.plan(query);
        if (shouldOptimizeForIndexFilters) {
            assertThat(plan, fetch(filter(query.getFilter(), coveringIndexScan(indexScan(allOf(indexName("customers-name"), unbounded()))))));
            assertEquals(-505715770, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
            assertEquals(-378020523, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
            assertEquals(-217210630, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
            assertEquals(Arrays.asList(1000L, 1001L, 1000L, 1001L, 1000L, 1001L, 1000L), fetchResultValues(plan, TestRecords4Proto.RestaurantRecord.REST_NO_FIELD_NUMBER, this::openNestedRecordStore, TestHelpers::assertDiscardedNone));
        } else {
            assertThat(plan, filter(query.getFilter(), indexScan(allOf(indexName("customers"), unbounded()))));
            assertEquals(1833106833, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
            assertEquals(201074216, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
            assertEquals(361884109, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
            assertEquals(Arrays.asList(1000L, 1001L, 1000L, 1001L, 1000L, 1000L, 1001L), fetchResultValues(plan, TestRecords4Proto.RestaurantRecord.REST_NO_FIELD_NUMBER, this::openNestedRecordStore, TestHelpers::assertDiscardedNone));
        }
        setOptimizeForIndexFilters(shouldOptimizeForIndexFilters);
        setDeferFetchAfterUnionAndIntersection(true);
        query = builder.setRemoveDuplicates(true).build();
        // Fetch(Covering(Index(customers <,>) -> [rest_no: KEY[1]]) | UnorderedPrimaryKeyDistinct()) | name GREATER_THAN A
        // Fetch(Covering(Index(customers-name <,>) -> [name: KEY[1], rest_no: KEY[2]]) | UnorderedPrimaryKeyDistinct() | name GREATER_THAN A)
        plan = planner.plan(query);
        if (shouldOptimizeForIndexFilters) {
            assertThat(plan, fetch(filter(query.getFilter(), primaryKeyDistinct(coveringIndexScan(indexScan(allOf(indexName("customers-name"), unbounded())))))));
            assertEquals(-505715763, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
            assertEquals(741213979, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
            assertEquals(902023872, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        } else {
            assertThat(plan, filter(query.getFilter(), fetch(primaryKeyDistinct(coveringIndexScan(indexScan(allOf(indexName("customers"), unbounded())))))));
            assertEquals(-1611344673, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
            assertEquals(-484615365, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
            assertEquals(-323805472, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        }
        assertEquals(Arrays.asList(1000L, 1001L), fetchResultValues(plan, TestRecords4Proto.RestaurantRecord.REST_NO_FIELD_NUMBER, this::openNestedRecordStore, context -> assertDiscardedAtMost(5, context)));
    }
    {
        RecordQuery.Builder builder = RecordQuery.newBuilder().setRecordType("RestaurantRecord").setFilter(Query.field("customer").oneOfThem().equalsValue("éponine")).setSort(field("name"));
        RecordQuery query = builder.setRemoveDuplicates(false).build();
        // Index(customers-name [[éponine],[éponine]])
        RecordQueryPlan plan = planner.plan(query);
        assertThat(plan, indexScan(allOf(indexName("customers-name"), bounds(hasTupleString("[[éponine],[éponine]]")))));
        assertEquals(-574773820, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(-1450272556, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(173295350, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        assertEquals(Arrays.asList(1001L, 1000L), fetchResultValues(plan, TestRecords4Proto.RestaurantRecord.REST_NO_FIELD_NUMBER, this::openNestedRecordStore, TestHelpers::assertDiscardedNone));
        query = builder.setRemoveDuplicates(true).build();
        // Index(customers-name [[éponine],[éponine]]) | UnorderedPrimaryKeyDistinct()
        plan = planner.plan(query);
        assertThat(plan, primaryKeyDistinct(indexScan(allOf(indexName("customers-name"), bounds(hasTupleString("[[éponine],[éponine]]"))))));
        assertEquals(-574773819, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(2049515086, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(-621884304, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        assertEquals(Arrays.asList(1001L, 1000L), fetchResultValues(plan, TestRecords4Proto.RestaurantRecord.REST_NO_FIELD_NUMBER, this::openNestedRecordStore, TestHelpers::assertDiscardedNone));
    }
    {
        RecordQuery.Builder builder = RecordQuery.newBuilder().setRecordType("RestaurantRecord").setFilter(Query.field("customer").oneOfThem().equalsValue("gavroche")).setSort(field("name"));
        RecordQuery query = builder.setRemoveDuplicates(false).build();
        // Index(customers-name [[gavroche],[gavroche]])
        RecordQueryPlan plan = planner.plan(query);
        assertThat(plan, indexScan(allOf(indexName("customers-name"), bounds(hasTupleString("[[gavroche],[gavroche]]")))));
        assertEquals(-1720782767, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(-1507776729, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(173295350, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        assertEquals(Collections.singletonList(1001L), fetchResultValues(plan, TestRecords4Proto.RestaurantRecord.REST_NO_FIELD_NUMBER, this::openNestedRecordStore, TestHelpers::assertDiscardedNone));
        query = builder.setRemoveDuplicates(true).build();
        // Index(customers-name [[gavroche],[gavroche]]) | UnorderedPrimaryKeyDistinct()
        plan = planner.plan(query);
        assertThat(plan, primaryKeyDistinct(indexScan(allOf(indexName("customers-name"), bounds(hasTupleString("[[gavroche],[gavroche]]"))))));
        assertEquals(-1720782766, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(1992010913, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(-621884304, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        assertEquals(Collections.singletonList(1001L), fetchResultValues(plan, TestRecords4Proto.RestaurantRecord.REST_NO_FIELD_NUMBER, this::openNestedRecordStore, TestHelpers::assertDiscardedNone));
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) TestRecords4Proto(com.apple.foundationdb.record.TestRecords4Proto) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordMetaDataBuilder(com.apple.foundationdb.record.RecordMetaDataBuilder) TestHelpers(com.apple.foundationdb.record.TestHelpers) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) BooleanSource(com.apple.test.BooleanSource)

Example 53 with BooleanSource

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

the class FDBLuceneQueryTest method delayFetchOnAndOfLuceneAndFieldFilter.

@ParameterizedTest
@BooleanSource
public void delayFetchOnAndOfLuceneAndFieldFilter(boolean shouldDeferFetch) throws Exception {
    initializeFlat();
    try (FDBRecordContext context = openContext()) {
        openRecordStore(context);
        final QueryComponent filter1 = new LuceneQueryComponent("civil blood makes civil hands unclean", Lists.newArrayList());
        // Query for full records
        QueryComponent filter2 = Query.field("doc_id").equalsValue(2L);
        RecordQuery query = RecordQuery.newBuilder().setRecordType(TextIndexTestUtils.SIMPLE_DOC).setFilter(Query.and(filter2, filter1)).build();
        setDeferFetchAfterUnionAndIntersection(shouldDeferFetch);
        RecordQueryPlan plan = planner.plan(query);
        Matcher<RecordQueryPlan> scanMatcher = fetch(filter(filter2, coveringIndexScan(indexScan(allOf(indexScanType(IndexScanType.BY_LUCENE_FULL_TEXT), indexScan("Complex$text_index"), bounds(hasTupleString("[[civil blood makes civil hands unclean],[civil blood makes civil hands unclean]]")))))));
        assertThat(plan, scanMatcher);
        RecordCursor<FDBQueriedRecord<Message>> primaryKeys;
        primaryKeys = recordStore.executeQuery(plan);
        final List<Long> keys = primaryKeys.map(FDBQueriedRecord::getPrimaryKey).map(t -> t.getLong(0)).asList().get();
        assertEquals(ImmutableSet.of(2L), ImmutableSet.copyOf(keys));
        if (shouldDeferFetch) {
            assertLoadRecord(3, context);
        } else {
            assertLoadRecord(4, context);
        }
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) LuceneQueryComponent(com.apple.foundationdb.record.query.expressions.LuceneQueryComponent) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) FDBQueriedRecord(com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) LuceneQueryComponent(com.apple.foundationdb.record.query.expressions.LuceneQueryComponent) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) BooleanSource(com.apple.test.BooleanSource)

Example 54 with BooleanSource

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

the class FDBLuceneQueryTest method delayFetchOnOrOfLuceneFiltersGivesUnion.

@ParameterizedTest
@BooleanSource
public void delayFetchOnOrOfLuceneFiltersGivesUnion(boolean shouldDeferFetch) throws Exception {
    initializeFlat();
    try (FDBRecordContext context = openContext()) {
        openRecordStore(context);
        final QueryComponent filter1 = new LuceneQueryComponent("(civil blood makes civil hands unclean)", Lists.newArrayList("text"), true);
        final QueryComponent filter2 = new LuceneQueryComponent("(was king from 966 to 1016)", Lists.newArrayList());
        // Query for full records
        RecordQuery query = RecordQuery.newBuilder().setRecordType(TextIndexTestUtils.SIMPLE_DOC).setFilter(Query.or(filter1, filter2)).build();
        setDeferFetchAfterUnionAndIntersection(shouldDeferFetch);
        RecordQueryPlan plan = planner.plan(query);
        Matcher<RecordQueryPlan> matcher = union(indexScan(allOf(indexScan("Complex$text_index"), indexScanType(IndexScanType.BY_LUCENE_FULL_TEXT), bounds(hasTupleString("[[(civil blood makes civil hands unclean)],[(civil blood makes civil hands unclean)]]")))), indexScan(allOf(indexScan("Complex$text_index"), indexScanType(IndexScanType.BY_LUCENE_FULL_TEXT), bounds(hasTupleString("[[(was king from 966 to 1016)],[(was king from 966 to 1016)]]")))), equalTo(field("doc_id")));
        if (shouldDeferFetch) {
            matcher = fetch(union(coveringIndexScan(indexScan(allOf(indexScan("Complex$text_index"), indexScanType(IndexScanType.BY_LUCENE_FULL_TEXT), bounds(hasTupleString("[[(civil blood makes civil hands unclean)],[(civil blood makes civil hands unclean)]]"))))), coveringIndexScan(indexScan(allOf(indexScan("Complex$text_index"), indexScanType(IndexScanType.BY_LUCENE_FULL_TEXT), bounds(hasTupleString("[[(was king from 966 to 1016)],[(was king from 966 to 1016)]]"))))), equalTo(field("doc_id"))));
        }
        assertThat(plan, matcher);
        List<Long> primaryKeys = recordStore.executeQuery(plan).map(FDBQueriedRecord::getPrimaryKey).map(t -> t.getLong(0)).asList().get();
        assertEquals(ImmutableSet.of(1L, 2L, 4L), ImmutableSet.copyOf(primaryKeys));
        if (shouldDeferFetch) {
            assertLoadRecord(5, context);
        } else {
            assertLoadRecord(6, context);
        }
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) LuceneQueryComponent(com.apple.foundationdb.record.query.expressions.LuceneQueryComponent) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) LuceneQueryComponent(com.apple.foundationdb.record.query.expressions.LuceneQueryComponent) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) BooleanSource(com.apple.test.BooleanSource)

Example 55 with BooleanSource

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

the class FDBLuceneQueryTest method delayFetchOnAndOfLuceneFilters.

@ParameterizedTest
@BooleanSource
public void delayFetchOnAndOfLuceneFilters(boolean shouldDeferFetch) throws Exception {
    initializeFlat();
    try (FDBRecordContext context = openContext()) {
        openRecordStore(context);
        final QueryComponent filter1 = new LuceneQueryComponent("the continuance", Lists.newArrayList());
        final QueryComponent filter2 = new LuceneQueryComponent("grudge", Lists.newArrayList());
        // Query for full records
        RecordQuery query = RecordQuery.newBuilder().setRecordType(TextIndexTestUtils.SIMPLE_DOC).setFilter(Query.and(filter1, filter2)).build();
        setDeferFetchAfterUnionAndIntersection(shouldDeferFetch);
        RecordQueryPlan plan = planner.plan(query);
        Matcher<RecordQueryPlan> matcher = indexScan(allOf(indexScanType(IndexScanType.BY_LUCENE_FULL_TEXT), indexName("Complex$text_index"), bounds(hasTupleString("[[(the continuance) AND (grudge)],[(the continuance) AND (grudge)]]"))));
        assertThat(plan, matcher);
        List<Long> primaryKeys = recordStore.executeQuery(plan).map(FDBQueriedRecord::getPrimaryKey).map(t -> t.getLong(0)).asList().get();
        assertEquals(ImmutableSet.of(4L), ImmutableSet.copyOf(primaryKeys));
        if (shouldDeferFetch) {
            assertLoadRecord(3, context);
        } else {
            assertLoadRecord(4, context);
        }
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) LuceneQueryComponent(com.apple.foundationdb.record.query.expressions.LuceneQueryComponent) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) LuceneQueryComponent(com.apple.foundationdb.record.query.expressions.LuceneQueryComponent) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) 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