use of com.apple.foundationdb.record.query.plan.RecordQueryPlanner in project fdb-record-layer by FoundationDB.
the class TextIndexTest method performQueryWithIndexScan.
@Nonnull
private Set<Long> performQueryWithIndexScan(@Nonnull RecordMetaDataHook hook, @Nonnull Index index, @Nonnull QueryComponent filter) throws Exception {
final ExecuteProperties executeProperties = ExecuteProperties.newBuilder().setTimeLimit(3000).build();
final RecordQuery query = RecordQuery.newBuilder().setRecordType(SIMPLE_DOC).setRequiredResults(Collections.singletonList(field("doc_id"))).setFilter(filter).build();
Set<Long> results = new HashSet<>();
RecordQueryPlan plan;
byte[] continuation;
try (FDBRecordContext context = openContext()) {
openRecordStore(context, hook);
RecordQueryPlanner planner = new RecordQueryPlanner(recordStore.getRecordMetaData(), recordStore.getRecordStoreState());
plan = planner.plan(query);
assertThat(filter, instanceOf(FieldWithComparison.class));
FieldWithComparison fieldFilter = (FieldWithComparison) filter;
if (fieldFilter.getComparison() instanceof Comparisons.TextContainsAllPrefixesComparison && ((Comparisons.TextContainsAllPrefixesComparison) fieldFilter.getComparison()).isStrict()) {
// Strict field field comparisons cannot be covering
assertThat(plan, descendant(textIndexScan(indexName(index.getName()))));
} else {
assertThat(plan, descendant(coveringIndexScan(textIndexScan(indexName(index.getName())))));
}
try (RecordCursor<Long> cursor = recordStore.executeQuery(plan, null, executeProperties).map(record -> record.getPrimaryKey().getLong(0))) {
cursor.forEach(results::add).get();
continuation = cursor.getNext().getContinuation().toBytes();
}
}
while (continuation != null) {
try (FDBRecordContext context = openContext()) {
openRecordStore(context, hook);
try (RecordCursor<Long> cursor = recordStore.executeQuery(plan, continuation, executeProperties).map(record -> record.getPrimaryKey().getLong(0))) {
cursor.forEach(results::add).get();
continuation = cursor.getNext().getContinuation().toBytes();
}
}
}
return results;
}
use of com.apple.foundationdb.record.query.plan.RecordQueryPlanner in project fdb-record-layer by FoundationDB.
the class BitmapValueIndexTest method filterIndexSelection.
@Test
void filterIndexSelection() {
try (FDBRecordContext context = openContext()) {
createOrOpenRecordStore(context, metaData(REC_NO_BY_STR_NUMS_HOOK));
saveRecords(100, 200);
commit(context);
}
try (FDBRecordContext context = openContext()) {
createOrOpenRecordStore(context, metaData(REC_NO_BY_STR_NUMS_HOOK));
setupPlanner(null);
final RecordQuery recordQuery = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.and(Query.field("str_value").equalsValue("odd"), Query.field("num_value_2").equalsValue(3))).setRequiredResults(Collections.singletonList(field("rec_no"))).build();
final RecordQueryPlan queryPlan = ComposedBitmapIndexAggregate.tryPlan((RecordQueryPlanner) planner, recordQuery, BITMAP_VALUE_REC_NO_BY_STR, IndexQueryabilityFilter.TRUE).orElseGet(() -> fail("Cannot plan query"));
assertThat(queryPlan, coveringIndexScan(indexScan(allOf(indexName("rec_no_by_str_num2"), indexScanType(IndexScanType.BY_GROUP), bounds(hasTupleString("[[odd, 3],[odd, 3]]"))))));
assertEquals(1188586655, queryPlan.planHash());
assertEquals(Optional.empty(), ComposedBitmapIndexAggregate.tryPlan((RecordQueryPlanner) planner, recordQuery, BITMAP_VALUE_REC_NO_BY_STR, IndexQueryabilityFilter.FALSE));
}
}
use of com.apple.foundationdb.record.query.plan.RecordQueryPlanner in project fdb-record-layer by FoundationDB.
the class FDBRecordStoreQueryTestBase method setOptimizeForIndexFilters.
protected void setOptimizeForIndexFilters(boolean shouldOptimizeForIndexFilters) {
assertTrue(planner instanceof RecordQueryPlanner);
RecordQueryPlanner recordQueryPlanner = (RecordQueryPlanner) planner;
recordQueryPlanner.setConfiguration(recordQueryPlanner.getConfiguration().asBuilder().setOptimizeForIndexFilters(shouldOptimizeForIndexFilters).build());
}
use of com.apple.foundationdb.record.query.plan.RecordQueryPlanner in project fdb-record-layer by FoundationDB.
the class FDBRestrictedIndexQueryTest method queryAllowedIndexes.
/**
* Verify that queries do not use prohibited indexes.
*/
@DualPlannerTest
void queryAllowedIndexes() {
RecordMetaDataHook hook = metaData -> {
metaData.removeIndex("MySimpleRecord$str_value_indexed");
metaData.addIndex("MySimpleRecord", new Index("limited_str_value_index", field("str_value_indexed"), Index.EMPTY_VALUE, IndexTypes.VALUE, IndexOptions.NOT_ALLOWED_FOR_QUERY_OPTIONS));
};
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context, hook);
recordStore.deleteAllRecords();
TestRecords1Proto.MySimpleRecord.Builder recBuilder = TestRecords1Proto.MySimpleRecord.newBuilder();
recBuilder.setRecNo(1);
recBuilder.setStrValueIndexed("abc");
recBuilder.setNumValueUnique(123);
recordStore.saveRecord(recBuilder.build());
recBuilder.setRecNo(2);
recBuilder.setStrValueIndexed("xyz");
recBuilder.setNumValueUnique(987);
recordStore.saveRecord(recBuilder.build());
commit(context);
}
RecordQuery query1 = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("str_value_indexed").equalsValue("abc")).build();
// Index(limited_str_value_index [[abc],[abc]])
// Scan(<,>) | [MySimpleRecord] | str_value_indexed EQUALS abc
RecordQueryPlan plan1 = planner.plan(query1);
assertThat("should not use prohibited index", plan1, hasNoDescendant(indexScan("limited_str_value_index")));
assertTrue(plan1.hasFullRecordScan(), "should use full record scan");
if (planner instanceof RecordQueryPlanner) {
assertEquals(-223683738, plan1.planHash(PlanHashable.PlanHashKind.LEGACY));
// TODO: Issue https://github.com/FoundationDB/fdb-record-layer/issues/1074
// assertEquals(1148834070, plan1.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertEquals(-2136471589, plan1.planHash(PlanHashable.PlanHashKind.LEGACY));
}
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context, hook);
try (RecordCursor<FDBQueriedRecord<Message>> cursor = recordStore.executeQuery(plan1)) {
FDBQueriedRecord<Message> rec = cursor.getNext().get();
TestRecords1Proto.MySimpleRecord.Builder myrec = TestRecords1Proto.MySimpleRecord.newBuilder();
myrec.mergeFrom(Objects.requireNonNull(rec).getRecord());
assertEquals("abc", myrec.getStrValueIndexed());
assertFalse(cursor.getNext().hasNext());
}
TestHelpers.assertDiscardedExactly(1, context);
clearStoreCounter(context);
}
RecordQuery query2 = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("str_value_indexed").equalsValue("abc")).setAllowedIndex("limited_str_value_index").build();
// Index(limited_str_value_index [[abc],[abc]])
RecordQueryPlan plan2 = planner.plan(query2);
assertThat("explicitly use prohibited index", plan2, descendant(indexScan("limited_str_value_index")));
assertFalse(plan2.hasRecordScan(), "should not use record scan");
assertEquals(-1573180774, plan2.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(994464666, plan2.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1531627068, plan2.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context, hook);
try (RecordCursor<FDBQueriedRecord<Message>> cursor = recordStore.executeQuery(plan2)) {
FDBQueriedRecord<Message> rec = cursor.getNext().get();
TestRecords1Proto.MySimpleRecord.Builder myrec = TestRecords1Proto.MySimpleRecord.newBuilder();
myrec.mergeFrom(Objects.requireNonNull(rec).getRecord());
assertEquals("abc", myrec.getStrValueIndexed());
assertFalse(cursor.getNext().hasNext());
}
TestHelpers.assertDiscardedNone(context);
}
}
use of com.apple.foundationdb.record.query.plan.RecordQueryPlanner in project fdb-record-layer by FoundationDB.
the class FDBRestrictedIndexQueryTest method indexQueryabilityFilter.
/**
* Verify that the query planner uses the specified {@link com.apple.foundationdb.record.query.IndexQueryabilityFilter}.
* If both allowed indexes and a queryability filter are set, verify that the planner uses the allowed indexes.
*/
@DualPlannerTest
void indexQueryabilityFilter() {
RecordMetaDataHook hook = metaData -> {
metaData.removeIndex("MySimpleRecord$str_value_indexed");
metaData.addIndex("MySimpleRecord", new Index("limited_str_value_index", field("str_value_indexed"), Index.EMPTY_VALUE, IndexTypes.VALUE, IndexOptions.NOT_ALLOWED_FOR_QUERY_OPTIONS));
};
try (FDBRecordContext context = openContext()) {
openSimpleRecordStore(context, hook);
recordStore.deleteAllRecords();
commit(context);
}
RecordQuery query1 = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("str_value_indexed").equalsValue("abc")).build();
// Scan(<,>) | [MySimpleRecord] | str_value_indexed EQUALS abc
// Scan(<,>) | [MySimpleRecord] | $5eb5afb5-7c31-4fa4-bd7a-cec3027b6ade/str_value_indexed EQUALS abc
RecordQueryPlan plan1 = planner.plan(query1);
assertThat("should not use prohibited index", plan1, hasNoDescendant(indexScan("limited_str_value_index")));
assertTrue(plan1.hasFullRecordScan(), "should use full record scan");
if (planner instanceof RecordQueryPlanner) {
assertEquals(-223683738, plan1.planHash(PlanHashable.PlanHashKind.LEGACY));
// TODO: Issue https://github.com/FoundationDB/fdb-record-layer/issues/1074
// assertEquals(-1148834070, plan1.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertEquals(-2136471589, plan1.planHash(PlanHashable.PlanHashKind.LEGACY));
}
RecordQuery query2 = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("str_value_indexed").equalsValue("abc")).setIndexQueryabilityFilter(IndexQueryabilityFilter.TRUE).build();
// Index(limited_str_value_index [[abc],[abc]])
RecordQueryPlan plan2 = planner.plan(query2);
assertThat("explicitly use any index", plan2, descendant(indexScan("limited_str_value_index")));
assertFalse(plan2.hasRecordScan(), "should not use record scan");
assertEquals(-1573180774, plan2.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(994464666, plan2.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1531627068, plan2.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
RecordQuery query3 = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.field("str_value_indexed").equalsValue("abc")).setIndexQueryabilityFilter(IndexQueryabilityFilter.FALSE).setAllowedIndex("limited_str_value_index").build();
// Index(limited_str_value_index [[abc],[abc]])
RecordQueryPlan plan3 = planner.plan(query3);
assertThat("should use allowed index despite index queryability filter", plan3, descendant(indexScan("limited_str_value_index")));
assertFalse(plan3.hasRecordScan(), "should not use record scan");
assertEquals(-1573180774, plan2.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(994464666, plan2.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1531627068, plan2.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
}
Aggregations