use of com.apple.foundationdb.record.query.plan.plans.RecordQueryCoveringIndexPlan 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.query.plan.plans.RecordQueryCoveringIndexPlan in project fdb-record-layer by FoundationDB.
the class RemoveSortRule method strictlyOrderedIfUnique.
// TODO: This suggests that ordering and distinct should be tracked together.
public static boolean strictlyOrderedIfUnique(@Nonnull RecordQueryPlan orderedPlan, @Nonnull final Function<String, Index> getIndex, final int nkeys) {
if (orderedPlan instanceof RecordQueryCoveringIndexPlan) {
orderedPlan = ((RecordQueryCoveringIndexPlan) orderedPlan).getIndexPlan();
}
if (orderedPlan instanceof RecordQueryIndexPlan) {
RecordQueryIndexPlan indexPlan = (RecordQueryIndexPlan) orderedPlan;
Index index = getIndex.apply(indexPlan.getIndexName());
return index.isUnique() && nkeys >= index.getColumnSize();
}
return false;
}
use of com.apple.foundationdb.record.query.plan.plans.RecordQueryCoveringIndexPlan in project fdb-record-layer by FoundationDB.
the class RecordQueryPlannerSubstitutionVisitor method removeIndexFetch.
@Nullable
public static RecordQueryPlan removeIndexFetch(@Nonnull RecordMetaData recordMetaData, @Nonnull PlannableIndexTypes indexTypes, @Nullable KeyExpression commonPrimaryKey, @Nonnull RecordQueryPlan plan, @Nonnull Set<KeyExpression> requiredFields) {
if (plan instanceof RecordQueryPlanWithIndex) {
RecordQueryPlanWithIndex indexPlan = (RecordQueryPlanWithIndex) plan;
Index index = recordMetaData.getIndex(indexPlan.getIndexName());
final Collection<RecordType> recordTypes = recordMetaData.recordTypesForIndex(index);
if (recordTypes.size() != 1) {
return null;
}
final RecordType recordType = Iterables.getOnlyElement(recordTypes);
AvailableFields fieldsFromIndex = AvailableFields.fromIndex(recordType, index, indexTypes, commonPrimaryKey);
Set<KeyExpression> fields = new HashSet<>(requiredFields);
if (commonPrimaryKey != null) {
// Need the primary key, even if it wasn't one of the explicit result fields.
fields.addAll(commonPrimaryKey.normalizeKeyForPositions());
}
if (fieldsFromIndex.containsAll(fields)) {
final IndexKeyValueToPartialRecord keyValueToPartialRecord = fieldsFromIndex.buildIndexKeyValueToPartialRecord(recordType).build();
if (keyValueToPartialRecord != null) {
return new RecordQueryCoveringIndexPlan(indexPlan, recordType.getName(), fieldsFromIndex, keyValueToPartialRecord);
}
}
} else if (plan instanceof RecordQueryFetchFromPartialRecordPlan) {
RecordQueryFetchFromPartialRecordPlan fetchPlan = (RecordQueryFetchFromPartialRecordPlan) plan;
if (fetchPlan.getChild().getAvailableFields().containsAll(requiredFields)) {
return ((RecordQueryFetchFromPartialRecordPlan) plan).getChild();
}
}
return null;
}
use of com.apple.foundationdb.record.query.plan.plans.RecordQueryCoveringIndexPlan in project fdb-record-layer by FoundationDB.
the class ComposedBitmapIndexMatcher method matchesSafely.
@Override
public boolean matchesSafely(@Nonnull RecordQueryPlan plan) {
if (!(plan instanceof ComposedBitmapIndexQueryPlan)) {
return false;
}
ComposedBitmapIndexQueryPlan composedBitmapPlan = (ComposedBitmapIndexQueryPlan) plan;
if (!composerMatcher.matches(composedBitmapPlan.getComposer())) {
return false;
}
List<RecordQueryCoveringIndexPlan> childPlans = composedBitmapPlan.getIndexPlans();
if (childPlans.size() != childMatchers.size()) {
return false;
}
for (int i = 0; i < childMatchers.size(); i++) {
if (!childMatchers.get(i).matches(childPlans.get(i))) {
return false;
}
}
return true;
}
use of com.apple.foundationdb.record.query.plan.plans.RecordQueryCoveringIndexPlan 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());
}
Aggregations