use of com.apple.foundationdb.record.query.expressions.Comparisons 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.expressions.Comparisons in project fdb-record-layer by FoundationDB.
the class FDBRecordStoreTest method testOverlappingPrimaryKey.
@Test
public void testOverlappingPrimaryKey() {
try (FDBRecordContext context = openContext()) {
RecordMetaDataBuilder builder = RecordMetaData.newBuilder().setRecords(TestRecordsWithHeaderProto.getDescriptor());
builder.getRecordType("MyRecord").setPrimaryKey(field("header").nest(concatenateFields("path", "rec_no")));
builder.addIndex("MyRecord", "MyRecord$path_str", concat(field("header").nest("path"), field("str_value")));
RecordMetaData metaData = builder.getRecordMetaData();
createOrOpenRecordStore(context, metaData);
TestRecordsWithHeaderProto.MyRecord.Builder recBuilder = TestRecordsWithHeaderProto.MyRecord.newBuilder();
TestRecordsWithHeaderProto.HeaderRecord.Builder headerBuilder = recBuilder.getHeaderBuilder();
headerBuilder.setPath("aaa");
headerBuilder.setRecNo(1);
recBuilder.setStrValue("hello");
recordStore.saveRecord(recBuilder.build());
headerBuilder.setPath("aaa");
headerBuilder.setRecNo(2);
recBuilder.setStrValue("goodbye");
recordStore.saveRecord(recBuilder.build());
headerBuilder.setPath("zzz");
headerBuilder.setRecNo(3);
recBuilder.setStrValue("end");
recordStore.saveRecord(recBuilder.build());
List<List<Object>> rows = new ArrayList<>();
Index index = metaData.getIndex("MyRecord$path_str");
ScanComparisons comparisons = ScanComparisons.from(new Comparisons.SimpleComparison(Comparisons.Type.EQUALS, "aaa"));
TupleRange range = comparisons.toTupleRange();
try (RecordCursor<IndexEntry> cursor = recordStore.scanIndex(index, IndexScanType.BY_VALUE, range, null, ScanProperties.FORWARD_SCAN)) {
cursor.forEach(row -> rows.add(row.getKey().getItems())).join();
}
assertEquals(Arrays.asList(Arrays.asList("aaa", "goodbye", 2L), Arrays.asList("aaa", "hello", 1L)), rows);
}
}
use of com.apple.foundationdb.record.query.expressions.Comparisons in project fdb-record-layer by FoundationDB.
the class FDBInQueryTest method testInQueryOrOverlap.
/**
* Verify that IN queries can be planned using index scans, then used in a UNION to implement an OR with IN whose
* elements overlap, and that the union with that comparison key deduplicates the records in the overlap.
*/
@DualPlannerTest
void testInQueryOrOverlap() throws Exception {
complexQuerySetup(NO_HOOK);
RecordQuery query = RecordQuery.newBuilder().setRecordType("MySimpleRecord").setFilter(Query.or(Query.field("num_value_unique").in(Arrays.asList(903, 905, 901)), Query.field("num_value_unique").in(Arrays.asList(906, 905, 904)))).build();
RecordQueryPlan plan = planner.plan(query);
if (planner instanceof RecordQueryPlanner) {
// Index(MySimpleRecord$num_value_unique [EQUALS $__in_num_value_unique__0]) WHERE __in_num_value_unique__0 IN [901, 903, 905] SORTED ∪[Field { 'num_value_unique' None}, Field { 'rec_no' None}] Index(MySimpleRecord$num_value_unique [EQUALS $__in_num_value_unique__0]) WHERE __in_num_value_unique__0 IN [904, 905, 906] SORTED
// Ordinary equality comparisons would be ordered just by the primary key so that would be the union comparison key.
// Must compare the IN field here; they are ordered, but not trivially (same value for each).
assertMatchesExactly(plan, unionPlan(inValuesJoinPlan(indexPlan().where(indexName("MySimpleRecord$num_value_unique")).and(scanComparisons(range("[EQUALS $__in_num_value_unique__0]")))).where(inValuesList(equalsObject(Arrays.asList(901, 903, 905)))), inValuesJoinPlan(indexPlan().where(indexName("MySimpleRecord$num_value_unique")).and(scanComparisons(range("[EQUALS $__in_num_value_unique__0]")))).where(inValuesList(equalsObject(Arrays.asList(904, 905, 906))))));
assertEquals(218263868, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(468995802, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(2098251608, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
} else {
assertMatchesExactly(plan, fetchFromPartialRecordPlan(unionPlan(inValuesJoinPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$num_value_unique")).and(scanComparisons(equalities(exactly(anyParameterComparison()))))))).where(inValuesList(equalsObject(Arrays.asList(901, 903, 905)))), inValuesJoinPlan(coveringIndexPlan().where(indexPlanOf(indexPlan().where(indexName("MySimpleRecord$num_value_unique")).and(scanComparisons(equalities(exactly(anyParameterComparison()))))))).where(inValuesList(equalsObject(Arrays.asList(904, 905, 906))))).where(comparisonKey(concat(field("num_value_unique"), primaryKey("MySimpleRecord"))))));
assertEquals(-1323754895, plan.planHash(PlanHashable.PlanHashKind.LEGACY));
assertEquals(856768529, plan.planHash(PlanHashable.PlanHashKind.FOR_CONTINUATION));
assertEquals(-1700358353, plan.planHash(PlanHashable.PlanHashKind.STRUCTURAL_WITHOUT_LITERALS));
}
Set<Long> dupes = new HashSet<>();
assertEquals(5, querySimpleRecordStore(NO_HOOK, plan, EvaluationContext::empty, record -> {
assertTrue(dupes.add(record.getRecNo()), "should not have duplicated records");
assertThat(record.getNumValueUnique(), anyOf(is(901), is(903), is(904), is(905), is(906)));
}, context -> TestHelpers.assertDiscardedAtMost(1, context)));
}
use of com.apple.foundationdb.record.query.expressions.Comparisons in project fdb-record-layer by FoundationDB.
the class RecordQueryPlanner method planVersion.
@Nullable
private ScoredPlan planVersion(@Nonnull CandidateScan candidateScan, @Nonnull KeyExpression indexExpr, @Nonnull QueryRecordFunctionWithComparison filter, @Nullable KeyExpression sort) {
if (indexExpr instanceof VersionKeyExpression) {
final Comparisons.Comparison comparison = filter.getComparison();
final ScanComparisons comparisons = ScanComparisons.from(comparison);
if (sort == null || sort.equals(VersionKeyExpression.VERSION)) {
IndexScanParameters scanParameters = IndexScanComparisons.byValue(comparisons);
RecordQueryPlan plan = new RecordQueryIndexPlan(candidateScan.index.getName(), scanParameters, candidateScan.reverse);
return new ScoredPlan(1, plan, Collections.emptyList(), false);
}
} else if (indexExpr instanceof ThenKeyExpression) {
ThenKeyExpression then = (ThenKeyExpression) indexExpr;
if (sort == null) {
// && !then.createsDuplicates()) {
return planVersion(candidateScan, then.getChildren().get(0), filter, null);
} else {
return new AndWithThenPlanner(candidateScan, then, Collections.singletonList(filter), sort).plan();
}
}
return null;
}
Aggregations