use of com.apple.foundationdb.record.query.plan.RecordQueryPlanner in project fdb-record-layer by FoundationDB.
the class FDBSortQueryIndexSelectionTest method testComplexQuery8x.
/**
* Verify that a query with a filter on one field and a sort on another uses the index of the sort preferentially,
* and falls back to filtering to implement the filter if an appropriate multi-field index is not available.
*/
@DualPlannerTest
public void testComplexQuery8x() throws Exception {
RecordMetaDataHook hook = complexQuerySetupHook();
complexQuerySetup(hook);
final QueryComponent filter = Query.field("str_value_indexed").equalsValue("even");
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(filter).setSort(field("num_value_3_indexed")).build();
RecordQueryPlan plan = planner.plan(query);
assertThat(plan, filter(filter, indexScan(allOf(indexName("MySimpleRecord$num_value_3_indexed"), unbounded()))));
if (planner instanceof RecordQueryPlanner) {
assertEquals(-1429997503, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
// TODO: Issue https://github.com/FoundationDB/fdb-record-layer/issues/1074
// assertEquals(-1729416480, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertEquals(952181942, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
}
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("even", myrec.getStrValueIndexed());
i++;
}
}
assertEquals(50, i);
assertDiscardedAtMost(50, context);
}
}
use of com.apple.foundationdb.record.query.plan.RecordQueryPlanner in project fdb-record-layer by FoundationDB.
the class FDBSortQueryIndexSelectionTest method sortUniqueNull.
/**
* Verify that sort with filter works with different null interpretation on unique index.
*/
@DualPlannerTest
void sortUniqueNull() {
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context, NULL_UNIQUE_HOOK);
for (int i = 0; i < 100; i++) {
TestRecords1Proto.MySimpleRecord.Builder recBuilder = TestRecords1Proto.MySimpleRecord.newBuilder();
recBuilder.setRecNo((1096 * i + 722) % 1289);
recBuilder.setNumValueUnique(i);
recordStore.saveRecord(recBuilder.build());
}
commit(context);
}
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("num_value_unique").greaterThanOrEquals(20)).setSort(field("num_value_unique")).build();
// Index(MySimpleRecord$num_value_unique [[20],>)
RecordQueryPlan plan = planner.plan(query);
assertThat(plan, indexScan(allOf(indexName("MySimpleRecord$num_value_unique"), bounds(hasTupleString("[[20],>")))));
if (planner instanceof RecordQueryPlanner) {
assertEquals(-535398101, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-1799532339, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1088253993, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertEquals(-535398101, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-1799532345, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1088253999, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
}
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context, NULL_UNIQUE_HOOK);
int i = 20;
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);
}
}
use of com.apple.foundationdb.record.query.plan.RecordQueryPlanner in project fdb-record-layer by FoundationDB.
the class FDBRecordStoreScanLimitTest method unorderedIntersectionWithScanLimit.
@ParameterizedTest(name = "unorderedIntersectionWithScanLimit [fail = {0}]")
@BooleanSource
public void unorderedIntersectionWithScanLimit(boolean fail) throws Exception {
// TODO: When there is an UnorderedIntersectionPlan (or whatever) add that to the unordered plans stream
RecordQueryPlanner planner = new RecordQueryPlanner(simpleMetaData(NO_HOOK), new RecordStoreState(null, null));
RecordQueryPlan leftPlan = planner.plan(RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("str_value_indexed").startsWith("ev")).build());
RecordQueryPlan rightPlan = planner.plan(RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("num_value_3_indexed").lessThanOrEquals(1)).build());
int maximumToScan;
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context);
maximumToScan = recordStore.executeQuery(leftPlan).getCount().get() + recordStore.executeQuery(rightPlan).getCount().get();
}
for (int limit = 0; limit < 3 * maximumToScan; limit = 2 * limit + 1) {
final int finalLimit = limit;
Function<byte[], RecordCursor<FDBQueriedRecord<Message>>> cursorFunction = (continuation) -> {
ExecuteProperties executeProperties = ExecuteProperties.newBuilder().setScannedRecordsLimit(finalLimit).setFailOnScanLimitReached(fail).build();
return ProbableIntersectionCursor.create(record -> record.getPrimaryKey().getItems(), Arrays.asList(leftContinuation -> leftPlan.execute(recordStore, EvaluationContext.EMPTY, leftContinuation, executeProperties), rightContinuation -> rightPlan.execute(recordStore, EvaluationContext.EMPTY, rightContinuation, executeProperties)), continuation, recordStore.getTimer());
};
assertNumberOfRecordsScanned(limit, cursorFunction, fail, "should" + (limit >= maximumToScan ? "not " : "") + " be limited by record scan limit");
}
}
use of com.apple.foundationdb.record.query.plan.RecordQueryPlanner in project fdb-record-layer by FoundationDB.
the class FDBAndQueryToIntersectionTest method intersectionVersusRange.
/**
* Verify that very complex AND clauses are implemented as combinations of range and index scans.
* The possible plans are an index scan for one field or an intersection for the other, in each case with the other
* condition as a filter. This checks that the intersection is only preferred when it accomplishes more.
*/
@DualPlannerTest
public void intersectionVersusRange() throws Exception {
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context, metaData -> {
metaData.addIndex("MySimpleRecord", "num_value_2");
metaData.removeIndex("MySimpleRecord$num_value_3_indexed");
metaData.addIndex("MySimpleRecord", new Index("index_2_3", "num_value_2", "num_value_3_indexed"));
});
}
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.and(Query.field("str_value_indexed").equalsValue("even"), Query.field("num_value_unique").equalsValue(0), Query.field("num_value_2").equalsValue(1), Query.field("num_value_3_indexed").greaterThanOrEquals(2), Query.field("num_value_3_indexed").lessThanOrEquals(3))).build();
// Index(index_2_3 [[1, 2],[1, 3]]) | And([str_value_indexed EQUALS even, num_value_unique EQUALS 0])
RecordQueryPlan plan = planner.plan(query);
assertThat("should have range scan in " + plan, plan, descendant(indexScan("index_2_3")));
assertFalse(plan.hasRecordScan(), "should not use record scan");
if (planner instanceof RecordQueryPlanner) {
assertMatchesExactly(plan, selfOrDescendantPlans(indexPlan().where(RecordQueryPlanMatchers.indexName("index_2_3"))));
assertEquals(2140693065, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-1517851081, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(1716318889, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertMatchesExactly(plan, predicatesFilterPlan(indexPlan().where(RecordQueryPlanMatchers.indexName("index_2_3")).and(scanComparisons(range("[[1, 2],[1, 3]]")))).where(predicates(valuePredicate(fieldValue("str_value_indexed"), new Comparisons.SimpleComparison(Comparisons.Type.EQUALS, "even")), valuePredicate(fieldValue("num_value_unique"), new Comparisons.SimpleComparison(Comparisons.Type.EQUALS, 0)))));
assertEquals(-476608798, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-119924960, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(409745570, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
}
}
use of com.apple.foundationdb.record.query.plan.RecordQueryPlanner in project fdb-record-layer by FoundationDB.
the class OnlineIndexerTest method openContext.
FDBRecordContext openContext(boolean checked) {
FDBRecordContext context = fdb.openContext();
FDBRecordStore.Builder builder = FDBRecordStore.newBuilder().setMetaDataProvider(metaData).setContext(context).setSubspace(subspace);
if (checked) {
recordStore = builder.createOrOpen(FDBRecordStoreBase.StoreExistenceCheck.NONE);
} else {
recordStore = builder.uncheckedOpen();
}
metaData = recordStore.getRecordMetaData();
planner = new RecordQueryPlanner(metaData, recordStore.getRecordStoreState(), recordStore.getTimer());
return context;
}
Aggregations