use of com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord in project fdb-record-layer by FoundationDB.
the class FDBOrQueryToUnionTest method testOrderedOrQueryWithAnd.
/**
* Verify that a query with an OR of an AND can be implemented as a union of an index scan with an intersection of index scans.
*/
@DualPlannerTest
void testOrderedOrQueryWithAnd() throws Exception {
RecordMetaDataHook hook = metaData -> {
metaData.addIndex("MySimpleRecord", "str_2", concat(field("str_value_indexed"), field("num_value_2")));
metaData.addIndex("MySimpleRecord", "nu_2", concat(field("num_value_unique"), field("num_value_2")));
metaData.addIndex("MySimpleRecord", "n3_2", concat(field("num_value_3_indexed"), field("num_value_2")));
};
complexQuerySetup(hook);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.or(Query.field("str_value_indexed").equalsValue("even"), Query.and(Query.field("num_value_3_indexed").equalsValue(1), Query.field("num_value_unique").equalsValue(909)))).setSort(field("num_value_2")).build();
// Index(str_2 [[even],[even]]) ∪[Field { 'num_value_2' None}, Field { 'rec_no' None}] Index(nu_2 [[909],[909]]) ∩ Index(n3_2 [[1],[1]])
RecordQueryPlan plan = planner.plan(query);
if (planner instanceof RecordQueryPlanner) {
final BindingMatcher<? extends RecordQueryPlan> planMatcher = unionPlan(indexPlan().where(indexName("str_2")).and(scanComparisons(range("[[even],[even]]"))), intersectionPlan(indexPlan().where(indexName("nu_2")).and(scanComparisons(range("[[909],[909]]"))), indexPlan().where(indexName("n3_2")).and(scanComparisons(range("[[1],[1]]"))))).where(comparisonKey(concat(field("num_value_2"), primaryKey("MySimpleRecord"))));
assertMatchesExactly(plan, planMatcher);
assertEquals(-1659601413, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-1344221020, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1474039530, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
final BindingMatcher<? extends RecordQueryPlan> planMatcher = fetchFromPartialRecordPlan(unionPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("str_2")).and(scanComparisons(range("[[even],[even]]"))))), intersectionPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("nu_2")).and(scanComparisons(range("[[909],[909]]"))))), coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("n3_2")).and(scanComparisons(range("[[1],[1]]"))))))).where(comparisonKey(concat(field("num_value_2"), primaryKey("MySimpleRecord")))));
assertMatchesExactly(plan, planMatcher);
assertEquals(1254181870, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(156652779, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(1906836981, 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());
assertTrue(myrec.getStrValueIndexed().equals("even") || (myrec.getNumValue3Indexed() == 1 && myrec.getNumValueUnique() == 909));
i++;
}
}
assertEquals(51, i);
}
}
use of com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord in project fdb-record-layer by FoundationDB.
the class FDBOrQueryToUnionTest method testOrQuery5WithLimits.
@DualPlannerTest
@MethodSource("query5WithLimitsArgs")
@ParameterizedTest(name = "testOrQuery5WithLimits [limit = {0}, removesDuplicates = {1}]")
void testOrQuery5WithLimits(int limit, boolean removesDuplicates) throws Exception {
RecordMetaDataHook hook = complexQuerySetupHook();
complexQuerySetup(hook);
setDeferFetchAfterUnionAndIntersection(true);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.or(Query.field("str_value_indexed").lessThan("m"), Query.field("num_value_3_indexed").greaterThan(3))).setRemoveDuplicates(removesDuplicates).build();
// Unordered(Index(MySimpleRecord$str_value_indexed ([null],[m])) ∪ Index(MySimpleRecord$num_value_3_indexed ([3],>))
RecordQueryPlan plan = planner.plan(query);
final BindingMatcher<RecordQueryUnorderedUnionPlan> unionPlanBindingMatcher = unorderedUnionPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$str_value_indexed")))), coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$num_value_3_indexed")))));
final BindingMatcher<? extends RecordQueryPlan> planMatcher;
if (removesDuplicates) {
planMatcher = fetchFromPartialRecordPlan(unorderedPrimaryKeyDistinctPlan(unionPlanBindingMatcher));
} else {
planMatcher = fetchFromPartialRecordPlan(unionPlanBindingMatcher);
}
assertMatchesExactly(plan, planMatcher);
if (planner instanceof RecordQueryPlanner) {
assertEquals(removesDuplicates ? 1898767693 : 1898767686, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(removesDuplicates ? -583062018 : 212117636, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(removesDuplicates ? 1864525478 : -1635262164, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertEquals(removesDuplicates ? 1898767693 : 1898767686, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(removesDuplicates ? -583062018 : 212117636, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(removesDuplicates ? 1864525478 : -1635262164, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
}
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context, hook);
boolean done = false;
byte[] continuation = null;
Set<Tuple> uniqueKeys = new HashSet<>();
int itr = 0;
while (!done) {
ExecuteProperties executeProperties = ExecuteProperties.newBuilder().setReturnedRowLimit(limit).build();
try (RecordCursorIterator<FDBQueriedRecord<Message>> cursor = recordStore.executeQuery(plan, continuation, executeProperties).asIterator()) {
int i = 0;
Set<Tuple> keysThisIteration = new HashSet<>();
while (cursor.hasNext()) {
FDBQueriedRecord<Message> rec = cursor.next();
TestRecords1Proto.MySimpleRecord.Builder myrec = TestRecords1Proto.MySimpleRecord.newBuilder();
myrec.mergeFrom(Objects.requireNonNull(rec).getRecord());
assertTrue(myrec.getStrValueIndexed().compareTo("m") < 0 || myrec.getNumValue3Indexed() > 3);
uniqueKeys.add(rec.getPrimaryKey());
if (removesDuplicates) {
assertThat(keysThisIteration.add(rec.getPrimaryKey()), is(true));
}
i++;
}
continuation = cursor.getContinuation();
done = cursor.getNoNextReason().isSourceExhausted();
if (!done) {
assertEquals(limit, i);
}
}
itr++;
assertThat("exceeded maximum iterations", itr, lessThan(500));
}
assertEquals(50 + 10, uniqueKeys.size());
}
}
use of com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord in project fdb-record-layer by FoundationDB.
the class FDBOrQueryToUnionTest method testOrQuery4.
/**
* Verify that queries with an OR of equality predicates on different fields are implemented using a union of indexes,
* if all fields are indexed.
*/
@DualPlannerTest
@ParameterizedTest
@BooleanSource
void testOrQuery4(boolean shouldDeferFetch) throws Exception {
RecordMetaDataHook hook = complexQuerySetupHook();
complexQuerySetup(hook);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.or(Query.field("str_value_indexed").equalsValue("even"), Query.field("num_value_3_indexed").equalsValue(1), Query.field("num_value_3_indexed").equalsValue(3))).build();
setDeferFetchAfterUnionAndIntersection(shouldDeferFetch);
// Fetch(Covering(Index(MySimpleRecord$str_value_indexed [[even],[even]]) -> [rec_no: KEY[1], str_value_indexed: KEY[0]]) ∪ Covering(Index(MySimpleRecord$num_value_3_indexed [[1],[1]]) -> [num_value_3_indexed: KEY[0], rec_no: KEY[1]]) ∪ Covering(Index(MySimpleRecord$num_value_3_indexed [[3],[3]]) -> [num_value_3_indexed: KEY[0], rec_no: KEY[1]]))
RecordQueryPlan plan = planner.plan(query);
if (shouldDeferFetch || planner instanceof CascadesPlanner) {
final BindingMatcher<? extends RecordQueryPlan> planMatcher = fetchFromPartialRecordPlan(unionPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$str_value_indexed")).and(scanComparisons(range("[[even],[even]]"))))), coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$num_value_3_indexed")).and(scanComparisons(range("[[1],[1]]"))))), coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$num_value_3_indexed")).and(scanComparisons(range("[[3],[3]]")))))).where(comparisonKey(primaryKey("MySimpleRecord"))));
assertMatchesExactly(plan, planMatcher);
assertEquals(-417814093, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-1082480572, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(233155848, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
final BindingMatcher<? extends RecordQueryPlan> planMatcher = unionPlan(indexPlan().where(indexName("MySimpleRecord$str_value_indexed")).and(scanComparisons(range("[[even],[even]]"))), indexPlan().where(indexName("MySimpleRecord$num_value_3_indexed")).and(scanComparisons(range("[[1],[1]]"))), indexPlan().where(indexName("MySimpleRecord$num_value_3_indexed")).and(scanComparisons(range("[[3],[3]]")))).where(comparisonKey(primaryKey("MySimpleRecord")));
assertMatchesExactly(plan, planMatcher);
assertEquals(-673254486, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(991016881, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1988313995, 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());
assertTrue(myrec.getStrValueIndexed().equals("even") || myrec.getNumValue3Indexed() == 1 || myrec.getNumValue3Indexed() == 3);
i++;
}
}
assertEquals(50 + 10 + 10, i);
assertDiscardedAtMost(20, context);
if (shouldDeferFetch) {
assertLoadRecord(50 + 10 + 10, context);
}
}
}
use of com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord in project fdb-record-layer by FoundationDB.
the class FDBAndQueryToIntersectionTest method testComplexQueryAndWithIncompatibleFilters.
/**
* Verify that a complex query with an AND of fields that are _not_ compatibly ordered generates a plan without
* an intersection (uses filter instead).
*/
@ParameterizedTest
@BooleanSource
public void testComplexQueryAndWithIncompatibleFilters(final boolean shouldOptimizeForIndexFilters) throws Exception {
RecordMetaDataHook hook = complexQuerySetupHook();
complexQuerySetup(hook);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.and(Query.field("str_value_indexed").startsWith("e"), Query.field("num_value_3_indexed").equalsValue(3))).build();
setOptimizeForIndexFilters(shouldOptimizeForIndexFilters);
// Index(MySimpleRecord$str_value_indexed {[e],[e]}) | num_value_3_indexed EQUALS 3
// Fetch(Covering(Index(multi_index {[e],[e]}) -> [num_value_2: KEY[1], num_value_3_indexed: KEY[2], rec_no: KEY[3], str_value_indexed: KEY[0]]) | num_value_3_indexed EQUALS 3)
RecordQueryPlan plan = planner.plan(query);
// Not an intersection plan, since not compatibly ordered.
if (shouldOptimizeForIndexFilters) {
assertThat(plan, allOf(hasNoDescendant(intersection(anything(), anything())), descendant(filter(Query.field("num_value_3_indexed").equalsValue(3), coveringIndexScan(indexScan(anyOf(indexName("multi_index"), bounds(hasTupleString("[[e],[e]]")))))))));
assertFalse(plan.hasRecordScan(), "should not use record scan");
assertEquals(-1810430840, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-1492232944, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1442514296, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertThat(plan, allOf(hasNoDescendant(intersection(anything(), anything())), descendant(indexScan(anyOf(indexName("MySimpleRecord$str_value_indexed"), indexName("MySimpleRecord$num_value_3_indexed"))))));
assertFalse(plan.hasRecordScan(), "should not use record scan");
assertEquals(746853985, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(312168193, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(361886841, 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("even", myrec.getStrValueIndexed());
assertTrue((myrec.getNumValue3Indexed() % 5) == 3);
i++;
}
}
assertEquals(10, i);
assertDiscardedExactly(40, context);
assertLoadRecord(50, context);
}
}
use of com.apple.foundationdb.record.provider.foundationdb.FDBQueriedRecord in project fdb-record-layer by FoundationDB.
the class FDBAndQueryToIntersectionTest method testComplexQueryAndWithTwoChildren.
/**
* Verify that a complex query with an AND of fields with compatibly ordered indexes generates an intersection plan.
*/
@ParameterizedTest
@BooleanSource
public void testComplexQueryAndWithTwoChildren(boolean shouldDeferFetch) throws Exception {
RecordMetaDataHook hook = complexQuerySetupHook();
complexQuerySetup(hook);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.and(Query.field("str_value_indexed").equalsValue("even"), Query.field("num_value_3_indexed").equalsValue(3))).build();
setDeferFetchAfterUnionAndIntersection(shouldDeferFetch);
// Index(MySimpleRecord$str_value_indexed [[even],[even]]) ∩ Index(MySimpleRecord$num_value_3_indexed [[3],[3]])
// Fetch(Covering(Index(MySimpleRecord$str_value_indexed [[even],[even]]) -> [rec_no: KEY[1], str_value_indexed: KEY[0]]) ∩ Covering(Index(MySimpleRecord$num_value_3_indexed [[3],[3]]) -> [num_value_3_indexed: KEY[0], rec_no: KEY[1]]))
RecordQueryPlan plan = planner.plan(query);
if (shouldDeferFetch) {
assertThat(plan, fetch(intersection(coveringIndexScan(indexScan(allOf(indexName("MySimpleRecord$str_value_indexed"), bounds(hasTupleString("[[even],[even]]"))))), coveringIndexScan(indexScan(allOf(indexName("MySimpleRecord$num_value_3_indexed"), bounds(hasTupleString("[[3],[3]]"))))), equalTo(field("rec_no")))));
assertEquals(-929788310, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-1914172894, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-271606869, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertThat(plan, intersection(indexScan(allOf(indexName("MySimpleRecord$str_value_indexed"), bounds(hasTupleString("[[even],[even]]")))), indexScan(allOf(indexName("MySimpleRecord$num_value_3_indexed"), bounds(hasTupleString("[[3],[3]]")))), equalTo(field("rec_no"))));
assertEquals(-1973527173, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(227253579, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(1869819604, 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("even", myrec.getStrValueIndexed());
assertTrue((myrec.getNumValue3Indexed() % 5) == 3);
i++;
}
}
assertEquals(10, i);
assertDiscardedExactly(50, context);
if (shouldDeferFetch) {
assertLoadRecord(10, context);
}
}
}
Aggregations