Interface RelationalExpression
-
- All Superinterfaces:
Bindable
,Correlated<RelationalExpression>
- All Known Subinterfaces:
QueryPlan<T>
,RecordQueryPlan
,RecordQueryPlanWithChild
,RecordQueryPlanWithChildren
,RecordQueryPlanWithComparisons
,RecordQueryPlanWithIndex
,RecordQueryPlanWithNoChildren
,RecordQueryPlanWithRequiredFields
,RelationalExpressionWithChildren
,RelationalExpressionWithPredicate
,TypeFilterExpression
- All Known Implementing Classes:
ComposedBitmapIndexQueryPlan
,ExplodeExpression
,FullUnorderedScanExpression
,IndexScanExpression
,LogicalDistinctExpression
,LogicalFilterExpression
,LogicalIntersectionExpression
,LogicalSortExpression
,LogicalTypeFilterExpression
,LogicalUnorderedUnionExpression
,MatchableSortExpression
,PrimaryScanExpression
,RecordQueryCoveringIndexPlan
,RecordQueryFetchFromPartialRecordPlan
,RecordQueryFilterPlan
,RecordQueryIndexPlan
,RecordQueryInJoinPlan
,RecordQueryInParameterJoinPlan
,RecordQueryIntersectionPlan
,RecordQueryInValuesJoinPlan
,RecordQueryLoadByKeysPlan
,RecordQueryPredicateFilterPlan
,RecordQueryScanPlan
,RecordQueryScoreForRankPlan
,RecordQueryTextIndexPlan
,RecordQueryTypeFilterPlan
,RecordQueryUnionPlan
,RecordQueryUnionPlanBase
,RecordQueryUnorderedDistinctPlan
,RecordQueryUnorderedPrimaryKeyDistinctPlan
,RecordQueryUnorderedUnionPlan
,SelectExpression
@API(EXPERIMENTAL) public interface RelationalExpression extends Bindable, Correlated<RelationalExpression>
A relational expression is aRelationalExpression
that represents a stream of records. At all times, the root expression being planned must be relational. This interface acts as a common tag interface forRecordQueryPlan
s, which can actually produce a stream of records, and various logical relational expressions (not yet introduced), which represent an abstract stream of records but can't be executed directly (such as an unimplemented sort). Other planner expressions such asQueryComponent
andKeyExpression
do not represent streams of records. The basic type that represents a part of the planner expression tree. An expression is generally an immutable object with two different kinds of fields: regular Java fields and reference fields. The regular fields represent "node information", which pertains only to this specific node in the tree. In contrast, the reference fields represent this expression's children in the tree, such as its inputs and filter/sort expressions, and are always hidden behind anExpressionRef
. Deciding whether certain fields constitute "node information" (and should therefore be a regular field) or "hierarchical information" (and therefore should not be) is subtle and more of an art than a science. There are two reasonable tests that can help make this decision:- When writing a planner rule to manipulate this field, does it make sense to match it separately or access it as a getter on the matched operator? Will you ever want to match to just this field?
- Should the planner memoize (and therefore optimize) this field separately from its parent?
RecordQueryIndexPlan
has only regular fields, including the index name and the comparisons to use when scanning it. Applying the first rule, it wouldn't really make sense to match the index name or the comparisons being performed on their own: they're what define an index scan, after all! Applying the second rule, they're relatively small immutable objects that don't need to be memoized. In contrast,RecordQueryFilterPlan
has no regular fields. A filter plan has two important fields: theQuery.Component
used for the filter and a child plan that provides input. Both of these might be matched by rules directly, in order to optimize them without regard for the fact that there's a filter. Similarly, they should both be memoized separately, since there might be many possible implementations of each.
-
-
Nested Class Summary
Nested Classes Modifier and Type Interface Description static interface
RelationalExpression.CombineFunction<R,S>
A functional interface to combine the matches computed over pairs of quantifiers during matching into a result (for the bound correlatedTo set handed intoRelationalExpression.CombineFunction.combine(com.apple.foundationdb.record.query.plan.temp.AliasMap, java.lang.Iterable<com.apple.foundationdb.record.query.plan.temp.matching.BoundMatch<com.apple.foundationdb.record.query.plan.temp.EnumeratingIterable<R>>>)
).static interface
RelationalExpression.CombinePredicate
A functional interface to combine the matches computed over pairs of quantifiers during matching into a boolean result (for the bound correlatedTo set handed intoRelationalExpression.CombinePredicate.combine(com.apple.foundationdb.record.query.plan.temp.AliasMap, java.lang.Iterable<com.apple.foundationdb.record.query.plan.temp.AliasMap>)
).-
Nested classes/interfaces inherited from interface com.apple.foundationdb.record.query.plan.temp.Correlated
Correlated.BoundEquivalence
-
-
Method Summary
All Methods Static Methods Instance Methods Abstract Methods Default Methods Modifier and Type Method Description default <U> U
acceptPropertyVisitor(PlannerProperty<U> visitor)
Apply the given property visitor to this planner expression and its children.default Optional<MatchInfo>
adjustMatch(RelationalExpression expression, PartialMatch partialMatch)
Override that is called byAdjustMatchRule
to improve an already existingPartialMatch
.default AliasMap
bindIdentities(RelationalExpression otherExpression, AliasMap boundAliasMap)
Given the correlatedTo setsc1
andc2
of this expression and some other expression compute a set of bindings that contains identity bindings (a -> a
) for the intersection ofc1
andc2
.default Stream<PlannerBindings>
bindTo(PlannerBindings outerBindings, ExpressionMatcher<? extends Bindable> matcher)
Matches a matcher expression to an expression tree rooted at this node, adding to some existing bindings.default boolean
canCorrelate()
Returns if this expression can be the anchor of a correlation.default Compensation
compensate(PartialMatch partialMatch, Map<CorrelationIdentifier,ComparisonRange> boundParameterPrefixMap)
default Iterable<AliasMap>
enumerateUnboundCorrelatedTo(AliasMap boundAliasMap, RelationalExpression otherExpression)
Method to enumerate all bindings of unbound correlations of this and some other expression.boolean
equalsWithoutChildren(RelationalExpression other, AliasMap equivalences)
default Iterable<MatchInfo>
exactlySubsumedBy(RelationalExpression candidateExpression, AliasMap aliasMap, IdentityBiMap<Quantifier,PartialMatch> partialMatchMap)
Helper method that can be called by sub classes to defer subsumption in a way that the particular expression only matches if it is semantically equivalent.default Iterable<AliasMap>
findMatches(RelationalExpression otherExpression, AliasMap aliasMap, MatchPredicate<Quantifier> matchPredicate, RelationalExpression.CombinePredicate combinePredicate)
Find matches between this expression and another given expression under the bindings given by theAliasMap
passed in.static RelationalExpression
fromRecordQuery(RecordQuery query, PlanContext context)
List<? extends Quantifier>
getQuantifiers()
Return an iterator of references to the children of this planner expression.default Optional<List<? extends Value>>
getResultValues()
int
hashCodeWithoutChildren()
default boolean
hasIncompatibleBoundQuantifiers(AliasMap aliasMap, Collection<? extends Quantifier> otherQuantifiers)
default boolean
hasUnboundQuantifiers(AliasMap aliasMap)
default <M,S>
Iterable<S>match(RelationalExpression otherExpression, AliasMap boundAliasMap, Function<Quantifier,Collection<AliasMap>> constraintsFunction, MatchFunction<Quantifier,M> matchFunction, RelationalExpression.CombineFunction<M,S> combineFunction)
Attempt to match this expression (this graph) with another expression (from another graph called the candidate graph) to produce matches of some kind.default <M,S>
Iterable<S>match(RelationalExpression otherExpression, AliasMap boundAliasMap, List<? extends Quantifier> quantifiers, List<? extends Quantifier> otherQuantifiers, Function<Quantifier,Collection<AliasMap>> constraintsFunction, MatchFunction<Quantifier,M> matchFunction, RelationalExpression.CombineFunction<M,S> combineFunction)
Attempt to match this expression (this graph) with another expression (from another graph called the candidate graph) to produce matches of some kind.default boolean
semanticEquals(Object other)
Overloaded method to callsemanticEquals(java.lang.Object)
with an empty alias map.default boolean
semanticEquals(Object other, AliasMap aliasMap)
Method to establish whether this relational expression is equal to another object under the bindings given by theAliasMap
passed in.default int
semanticHashCode()
Compute the semantic hash code of this expression.default String
show(boolean renderSingleGroups)
This is needed for graph integration into IntelliJ as IntelliJ only ever evaluates selfish methods.default Iterable<MatchInfo>
subsumedBy(RelationalExpression candidateExpression, AliasMap aliasMap, IdentityBiMap<Quantifier,PartialMatch> partialMatchMap)
Try to establish ifotherExpression
subsumes this one.-
Methods inherited from interface com.apple.foundationdb.record.query.plan.temp.Correlated
getCorrelatedTo, rebase
-
-
-
-
Method Detail
-
fromRecordQuery
@Nonnull static RelationalExpression fromRecordQuery(@Nonnull RecordQuery query, @Nonnull PlanContext context)
-
bindTo
@Nonnull default Stream<PlannerBindings> bindTo(@Nonnull PlannerBindings outerBindings, @Nonnull ExpressionMatcher<? extends Bindable> matcher)
Matches a matcher expression to an expression tree rooted at this node, adding to some existing bindings.
-
getQuantifiers
@Nonnull List<? extends Quantifier> getQuantifiers()
Return an iterator of references to the children of this planner expression. The iterators returned by different calls are guaranteed to be independent (i.e., advancing one will not advance another). However, they might point to the same object, as whenCollections.emptyIterator()
is returned. The returned iterator should be treated as an immutable object and may throw an exception ifIterator.remove()
is called. The iterator must return its elements in a consistent order.- Returns:
- an iterator of references to the children of this planner expression
-
canCorrelate
default boolean canCorrelate()
Returns if this expression can be the anchor of a correlation. A correlation is always formed between three entities:- the
Quantifier
that flows data - 2. the anchor (which is a
RelationalExpression
) that ranges directly over the source - 3. the consumers (or dependents) of the correlation which must be a descendant of the anchor.
LogicalUnorderedUnionExpression
cannot correlate (this method returnsfalse
) because it is not meaningful to bind a record from one child of the union while providing bound values to another. In another example, a logical select expression can correlate which means that one child of the SELECT expression can be evaluated and the resulting records can bound individually one after another. For each bound record flowing along that quantifier the other children of the SELECT expression can be evaluated, potentially causing more correlation values to be bound, etc. These concepts follow closely to the mechanics of what SQL calls a query block. The existence of a correlation between source, anchor, and dependents may adversely affect planning because a correlation always imposes order between the evaluated of children of an expression. This may or may not tie the hands of the planner to produce an optimal plan. In certain cases, queries written in a correlated way can be de-correlated to allow for better optimization techniques.- Returns:
true
if this expression can be the anchor of a correlation,false
otherwise.
- the
-
equalsWithoutChildren
boolean equalsWithoutChildren(@Nonnull RelationalExpression other, @Nonnull AliasMap equivalences)
-
hashCodeWithoutChildren
int hashCodeWithoutChildren()
-
semanticEquals
default boolean semanticEquals(@Nullable Object other)
Overloaded method to callsemanticEquals(java.lang.Object)
with an empty alias map.- Parameters:
other
- object to compare to this expression- Returns:
true
if this object is semantically equal toother
that isthis
andother
produce the same result when invoked with no bindings,false
otherwise.
-
semanticEquals
default boolean semanticEquals(@Nullable Object other, @Nonnull AliasMap aliasMap)
Method to establish whether this relational expression is equal to another object under the bindings given by theAliasMap
passed in.- Specified by:
semanticEquals
in interfaceCorrelated<RelationalExpression>
- Parameters:
other
- the other object to establish equality withaliasMap
- a map ofCorrelationIdentifier
sids
toids'
. A correlation identifierid
used inthis
should be considered equal to another correlation identifierid'
used inother
if either they are the same byObject.equals(java.lang.Object)
of if there is a mapping fromid
toid'
.- Returns:
true
if this is considered equal toother
, false otherwise
-
findMatches
@Nonnull default Iterable<AliasMap> findMatches(@Nonnull RelationalExpression otherExpression, @Nonnull AliasMap aliasMap, @Nonnull MatchPredicate<Quantifier> matchPredicate, @Nonnull RelationalExpression.CombinePredicate combinePredicate)
Find matches between this expression and another given expression under the bindings given by theAliasMap
passed in.- Parameters:
otherExpression
- other expressionaliasMap
- alias map with external bindingsmatchPredicate
- a predicate uses for matching a pair ofQuantifier
scombinePredicate
- a predicate to accept or reject a match- Returns:
- an
Iterable
ofAliasMap
s where each alias map is a match.
-
match
@Nonnull default <M,S> Iterable<S> match(@Nonnull RelationalExpression otherExpression, @Nonnull AliasMap boundAliasMap, @Nonnull Function<Quantifier,Collection<AliasMap>> constraintsFunction, @Nonnull MatchFunction<Quantifier,M> matchFunction, @Nonnull RelationalExpression.CombineFunction<M,S> combineFunction)
Attempt to match this expression (this graph) with another expression (from another graph called the candidate graph) to produce matches of some kind. This overload matches over all quantifiers owned by this expression respectively theotherExpression
. Seematch(RelationalExpression, AliasMap, List, List, Function, MatchFunction, CombineFunction)
for more information about the matching process.- Type Parameters:
M
- intermediate type to represent match resultsS
- final type to represent match results- Parameters:
otherExpression
- the expression to match this expression withboundAliasMap
- alias map containing bound aliasesconstraintsFunction
- function constraining the number of permutations to enumeratematchFunction
- function producing a match result as iterable of typeM
combineFunction
- function to produce an iterable of typeS
by combining on bound matches of typeM
- Returns:
- an
Iterable
of typeS
of matches ofthis
expression withotherExpression
.
-
match
@Nonnull default <M,S> Iterable<S> match(@Nonnull RelationalExpression otherExpression, @Nonnull AliasMap boundAliasMap, @Nonnull List<? extends Quantifier> quantifiers, @Nonnull List<? extends Quantifier> otherQuantifiers, @Nonnull Function<Quantifier,Collection<AliasMap>> constraintsFunction, @Nonnull MatchFunction<Quantifier,M> matchFunction, @Nonnull RelationalExpression.CombineFunction<M,S> combineFunction)
Attempt to match this expression (this graph) with another expression (from another graph called the candidate graph) to produce matches of some kind. Two relational expressions can only match if the sub-graphs of the quantifiers they range over match themselves under a bijective association (mapping between the quantifiers of this expression and the quantifier of the candidate expression). To this end, thematchFunction
passed in to this method is used to determine the matches between two quantifiers: one from this graph and one from the candidate graph. ThematchFunction
can produce zero, one or many matches which are returned as anIterable
of typeM
. This method attempts to find that bijective mapping between the quantifiers contained by their respective expressions. Naturally, if the expressions that are being matched own a different number of quantifiers we cannot ever find a bijective mapping. In that case, the two expressions do not match at all. If, on the other hand the expressions that are being matched do have the same number of quantifiers, we need to enumerate all possible associations in order to potentially find matches. In a naive implementation, and not considering any other constraints, such an enumeration produces a number of mappings that is equal to the enumeration of all permutations of sets of sizen
which isn!
. Fortunately, it is possible for most cases to impose strict constraints on the enumeration of mappings and therefore reduce the degrees of freedom we seemingly have at first considerably. For instance, if this expression can be the anchor of a correlation, there might be an implied necessary order imposed by a correlation between two quantifiersq1
andq2
whereq2
depends onq1
, denoted byq1 -> q2
. This implies that every enumerated mapping must containq1
beforeq2
which therefore decreases the number of all mappings that need to be enumerated. One complicating factor are correlations to parts of the graph that are not contained in the sub-graphs underneaththis
respectively the candidate expression. These correlations are enumerated and bound prior to matching the quantifiers.- Type Parameters:
M
- intermediate type to represent match resultsS
- final type to represent match results- Parameters:
otherExpression
- the expression to match this expression withboundAliasMap
- alias map containing bound aliasesquantifiers
- the set of quantifiers owned by this expression that is matched overotherQuantifiers
- the set of quantifiers owned byotherExpression
that is matched overconstraintsFunction
- function constraining the number of permutations to enumeratematchFunction
- function producing a match result as iterable of typeM
combineFunction
- function to produce an iterable of typeS
by combining on bound matches of typeM
- Returns:
- an
Iterable
of typeS
of matches ofthis
expression withotherExpression
.
-
enumerateUnboundCorrelatedTo
@Nonnull default Iterable<AliasMap> enumerateUnboundCorrelatedTo(@Nonnull AliasMap boundAliasMap, @Nonnull RelationalExpression otherExpression)
Method to enumerate all bindings of unbound correlations of this and some other expression. Example:this (correlated to a1, a2, a3) other (correlated to aa, ab, ac) /|\ /|\ ..... .....
boundAliasMap: (a2 -> ac) result: iterable of: (a1 -> aa, a3 -> ab) (a1 -> ab, a3 -> aa)
boundAliasMap: (empty) result: iterable of: (a1 -> aa, a2 -> ab, a3 -> ac) (a1 -> aa, a2 -> ac, a3 -> ab) (a1 -> ab, a2 -> aa, a3 -> ac) (a1 -> ab, a2 -> ac, a3 -> aa) (a1 -> ac, a2 -> aa, a3 -> ab) (a1 -> ac, a2 -> ab, a3 -> aa)
- Parameters:
boundAliasMap
- alias map of bindings that should be considered pre-boundotherExpression
- the other expression- Returns:
- an iterable of sets of bindings
-
bindIdentities
@Nonnull default AliasMap bindIdentities(@Nonnull RelationalExpression otherExpression, @Nonnull AliasMap boundAliasMap)
Given the correlatedTo setsc1
andc2
of this expression and some other expression compute a set of bindings that contains identity bindings (a -> a
) for the intersection ofc1
andc2
.- Parameters:
otherExpression
- other expressionboundAliasMap
- alias map of bindings that should be considered pre-bound meaning that this method does not include aliases participating in this map into the identities bindings.- Returns:
- an
AliasMap
for containing only identity bindings for the intersection of the correlatedTo set of this expression and the other expression
-
subsumedBy
@Nonnull default Iterable<MatchInfo> subsumedBy(@Nonnull RelationalExpression candidateExpression, @Nonnull AliasMap aliasMap, @Nonnull IdentityBiMap<Quantifier,PartialMatch> partialMatchMap)
Try to establish ifotherExpression
subsumes this one. If two expression are semantically equal (e.g. in structure or by other means of reasoning) they should exactly return the same records. There are use cases where semantic equality is too strict and not that useful. During index matching we don't necessarily need to know if two expressions produce the same result, we just need to know that the candidate scan produces a (non-proper) super multiset of records (the candidate therefore includes all records warranted by the query) and we can match query against that candidate. The difference between result set produced by the candidate and the query then must be corrected by applying compensation. The following tautologies apply:- If query and candidate are semantically equivalent, the query side should match to the candidate side without any compensation. In other words the query expression can simply be replaced by the candidate expression.
- If the candidate is matched and we decide to rewrite this query expression with the appropriate top expression on the candidate side then it holds that the query expression is equivalent to the computed compensation of the match over the candidate scan.
- A query cannot match to a candidate if it cannot be proven that the candidate cannot at least produce all the records that the query may produce.
- Parameters:
candidateExpression
- the candidate expressionaliasMap
- a map of alias defining the equivalence between aliases and therefore quantifierspartialMatchMap
- a map from quantifier to aPartialMatch
that pulled up along that quantifier from one of the expressions below that quantifier- Returns:
- an iterable of
MatchInfo
s if subsumption between this expression and the candidate expression can be established
-
exactlySubsumedBy
@Nonnull default Iterable<MatchInfo> exactlySubsumedBy(@Nonnull RelationalExpression candidateExpression, @Nonnull AliasMap aliasMap, @Nonnull IdentityBiMap<Quantifier,PartialMatch> partialMatchMap)
Helper method that can be called by sub classes to defer subsumption in a way that the particular expression only matches if it is semantically equivalent.- Parameters:
candidateExpression
- the candidate expressionaliasMap
- a map of alias defining the equivalence between aliases and therefore quantifierspartialMatchMap
- a map from quantifier to aPartialMatch
that pulled up along that quantifier from one of the expressions below that quantifier- Returns:
- an iterable of
MatchInfo
s if semantic equivalence between this expression and the candidate expression can be established
-
adjustMatch
@Nonnull default Optional<MatchInfo> adjustMatch(@Nonnull RelationalExpression expression, @Nonnull PartialMatch partialMatch)
Override that is called byAdjustMatchRule
to improve an already existingPartialMatch
.- Parameters:
expression
- the query expressionpartialMatch
- the partial match already existing betweenexpression
andthis
- Returns:
Optional.empty()
if the match could not be adjusted, Optional.of(matchInfo) for a new adjusted match, otherwise.
-
hasUnboundQuantifiers
default boolean hasUnboundQuantifiers(AliasMap aliasMap)
-
hasIncompatibleBoundQuantifiers
default boolean hasIncompatibleBoundQuantifiers(AliasMap aliasMap, Collection<? extends Quantifier> otherQuantifiers)
-
compensate
default Compensation compensate(@Nonnull PartialMatch partialMatch, @Nonnull Map<CorrelationIdentifier,ComparisonRange> boundParameterPrefixMap)
-
semanticHashCode
default int semanticHashCode()
Compute the semantic hash code of this expression. The logic computing the hash code is agnostic to the order of owned quantifiers.- Specified by:
semanticHashCode
in interfaceCorrelated<RelationalExpression>
- Returns:
- the semantic hash code
-
acceptPropertyVisitor
@Nullable default <U> U acceptPropertyVisitor(@Nonnull PlannerProperty<U> visitor)
Apply the given property visitor to this planner expression and its children. Returnsnull
ifPlannerProperty.shouldVisit(RelationalExpression)
called on this expression returnsfalse
.- Type Parameters:
U
- the type of the evaluated property- Parameters:
visitor
- aPlannerProperty
visitor to evaluate- Returns:
- the result of evaluating the property on the subtree rooted at this expression
-
show
@Nonnull default String show(boolean renderSingleGroups)
This is needed for graph integration into IntelliJ as IntelliJ only ever evaluates selfish methods. Add this method as a custom renderer for the typeRelationalExpression
. During debugging you can then for instance click show() on an instance and enjoy the query graph it represents rendered in your standard browser.- Parameters:
renderSingleGroups
- whether to render group references with just one member- Returns:
- the String "done"
-
-