use of com.apple.foundationdb.record.EvaluationContext in project fdb-record-layer by FoundationDB.
the class FDBInQueryTest method testInQueryOrMultipleIndexes.
/**
* Verify an IN clause prevents index usage because the IN loop is not compatible with index ordering in the old
* planner but causes an IN-UNION to be created in the new planner.
*/
@DualPlannerTest
void testInQueryOrMultipleIndexes() throws Exception {
complexQuerySetup(NO_HOOK);
planner.setConfiguration(InAsOrUnionMode.AS_UNION.configure(planner.getConfiguration().asBuilder()).build());
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.or(Query.field("str_value_indexed").equalsValue("odd"), Query.field("num_value_3_indexed").in(Arrays.asList(1, 3)))).build();
RecordQueryPlan plan = planner.plan(query);
if (planner instanceof RecordQueryPlanner) {
// Two ordinary equals single-column index scans would be compatible on the following primary key, but
// the IN loop inside one branch prevents that here. A regular filter would not.
assertMatchesExactly(plan, unorderedPrimaryKeyDistinctPlan(unorderedUnionPlan(indexPlan().where(indexName("MySimpleRecord$str_value_indexed")).and(scanComparisons(range("[[odd],[odd]]"))), inValuesJoinPlan(indexPlan().where(indexName("MySimpleRecord$num_value_3_indexed")).and(scanComparisons(range("[EQUALS $__in_num_value_3_indexed__0]")))).where(inValuesList(equalsObject(Arrays.asList(1, 3)))))));
assertEquals(-1310248168, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(1826025907, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1395411845, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertMatchesExactly(plan, fetchFromPartialRecordPlan(unionPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$str_value_indexed")))), inUnionPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$num_value_3_indexed")).and(scanComparisons(equalities(exactly(anyParameterComparison()))))))).where(inUnionComparisonKey(primaryKey("MySimpleRecord"))).and(inUnionValuesSources(exactly(inUnionInValues(equalsObject(ImmutableList.of(1, 3)))))))));
assertEquals(2086306995, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(527952105, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(626043938, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
}
Set<Long> dupes = new HashSet<>();
assertEquals(50 + 10 + 10, querySimpleRecordStore(NO_HOOK, plan, EvaluationContext::empty, record -> {
assertTrue(dupes.add(record.getRecNo()), "should not have duplicated records");
assertTrue(record.getStrValueIndexed().equals("odd") || record.getNumValue3Indexed() == 1 || record.getNumValue3Indexed() == 3);
}, context -> TestHelpers.assertDiscardedAtMost(20, context)));
}
use of com.apple.foundationdb.record.EvaluationContext in project fdb-record-layer by FoundationDB.
the class FDBInQueryTest method inQueryWithSortBySecondFieldOfCompoundIndex.
/**
* Verify that an IN query with a sort can be implemented as an ordered union of compound indexes that can satisfy
* the sort once the equality predicates from the IN have been pushed onto the indexes.
* @see com.apple.foundationdb.record.query.plan.planning.InExtractor#asOr()
*/
@ParameterizedTest
@EnumSource(InAsOrUnionMode.class)
void inQueryWithSortBySecondFieldOfCompoundIndex(InAsOrUnionMode inAsOrMode) throws Exception {
RecordMetaDataHook hook = metaData -> metaData.addIndex("MySimpleRecord", "compoundIndex", concat(field("num_value_3_indexed"), field("str_value_indexed")));
complexQuerySetup(hook);
final List<Integer> inList = asList(1, 4, 2);
final QueryComponent filter = Query.field("num_value_3_indexed").in(inList);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(filter).setSort(field("str_value_indexed")).build();
// The configuration is planner-specific.
assertTrue(planner instanceof RecordQueryPlanner);
planner.setConfiguration(inAsOrMode.configure(planner.getConfiguration().asBuilder()).build());
// Index(MySimpleRecord$str_value_indexed <,>) | num_value_3_indexed IN [1, 4, 2]
// Index(compoundIndex [[1],[1]]) ∪[Field { 'str_value_indexed' None}, Field { 'rec_no' None}] Index(compoundIndex [[4],[4]]) ∪[Field { 'str_value_indexed' None}, Field { 'rec_no' None}] Index(compoundIndex [[2],[2]])
// ∪(__in_num_value_3_indexed__0 IN [1, 4, 2]) Index(compoundIndex [EQUALS $__in_num_value_3_indexed__0])
RecordQueryPlan plan = planner.plan(query);
if (inAsOrMode == InAsOrUnionMode.AS_OR) {
assertMatchesExactly(plan, unionPlan(inList.stream().map(number -> indexPlan().where(indexName("compoundIndex")).and(scanComparisons(range(String.format("[[%d],[%d]]", number, number))))).collect(ImmutableList.toImmutableList())).where(comparisonKey(concat(field("str_value_indexed"), primaryKey("MySimpleRecord")))));
assertEquals(-1813975352, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-1188407258, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(2089555085, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else if (inAsOrMode == InAsOrUnionMode.AS_UNION) {
assertMatchesExactly(plan, inUnionPlan(indexPlan().where(indexName("compoundIndex")).and(scanComparisons(range("[EQUALS $__in_num_value_3_indexed__0]")))).where(inUnionComparisonKey(concat(field("str_value_indexed"), primaryKey("MySimpleRecord")))).and(inUnionValuesSources(exactly(inUnionInValues(equalsObject(inList)).and(inUnionBindingName("__in_num_value_3_indexed__0"))))));
assertEquals(406364040, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(494706693, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-628125702, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertMatchesExactly(plan, filterPlan(indexPlan().where(indexName("MySimpleRecord$str_value_indexed")).and(scanComparisons(unbounded()))).where(queryComponents(exactly(equalsObject(filter)))));
assertEquals(1775865786, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(972267, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(212572525, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
}
assertEquals(60, querySimpleRecordStore(hook, plan, EvaluationContext::empty, record -> assertThat(record.getNumValue3Indexed(), anyOf(is(1), is(2), is(4))), context -> TestHelpers.assertDiscardedAtMost(40, context)));
}
use of com.apple.foundationdb.record.EvaluationContext in project fdb-record-layer by FoundationDB.
the class FDBInQueryTest method testInQueryOrCompound.
/**
* Verify that a complex query involving IN, AND, and OR is planned using a union of scans and joins on a
* multi-field index, where the left subset has equality and the final field has an IN plus inequality on that same
* field.
*/
@DualPlannerTest
void testInQueryOrCompound() throws Exception {
RecordMetaDataHook hook = complexQuerySetupHook();
complexQuerySetup(hook);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.and(Query.field("str_value_indexed").equalsValue("odd"), Query.field("num_value_2").equalsValue(0), Query.or(Query.field("num_value_3_indexed").in(Arrays.asList(1, 3)), Query.field("num_value_3_indexed").greaterThanOrEquals(4)))).build();
// Index(multi_index [EQUALS odd, EQUALS 0, EQUALS $__in_num_value_3_indexed__0]) WHERE __in_num_value_3_indexed__0 IN [1, 3] SORTED ∪[Field { 'num_value_3_indexed' None}, Field { 'rec_no' None}] Index(multi_index [[odd, 0, 4],[odd, 0]])
RecordQueryPlan plan = planner.plan(query);
if (planner instanceof RecordQueryPlanner) {
assertMatchesExactly(plan, unionPlan(inValuesJoinPlan(indexPlan().where(indexName("multi_index")).and(scanComparisons(range("[EQUALS odd, EQUALS 0, EQUALS $__in_num_value_3_indexed__0]")))).where(inValuesList(equalsObject(Arrays.asList(1, 3)))), indexPlan().where(indexName("multi_index")).and(scanComparisons(range("[[odd, 0, 4],[odd, 0]]")))));
assertEquals(468569345, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(1312398381, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(1327693258, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertMatchesExactly(plan, fetchFromPartialRecordPlan(unionPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("multi_index")))), inValuesJoinPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("multi_index")).and(scanComparisons(equalities(exactly(equalsObject(new Comparisons.SimpleComparison(Comparisons.Type.EQUALS, "odd")), equalsObject(new Comparisons.SimpleComparison(Comparisons.Type.EQUALS, 0)), anyParameterComparison()))))))).where(inValuesList(equalsObject(Arrays.asList(1, 3))))).where(comparisonKey(concat(field("num_value_3_indexed"), primaryKey("MySimpleRecord"))))));
assertEquals(687944558, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(-913554911, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-137232979, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
}
assertEquals(3 + 4 + 4, querySimpleRecordStore(hook, plan, EvaluationContext::empty, record -> {
assertThat(record.getStrValueIndexed(), is("odd"));
assertThat(record.getNumValue2(), is(0));
assertThat(record.getNumValue3Indexed(), anyOf(is(1), is(3), greaterThanOrEqualTo(4)));
}, TestHelpers::assertDiscardedNone));
}
use of com.apple.foundationdb.record.EvaluationContext in project fdb-record-layer by FoundationDB.
the class RankIndexTest method rankPlusRankIn2.
@Test
public void rankPlusRankIn2() throws Exception {
// Different rank predicates: at most one can be used in the scan.
RecordQuery query = RecordQuery.newBuilder().setRecordType("BasicRankedRecord").setFilter(Query.and(Query.field("gender").equalsValue("M"), Query.rank(Key.Expressions.field("score").ungrouped()).lessThan(3L), Query.rank(Key.Expressions.field("score").groupBy(Key.Expressions.field("gender"))).in("mranks"))).build();
RecordQueryPlan plan = planner.plan(query);
assertThat(plan, inParameter(equalTo("mranks"), scoreForRank(containsInAnyOrder(hasToString("__rank_0 = BasicRankedRecord$score.score_for_rank_else_skip(3)")), fetch(filter(rankComparisonFor("score", Comparisons.Type.LESS_THAN, "__rank_0"), coveringIndexScan(indexScan(allOf(indexName("rank_by_gender"), bounds(hasTupleString("[EQUALS M, EQUALS $__in_rank([Field { 'gender' None}, Field { 'score' None}] group 1)__0]"))))))))));
try (FDBRecordContext context = openContext()) {
openRecordStore(context);
EvaluationContext bound = EvaluationContext.forBinding("mranks", Arrays.asList(0L, 1L, 3L));
List<String> names = plan.execute(recordStore, bound).map(rec -> TestRecordsRankProto.BasicRankedRecord.newBuilder().mergeFrom(rec.getRecord()).getName()).asList().join();
assertEquals(Arrays.asList("hector", "achilles"), names);
commit(context);
}
}
use of com.apple.foundationdb.record.EvaluationContext in project fdb-record-layer by FoundationDB.
the class GeophileQueryTest method testDistance.
@Test
@Tag(Tags.Slow)
public void testDistance() throws Exception {
final RecordMetaDataHook hook = md -> {
md.addIndex("City", CITY_LOCATION_COVERING_INDEX);
};
loadCities(hook, 0);
final int centerId = 5391959;
final double distance = 1;
final int scanLimit = 5000;
final RecordQueryPlan scanPlan = distanceFilterScan(distance);
final Set<Integer> scanResults = new HashSet<>();
byte[] continuation = null;
do {
try (FDBRecordContext context = openContext()) {
openRecordStore(context, hook);
EvaluationContext joinContext = bindCenter(centerId);
ExecuteProperties executeProperties = ExecuteProperties.newBuilder().setScannedRecordsLimit(scanLimit).build();
RecordCursor<FDBQueriedRecord<Message>> recordCursor = scanPlan.execute(recordStore, joinContext, continuation, executeProperties);
recordCursor.forEach(city -> {
TestRecordsGeoProto.City.Builder cityBuilder = TestRecordsGeoProto.City.newBuilder().mergeFrom(city.getRecord());
LOGGER.debug(String.format("Scan found %s: %s", cityBuilder.getGeoNameId(), cityBuilder.getName()));
scanResults.add(cityBuilder.getGeoNameId());
}).join();
continuation = recordCursor.getNext().getContinuation().toBytes();
commit(context);
}
} while (continuation != null);
final RecordQueryPlan indexPlan = distanceSpatialQuery(distance, false);
final Set<Integer> indexResults = new HashSet<>();
try (FDBRecordContext context = openContext()) {
openRecordStore(context, hook);
RecordCursor<FDBQueriedRecord<Message>> recordCursor = indexPlan.execute(recordStore, bindCenter(centerId));
recordCursor.forEach(city -> {
TestRecordsGeoProto.City.Builder cityBuilder = TestRecordsGeoProto.City.newBuilder().mergeFrom(city.getRecord());
LOGGER.debug(String.format("Index found %s: %s", cityBuilder.getGeoNameId(), cityBuilder.getName()));
indexResults.add(cityBuilder.getGeoNameId());
}).join();
int given = timer.getCount(FDBStoreTimer.Counts.QUERY_FILTER_GIVEN);
int passed = timer.getCount(FDBStoreTimer.Counts.QUERY_FILTER_PASSED);
int discarded = timer.getCount(FDBStoreTimer.Counts.QUERY_DISCARDED);
assertThat("Should have passed more than discarded", passed, greaterThan(discarded));
commit(context);
}
final RecordQueryPlan coveringPlan = distanceSpatialQuery(distance, true);
final Set<Integer> coveringResults = new HashSet<>();
try (FDBRecordContext context = openContext()) {
openRecordStore(context, hook);
RecordCursor<FDBQueriedRecord<Message>> recordCursor = indexPlan.execute(recordStore, bindCenter(centerId));
recordCursor.forEach(city -> {
TestRecordsGeoProto.City.Builder cityBuilder = TestRecordsGeoProto.City.newBuilder().mergeFrom(city.getRecord());
LOGGER.debug(String.format("Covering found %s: %s", cityBuilder.getGeoNameId(), cityBuilder.getName()));
coveringResults.add(cityBuilder.getGeoNameId());
}).join();
commit(context);
}
assertEquals(scanResults, indexResults);
assertEquals(scanResults, coveringResults);
}
Aggregations