use of com.apple.foundationdb.record.metadata.Index in project fdb-record-layer by FoundationDB.
the class OrderingProperty method fromIndexScanOrCoveringIndexScan.
@Nonnull
private static Optional<Ordering> fromIndexScanOrCoveringIndexScan(@Nonnull final PlanContext context, @Nonnull final RecordQueryPlan plan) {
final RecordQueryIndexPlan recordQueryIndexPlan;
if (plan instanceof RecordQueryIndexPlan) {
recordQueryIndexPlan = (RecordQueryIndexPlan) plan;
} else if (plan instanceof RecordQueryCoveringIndexPlan) {
final RecordQueryPlanWithIndex planWithIndex = ((RecordQueryCoveringIndexPlan) plan).getIndexPlan();
if (planWithIndex instanceof RecordQueryIndexPlan) {
recordQueryIndexPlan = (RecordQueryIndexPlan) planWithIndex;
} else {
return Optional.empty();
}
} else {
return Optional.empty();
}
final String indexName = recordQueryIndexPlan.getIndexName();
final RecordMetaData metaData = context.getMetaData();
final Index index = metaData.getIndex(indexName);
final Collection<RecordType> recordTypesForIndex = metaData.recordTypesForIndex(index);
final KeyExpression commonPrimaryKeyForIndex = RecordMetaData.commonPrimaryKey(recordTypesForIndex);
final KeyExpression keyExpression = ValueIndexExpansionVisitor.fullKey(index, commonPrimaryKeyForIndex);
final ScanComparisons scanComparisons = recordQueryIndexPlan.getComparisons();
return fromKeyAndScanComparisons(keyExpression, scanComparisons, plan.isReverse(), index.isUnique());
}
use of com.apple.foundationdb.record.metadata.Index in project fdb-record-layer by FoundationDB.
the class FDBFilterCoalescingQueryTest method duplicateFilters.
/**
* Verify that the planner removes duplicate filters.
* TODO We currently don't. Update this test when it gets implemented.
* TODO: Some query plans include redundant filtering operations even when the index is a complete specification (https://github.com/FoundationDB/fdb-record-layer/issues/2)
*/
@Test
public void duplicateFilters() throws Exception {
RecordMetaDataHook hook = metaData -> {
metaData.addIndex("MySimpleRecord", new Index("multi_index", "str_value_indexed", "num_value_3_indexed"));
};
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), Query.field("num_value_3_indexed").equalsValue(3))).build();
// Fetch(Covering(Index(multi_index [[even, 3],[even, 3]]) -> [num_value_3_indexed: KEY[1], rec_no: KEY[2], str_value_indexed: KEY[0]]) | num_value_3_indexed EQUALS 3)
RecordQueryPlan plan = planner.plan(query);
assertThat(plan, descendant(coveringIndexScan(indexScan(allOf(indexName("multi_index"), bounds(hasTupleString("[[even, 3],[even, 3]]")))))));
assertEquals(-766201402, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-1632715349, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1418679945, 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());
assertEquals(3, myrec.getNumValue3Indexed());
assertEquals(3, myrec.getRecNo() % 5);
i++;
}
}
assertEquals(10, i);
assertDiscardedNone(context);
}
}
use of com.apple.foundationdb.record.metadata.Index in project fdb-record-layer by FoundationDB.
the class FDBFilterCoalescingQueryTest method versionRangeCoalesce.
/**
* Validate that a query for all values within a given range of versions will be coalesced into a single scan.
* This is similar to the {@link #simpleRangeCoalesce()} test above, but it is for version key expressions in
* particular.
*/
@Test
public void versionRangeCoalesce() throws Exception {
Index versionIndex = new Index("MySimpleRecord$version", VersionKeyExpression.VERSION, IndexTypes.VERSION);
RecordMetaDataHook hook = metaData -> {
metaData.setStoreRecordVersions(true);
metaData.addIndex("MySimpleRecord", versionIndex);
};
complexQuerySetup(hook);
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context, hook);
long readVersion = context.getReadVersion();
FDBRecordVersion lowBoundary = FDBRecordVersion.firstInDBVersion(0);
FDBRecordVersion highBoundary = FDBRecordVersion.lastInDBVersion(readVersion);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.and(Query.version().greaterThan(lowBoundary), Query.version().lessThan(highBoundary))).build();
RecordQueryPlan plan = planner.plan(query);
assertThat(plan, indexScan(allOf(indexName(versionIndex.getName()), bounds(hasTupleString("([" + lowBoundary.toVersionstamp() + "],[" + highBoundary.toVersionstamp() + "])")))));
try (RecordCursorIterator<FDBQueriedRecord<Message>> cursor = recordStore.executeQuery(plan).asIterator()) {
int i = 0;
while (cursor.hasNext()) {
FDBQueriedRecord<Message> rec = cursor.next();
FDBRecordVersion version = rec.getVersion();
assertNotNull(version);
assertThat(version, allOf(lessThan(highBoundary), greaterThan(lowBoundary)));
i++;
}
assertEquals(100, i);
assertDiscardedNone(context);
}
}
}
use of com.apple.foundationdb.record.metadata.Index 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.metadata.Index 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);
}
Aggregations