Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(interactive): Convert Label Condition to Type Constraint #3441

Merged
merged 10 commits into from
Dec 21, 2023
Original file line number Diff line number Diff line change
@@ -1,34 +1,21 @@
package com.alibaba.graphscope.common.ir.planner.rules;

import com.alibaba.graphscope.common.ir.rel.graph.AbstractBindableTableScan;
import com.alibaba.graphscope.common.ir.rel.PushFilterVisitor;
import com.alibaba.graphscope.common.ir.rel.graph.match.AbstractLogicalMatch;
import com.alibaba.graphscope.common.ir.rel.graph.match.GraphLogicalMultiMatch;
import com.alibaba.graphscope.common.ir.rel.graph.match.GraphLogicalSingleMatch;
import com.alibaba.graphscope.common.ir.rex.RexGraphVariable;
import com.alibaba.graphscope.common.ir.rex.RexVariableAliasCollector;
import com.alibaba.graphscope.common.ir.rex.RexVariableAliasConverter;
import com.alibaba.graphscope.common.ir.tools.AliasInference;
import com.alibaba.graphscope.common.ir.tools.GraphBuilder;
import com.google.common.collect.ImmutableList;

import org.apache.calcite.plan.RelOptRuleCall;
import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.plan.RelRule;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Filter;
import org.apache.calcite.rel.rules.TransformationRule;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.tools.RelBuilderFactory;
import org.apache.commons.lang3.ObjectUtils;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

