Search in sources :

Example 51 with RecordQueryPlan

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

the class FDBCollateQueryTest method coveringIndex.

@Test
public void coveringIndex() throws Exception {
    // Note how the name field needs to be repeated in the value because it can't be recovered from an index
    // entry after transformation to a collation key.
    final KeyExpression collateKey = function(collateFunctionName, concat(NAME_FIELD, value("da_DK")));
    final KeyExpression indexKey = keyWithValue(concat(collateKey, NAME_FIELD), 1);
    final RecordMetaDataHook hook = md -> {
        md.removeIndex("MySimpleRecord$str_value_indexed");
        md.addIndex("MySimpleRecord", "collated_name", indexKey);
    };
    loadNames(hook);
    final RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.keyExpression(collateKey).lessThan("B")).setRequiredResults(Arrays.asList(NAME_FIELD)).build();
    final List<String> actual = queryNames(query, hook);
    final List<String> expected = Arrays.asList("Ampère");
    assertEquals(expected, actual);
    RecordQueryPlan plan = planner.plan(query);
    assertThat(plan, coveringIndexScan(indexScan("collated_name")));
}
Also used : Arrays(java.util.Arrays) PlanMatchers.indexScan(com.apple.foundationdb.record.query.plan.match.PlanMatchers.indexScan) Bindings(com.apple.foundationdb.record.Bindings) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) PlanMatchers.bounds(com.apple.foundationdb.record.query.plan.match.PlanMatchers.bounds) Expressions.concat(com.apple.foundationdb.record.metadata.Key.Expressions.concat) CollateFunctionKeyExpressionFactoryJRE(com.apple.foundationdb.record.metadata.expressions.CollateFunctionKeyExpressionFactoryJRE) Tag(org.junit.jupiter.api.Tag) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) Nonnull(javax.annotation.Nonnull) Expressions.field(com.apple.foundationdb.record.metadata.Key.Expressions.field) PlanMatchers.coveringIndexScan(com.apple.foundationdb.record.query.plan.match.PlanMatchers.coveringIndexScan) Query(com.apple.foundationdb.record.query.expressions.Query) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) TestRecords1Proto(com.apple.foundationdb.record.TestRecords1Proto) Tags(com.apple.test.Tags) Matchers.allOf(org.hamcrest.Matchers.allOf) Expressions.keyWithValue(com.apple.foundationdb.record.metadata.Key.Expressions.keyWithValue) Test(org.junit.jupiter.api.Test) PlanMatchers.hasTupleString(com.apple.foundationdb.record.query.plan.match.PlanMatchers.hasTupleString) List(java.util.List) PlanMatchers.indexName(com.apple.foundationdb.record.query.plan.match.PlanMatchers.indexName) Expressions.value(com.apple.foundationdb.record.metadata.Key.Expressions.value) EvaluationContext(com.apple.foundationdb.record.EvaluationContext) Expressions.function(com.apple.foundationdb.record.metadata.Key.Expressions.function) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) PlanMatchers.hasTupleString(com.apple.foundationdb.record.query.plan.match.PlanMatchers.hasTupleString) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) Test(org.junit.jupiter.api.Test)

Example 52 with RecordQueryPlan

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

the class FDBCollateQueryTest method compareParameter.

