use of com.apple.foundationdb.record.metadata.expressions.KeyExpression in project fdb-record-layer by FoundationDB.
the class RecordQueryPlanner method planFilterForInJoin.
private ScoredPlan planFilterForInJoin(@Nonnull PlanContext planContext, @Nonnull QueryComponent filter, boolean needOrdering) {
planContext.rankComparisons = new RankComparisons(filter, planContext.indexes);
List<ScoredPlan> intersectionCandidates = new ArrayList<>();
ScoredPlan bestPlan = null;
Index bestIndex = null;
if (planContext.commonPrimaryKey != null) {
bestPlan = planIndex(planContext, filter, null, planContext.commonPrimaryKey, intersectionCandidates);
}
for (Index index : planContext.indexes) {
KeyExpression indexKeyExpression = indexKeyExpressionForPlan(planContext.commonPrimaryKey, index);
ScoredPlan p = planIndex(planContext, filter, index, indexKeyExpression, intersectionCandidates);
if (p != null) {
// * need for type filtering if row scan with multiple types.
if (isBetterThanOther(planContext, p, index, bestPlan, bestIndex)) {
bestPlan = p;
bestIndex = index;
}
}
}
if (bestPlan != null) {
if (bestPlan.getNumNonSargables() > 0) {
bestPlan = handleNonSargables(bestPlan, intersectionCandidates, planContext);
}
if (needOrdering) {
bestPlan.planOrderingKey = PlanOrderingKey.forPlan(metaData, bestPlan.plan, planContext.commonPrimaryKey);
}
}
return bestPlan;
}
use of com.apple.foundationdb.record.metadata.expressions.KeyExpression in project fdb-record-layer by FoundationDB.
the class RecordQueryPlanner method planUnorderedUnion.
@Nullable
private ScoredPlan planUnorderedUnion(@Nonnull PlanContext planContext, @Nonnull List<ScoredPlan> subplans) {
final KeyExpression sort = planContext.query.getSort();
if (sort != null) {
return null;
}
List<RecordQueryPlan> childPlans = new ArrayList<>(subplans.size());
Set<RankComparisons.RankComparison> includedRankComparisons = null;
for (ScoredPlan subplan : subplans) {
childPlans.add(subplan.plan);
includedRankComparisons = mergeRankComparisons(includedRankComparisons, subplan.includedRankComparisons);
}
final RecordQueryUnorderedUnionPlan unionPlan = RecordQueryUnorderedUnionPlan.from(childPlans);
if (unionPlan.getComplexity() > configuration.getComplexityThreshold()) {
throw new RecordQueryPlanComplexityException(unionPlan);
}
return new ScoredPlan(unionPlan, Collections.emptyList(), Collections.emptyList(), 1, true, includedRankComparisons);
}
use of com.apple.foundationdb.record.metadata.expressions.KeyExpression in project fdb-record-layer by FoundationDB.
the class RecordQueryPlanner method handleNonSargables.
@Nonnull
private ScoredPlan handleNonSargables(@Nonnull ScoredPlan bestPlan, @Nonnull List<ScoredPlan> intersectionCandidates, @Nonnull PlanContext planContext) {
if (planContext.commonPrimaryKey != null && !intersectionCandidates.isEmpty()) {
KeyExpression comparisonKey = planContext.commonPrimaryKey;
final KeyExpression sort = planContext.query.getSort();
comparisonKey = getKeyForMerge(sort, comparisonKey);
ScoredPlan intersectionPlan = planIntersection(intersectionCandidates, comparisonKey);
if (intersectionPlan != null) {
if (intersectionPlan.unsatisfiedFilters.isEmpty()) {
return intersectionPlan;
} else if (bestPlan.getNumNonSargables() > intersectionPlan.getNumNonSargables()) {
bestPlan = intersectionPlan;
}
}
}
if (bestPlan.getNumNonSargables() > 0) {
final RecordQueryPlan filtered = new RecordQueryFilterPlan(bestPlan.plan, planContext.rankComparisons.planComparisonSubstitutes(bestPlan.combineNonSargables()));
// TODO: further optimization requires knowing which filters are satisfied
return new ScoredPlan(filtered, Collections.emptyList(), Collections.emptyList(), bestPlan.score, bestPlan.createsDuplicates, bestPlan.includedRankComparisons);
} else {
return bestPlan;
}
}
use of com.apple.foundationdb.record.metadata.expressions.KeyExpression in project fdb-record-layer by FoundationDB.
the class RecordQueryPlanner method planIndex.
@Nullable
private ScoredPlan planIndex(@Nonnull PlanContext planContext, @Nonnull QueryComponent filter, @Nullable Index index, @Nonnull KeyExpression indexExpr, @Nonnull List<ScoredPlan> intersectionCandidates) {
final KeyExpression sort = planContext.query.getSort();
final boolean sortReverse = planContext.query.isSortReverse();
final CandidateScan candidateScan = new CandidateScan(planContext, index, sortReverse);
ScoredPlan p = null;
if (index != null) {
if (indexTypes.getRankTypes().contains(index.getType())) {
GroupingKeyExpression grouping = (GroupingKeyExpression) indexExpr;
p = planRank(candidateScan, index, grouping, filter);
// Plan as just value index.
indexExpr = grouping.getWholeKey();
} else if (indexTypes.getTextTypes().contains(index.getType())) {
p = planText(candidateScan, index, filter, sort);
if (p != null) {
p = planRemoveDuplicates(planContext, p);
}
if (p != null) {
p = computeIndexFilters(planContext, p);
}
return p;
} else if (indexTypes.getLuceneTypes().contains(index.getType())) {
p = planLucene(candidateScan, index, filter, sort);
if (p != null) {
p = planRemoveDuplicates(planContext, p);
}
if (p != null) {
p = computeIndexFilters(planContext, p);
}
return p;
} else if (!indexTypes.getValueTypes().contains(index.getType())) {
return null;
}
}
if (p == null) {
p = planCandidateScan(candidateScan, indexExpr, filter, sort);
}
if (p == null) {
// we can't match the filter, but maybe the sort
p = planSortOnly(candidateScan, indexExpr, sort);
if (p != null) {
final List<QueryComponent> unsatisfiedFilters = filter instanceof AndComponent ? ((AndComponent) filter).getChildren() : Collections.singletonList(filter);
p = new ScoredPlan(0, p.plan, unsatisfiedFilters, p.createsDuplicates);
}
}
if (p != null) {
if (getConfiguration().shouldOptimizeForIndexFilters()) {
// partition index filters
if (index == null) {
// if we scan without an index all filters become index filters as we don't need a fetch
// to evaluate these filters
p = p.withFilters(p.combineNonSargables(), Collections.emptyList());
} else {
p = computeIndexFilters(planContext, p);
}
}
}
if (p != null) {
p = planRemoveDuplicates(planContext, p);
if (p != null && p.getNumNonSargables() > 0) {
PlanOrderingKey planOrderingKey = PlanOrderingKey.forPlan(metaData, p.plan, planContext.commonPrimaryKey);
if (planOrderingKey != null && (sort != null || planOrderingKey.isPrimaryKeyOrdered())) {
// If there is a sort, all chosen plans should be ordered by it and so compatible.
// Otherwise, by requiring pkey order, we miss out on the possible intersection of
// X < 10 AND X < 5, which should have been handled already. We gain simplicity
// in not trying X < 10 AND Y = 5 AND Z = 'foo', where we would need to throw
// some out as we fail to align them all.
p.planOrderingKey = planOrderingKey;
intersectionCandidates.add(p);
}
}
}
return p;
}
use of com.apple.foundationdb.record.metadata.expressions.KeyExpression in project fdb-record-layer by FoundationDB.
the class InExtractor method extractInClauses.
@SuppressWarnings("unchecked")
private QueryComponent extractInClauses() {
final AtomicInteger bindingIndex = new AtomicInteger();
return mapClauses(filter, (withComparison, fields) -> {
if (withComparison.getComparison().getType() == Comparisons.Type.IN) {
String bindingName = Bindings.Internal.IN.bindingName(withComparison.getName() + "__" + bindingIndex.getAndIncrement());
List<FieldKeyExpression> nestedFields = null;
if (fields != null && (withComparison instanceof FieldWithComparison || withComparison instanceof OneOfThemWithComparison)) {
nestedFields = new ArrayList<>(fields);
nestedFields.add(Key.Expressions.field(((BaseField) withComparison).getFieldName(), withComparison instanceof FieldWithComparison ? KeyExpression.FanType.None : KeyExpression.FanType.FanOut));
}
KeyExpression orderingKey = getOrderingKey(nestedFields);
if (withComparison.getComparison() instanceof Comparisons.ComparisonWithParameter) {
final String parameterName = ((Comparisons.ComparisonWithParameter) withComparison.getComparison()).getParameter();
inClauses.add(new InParameterClause(bindingName, parameterName, orderingKey));
} else {
final List<Object> comparand = (List<Object>) withComparison.getComparison().getComparand();
// ListComparison does not allow empty/null
if (comparand != null && comparand.size() == 1) {
return withComparison.withOtherComparison(new Comparisons.SimpleComparison(Comparisons.Type.EQUALS, comparand.get(0)));
}
inClauses.add(new InValuesClause(bindingName, comparand, orderingKey));
}
return withComparison.withOtherComparison(new Comparisons.ParameterComparison(Comparisons.Type.EQUALS, bindingName, Bindings.Internal.IN));
} else {
return withComparison;
}
}, Collections.emptyList());
}
Aggregations