use of com.apple.foundationdb.record.query.plan.RecordQueryPlanner in project fdb-record-layer by FoundationDB.
the class FDBInQueryTest method testInQueryIndex.
/**
* Verify that an IN with an index is implemented as an index scan, with an IN join.
*/
@DualPlannerTest
void testInQueryIndex() throws Exception {
complexQuerySetup(NO_HOOK);
List<Integer> ls = asList(1, 2, 4);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("num_value_3_indexed").in(ls)).setSort(field("num_value_3_indexed")).build();
planner.setConfiguration(InAsOrUnionMode.AS_UNION.configure(planner.getConfiguration().asBuilder()).build());
RecordQueryPlan plan = planner.plan(query);
if (planner instanceof RecordQueryPlanner) {
// Index(MySimpleRecord$num_value_3_indexed [EQUALS $__in_num_value_3_indexed__0]) WHERE __in_num_value_3_indexed__0 IN [1, 2, 4]
assertMatchesExactly(plan, inValuesJoinPlan(indexPlan().where(indexName("MySimpleRecord$num_value_3_indexed")).and(scanComparisons(range("[EQUALS $__in_num_value_3_indexed__0]")))).where(inValuesList(equalsObject(ls))));
assertEquals(-2004060309, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(571226247, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(571195399, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertMatchesExactly(plan, fetchFromPartialRecordPlan(inValuesJoinPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$num_value_3_indexed")).and(scanComparisons(equalities(only(anyParameterComparison()))))))).where(inValuesList(equalsObject(ls)))));
assertEquals(-2068499040, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-992959779, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1998042418, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
}
assertEquals(60, querySimpleRecordStore(NO_HOOK, plan, EvaluationContext::empty, record -> assertThat(record.getNumValue3Indexed(), anyOf(is(1), is(2), is(4))), TestHelpers::assertDiscardedNone));
}
use of com.apple.foundationdb.record.query.plan.RecordQueryPlanner in project fdb-record-layer by FoundationDB.
the class FDBInQueryTest method testMultipleInQueryIndex.
/**
* Verify that a query with multiple INs is translated into an index scan within multiple IN joins.
*/
@DualPlannerTest
void testMultipleInQueryIndex() throws Exception {
final RecordMetaDataHook recordMetaDataHook = metaData -> {
metaData.getRecordType("MyRecord").setPrimaryKey(field("str_value"));
metaData.addIndex("MyRecord", "ind", field("header").nest(field("rec_no"), field("path")));
};
setupRecordsWithHeader(recordMetaDataHook, (i, record) -> {
record.setStrValue("_" + i);
record.getHeaderBuilder().setRecNo(i % 5).setPath("String" + i % 50).setNum(i);
});
List<Long> longList = asList(1L, 4L);
List<String> stringList = asList("String6", "String25", "String1", "String34");
RecordQuery query = RecordQuery.newBuilder().setRecordType("MyRecord").setFilter(Query.field("header").matches(Query.and(Query.field("rec_no").in(longList), Query.field("path").in(stringList)))).build();
// Index(ind [EQUALS $__in_rec_no__0, EQUALS $__in_path__1]) WHERE __in_path__1 IN [String6, String25, String1, String34] WHERE __in_rec_no__0 IN [1, 4]
RecordQueryPlan plan = planner.plan(query);
if (planner instanceof RecordQueryPlanner) {
final BindingMatcher<RecordQueryIndexPlan> indexPlanMatcher = indexPlan().where(indexName("ind")).and(scanComparisons(range("[EQUALS $__in_rec_no__0, EQUALS $__in_path__1]")));
assertMatchesExactly(plan, inValuesJoinPlan(inValuesJoinPlan(indexPlanMatcher).where(inValuesList(equalsObject(stringList)))).where(inValuesList(equalsObject(longList))).or(inValuesJoinPlan(inValuesJoinPlan(indexPlanMatcher).where(inValuesList(equalsObject(longList)))).where(inValuesList(equalsObject(stringList)))));
assertEquals(-1869764109, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(1234840472, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(297055958, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertMatchesExactly(plan, fetchFromPartialRecordPlan(inValuesJoinPlan(inValuesJoinPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("ind")).and(scanComparisons(equalities(exactly(anyParameterComparison(), anyParameterComparison()))))))).where(inValuesList(equalsObject(longList)))).where(inValuesList(equalsObject(stringList)))));
assertEquals(-2124922292, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(2055315359, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(1810804415, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
}
queryRecordsWithHeader(recordMetaDataHook, plan, cursor -> assertEquals(asList("_56", "_6", "_1", "_51", "_34", "_84"), cursor.map(TestRecordsWithHeaderProto.MyRecord.Builder::getStrValue).asList().get()), TestHelpers::assertDiscardedNone);
}
use of com.apple.foundationdb.record.query.plan.RecordQueryPlanner in project fdb-record-layer by FoundationDB.
the class FDBInQueryTest method testInQueryParameter.
/**
* Verify that an IN (with parameter) with an index is implemented as an index scan, with an IN join.
*/
@DualPlannerTest
void testInQueryParameter() throws Exception {
complexQuerySetup(NO_HOOK);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("num_value_3_indexed").in("valueThrees")).build();
planner.setConfiguration(InAsOrUnionMode.AS_UNION.configure(planner.getConfiguration().asBuilder()).build());
RecordQueryPlan plan = planner.plan(query);
if (planner instanceof RecordQueryPlanner) {
// Index(MySimpleRecord$num_value_3_indexed [EQUALS $__in_num_value_3_indexed__0]) WHERE __in_num_value_3_indexed__0 IN $valueThrees
assertMatchesExactly(plan, inParameterJoinPlan(indexPlan().where(indexName("MySimpleRecord$num_value_3_indexed")).and(scanComparisons(range("[EQUALS $__in_num_value_3_indexed__0]")))).where(RecordQueryPlanMatchers.inParameter(equalsObject("valueThrees"))));
assertEquals(883815022, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(514739864, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(514739864, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertMatchesExactly(plan, fetchFromPartialRecordPlan(inParameterJoinPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$num_value_3_indexed")).and(scanComparisons(equalities(only(anyParameterComparison()))))))).where(RecordQueryPlanMatchers.inParameter(equalsObject("valueThrees")))));
assertEquals(1152354842, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-1759971309, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1759971309, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
}
int count = querySimpleRecordStore(NO_HOOK, plan, () -> EvaluationContext.forBinding("valueThrees", asList(1, 3, 4)), myrec -> assertThat(myrec.getNumValue3Indexed(), anyOf(is(1), is(3), is(4))), TestHelpers::assertDiscardedNone);
assertEquals(60, count);
}
use of com.apple.foundationdb.record.query.plan.RecordQueryPlanner in project fdb-record-layer by FoundationDB.
the class FDBInQueryTest method testInQueryNoIndex.
/**
* Verify that an IN without an index is implemented as a filter on a scan, as opposed to a loop of a filter on a scan.
*/
@DualPlannerTest
void testInQueryNoIndex() throws Exception {
complexQuerySetup(NO_HOOK);
final QueryComponent filter = Query.field("num_value_2").in(asList(0, 2));
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(filter).build();
// Scan(<,>) | [MySimpleRecord] | num_value_2 IN [0, 2]
RecordQueryPlan plan = planner.plan(query);
if (planner instanceof RecordQueryPlanner) {
assertMatchesExactly(plan, filterPlan(descendantPlans(scanPlan().where(scanComparisons(unbounded())))).where(queryComponents(exactly(equalsObject(filter)))));
assertEquals(-1139367278, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-1907300063, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1694772440, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertMatchesExactly(plan, predicatesFilterPlan(descendantPlans(scanPlan().where(scanComparisons(unbounded())))).where(predicates(valuePredicate(fieldValue("num_value_2"), new Comparisons.ListComparison(Comparisons.Type.IN, ImmutableList.of(0, 2))))));
assertEquals(997592219, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-1107686929, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-895159306, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
}
assertEquals(67, querySimpleRecordStore(NO_HOOK, plan, EvaluationContext::empty, record -> assertThat(record.getNumValue2(), anyOf(is(0), is(2))), context -> assertDiscardedAtMost(33, context)));
}
use of com.apple.foundationdb.record.query.plan.RecordQueryPlanner in project fdb-record-layer by FoundationDB.
the class FDBRecordStoreQueryTest method queryWithContinuation.
/**
* Verify that simple queries execute properly with continuations.
*/
@DualPlannerTest
void queryWithContinuation() throws Exception {
setupSimpleRecordStore(null, (i, builder) -> {
builder.setRecNo(i);
builder.setNumValue2(i % 2);
builder.setStrValueIndexed((i % 2 == 0) ? "even" : "odd");
});
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context, null);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setAllowedIndexes(Collections.emptyList()).build();
// Scan(<,>) | [MySimpleRecord]
RecordQueryPlan plan = planner.plan(query);
assertMatchesExactly(plan, typeFilterPlan(scanPlan().where(scanComparisons(unbounded()))).where(recordTypes(containsAll(ImmutableSet.of("MySimpleRecord")))));
assertEquals(1623132336, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(1955010341, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(1955010341, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
byte[] continuation = null;
List<TestRecords1Proto.MySimpleRecord> retrieved = new ArrayList<>(100);
while (true) {
RecordCursor<TestRecords1Proto.MySimpleRecord> cursor = recordStore.executeQuery(plan, continuation, ExecuteProperties.newBuilder().setReturnedRowLimit(10).build()).map(rec -> TestRecords1Proto.MySimpleRecord.newBuilder().mergeFrom(rec.getRecord()).build());
List<TestRecords1Proto.MySimpleRecord> list = cursor.asList().get();
assertEquals(Math.min(10, 100 - retrieved.size()), list.size());
for (int i = 0; i < list.size(); i++) {
assertEquals(retrieved.size() + i, list.get(i).getRecNo());
}
assertDiscardedNone(context);
retrieved.addAll(list);
if (retrieved.size() > 100) {
fail("added more records than were present");
}
continuation = cursor.getNext().getContinuation().toBytes();
if (continuation == null) {
break;
}
}
query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("str_value_indexed").equalsValue("odd")).build();
// Index(MySimpleRecord$str_value_indexed [[odd],[odd]])
plan = planner.plan(query);
assertMatchesExactly(plan, indexPlan().where(indexName("MySimpleRecord$str_value_indexed")).and(scanComparisons(range("[[odd],[odd]]"))));
assertEquals(-1917280682, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-1357054180, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(9136435, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
continuation = null;
retrieved = new ArrayList<>(50);
while (true) {
RecordCursor<TestRecords1Proto.MySimpleRecord> cursor = recordStore.executeQuery(plan, continuation, ExecuteProperties.newBuilder().setReturnedRowLimit(5).build()).map(rec -> TestRecords1Proto.MySimpleRecord.newBuilder().mergeFrom(rec.getRecord()).build());
List<TestRecords1Proto.MySimpleRecord> list = cursor.asList().get();
assertEquals(Math.min(5, 50 - retrieved.size()), list.size());
for (int i = 0; i < list.size(); i++) {
assertEquals(2 * (retrieved.size() + i) + 1, list.get(i).getRecNo());
}
assertDiscardedNone(context);
retrieved.addAll(list);
if (retrieved.size() > 50) {
fail("added more records than met filter");
}
continuation = cursor.getNext().getContinuation().toBytes();
if (continuation == null) {
break;
}
}
clearStoreCounter(context);
final QueryComponent filter = Query.field("num_value_2").equalsValue(0);
query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(filter).build();
plan = planner.plan(query);
if (planner instanceof RecordQueryPlanner) {
assertMatchesExactly(plan, filterPlan(typeFilterPlan(scanPlan().where(scanComparisons(unbounded())))).where(queryComponents(exactly(equalsObject(filter)))));
assertEquals(913370522, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
// TODO: https://github.com/FoundationDB/fdb-record-layer/issues/1074
// assertEquals(389700036, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertMatchesExactly(plan, predicatesFilterPlan(typeFilterPlan(scanPlan().where(scanComparisons(unbounded())))).where(predicates(only(valuePredicate(fieldValue(anyValue(), "num_value_2"), new Comparisons.SimpleComparison(Comparisons.Type.EQUALS, 0))))));
assertEquals(-1244637277, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
}
continuation = null;
retrieved = new ArrayList<>(50);
while (true) {
RecordCursor<TestRecords1Proto.MySimpleRecord> cursor = recordStore.executeQuery(plan, continuation, ExecuteProperties.newBuilder().setReturnedRowLimit(15).build()).map(rec -> TestRecords1Proto.MySimpleRecord.newBuilder().mergeFrom(rec.getRecord()).build());
List<TestRecords1Proto.MySimpleRecord> list = cursor.asList().get();
assertEquals(Math.min(15, 50 - retrieved.size()), list.size());
for (int i = 0; i < list.size(); i++) {
assertEquals(2 * (retrieved.size() + i), list.get(i).getRecNo());
}
retrieved.addAll(list);
if (retrieved.size() > 50) {
fail("added more records than met filter");
}
continuation = cursor.getNext().getContinuation().toBytes();
if (continuation == null) {
break;
}
}
assertDiscardedAtMost(51, context);
}
}
Aggregations