@Test
public void compareParameter() throws Exception {
    final KeyExpression key = function(collateFunctionName, concat(NAME_FIELD, value("de_DE")));
    final RecordMetaDataHook hook = md -> {
        md.removeIndex("MySimpleRecord$str_value_indexed");
        md.addIndex("MySimpleRecord", "collated_name", key);
    };
    loadNames(hook);
    final RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.keyExpression(key).equalsParameter("name")).setRequiredResults(Arrays.asList(NAME_FIELD)).build();
    final List<String> actual = queryNames(query, hook, "name", "gauss");
    final List<String> expected = Arrays.asList("Gauß");
    assertEquals(expected, actual);
    RecordQueryPlan plan = planner.plan(query);
    assertThat(plan, indexScan(allOf(indexName("collated_name"), bounds(hasTupleString(String.format("[EQUALS %s($name)]", collateFunctionName))))));
}
Also used : Arrays(java.util.Arrays) PlanMatchers.indexScan(com.apple.foundationdb.record.query.plan.match.PlanMatchers.indexScan) Bindings(com.apple.foundationdb.record.Bindings) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) PlanMatchers.bounds(com.apple.foundationdb.record.query.plan.match.PlanMatchers.bounds) Expressions.concat(com.apple.foundationdb.record.metadata.Key.Expressions.concat) CollateFunctionKeyExpressionFactoryJRE(com.apple.foundationdb.record.metadata.expressions.CollateFunctionKeyExpressionFactoryJRE) Tag(org.junit.jupiter.api.Tag) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) Nonnull(javax.annotation.Nonnull) Expressions.field(com.apple.foundationdb.record.metadata.Key.Expressions.field) PlanMatchers.coveringIndexScan(com.apple.foundationdb.record.query.plan.match.PlanMatchers.coveringIndexScan) Query(com.apple.foundationdb.record.query.expressions.Query) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) TestRecords1Proto(com.apple.foundationdb.record.TestRecords1Proto) Tags(com.apple.test.Tags) Matchers.allOf(org.hamcrest.Matchers.allOf) Expressions.keyWithValue(com.apple.foundationdb.record.metadata.Key.Expressions.keyWithValue) Test(org.junit.jupiter.api.Test) PlanMatchers.hasTupleString(com.apple.foundationdb.record.query.plan.match.PlanMatchers.hasTupleString) List(java.util.List) PlanMatchers.indexName(com.apple.foundationdb.record.query.plan.match.PlanMatchers.indexName) Expressions.value(com.apple.foundationdb.record.metadata.Key.Expressions.value) EvaluationContext(com.apple.foundationdb.record.EvaluationContext) Expressions.function(com.apple.foundationdb.record.metadata.Key.Expressions.function) RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) KeyExpression(com.apple.foundationdb.record.metadata.expressions.KeyExpression) PlanMatchers.hasTupleString(com.apple.foundationdb.record.query.plan.match.PlanMatchers.hasTupleString) RecordQuery(com.apple.foundationdb.record.query.RecordQuery) Test(org.junit.jupiter.api.Test)

Example 53 with RecordQueryPlan

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

the class FDBCoveringIndexQueryTest method coveringOff.

/**
 * Verify that a covering index is used when possible.
 */
