use of com.apple.foundationdb.record.metadata.expressions.KeyExpression in project fdb-record-layer by FoundationDB.
the class ImplementInUnionRule method orderingForInUnion.
private static Optional<Ordering> orderingForInUnion(@Nonnull Ordering providedOrdering, @Nonnull RequestedOrdering requestedOrdering, @Nonnull Set<KeyExpression> innerBoundExpressions) {
final var availableInnerBoundExpressions = Sets.newHashSet(innerBoundExpressions);
final var providedKeyPartIterator = Iterators.peekingIterator(providedOrdering.getOrderingKeyParts().iterator());
final ImmutableList.Builder<KeyPart> resultingOrderingKeyPartBuilder = ImmutableList.builder();
for (final var requestedKeyPart : requestedOrdering.getOrderingKeyParts()) {
KeyPart toBeAdded = null;
if (providedKeyPartIterator.hasNext()) {
final var providedKeyPart = providedKeyPartIterator.peek();
if (requestedKeyPart.equals(providedKeyPart)) {
toBeAdded = providedKeyPart;
providedKeyPartIterator.next();
}
}
if (toBeAdded == null) {
final var requestedKeyExpression = requestedKeyPart.getNormalizedKeyExpression();
if (innerBoundExpressions.contains(requestedKeyExpression)) {
toBeAdded = requestedKeyPart;
availableInnerBoundExpressions.remove(requestedKeyExpression);
}
}
if (toBeAdded != null) {
resultingOrderingKeyPartBuilder.add(toBeAdded);
} else {
return Optional.empty();
}
}
//
while (providedKeyPartIterator.hasNext()) {
final var providedKeyPart = providedKeyPartIterator.next();
resultingOrderingKeyPartBuilder.add(providedKeyPart);
}
final SetMultimap<KeyExpression, Comparisons.Comparison> resultEqualityBoundKeyMap = HashMultimap.create(providedOrdering.getEqualityBoundKeyMap());
innerBoundExpressions.forEach(resultEqualityBoundKeyMap::removeAll);
return Optional.of(new Ordering(resultEqualityBoundKeyMap, resultingOrderingKeyPartBuilder.build(), providedOrdering.isDistinct()));
}
use of com.apple.foundationdb.record.metadata.expressions.KeyExpression in project fdb-record-layer by FoundationDB.
the class ImplementInUnionRule method onMatch.
@SuppressWarnings({ "unchecked", "java:S135" })
@Override
public void onMatch(@Nonnull PlannerRuleCall call) {
final var context = call.getContext();
final var bindings = call.getBindings();
final var requestedOrderingsOptional = call.getInterestingProperty(OrderingAttribute.ORDERING);
if (requestedOrderingsOptional.isEmpty()) {
return;
}
final var requestedOrderings = requestedOrderingsOptional.get();
final var commonPrimaryKey = context.getCommonPrimaryKey();
if (commonPrimaryKey == null) {
return;
}
final var selectExpression = bindings.get(root);
if (!selectExpression.getPredicates().isEmpty()) {
return;
}
final var explodeQuantifiers = bindings.get(explodeQuantifiersMatcher);
if (explodeQuantifiers.isEmpty()) {
return;
}
final var explodeAliases = Quantifiers.aliases(explodeQuantifiers);
final var innerQuantifierOptional = findInnerQuantifier(selectExpression, explodeQuantifiers, explodeAliases);
if (innerQuantifierOptional.isEmpty()) {
return;
}
final var innerQuantifier = innerQuantifierOptional.get();
final List<? extends Value> resultValues = selectExpression.getResultValues();
if (resultValues.stream().anyMatch(resultValue -> !(resultValue instanceof QuantifiedColumnValue) || !((QuantifiedColumnValue) resultValue).getAlias().equals(innerQuantifier.getAlias()))) {
return;
}
final var explodeExpressions = bindings.getAll(explodeExpressionMatcher);
final var quantifierToExplodeBiMap = computeQuantifierToExplodeMap(explodeQuantifiers, explodeExpressions.stream().collect(LinkedIdentitySet.toLinkedIdentitySet()));
final var explodeToQuantifierBiMap = quantifierToExplodeBiMap.inverse();
final var sourcesBuilder = ImmutableList.<InSource>builder();
for (final var explodeExpression : explodeExpressions) {
final var explodeQuantifier = Objects.requireNonNull(explodeToQuantifierBiMap.getUnwrapped(explodeExpression));
final List<? extends Value> explodeResultValues = explodeExpression.getResultValues();
if (explodeResultValues.size() != 1) {
return;
}
final Value explodeValue = Iterables.getOnlyElement(explodeResultValues);
//
// Create the source for the in-union plan
//
final InSource inSource;
if (explodeValue instanceof LiteralValue<?>) {
final Object literalValue = ((LiteralValue<?>) explodeValue).getLiteralValue();
if (literalValue instanceof List<?>) {
inSource = new InValuesSource(CORRELATION.bindingName(explodeQuantifier.getAlias().getId()), (List<Object>) literalValue);
} else {
return;
}
} else if (explodeValue instanceof QuantifiedColumnValue) {
inSource = new InParameterSource(CORRELATION.bindingName(explodeQuantifier.getAlias().getId()), ((QuantifiedColumnValue) explodeValue).getAlias().getId());
} else {
return;
}
sourcesBuilder.add(inSource);
}
final var inSources = sourcesBuilder.build();
final Map<Ordering, ImmutableList<RecordQueryPlan>> groupedByOrdering = innerQuantifier.getRangesOver().getMembers().stream().flatMap(relationalExpression -> relationalExpression.narrowMaybe(RecordQueryPlan.class).stream()).flatMap(plan -> {
final Optional<Ordering> orderingForLegOptional = OrderingProperty.evaluate(plan, context);
return orderingForLegOptional.stream().map(ordering -> Pair.of(ordering, plan));
}).collect(Collectors.groupingBy(Pair::getLeft, Collectors.mapping(Pair::getRight, ImmutableList.toImmutableList())));
final int attemptFailedInJoinAsUnionMaxSize = call.getContext().getPlannerConfiguration().getAttemptFailedInJoinAsUnionMaxSize();
for (final Map.Entry<Ordering, ImmutableList<RecordQueryPlan>> providedOrderingEntry : groupedByOrdering.entrySet()) {
for (final RequestedOrdering requestedOrdering : requestedOrderings) {
final var providedOrdering = providedOrderingEntry.getKey();
final var matchingKeyExpressionsBuilder = ImmutableSet.<KeyExpression>builder();
for (Map.Entry<KeyExpression, Comparisons.Comparison> expressionComparisonEntry : providedOrdering.getEqualityBoundKeyMap().entries()) {
final Comparisons.Comparison comparison = expressionComparisonEntry.getValue();
if (comparison.getType() == Comparisons.Type.EQUALS && comparison instanceof Comparisons.ParameterComparison) {
final Comparisons.ParameterComparison parameterComparison = (Comparisons.ParameterComparison) comparison;
if (parameterComparison.isCorrelation() && explodeAliases.containsAll(parameterComparison.getCorrelatedTo())) {
matchingKeyExpressionsBuilder.add(expressionComparisonEntry.getKey());
}
}
}
// Compute a comparison key that satisfies the requested ordering
final Optional<Ordering> combinedOrderingOptional = orderingForInUnion(providedOrdering, requestedOrdering, matchingKeyExpressionsBuilder.build());
if (combinedOrderingOptional.isEmpty()) {
continue;
}
final Ordering combinedOrdering = combinedOrderingOptional.get();
final List<KeyPart> orderingKeyParts = combinedOrdering.getOrderingKeyParts();
final List<KeyExpression> orderingKeys = orderingKeyParts.stream().map(KeyPart::getNormalizedKeyExpression).collect(ImmutableList.toImmutableList());
//
// At this point we know we can implement the distinct union over the partitions of compatibly ordered plans
//
final KeyExpression comparisonKey = orderingKeys.size() == 1 ? Iterables.getOnlyElement(orderingKeys) : Key.Expressions.concat(orderingKeys);
final GroupExpressionRef<RecordQueryPlan> newInnerPlanReference = GroupExpressionRef.from(providedOrderingEntry.getValue());
final Quantifier.Physical newInnerQuantifier = Quantifier.physical(newInnerPlanReference);
call.yield(call.ref(new RecordQueryInUnionPlan(newInnerQuantifier, inSources, comparisonKey, RecordQueryUnionPlanBase.isReversed(ImmutableList.of(newInnerQuantifier)), attemptFailedInJoinAsUnionMaxSize)));
}
}
}
use of com.apple.foundationdb.record.metadata.expressions.KeyExpression in project fdb-record-layer by FoundationDB.
the class OrderingProperty method deriveForPredicatesFilterFromOrderings.
public static Optional<Ordering> deriveForPredicatesFilterFromOrderings(@Nonnull final List<Optional<Ordering>> orderingOptionals, @Nonnull final RecordQueryPredicatesFilterPlan predicatesFilterPlan) {
final Optional<Ordering> childOrderingOptional = Iterables.getOnlyElement(orderingOptionals);
if (childOrderingOptional.isPresent()) {
final Ordering childOrdering = childOrderingOptional.get();
final SetMultimap<KeyExpression, Comparisons.Comparison> equalityBoundFileKeyExpressions = predicatesFilterPlan.getPredicates().stream().flatMap(queryPredicate -> {
if (!(queryPredicate instanceof ValuePredicate)) {
return Stream.empty();
}
final ValuePredicate valuePredicate = (ValuePredicate) queryPredicate;
if (!valuePredicate.getComparison().getType().isEquality()) {
return Stream.empty();
}
if (!(valuePredicate.getValue() instanceof FieldValue)) {
return Stream.of();
}
return Stream.of(Pair.of((FieldValue) valuePredicate.getValue(), valuePredicate.getComparison()));
}).map(valueComparisonPair -> {
final FieldValue fieldValue = valueComparisonPair.getLeft();
final String fieldName = fieldValue.getFieldName();
KeyExpression keyExpression = Key.Expressions.field(fieldName);
final List<String> fieldPrefix = fieldValue.getFieldPrefix();
for (int i = fieldPrefix.size() - 1; i >= 0; i--) {
keyExpression = Key.Expressions.field(fieldPrefix.get(i)).nest(keyExpression);
}
return Pair.of(keyExpression, valueComparisonPair.getRight());
}).collect(ImmutableSetMultimap.toImmutableSetMultimap(Pair::getLeft, Pair::getRight));
final ImmutableList<KeyPart> resultOrderingKeyParts = childOrdering.getOrderingKeyParts().stream().filter(keyPart -> !equalityBoundFileKeyExpressions.containsKey(keyPart.getNormalizedKeyExpression())).collect(ImmutableList.toImmutableList());
final SetMultimap<KeyExpression, Comparisons.Comparison> resultEqualityBoundKeyMap = HashMultimap.create(childOrdering.getEqualityBoundKeyMap());
equalityBoundFileKeyExpressions.forEach(resultEqualityBoundKeyMap::put);
return Optional.of(new Ordering(resultEqualityBoundKeyMap, resultOrderingKeyParts, childOrdering.isDistinct()));
} else {
return Optional.empty();
}
}
use of com.apple.foundationdb.record.metadata.expressions.KeyExpression in project fdb-record-layer by FoundationDB.
the class OrderingProperty method deriveForUnionFromOrderings.
public static Optional<Ordering> deriveForUnionFromOrderings(@Nonnull final List<Optional<Ordering>> orderingOptionals, @Nonnull final RequestedOrdering requestedOrdering, @Nonnull final BinaryOperator<SetMultimap<KeyExpression, Comparisons.Comparison>> combineFn) {
final Optional<SetMultimap<KeyExpression, Comparisons.Comparison>> commonEqualityBoundKeysMapOptional = Ordering.combineEqualityBoundKeys(orderingOptionals, combineFn);
if (commonEqualityBoundKeysMapOptional.isEmpty()) {
return Optional.empty();
}
final var commonEqualityBoundKeysMap = commonEqualityBoundKeysMapOptional.get();
final Optional<List<KeyPart>> commonOrderingKeysOptional = Ordering.commonOrderingKeys(orderingOptionals, requestedOrdering);
if (commonOrderingKeysOptional.isEmpty()) {
return Optional.empty();
}
final var commonOrderingKeys = commonOrderingKeysOptional.get().stream().filter(keyPart -> !commonEqualityBoundKeysMap.containsKey(keyPart.getNormalizedKeyExpression())).collect(ImmutableList.toImmutableList());
return Optional.of(new Ordering(commonEqualityBoundKeysMap, commonOrderingKeys, false));
}
use of com.apple.foundationdb.record.metadata.expressions.KeyExpression in project fdb-record-layer by FoundationDB.
the class OrderingProperty method evaluateAtRef.
@Nonnull
@Override
public Optional<Ordering> evaluateAtRef(@Nonnull ExpressionRef<? extends RelationalExpression> ref, @Nonnull List<Optional<Ordering>> orderingOptionals) {
final Optional<SetMultimap<KeyExpression, Comparisons.Comparison>> commonEqualityBoundKeysMapOptional = Ordering.combineEqualityBoundKeys(orderingOptionals, Ordering::intersectEqualityBoundKeys);
if (commonEqualityBoundKeysMapOptional.isEmpty()) {
return Optional.empty();
}
final var commonEqualityBoundKeysMap = commonEqualityBoundKeysMapOptional.get();
final Optional<List<KeyPart>> commonOrderingKeysOptional = Ordering.commonOrderingKeys(orderingOptionals, RequestedOrdering.preserve());
if (commonOrderingKeysOptional.isEmpty()) {
return Optional.empty();
}
final var commonOrderingKeys = commonOrderingKeysOptional.get().stream().filter(keyPart -> !commonEqualityBoundKeysMap.containsKey(keyPart.getNormalizedKeyExpression())).collect(ImmutableList.toImmutableList());
final var allAreDistinct = orderingOptionals.stream().allMatch(orderingOptional -> orderingOptional.map(Ordering::isDistinct).orElse(false));
return Optional.of(new Ordering(commonEqualityBoundKeysMap, commonOrderingKeys, allAreDistinct));
}
Aggregations