Skip to content

Commit

Permalink
fix(interactive): Convert Label Condition to Type Constraint (#3441)
Browse files Browse the repository at this point in the history
<!--
Thanks for your contribution! please review
https://github.com/alibaba/GraphScope/blob/main/CONTRIBUTING.md before
opening an issue.
-->

## What do these changes do?
as titled.

<!-- Please give a short brief about these changes. -->

## Related issue number

<!-- Are there any issues opened that will be resolved by merging this
change? -->

Fixes #3378

---------

Co-authored-by: Longbin Lai <[email protected]>
Co-authored-by: Zhang Lei <[email protected]>
  • Loading branch information
3 people authored Dec 21, 2023
1 parent 0435bb8 commit 1b9d100
Show file tree
Hide file tree
Showing 18 changed files with 416 additions and 115 deletions.
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

0 comments on commit 1b9d100

Please sign in to comment.