@SuppressWarnings("unchecked")
@DualPlannerTest
void coveringOff() throws Exception {
    complexQuerySetup(null);
    RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("num_value_unique").greaterThan(990)).setSort(field("num_value_unique")).setRequiredResults(Collections.singletonList(field("num_value_unique"))).build();
    // Covering(Index(MySimpleRecord$num_value_unique ([990],>) -> [num_value_unique: KEY[0], rec_no: KEY[1]])
    planner.setConfiguration(planner.getConfiguration().asBuilder().setDisabledTransformationRuleNames(ImmutableSet.of("PushFilterThroughFetchRule", "PushDistinctThroughFetchRule", "PushSetOperationThroughFetchRule", "MergeProjectionAndFetchRule"), PlannerRuleSet.DEFAULT).build());
    RecordQueryPlan plan = planner.plan(query);
    if (planner instanceof RecordQueryPlanner) {
        final BindingMatcher<? extends RecordQueryPlan> planMatcher = coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$num_value_unique")).and(scanComparisons(range("([990],>")))));
        assertMatchesExactly(plan, planMatcher);
        assertEquals(-158312359, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(-1293351441, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(-1374755849, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    } else {
        final BindingMatcher<? extends RecordQueryPlan> planMatcher = indexPlan().where(indexName("MySimpleRecord$num_value_unique")).and(scanComparisons(range("([990],>")));
        assertMatchesExactly(plan, planMatcher);
        assertEquals(-158312359, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(594363437, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(512959029, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    }
    try (FDBRecordContext context = openContext()) {
        openSimpleRecordStore(context);
        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.getNumValueUnique() > 990);
                i++;
            }
        }
        assertEquals(10, 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 54 with RecordQueryPlan

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

the class FDBCoveringIndexQueryTest method coveringSimpleInsufficient.

/**
 * Verify that a covering index is not used when it does not include enough fields; a regular index is used instead.
 */
@DualPlannerTest
void coveringSimpleInsufficient() throws Exception {
    complexQuerySetup(null);
    RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("num_value_unique").greaterThan(990)).setSort(field("num_value_unique"), true).setRequiredResults(Arrays.asList(field("num_value_unique"), field("num_value_3_indexed"))).build();
    // Index(MySimpleRecord$num_value_unique ([990],> REVERSE)
    RecordQueryPlan plan = planner.plan(query);
    assertTrue(plan.isReverse());
    if (planner instanceof RecordQueryPlanner) {
        final BindingMatcher<? extends RecordQueryPlan> planMatcher = indexPlan().where(indexName("MySimpleRecord$num_value_unique")).and(scanComparisons(range("([990],>")));
        assertMatchesExactly(plan, planMatcher);
        assertEquals(-158312358, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(594363257, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(512958849, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    } else {
        final BindingMatcher<? extends RecordQueryPlan> planMatcher = indexPlan().where(indexName("MySimpleRecord$num_value_unique")).and(scanComparisons(range("([990],>")));
        assertMatchesExactly(plan, planMatcher);
        assertEquals(-158312358, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
        assertEquals(594363251, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
        assertEquals(512958843, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner) RecordQuery(com.apple.foundationdb.record.query.RecordQuery)

Example 55 with RecordQueryPlan

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

the class FDBCoveringIndexQueryTest method coveringWithAdditionalNestedFilter.

/**
 * Verify that an extra covering filter can use a nested field.
 */
@DualPlannerTest
void coveringWithAdditionalNestedFilter() {
    try (FDBRecordContext context = openContext()) {
        RecordMetaDataBuilder builder = RecordMetaData.newBuilder().setRecords(TestRecordsWithHeaderProto.getDescriptor());
        builder.getRecordType("MyRecord").setPrimaryKey(field("header").nest(field("rec_no")));
        builder.addIndex("MyRecord", "multi", concat(field("str_value"), field("header").nest(concatenateFields("path", "num"))));
        RecordMetaData metaData = builder.getRecordMetaData();
        createOrOpenRecordStore(context, metaData);
        RecordQuery query = RecordQuery.newBuilder().setRecordType("MyRecord").setFilter(Query.and(Query.field("str_value").equalsValue("abc"), Query.field("header").matches(Query.field("num").equalsValue(1)))).build();
        // Fetch(Covering(Index(multi [[abc],[abc]]) -> [str_value: KEY[0], header: [num: KEY[2], path: KEY[1], rec_no: KEY[3]]]) | header/{num EQUALS 1})
        RecordQueryPlan plan = planner.plan(query);
        if (planner instanceof RecordQueryPlanner) {
            final BindingMatcher<? extends RecordQueryPlan> planMatcher = fetchFromPartialRecordPlan(filterPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("multi")).and(scanComparisons(range("[[abc],[abc]]")))))).where(queryComponents(exactly(equalsObject(Query.field("header").matches(Query.field("num").equalsValue(1)))))));
            assertMatchesExactly(plan, planMatcher);
            assertEquals(-1536005152, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
            assertEquals(1350035332, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
            assertEquals(-1843652335, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        } else {
            final BindingMatcher<? extends RecordQueryPlan> planMatcher = fetchFromPartialRecordPlan(predicatesFilterPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("multi")).and(scanComparisons(range("[[abc],[abc]]")))))).where(predicates(only(valuePredicate(fieldValue("header.num"), new Comparisons.SimpleComparison(Comparisons.Type.EQUALS, 1))))));
            assertMatchesExactly(plan, planMatcher);
            assertEquals(1623341655, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
            assertEquals(2019556616, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
            assertEquals(-1174131051, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
        }
    }
}
Also used : RecordQueryPlan(com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan) RecordMetaData(com.apple.foundationdb.record.RecordMetaData) FDBRecordContext(com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext) RecordMetaDataBuilder(com.apple.foundationdb.record.RecordMetaDataBuilder) RecordQueryPlanMatchers.scanComparisons(com.apple.foundationdb.record.query.plan.temp.matchers.RecordQueryPlanMatchers.scanComparisons) Comparisons(com.apple.foundationdb.record.query.expressions.Comparisons) RecordQueryPlanner(com.apple.foundationdb.record.query.plan.RecordQueryPlanner) RecordQuery(com.apple.foundationdb.record.query.RecordQuery)

Aggregations

RecordQueryPlan (com.apple.foundationdb.record.query.plan.plans.RecordQueryPlan)373 RecordQuery (com.apple.foundationdb.record.query.RecordQuery)265 FDBRecordContext (com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext)245 Test (org.junit.jupiter.api.Test)228 FDBQueriedRecord (com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord)174 Message (com.google.protobuf.Message)167 Query (com.apple.foundationdb.record.query.expressions.Query)123 Tags (com.apple.test.Tags)121 Tag (org.junit.jupiter.api.Tag)121 Index (com.apple.foundationdb.record.metadata.Index)119 RecordQueryPlanner (com.apple.foundationdb.record.query.plan.RecordQueryPlanner)118 Assertions.assertEquals (org.junit.jupiter.api.Assertions.assertEquals)118 QueryComponent (com.apple.foundationdb.record.query.expressions.QueryComponent)117 List (java.util.List)114 MatcherAssert.assertThat (org.hamcrest.MatcherAssert.assertThat)114 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)113 Expressions.field (com.apple.foundationdb.record.metadata.Key.Expressions.field)107 Arrays (java.util.Arrays)107 Collections (java.util.Collections)106 ArrayList (java.util.ArrayList)100