use of com.apple.foundationdb.record.provider.foundationdb.IndexScanParameters in project fdb-record-layer by FoundationDB.
the class ExpressionMatcherTest method matchChildrenAsReferences.
@Test
public void matchChildrenAsReferences() {
BindingMatcher<? extends ExpressionRef<? extends RelationalExpression>> childMatcher1 = ReferenceMatchers.anyRef();
BindingMatcher<? extends ExpressionRef<? extends RelationalExpression>> childMatcher2 = ReferenceMatchers.anyRef();
BindingMatcher<RecordQueryUnionPlan> matcher = RecordQueryPlanMatchers.union(ListMatcher.exactly(QuantifierMatchers.physicalQuantifierOverRef(childMatcher1), QuantifierMatchers.physicalQuantifierOverRef(childMatcher2)));
IndexScanParameters fullValueScan = IndexScanComparisons.byValue();
RecordQueryIndexPlan child1 = new RecordQueryIndexPlan("an_index", fullValueScan, true);
RecordQueryScanPlan child2 = new RecordQueryScanPlan(ScanComparisons.EMPTY, true);
RelationalExpression root = // union with arbitrary comparison key
RecordQueryUnionPlan.from(child1, child2, EmptyKeyExpression.EMPTY, false);
Optional<PlannerBindings> possibleBindings = matcher.bindMatches(PlannerBindings.empty(), root).findFirst();
assertTrue(possibleBindings.isPresent());
PlannerBindings newBindings = possibleBindings.get().mergedWith(getExistingBindings());
assertExistingBindingsSurvived(newBindings);
// check that root matches
assertEquals(root, newBindings.get(matcher));
// check that children are behind references
assertEquals(child1, newBindings.get(childMatcher1).get());
assertEquals(child2, newBindings.get(childMatcher2).get());
}
use of com.apple.foundationdb.record.provider.foundationdb.IndexScanParameters in project fdb-record-layer by FoundationDB.
the class RecordQueryPlanner method planCoveringAggregateIndex.
@Nullable
public RecordQueryCoveringIndexPlan planCoveringAggregateIndex(@Nonnull RecordQuery query, @Nonnull Index index, @Nonnull KeyExpression indexExpr) {
final Collection<RecordType> recordTypes = metaData.recordTypesForIndex(index);
if (recordTypes.size() != 1) {
// Unfortunately, since we materialize partial records, we need a unique type for them.
return null;
}
final RecordType recordType = recordTypes.iterator().next();
final PlanContext planContext = getPlanContext(query);
planContext.rankComparisons = new RankComparisons(query.getFilter(), planContext.indexes);
// Repeated fields will be scanned one at a time by covering aggregate, so there is no issue with fan out.
planContext.allowDuplicates = true;
final CandidateScan candidateScan = new CandidateScan(planContext, index, query.isSortReverse());
final ScoredPlan scoredPlan = planCandidateScan(candidateScan, indexExpr, BooleanNormalizer.forConfiguration(configuration).normalizeIfPossible(query.getFilter()), query.getSort());
// It would be possible to handle unsatisfiedFilters if they, too, only involved group key (covering) fields.
if (scoredPlan == null || !scoredPlan.unsatisfiedFilters.isEmpty() || !(scoredPlan.plan instanceof RecordQueryIndexPlan)) {
return null;
}
final IndexKeyValueToPartialRecord.Builder builder = IndexKeyValueToPartialRecord.newBuilder(recordType);
final List<KeyExpression> keyFields = index.getRootExpression().normalizeKeyForPositions();
final List<KeyExpression> valueFields = Collections.emptyList();
for (KeyExpression resultField : query.getRequiredResults()) {
if (!addCoveringField(resultField, builder, keyFields, valueFields)) {
return null;
}
}
builder.addRequiredMessageFields();
if (!builder.isValid(true)) {
return null;
}
RecordQueryIndexPlan plan = (RecordQueryIndexPlan) scoredPlan.plan;
IndexScanParameters scanParameters = new IndexScanComparisons(IndexScanType.BY_GROUP, plan.getComparisons());
plan = new RecordQueryIndexPlan(plan.getIndexName(), scanParameters, plan.isReverse());
return new RecordQueryCoveringIndexPlan(plan, recordType.getName(), AvailableFields.NO_FIELDS, builder.build());
}
use of com.apple.foundationdb.record.provider.foundationdb.IndexScanParameters 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;
}
use of com.apple.foundationdb.record.provider.foundationdb.IndexScanParameters in project fdb-record-layer by FoundationDB.
the class ValueIndexScanMatchCandidate method tryFetchCoveringIndexScan.
@Nonnull
private Optional<RelationalExpression> tryFetchCoveringIndexScan(@Nonnull final PartialMatch partialMatch, @Nonnull final List<ComparisonRange> comparisonRanges, final boolean isReverse) {
if (recordTypes.size() > 1) {
return Optional.empty();
}
final RecordType recordType = Iterables.getOnlyElement(recordTypes);
final IndexKeyValueToPartialRecord.Builder builder = IndexKeyValueToPartialRecord.newBuilder(recordType);
for (int i = 0; i < indexKeyValues.size(); i++) {
final Value keyValue = indexKeyValues.get(i);
if (keyValue instanceof FieldValue && keyValue.isFunctionallyDependentOn(recordValue)) {
final AvailableFields.FieldData fieldData = AvailableFields.FieldData.of(IndexKeyValueToPartialRecord.TupleSource.KEY, i);
addCoveringField(builder, (FieldValue) keyValue, fieldData);
}
}
for (int i = 0; i < indexValueValues.size(); i++) {
final Value valueValue = indexValueValues.get(i);
if (valueValue instanceof FieldValue && valueValue.isFunctionallyDependentOn(recordValue)) {
final AvailableFields.FieldData fieldData = AvailableFields.FieldData.of(IndexKeyValueToPartialRecord.TupleSource.VALUE, i);
addCoveringField(builder, (FieldValue) valueValue, fieldData);
}
}
if (!builder.isValid()) {
return Optional.empty();
}
final IndexScanParameters scanParameters = IndexScanComparisons.byValue(toScanComparisons(comparisonRanges));
final RecordQueryPlanWithIndex indexPlan = new RecordQueryIndexPlan(index.getName(), scanParameters, isReverse, false, (ValueIndexScanMatchCandidate) partialMatch.getMatchCandidate());
final RecordQueryCoveringIndexPlan coveringIndexPlan = new RecordQueryCoveringIndexPlan(indexPlan, recordType.getName(), // not used except for old planner properties
AvailableFields.NO_FIELDS, builder.build());
return Optional.of(new RecordQueryFetchFromPartialRecordPlan(coveringIndexPlan, coveringIndexPlan::pushValueThroughFetch));
}
Aggregations