public class FilterMatchRule<C extends FilterMatchRule.Config> extends RelRule<C>
implements TransformationRule {
Expand All @@ -41,13 +28,14 @@ public void onMatch(RelOptRuleCall call) {
Filter filter = call.rel(0);
AbstractLogicalMatch match = call.rel(1);
// do the transformation
List<RelNode> sentences = getSentences(match);
List<RexNode> conjunctions = RelOptUtil.conjunctions(filter.getCondition());
int origSize = conjunctions.size();
GraphBuilder graphBuilder = (GraphBuilder) call.builder();
for (Iterator<RexNode> it = conjunctions.iterator(); it.hasNext(); ) {
RexNode condition = it.next();
if (pushFilter(sentences, condition, graphBuilder)) {
PushFilterVisitor visitor = new PushFilterVisitor(graphBuilder, condition);
match = (AbstractLogicalMatch) match.accept(visitor);
if (visitor.isPushed()) {
it.remove();
}
}
Expand All @@ -59,76 +47,6 @@ public void onMatch(RelOptRuleCall call) {
call.transformTo(newNode);
}

private boolean pushFilter(
List<RelNode> sentences, RexNode condition, GraphBuilder graphBuilder) {
boolean pushed = false;
List<Integer> distinctAliasIds =
condition
.accept(new RexVariableAliasCollector<>(true, RexGraphVariable::getAliasId))
.stream()
.distinct()
.collect(Collectors.toList());
if (distinctAliasIds.size() != 1) {
return pushed;
}
int aliasId = distinctAliasIds.get(0);
List<RelNode> inputsQueue = new ArrayList<>();
for (RelNode node : sentences) {
inputsQueue.add(node);
while (!inputsQueue.isEmpty()) {
RelNode cur = inputsQueue.remove(0);
List<AbstractBindableTableScan> candidates = new ArrayList<>();
if (cur instanceof AbstractBindableTableScan) {
candidates.add((AbstractBindableTableScan) cur);
}
for (AbstractBindableTableScan candidate : candidates) {
RelDataType rowType = candidate.getRowType();
for (RelDataTypeField field : rowType.getFieldList()) {
if (aliasId != AliasInference.DEFAULT_ID && field.getIndex() == aliasId) {
RexNode transform =
condition.accept(
new RexVariableAliasConverter(
true,
graphBuilder,
AliasInference.DEFAULT_NAME,
AliasInference.DEFAULT_ID));
if (ObjectUtils.isEmpty(candidate.getFilters())) {
candidate.setFilters(ImmutableList.of(transform));
} else {
ImmutableList.Builder builder = new ImmutableList.Builder();
builder.addAll(candidate.getFilters()).add(transform);
candidate.setFilters(
ImmutableList.of(
RexUtil.composeConjunction(
graphBuilder.getRexBuilder(),
builder.build())));
}
pushed = true;
break;
}
}
}
if (!cur.getInputs().isEmpty()) {
inputsQueue.addAll(cur.getInputs());
}
}
}
return pushed;
}

private List<RelNode> getSentences(AbstractLogicalMatch match) {
List<RelNode> sentences = new ArrayList<>();
if (match instanceof GraphLogicalSingleMatch) {
sentences.add(((GraphLogicalSingleMatch) match).getSentence());
} else if (match instanceof GraphLogicalMultiMatch) {
sentences.addAll(((GraphLogicalMultiMatch) match).getSentences());
} else {
throw new UnsupportedOperationException(
"match type " + match.getClass() + " is unsupported");
}
return sentences;
}

public static class Config implements RelRule.Config {
public static FilterMatchRule.Config DEFAULT =
new Config()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.RelShuttle;
import org.apache.calcite.rel.RelWriter;
import org.apache.calcite.rel.core.Aggregate;
import org.apache.calcite.rel.core.AggregateCall;
Expand Down Expand Up @@ -130,4 +131,12 @@ public GraphGroupKeys getGroupKey() {
public List<GraphAggCall> getAggCalls() {
return Collections.unmodifiableList(aggCalls);
}

@Override
public RelNode accept(RelShuttle shuttle) {
if (shuttle instanceof GraphRelVisitor) {
return ((GraphRelVisitor) shuttle).visit(this);
}
return shuttle.visit(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.RelShuttle;
import org.apache.calcite.rel.RelWriter;
import org.apache.calcite.rel.core.Project;
import org.apache.calcite.rel.hint.RelHint;
Expand Down Expand Up @@ -80,4 +81,12 @@ public Project copy(
public RelWriter explainTerms(RelWriter pw) {
return super.explainTerms(pw).item("isAppend", isAppend);
}

@Override
public RelNode accept(RelShuttle shuttle) {
if (shuttle instanceof GraphRelVisitor) {
return ((GraphRelVisitor) shuttle).visit(this);
}
return shuttle.visit(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.apache.calcite.rel.RelCollation;
import org.apache.calcite.rel.RelFieldCollation;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.RelShuttle;
import org.apache.calcite.rel.core.Sort;
import org.apache.calcite.rel.hint.RelHint;
import org.apache.calcite.rex.RexNode;
Expand Down Expand Up @@ -78,4 +79,12 @@ public Sort copy(
return new GraphLogicalSort(
getCluster(), traitSet, getHints(), newInput, newCollation, offset, fetch);
}

@Override
public RelNode accept(RelShuttle shuttle) {
if (shuttle instanceof GraphRelVisitor) {
return ((GraphRelVisitor) shuttle).visit(this);
}
return shuttle.visit(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright 2020 Alibaba Group Holding Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.alibaba.graphscope.common.ir.rel;

import com.alibaba.graphscope.common.ir.rel.graph.*;
import com.alibaba.graphscope.common.ir.rel.graph.match.GraphLogicalMultiMatch;
import com.alibaba.graphscope.common.ir.rel.graph.match.GraphLogicalSingleMatch;

import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.RelShuttleImpl;

/**
* the class is used to visit a graph relation tree
*/
public abstract class GraphRelVisitor extends RelShuttleImpl {
public RelNode visit(GraphLogicalSource source) {
return source;
}

public RelNode visit(GraphLogicalExpand expand) {
return visitChildren(expand);
}

public RelNode visit(GraphLogicalExpandDegree degree) {
return visitChildren(degree);
}

public RelNode visit(GraphLogicalGetV getV) {
return visitChildren(getV);
}

public RelNode visit(GraphLogicalPathExpand expand) {
return visitChildren(expand);
}

public RelNode visit(GraphLogicalSingleMatch match) {
return match;
}

public RelNode visit(GraphLogicalMultiMatch match) {
return match;
}

public RelNode visit(GraphLogicalAggregate aggregate) {
return visitChildren(aggregate);
}

public RelNode visit(GraphLogicalProject project) {
return visitChildren(project);
}

public RelNode visit(GraphLogicalSort sort) {
return visitChildren(sort);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Copyright 2020 Alibaba Group Holding Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.alibaba.graphscope.common.ir.rel;

import com.alibaba.graphscope.common.ir.rel.graph.GraphLogicalExpand;
import com.alibaba.graphscope.common.ir.rel.graph.GraphLogicalGetV;
import com.alibaba.graphscope.common.ir.rel.graph.GraphLogicalSource;
import com.alibaba.graphscope.common.ir.rel.graph.match.GraphLogicalMultiMatch;
import com.alibaba.graphscope.common.ir.rel.graph.match.GraphLogicalSingleMatch;
import com.alibaba.graphscope.common.ir.rex.RexGraphVariable;
import com.alibaba.graphscope.common.ir.rex.RexVariableAliasCollector;
import com.alibaba.graphscope.common.ir.tools.AliasInference;
import com.alibaba.graphscope.common.ir.tools.GraphBuilder;

import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.rex.RexNode;

import java.util.List;
import java.util.stream.Collectors;

/**
* visit a graph relation tree and push filter to the corresponding source
*/
public class PushFilterVisitor extends GraphRelVisitor {
private final GraphBuilder builder;
private final RexNode condition;
private final List<Integer> distinctAliasIds;
private boolean pushed;

public PushFilterVisitor(GraphBuilder builder, RexNode condition) {
this.builder = builder;
this.condition = condition;
this.distinctAliasIds =
condition
.accept(new RexVariableAliasCollector<>(true, RexGraphVariable::getAliasId))
.stream()
.distinct()
.collect(Collectors.toList());
}

@Override
public RelNode visit(GraphLogicalSingleMatch match) {
RelNode sentence = match.getSentence().accept(this);
if (!sentence.equals(match.getSentence())) {
return builder.match(sentence, match.getMatchOpt()).build();
}
return match;
}

@Override
public RelNode visit(GraphLogicalMultiMatch match) {
List<RelNode> sentences =
match.getSentences().stream().map(k -> k.accept(this)).collect(Collectors.toList());
if (!sentences.equals(match.getSentences())) {
return builder.match(sentences.get(0), sentences.subList(1, sentences.size())).build();
}
return match;
}

@Override
public RelNode visit(GraphLogicalSource source) {
return fuseFilter(source);
}

@Override
public RelNode visit(GraphLogicalExpand expand) {
return fuseFilter(visitChildren(expand));
}

@Override
public RelNode visit(GraphLogicalGetV getV) {
return fuseFilter(visitChildren(getV));
}

public boolean isPushed() {
return pushed;
}

private RelNode fuseFilter(RelNode node) {
if (distinctAliasIds.size() != 1) return node;
int aliasId = distinctAliasIds.get(0);
RelDataType rowType = node.getRowType();
for (RelDataTypeField field : rowType.getFieldList()) {
if (aliasId != AliasInference.DEFAULT_ID && field.getIndex() == aliasId) {
pushed = true;
return builder.push(node).filter(condition).build();
}
}
return node;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@

package com.alibaba.graphscope.common.ir.rel.graph;

import com.alibaba.graphscope.common.ir.rel.GraphRelVisitor;
import com.alibaba.graphscope.common.ir.rel.type.AliasNameWithId;
import com.alibaba.graphscope.common.ir.rel.type.TableConfig;
import com.alibaba.graphscope.common.ir.tools.config.GraphOpt;

import org.apache.calcite.plan.GraphOptCluster;
import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.RelShuttle;
import org.apache.calcite.rel.RelWriter;
import org.apache.calcite.rel.hint.RelHint;
import org.checkerframework.checker.nullness.qual.Nullable;
Expand Down Expand Up @@ -75,4 +77,12 @@ public GraphLogicalExpand copy(RelTraitSet traitSet, List<RelNode> inputs) {
this.getAliasName(),
this.getStartAlias());
}

@Override
public RelNode accept(RelShuttle shuttle) {
if (shuttle instanceof GraphRelVisitor) {
return ((GraphRelVisitor) shuttle).visit(this);
}
return shuttle.visit(this);
}
}
Loading
Loading