Search in sources :

Example 31 with RecordCursorIterator

use of com.apple.foundationdb.record.RecordCursorIterator in project fdb-record-layer by FoundationDB.

the class FDBSortQueryIndexSelectionTest method sortNested.

/**
 * Verify that sorts on nested fields are implemented using nested record field indexes.
 */
@SuppressWarnings("java:S5961")
@DualPlannerTest
void sortNested() {
    try (FDBRecordContext context = openContext()) {
        RecordMetaDataBuilder builder = RecordMetaData.newBuilder().setRecords(TestRecordsWithHeaderProto.getDescriptor());
        builder.getRecordType("MyRecord").setPrimaryKey(field("header").nest(concatenateFields("path", "rec_no")));
        builder.addIndex("MyRecord", "MyRecord$header_num", concat(field("header").nest("num"), field("str_value")));
        RecordMetaData metaData = builder.getRecordMetaData();
        createOrOpenRecordStore(context, metaData);
        for (int i = 0; i < 100; i++) {
            TestRecordsWithHeaderProto.MyRecord.Builder recBuilder = TestRecordsWithHeaderProto.MyRecord.newBuilder();
            TestRecordsWithHeaderProto.HeaderRecord.Builder headerBuilder = recBuilder.getHeaderBuilder();
            // Carter-Wegman hash, with large enough prime
            headerBuilder.setRecNo((1096 * i + 722) % 1289);
            headerBuilder.setPath("root");
            headerBuilder.setNum(i);
            recBuilder.setStrValue(Integer.toString(i));
            recordStore.saveRecord(recBuilder.build());
        }
        {
            RecordQuery query = RecordQuery.newBuilder().setRecordType("MyRecord").setSort(field("header").nest("num")).build();
            // Index(MyRecord$header_num <,>)
            RecordQueryPlan plan = planner.plan(query);
            assertThat(plan, indexScan(allOf(indexName("MyRecord$header_num"), unbounded())));
            assertEquals(-1173952475, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
            assertEquals(1008825832, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
            assertEquals(1008825832, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
            int i = 0;
            try (RecordCursorIterator<FDBQueriedRecord<Message>> cursor = recordStore.executeQuery(plan).asIterator()) {
                while (cursor.hasNext()) {
                    FDBQueriedRecord<Message> rec = cursor.next();
                    TestRecordsWithHeaderProto.MyRecord.Builder myrec = TestRecordsWithHeaderProto.MyRecord.newBuilder();
                    myrec.mergeFrom(Objects.requireNonNull(rec).getRecord());
                    assertEquals(i++, myrec.getHeader().getNum());
                }
            }
            assertEquals(100, i);
            assertDiscardedNone(context);
        }
        {
            RecordQuery query = RecordQuery.newBuilder().setRecordType("MyRecord").setFilter(Query.field("header").matches(Query.field("num").lessThan(50))).setSort(field("header").nest("num")).build();
            // Index(MyRecord$header_num ([null],[50]))
            RecordQueryPlan plan = planner.plan(query);
            assertThat(plan, indexScan(allOf(indexName("MyRecord$header_num"), bounds(hasTupleString("([null],[50])")))));
            if (planner instanceof RecordQueryPlanner) {
                assertEquals(2008179964, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
                assertEquals(2049006062, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
                assertEquals(-204519612, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
            } else {
                assertEquals(2008179964, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
                // TODO strictly sorted is not set
                assertEquals(2049006068, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
                // TODO strictly sorted is not set
                assertEquals(-204519606, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
            }
            int i = 0;
            try (RecordCursorIterator<FDBQueriedRecord<Message>> cursor = recordStore.executeQuery(plan).asIterator()) {
                while (cursor.hasNext()) {
                    FDBQueriedRecord<Message> rec = cursor.next();
                    TestRecordsWithHeaderProto.MyRecord.Builder myrec = TestRecordsWithHeaderProto.MyRecord.newBuilder();
                    myrec.mergeFrom(Objects.requireNonNull(rec).getRecord());
                    assertEquals(i++, myrec.getHeader().getNum());
                }
            }
            assertEquals(50, i);
            assertDiscardedNone(context);
        }
        {
            RecordQuery query = RecordQuery.newBuilder().setRecordType("MyRecord").setFilter(Query.field("header").matches(Query.field("num").equalsValue(1))).setSort(field("str_value")).build();
            // Index(MyRecord$header_num [[1],[1]])
            RecordQueryPlan plan = planner.plan(query);
            assertThat(plan, indexScan(allOf(indexName("MyRecord$header_num"), bounds(hasTupleString("[[1],[1]]")))));
            assertEquals(878861315, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
            assertEquals(653879397, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
            assertEquals(998239886, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
            int i = 0;
            try (RecordCursorIterator<FDBQueriedRecord<Message>> cursor = recordStore.executeQuery(plan).asIterator()) {
                while (cursor.hasNext()) {
                    FDBQueriedRecord<Message> rec = cursor.next();
                    TestRecordsWithHeaderProto.MyRecord.Builder myrec = TestRecordsWithHeaderProto.MyRecord.newBuilder();
                    myrec.mergeFrom(Objects.requireNonNull(rec).getRecord());
                    assertEquals(1, myrec.getHeader().getNum());
                    i++;
                }
            }
            assertEquals(1, i);
            assertDiscardedNone(context);
        }
        {
            RecordQuery query = RecordQuery.newBuilder().setRecordType("MyRecord").setFilter(Query.and(Query.field("header").matches(Query.field("num").isNull()), Query.field("str_value").greaterThan("middle"))).setSort(field("str_value")).build();
            // Index(MyRecord$header_num ([null, middle],[null]])
            RecordQueryPlan plan = planner.plan(query);
            assertThat(plan, indexScan(allOf(indexName("MyRecord$header_num"), bounds(hasTupleString("([null, middle],[null]]")))));
            assertEquals(1553479768, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
            assertEquals(1072001836, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
            assertEquals(-1653404355, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        }
        {
            final QueryComponent filter = Query.field("header").matches(Query.field("rec_no").greaterThan(0L));
            RecordQuery query = RecordQuery.newBuilder().setRecordType("MyRecord").setFilter(filter).setSort(field("header").nest("num")).build();
            // Fetch(Covering(Index(MyRecord$header_num <,>) -> [str_value: KEY[1], header: [num: KEY[0], path: KEY[2], rec_no: KEY[3]]]) | header/{rec_no GREATER_THAN 0})
            RecordQueryPlan plan = planner.plan(query);
            assertThat(plan, fetch(filter(filter, coveringIndexScan(indexScan(allOf(indexName("MyRecord$header_num"), unbounded()))))));
            if (planner instanceof RecordQueryPlanner) {
                assertEquals(673903077, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
                assertEquals(-582153460, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
                assertEquals(-421343502, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
            } else {
                assertEquals(749683984, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
                assertEquals(87367824, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
                assertEquals(248177782, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
            }
            try (RecordCursorIterator<FDBQueriedRecord<Message>> cursor = recordStore.executeQuery(plan).asIterator()) {
                while (cursor.hasNext()) {
                    FDBQueriedRecord<Message> rec = cursor.next();
                    TestRecordsWithHeaderProto.MyRecord.Builder myrec = TestRecordsWithHeaderProto.MyRecord.newBuilder();
                    myrec.mergeFrom(Objects.requireNonNull(rec).getRecord());
                    assertTrue(myrec.hasHeader(), "Retrieved record missing header");
                    assertTrue(myrec.getHeader().hasRecNo(), "Retrieved record missing rec_no");
                    long recNo = myrec.getHeader().getRecNo();
                    assertTrue(recNo > 0L, "Record does not match filter (rec_no " + recNo + "<= 0)");
                }
            }
            assertDiscardedExactly(0, context);
            clearStoreCounter(context);
        }
        {
            RecordQuery query = RecordQuery.newBuilder().setRecordType("MyRecord").setFilter(Query.field("header").matches(Query.and(Query.field("rec_no").greaterThan(10L), Query.field("num").lessThan(50)))).setSort(field("header").nest("num")).build();
            // Fetch(Covering(Index(MyRecord$header_num ([null],[50])) -> [str_value: KEY[1], header: [num: KEY[0], path: KEY[2], rec_no: KEY[3]]]) | header/{rec_no GREATER_THAN 10})
            RecordQueryPlan plan = planner.plan(query);
            assertThat(plan, fetch(filter(Query.field("header").matches(Query.field("rec_no").greaterThan(10L)), coveringIndexScan(indexScan(allOf(indexName("MyRecord$header_num"), bounds(hasTupleString("([null],[50])"))))))));
            if (planner instanceof RecordQueryPlanner) {
                assertEquals(1473993740, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
                assertEquals(1598662608, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
                assertEquals(619653398, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
            } else {
                assertEquals(1549774647, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
                assertEquals(-2026783218, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
                assertEquals(1289174868, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
            }
            try (RecordCursorIterator<FDBQueriedRecord<Message>> cursor = recordStore.executeQuery(plan).asIterator()) {
                while (cursor.hasNext()) {
                    FDBQueriedRecord<Message> rec = cursor.next();
                    TestRecordsWithHeaderProto.MyRecord.Builder myrec = TestRecordsWithHeaderProto.MyRecord.newBuilder();
                    myrec.mergeFrom(Objects.requireNonNull(rec).getRecord());
                    assertTrue(myrec.hasHeader(), "Retrieved record missing header");
                    assertTrue(myrec.getHeader().hasRecNo(), "Retrieved record missing rec_no");
                    assertTrue(myrec.getHeader().hasNum(), "Retrieved record missing num");
                    long recNo = myrec.getHeader().getRecNo();
                    int num = myrec.getHeader().getNum();
                    assertTrue(recNo > 10L && num < 50, "Retrieved record does not match filter (rec_no = " + recNo + " and num = " + num + ")");
                }
            }
            assertDiscardedExactly(0, context);
        }
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) RecordMetaData(com.apple.foundationdb.record.RecordMetaData) TestRecordsWithHeaderProto(com.apple.foundationdb.record.TestRecordsWithHeaderProto) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) Message(com.google.protobuf.Message) RecordMetaDataBuilder(com.apple.foundationdb.record.RecordMetaDataBuilder) RecordCursorIterator(com.apple.foundationdb.record.RecordCursorIterator) FDBQueriedRecord(com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordMetaDataBuilder(com.apple.foundationdb.record.RecordMetaDataBuilder) RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner) RecordQuery(com.apple.foundationdb.record.query.RecordQuery)

Example 32 with RecordCursorIterator

use of com.apple.foundationdb.record.RecordCursorIterator in project fdb-record-layer by FoundationDB.

the class FDBRecordStoreQueryTest method enumFields.

/**
 * Verify that enum field indexes are used.
 */
@DualPlannerTest
void enumFields() throws Exception {
    RecordMetaDataHook hook = metaData -> {
        final RecordTypeBuilder type = metaData.getRecordType("MyShapeRecord");
        metaData.addIndex(type, new Index("size", field("size")));
        metaData.addIndex(type, new Index("color", field("color")));
        metaData.addIndex(type, new Index("shape", field("shape")));
    };
    setupEnumShapes(hook);
    RecordQuery query = RecordQuery.newBuilder().setRecordType("MyShapeRecord").setFilter(Query.field("color").equalsValue(TestRecordsEnumProto.MyShapeRecord.Color.RED)).build();
    // Index(color [[10],[10]])
    RecordQueryPlan plan = planner.plan(query);
    assertMatchesExactly(plan, indexPlan().where(indexName("color")));
    assertFalse(plan.hasRecordScan(), "should not use record scan");
    assertEquals(1393755963, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
    assertEquals(-14917443, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
    assertEquals(-2083866282, 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());
                assertEquals(TestRecordsEnumProto.MyShapeRecord.Color.RED, shapeRec.getColor());
                i++;
            }
        }
        assertEquals(9, i);
        assertDiscardedNone(context);
    }
}
Also used : Arrays(java.util.Arrays) RecordQueryPlanMatchers.scanPlan(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.scanPlan) Bindings(com.apple.foundationdb.record.Bindings) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordQueryPlanMatchers.predicates(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.predicates) RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner) TestHelpers.assertDiscardedNone(com.apple.foundationdb.record.TestHelpers.assertDiscardedNone) TestRecordsMultiProto(com.apple.foundationdb.record.TestRecordsMultiProto) Tuple(com.apple.foundationdb.tuple.Tuple) RecordCursorResult(com.apple.foundationdb.record.RecordCursorResult) ListMatcher.only(com.apple.foundationdb.record.query.plan.temp.matchers.ListMatcher.only) Assertions.assertFalse(org.junit.jupiter.api.Assertions.assertFalse) RecordQueryPlanMatchers.indexName(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.indexName) Tag(org.junit.jupiter.api.Tag) Query(com.apple.foundationdb.record.query.expressions.Query) ImmutableSet(com.google.common.collect.ImmutableSet) TestRecords1Proto(com.apple.foundationdb.record.TestRecords1Proto) RecordQueryPlanMatchers.recordTypes(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.recordTypes) UUID(java.util.UUID) Collectors(java.util.stream.Collectors) Test(org.junit.jupiter.api.Test) Objects(java.util.Objects) List(java.util.List) ScanComparisons.range(com.apple.foundationdb.record.query.plan.ScanComparisons.range) Matchers.containsInAnyOrder(org.hamcrest.Matchers.containsInAnyOrder) EvaluationContext(com.apple.foundationdb.record.EvaluationContext) FDBQueriedRecord(com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord) Assertions.assertTrue(org.junit.jupiter.api.Assertions.assertTrue) TestRecordsEnumProto(com.apple.foundationdb.record.TestRecordsEnumProto) RecordQueryPlanComplexityException(com.apple.foundationdb.record.query.plan.RecordQueryPlanComplexityException) RecordQueryPlanMatchers.unionPlan(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.unionPlan) RecordQueryPlanMatchers(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers) RecordQueryPlanMatchers.predicatesFilterPlan(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.predicatesFilterPlan) IntStream(java.util.stream.IntStream) Assertions.assertThrows(org.junit.jupiter.api.Assertions.assertThrows) Assertions.fail(org.junit.jupiter.api.Assertions.fail) ValueMatchers.anyValue(com.apple.foundationdb.record.query.plan.temp.matchers.ValueMatchers.anyValue) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) PrimitiveMatchers.equalsObject(com.apple.foundationdb.record.query.plan.temp.matchers.PrimitiveMatchers.equalsObject) QueryPredicateMatchers.queryComponentPredicate(com.apple.foundationdb.record.query.plan.temp.matchers.QueryPredicateMatchers.queryComponentPredicate) TestRecordsTupleFieldsProto(com.apple.foundationdb.record.TestRecordsTupleFieldsProto) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) PlanHashable(com.apple.foundationdb.record.PlanHashable) ArrayList(java.util.ArrayList) ExecuteProperties(com.apple.foundationdb.record.ExecuteProperties) Lists(com.google.common.collect.Lists) RecordCursorIterator(com.apple.foundationdb.record.RecordCursorIterator) RecordQueryPlanMatchers.scanComparisons(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.scanComparisons) RecordQueryPlanMatchers.unorderedPrimaryKeyDistinctPlan(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.unorderedPrimaryKeyDistinctPlan) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) Expressions.field(com.apple.foundationdb.record.metadata.Key.Expressions.field) FDBStoredRecord(com.apple.foundationdb.record.provider.foundationdb.FDBStoredRecord) IsolationLevel(com.apple.foundationdb.record.IsolationLevel) LongStream(java.util.stream.LongStream) ScanComparisons.unbounded(com.apple.foundationdb.record.query.plan.ScanComparisons.unbounded) RecordTypeBuilder(com.apple.foundationdb.record.metadata.RecordTypeBuilder) TupleFieldsHelper(com.apple.foundationdb.record.metadata.expressions.TupleFieldsHelper) Tags(com.apple.test.Tags) QueryPredicateMatchers.valuePredicate(com.apple.foundationdb.record.query.plan.temp.matchers.QueryPredicateMatchers.valuePredicate) PrimitiveMatchers.containsAll(com.apple.foundationdb.record.query.plan.temp.matchers.PrimitiveMatchers.containsAll) RecordQueryPlanMatchers.queryComponents(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.queryComponents) RecordQueryPlanMatchers.typeFilterPlan(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.typeFilterPlan) Comparisons(com.apple.foundationdb.record.query.expressions.Comparisons) RecordQueryPlanMatchers.filterPlan(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.filterPlan) 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) RecordCursor(com.apple.foundationdb.record.RecordCursor) QueryComponent(com.apple.foundationdb.record.query.expressions.QueryComponent) ListMatcher.exactly(com.apple.foundationdb.record.query.plan.temp.matchers.ListMatcher.exactly) Collections(java.util.Collections) TestRecordsBytesProto(com.apple.foundationdb.record.TestRecordsBytesProto) ValueMatchers.fieldValue(com.apple.foundationdb.record.query.plan.temp.matchers.ValueMatchers.fieldValue) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) Message(com.google.protobuf.Message) Index(com.apple.foundationdb.record.metadata.Index) RecordTypeBuilder(com.apple.foundationdb.record.metadata.RecordTypeBuilder) FDBQueriedRecord(com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordQuery(com.apple.foundationdb.record.query.RecordQuery)

Aggregations

RecordCursorIterator (com.apple.foundationdb.record.RecordCursorIterator)32 Message (com.google.protobuf.Message)30 Test (org.junit.jupiter.api.Test)30 FDBRecordContext (com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext)29 Tags (com.apple.test.Tags)29 Assertions.assertEquals (org.junit.jupiter.api.Assertions.assertEquals)29 Tag (org.junit.jupiter.api.Tag)29 Index (com.apple.foundationdb.record.metadata.Index)27 RecordQuery (com.apple.foundationdb.record.query.RecordQuery)27 Query (com.apple.foundationdb.record.query.expressions.Query)27 RecordQueryPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan)26 MatcherAssert.assertThat (org.hamcrest.MatcherAssert.assertThat)26 TestRecords1Proto (com.apple.foundationdb.record.TestRecords1Proto)25 FDBQueriedRecord (com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord)25 Assertions.assertTrue (org.junit.jupiter.api.Assertions.assertTrue)25 Arrays (java.util.Arrays)23 PlanHashable (com.apple.foundationdb.record.PlanHashable)22 IndexTypes (com.apple.foundationdb.record.metadata.IndexTypes)22 Expressions.field (com.apple.foundationdb.record.metadata.Key.Expressions.field)22 Assertions.assertFalse (org.junit.jupiter.api.Assertions.assertFalse)22