use of com.apple.foundationdb.record.query.RecordQuery in project fdb-record-layer by FoundationDB.
the class FDBSimpleJoinQueryTest method joinParentToChild.
/**
* Verify that simple binding joins in parent/child relationships work.
*/
@Test
public void joinParentToChild() throws Exception {
createJoinRecords(true);
RecordQuery parentQuery = RecordQuery.newBuilder().setRecordType("MyParentRecord").setFilter(Query.field("str_value_indexed").equalsValue("even")).build();
RecordQueryPlan parentPlan = planner.plan(parentQuery);
RecordQueryPlan childPlan = new RecordQueryLoadByKeysPlan("children");
try (FDBRecordContext context = openContext()) {
openJoinRecordStore(context);
RecordCursor<FDBQueriedRecord<Message>> parentCursor = recordStore.executeQuery(parentPlan);
RecordCursor<FDBQueriedRecord<Message>> childCursor = RecordCursor.flatMapPipelined(ignore -> recordStore.executeQuery(parentPlan), (rec, ignore) -> {
TestRecordsParentChildRelationshipProto.MyParentRecord.Builder parentRec = TestRecordsParentChildRelationshipProto.MyParentRecord.newBuilder();
parentRec.mergeFrom(rec.getRecord());
EvaluationContext childContext = EvaluationContext.forBinding("children", parentRec.getChildRecNosList().stream().map(Tuple::from).collect(Collectors.toList()));
return childPlan.execute(recordStore, childContext);
}, null, 10);
RecordCursor<String> resultsCursor = childCursor.map(rec -> {
TestRecordsParentChildRelationshipProto.MyChildRecord.Builder childRec = TestRecordsParentChildRelationshipProto.MyChildRecord.newBuilder();
childRec.mergeFrom(rec.getRecord());
return childRec.getStrValue();
});
assertEquals(Arrays.asList("2.1", "2.2", "2.3", "4.1", "4.2", "4.3"), resultsCursor.asList().join());
assertDiscardedNone(context);
}
}
use of com.apple.foundationdb.record.query.RecordQuery in project fdb-record-layer by FoundationDB.
the class FDBSortQueryIndexSelectionTest method sortWithScannableFilterOnIndex.
/**
* Verify that if the sort matches an index that can satisfy a filter that the index is used.
*/
@ParameterizedTest
@MethodSource("hooks")
void sortWithScannableFilterOnIndex(RecordMetaDataHook hook, PlannableIndexTypes indexTypes) throws Exception {
setupSimpleRecordStore(hook, (i, builder) -> builder.setRecNo(i).setNumValue2(i % 2).setNumValue3Indexed(i % 3));
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("num_value_3_indexed").greaterThanOrEquals(2)).setSort(field("num_value_3_indexed")).build();
setupPlanner(indexTypes);
// Index(MySimpleRecord$num_value_3_indexed [[2],>)
RecordQueryPlan plan = planner.plan(query);
assertThat(plan, indexScan(allOf(indexName("MySimpleRecord$num_value_3_indexed"), bounds(hasTupleString("[[2],>")))));
assertEquals(1008857205, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-2059045225, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1347749581, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
AtomicInteger lastNumValue3 = new AtomicInteger(Integer.MIN_VALUE);
int returned = querySimpleRecordStore(hook, plan, EvaluationContext::empty, builder -> {
assertThat(builder.getNumValue3Indexed(), greaterThanOrEqualTo(2));
assertThat(builder.getNumValue3Indexed(), greaterThanOrEqualTo(lastNumValue3.get()));
lastNumValue3.set(builder.getNumValue3Indexed());
}, TestHelpers::assertDiscardedNone);
assertEquals(33, returned);
// reset planner
setupPlanner(null);
}
use of com.apple.foundationdb.record.query.RecordQuery in project fdb-record-layer by FoundationDB.
the class FDBSortQueryIndexSelectionTest method sortByPrimaryKeyWithFilter.
private void sortByPrimaryKeyWithFilter(@Nonnull QueryComponent filter, boolean reverse, int planHash, int expectedReturn, int maxDiscarded, @Nonnull Matcher<RecordQueryPlan> planMatcher, @Nonnull TestHelpers.DangerousConsumer<TestRecords1Proto.MySimpleRecord.Builder> checkRecord) throws Exception {
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(filter).setSort(field("rec_no"), reverse).build();
RecordQueryPlan plan = planner.plan(query);
assertThat("unexpected plan for filter: " + filter, plan, planMatcher);
assertEquals(planHash, plan.planHash(PlanHashable.PlanHashKind.LEGACY), "unexpected plan hash for filter: " + filter);
AtomicLong lastId = new AtomicLong(reverse ? Long.MAX_VALUE : Long.MIN_VALUE);
int returned = querySimpleRecordStore(NO_HOOK, plan, EvaluationContext::empty, builder -> {
checkRecord.accept(builder);
if (reverse) {
assertThat(builder.getRecNo(), lessThan(lastId.get()));
} else {
assertThat(builder.getRecNo(), greaterThan(lastId.get()));
}
lastId.set(builder.getRecNo());
}, context -> assertDiscardedAtMost(maxDiscarded, context));
assertEquals(expectedReturn, returned, "unexpected return count for filter: " + filter);
}
use of com.apple.foundationdb.record.query.RecordQuery in project fdb-record-layer by FoundationDB.
the class FDBSortQueryIndexSelectionTest method sortWithNonScannableFilterWithAnd.
/**
* Verify that if we have an "and" query where one of the filters matches the sort but we can't use a scan
* that the index is used only for sorting and not to satisfy the predicate.
*/
@ParameterizedTest
@MethodSource("hooks")
void sortWithNonScannableFilterWithAnd(RecordMetaDataHook hook, PlannableIndexTypes indexTypes) throws Exception {
setupSimpleRecordStore(hook, (i, builder) -> builder.setRecNo(i).setNumValue2(i % 2).setNumValue3Indexed(i % 3));
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.and(Query.field("num_value_3_indexed").notEquals(1), Query.field("num_value_2").equalsValue(0))).setSort(field("num_value_3_indexed")).build();
setupPlanner(indexTypes);
// Fetch(Covering(Index(MySimpleRecord$num_value_3_indexed <,>) -> [num_value_3_indexed: KEY[0], rec_no: KEY[1]]) | num_value_3_indexed NOT_EQUALS 1) | num_value_2 EQUALS 0
RecordQueryPlan plan = planner.plan(query);
assertThat(plan, filter(Query.field("num_value_2").equalsValue(0), fetch(filter(Objects.requireNonNull(Query.field("num_value_3_indexed").notEquals(1)), coveringIndexScan(indexScan(allOf(indexName("MySimpleRecord$num_value_3_indexed"), unbounded())))))));
assertEquals(-2013739934, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-1437222023, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-867524414, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
AtomicInteger lastNumValue3 = new AtomicInteger(Integer.MIN_VALUE);
int returned = querySimpleRecordStore(hook, plan, EvaluationContext::empty, builder -> {
assertThat(builder.getNumValue3Indexed(), not(equalTo(1)));
assertThat(builder.getNumValue2(), equalTo(0));
assertThat(builder.getNumValue3Indexed(), greaterThanOrEqualTo(lastNumValue3.get()));
lastNumValue3.set(builder.getNumValue3Indexed());
}, context -> assertDiscardedAtMost(66, context));
assertEquals(34, returned);
// reset the planner
setupPlanner(null);
}
use of com.apple.foundationdb.record.query.RecordQuery in project fdb-record-layer by FoundationDB.
the class FDBSortQueryIndexSelectionTest method sortOnlyUnique.
private void sortOnlyUnique(RecordMetaDataHook hook) {
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context, hook);
for (int i = 0; i < 100; i++) {
TestRecords1Proto.MySimpleRecord.Builder recBuilder = TestRecords1Proto.MySimpleRecord.newBuilder();
// Carter-Wegman hash, with large enough prime
recBuilder.setRecNo((1096 * i + 722) % 1289);
recBuilder.setNumValueUnique(i);
recordStore.saveRecord(recBuilder.build());
}
commit(context);
}
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setSort(field("num_value_unique")).build();
// Index(MySimpleRecord$num_value_unique <,>)
RecordQueryPlan plan = planner.plan(query);
assertThat(plan, indexScan(allOf(indexName("MySimpleRecord$num_value_unique"), unbounded())));
assertEquals(-1130465929, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-491910604, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-491910604, 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(Objects.requireNonNull(rec).getRecord());
assertEquals(i++, myrec.getNumValueUnique());
}
}
assertEquals(100, i);
assertDiscardedNone(context);
}
}
Aggregations