use of com.apple.foundationdb.record.query.expressions.NestedField in project fdb-record-layer by FoundationDB.
the class RecordQueryPlanner method planAndWithNesting.
@Nullable
private ScoredPlan planAndWithNesting(@Nonnull CandidateScan candidateScan, @Nonnull NestingKeyExpression indexExpr, @Nonnull AndComponent filter, @Nullable KeyExpression sort) {
final FieldKeyExpression parent = indexExpr.getParent();
if (parent.getFanType() == FanType.None) {
// For non-spread case, we can do a better job trying to match more than one of the filter children if
// they have the same nesting.
final List<QueryComponent> nestedFilters = new ArrayList<>();
final List<QueryComponent> remainingFilters = new ArrayList<>();
for (QueryComponent filterChild : filter.getChildren()) {
QueryComponent filterComponent = candidateScan.planContext.rankComparisons.planComparisonSubstitute(filterChild);
if (filterComponent instanceof NestedField) {
final NestedField nestedField = (NestedField) filterComponent;
if (parent.getFieldName().equals(nestedField.getFieldName())) {
nestedFilters.add(nestedField.getChild());
continue;
}
}
remainingFilters.add(filterChild);
}
if (nestedFilters.size() > 1) {
final NestedField nestedAnd = new NestedField(parent.getFieldName(), Query.and(nestedFilters));
final ScoredPlan plan = planNestedField(candidateScan, indexExpr, nestedAnd, sort);
if (plan != null) {
if (remainingFilters.isEmpty()) {
return plan;
} else {
return plan.withUnsatisfiedFilters(remainingFilters);
}
} else {
return null;
}
}
}
List<QueryComponent> unsatisfiedFilters = new ArrayList<>(filter.getChildren());
for (QueryComponent filterChild : filter.getChildren()) {
QueryComponent filterComponent = candidateScan.planContext.rankComparisons.planComparisonSubstitute(filterChild);
if (filterComponent instanceof NestedField) {
NestedField nestedField = (NestedField) filterComponent;
final ScoredPlan plan = planNestedField(candidateScan, indexExpr, nestedField, sort);
if (plan != null) {
unsatisfiedFilters.remove(filterChild);
return plan.withUnsatisfiedFilters(unsatisfiedFilters);
}
}
}
return null;
}
use of com.apple.foundationdb.record.query.expressions.NestedField in project fdb-record-layer by FoundationDB.
the class InExtractor method mapClauses.
private QueryComponent mapClauses(QueryComponent filter, BiFunction<ComponentWithComparison, List<FieldKeyExpression>, QueryComponent> mapper, @Nullable List<FieldKeyExpression> fields) {
if (filter instanceof ComponentWithComparison) {
final ComponentWithComparison withComparison = (ComponentWithComparison) filter;
return mapper.apply(withComparison, fields);
} else if (filter instanceof ComponentWithChildren) {
ComponentWithChildren componentWithChildren = (ComponentWithChildren) filter;
return componentWithChildren.withOtherChildren(componentWithChildren.getChildren().stream().map(component -> mapClauses(component, mapper, fields)).collect(Collectors.toList()));
} else if (filter instanceof ComponentWithSingleChild) {
ComponentWithSingleChild componentWithSingleChild = (ComponentWithSingleChild) filter;
List<FieldKeyExpression> nestedFields = null;
if (fields != null && (componentWithSingleChild instanceof NestedField || componentWithSingleChild instanceof OneOfThemWithComponent)) {
nestedFields = new ArrayList<>(fields);
nestedFields.add(Key.Expressions.field(((BaseField) componentWithSingleChild).getFieldName(), componentWithSingleChild instanceof NestedField ? KeyExpression.FanType.None : KeyExpression.FanType.FanOut));
}
return componentWithSingleChild.withOtherChild(mapClauses(componentWithSingleChild.getChild(), mapper, nestedFields));
} else if (filter instanceof ComponentWithNoChildren) {
return filter;
} else {
throw new Query.InvalidExpressionException("Unsupported query type " + filter.getClass());
}
}
use of com.apple.foundationdb.record.query.expressions.NestedField in project fdb-record-layer by FoundationDB.
the class IndexAggregateFunctionCall method extractFieldPaths.
/**
* Helper method to extract a set of key expressions that are bound through some comparison in the
* query component passed in.
* @param queryComponent the query component
* @param predicate a predicate used for filtering each encountered {@link FieldWithComparison}
* @return a set of {@link KeyExpression}s where each element is a key expression of a field (i.e. a
* {@link com.apple.foundationdb.record.metadata.expressions.FieldKeyExpression}) or a simple nesting field
* (i.e. a {@link com.apple.foundationdb.record.metadata.expressions.NestingKeyExpression}) that is bound
* through some comparison
*/
@Nonnull
public static Set<KeyExpression> extractFieldPaths(@Nonnull QueryComponent queryComponent, @Nonnull final Predicate<FieldWithComparison> predicate) {
if (queryComponent instanceof BaseField) {
final BaseField baseField = (BaseField) queryComponent;
if (baseField instanceof NestedField) {
final NestedField nestedField = (NestedField) baseField;
final Set<KeyExpression> nestedExpressions = extractFieldPaths(nestedField.getChild(), predicate);
return nestedExpressions.stream().map(nestedExpression -> Key.Expressions.field(nestedField.getFieldName()).nest(nestedExpression)).collect(ImmutableSet.toImmutableSet());
}
if (baseField instanceof FieldWithComparison) {
final FieldWithComparison fieldWithComparison = (FieldWithComparison) baseField;
if (predicate.test(fieldWithComparison)) {
return ImmutableSet.of(Key.Expressions.field(fieldWithComparison.getFieldName()));
}
}
return ImmutableSet.of();
} else if (queryComponent instanceof AndComponent) {
final Set<KeyExpression> boundFields = Sets.newHashSet();
final AndComponent andComponent = (AndComponent) queryComponent;
andComponent.getChildren().forEach(child -> boundFields.addAll(extractEqualityBoundFields(child)));
return boundFields;
}
return ImmutableSet.of();
}
use of com.apple.foundationdb.record.query.expressions.NestedField in project fdb-record-layer by FoundationDB.
the class RankComparisons method findComparison.
private void findComparison(@Nonnull QueryRecordFunctionWithComparison comparison, @Nonnull List<Index> indexes, @Nonnull List<QueryComponent> potentialGroupFilters, @Nonnull AtomicInteger counter) {
RecordFunction<?> recordFunction = comparison.getFunction();
// TODO: Should share with indexMaintainerForAggregateFunction
// TODO: Move index-specific query planning behavior outside of planner (https://github.com/FoundationDB/fdb-record-layer/issues/17)
List<String> requiredIndexTypes;
if (recordFunction.getName().equals(FunctionNames.RANK)) {
requiredIndexTypes = Arrays.asList(IndexTypes.RANK, IndexTypes.TIME_WINDOW_LEADERBOARD);
} else if (recordFunction.getName().equals(FunctionNames.TIME_WINDOW_RANK)) {
requiredIndexTypes = Collections.singletonList(IndexTypes.TIME_WINDOW_LEADERBOARD);
} else {
requiredIndexTypes = null;
}
if (requiredIndexTypes != null) {
final GroupingKeyExpression operand = ((IndexRecordFunction) recordFunction).getOperand();
Optional<Index> matchingIndex = indexes.stream().filter(index -> requiredIndexTypes.contains(index.getType()) && index.getRootExpression().equals(operand)).min(Comparator.comparing(Index::getColumnSize));
if (matchingIndex.isPresent()) {
final KeyExpression groupBy = operand.getGroupingSubKey();
final List<QueryComponent> groupFilters = new ArrayList<>();
final List<Comparisons.Comparison> groupComparisons = new ArrayList<>();
if (!GroupingValidator.findGroupKeyFilters(potentialGroupFilters, groupBy, groupFilters, groupComparisons)) {
return;
}
QueryComponent substitute = null;
String bindingName = null;
final Comparisons.Type comparisonType = comparison.getComparison().getType();
if (!operand.createsDuplicates() && !comparisonType.isUnary()) {
bindingName = Bindings.Internal.RANK.bindingName(Integer.toString(counter.getAndIncrement()));
Comparisons.Comparison substituteComparison = new Comparisons.ParameterComparison(comparisonType, bindingName, Bindings.Internal.RANK);
final KeyExpression grouped = operand.getGroupedSubKey();
if (grouped instanceof FieldKeyExpression) {
substitute = new FieldWithComparison(((FieldKeyExpression) grouped).getFieldName(), substituteComparison);
} else if (grouped instanceof NestingKeyExpression) {
NestingKeyExpression nesting = (NestingKeyExpression) grouped;
if (nesting.getChild() instanceof FieldKeyExpression) {
substitute = new NestedField(nesting.getParent().getFieldName(), new FieldWithComparison(((FieldKeyExpression) nesting.getChild()).getFieldName(), substituteComparison));
}
}
if (substitute == null) {
bindingName = null;
}
}
comparisons.put(comparison, new RankComparison(comparison, matchingIndex.get(), groupFilters, groupComparisons, substitute, bindingName));
}
}
}
use of com.apple.foundationdb.record.query.expressions.NestedField in project fdb-record-layer by FoundationDB.
the class BindingFunctions method javaComparisonType.
@Nullable
private static Descriptors.FieldDescriptor.JavaType javaComparisonType(@Nonnull QueryComponent fieldComparison, @Nonnull Index index, @Nonnull RecordMetaData metaData) {
Descriptors.FieldDescriptor.JavaType javaType = null;
for (RecordType recordType : metaData.recordTypesForIndex(index)) {
Descriptors.Descriptor descriptor = recordType.getDescriptor();
QueryComponent component = fieldComparison;
while (component instanceof NestedField) {
Descriptors.FieldDescriptor fieldDescriptor = descriptor.findFieldByName(((NestedField) component).getName());
if (fieldDescriptor == null) {
return null;
}
descriptor = fieldDescriptor.getMessageType();
component = ((NestedField) component).getChild();
}
if (component instanceof FieldWithComparison) {
Descriptors.FieldDescriptor fieldDescriptor = descriptor.findFieldByName(((FieldWithComparison) component).getName());
if (fieldDescriptor == null) {
return null;
}
if (javaType == null) {
javaType = fieldDescriptor.getJavaType();
} else if (javaType != fieldDescriptor.getJavaType()) {
return null;
}
} else {
return null;
}
}
return javaType;
}
Aggregations