DRILL-6089: Removed ordering trait from HashJoin in planner and verified the planner does not assume HashJoin preserves ordering.
closes #1117 Project: http://git-wip-us.apache.org/repos/asf/drill/repo Commit: http://git-wip-us.apache.org/repos/asf/drill/commit/24a7acd4 Tree: http://git-wip-us.apache.org/repos/asf/drill/tree/24a7acd4 Diff: http://git-wip-us.apache.org/repos/asf/drill/diff/24a7acd4 Branch: refs/heads/master Commit: 24a7acd440d29b7340a378306f339e1307892208 Parents: 20185c9 Author: Timothy Farkas <timothyfar...@apache.org> Authored: Fri Jan 26 13:46:22 2018 -0800 Committer: Vitalii Diravka <vitalii.dira...@gmail.com> Committed: Fri Feb 16 20:32:54 2018 +0000 ---------------------------------------------------------------------- .../exec/planner/physical/JoinPruleBase.java | 10 +++--- .../drill/exec/planner/physical/PrelUtil.java | 15 ++++++++ .../java/org/apache/drill/PlanTestBase.java | 37 +++++++++++++++----- .../impl/join/TestHashJoinAdvanced.java | 16 +++++++-- 4 files changed, 60 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/drill/blob/24a7acd4/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/JoinPruleBase.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/JoinPruleBase.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/JoinPruleBase.java index 80e8dda..8b0d69a 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/JoinPruleBase.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/JoinPruleBase.java @@ -116,7 +116,6 @@ public abstract class JoinPruleBase extends Prule { } } - // Create join plan with both left and right children hash distributed. If the physical join type // is MergeJoin, a collation must be provided for both left and right child and the plan will contain // sort converter if necessary to provide the collation. @@ -126,8 +125,6 @@ public abstract class JoinPruleBase extends Prule { RelCollation collationLeft, RelCollation collationRight, DrillDistributionTrait hashLeftPartition, DrillDistributionTrait hashRightPartition) throws InvalidRelException { - //DrillDistributionTrait hashLeftPartition = new DrillDistributionTrait(DrillDistributionTrait.DistributionType.HASH_DISTRIBUTED, ImmutableList.copyOf(getDistributionField(join.getLeftKeys()))); - //DrillDistributionTrait hashRightPartition = new DrillDistributionTrait(DrillDistributionTrait.DistributionType.HASH_DISTRIBUTED, ImmutableList.copyOf(getDistributionField(join.getRightKeys()))); RelTraitSet traitsLeft = null; RelTraitSet traitsRight = null; @@ -146,7 +143,8 @@ public abstract class JoinPruleBase extends Prule { DrillJoinRelBase newJoin = null; if (physicalJoinType == PhysicalJoinType.HASH_JOIN) { - newJoin = new HashJoinPrel(join.getCluster(), traitsLeft, + final RelTraitSet traitSet = PrelUtil.removeCollation(traitsLeft, call); + newJoin = new HashJoinPrel(join.getCluster(), traitSet, convertedLeft, convertedRight, join.getCondition(), join.getJoinType()); @@ -236,7 +234,8 @@ public abstract class JoinPruleBase extends Prule { call.transformTo(new MergeJoinPrel(join.getCluster(), convertedLeft.getTraitSet(), convertedLeft, convertedRight, joinCondition, join.getJoinType())); } else if (physicalJoinType == PhysicalJoinType.HASH_JOIN) { - call.transformTo(new HashJoinPrel(join.getCluster(), convertedLeft.getTraitSet(), convertedLeft, + final RelTraitSet traitSet = PrelUtil.removeCollation(convertedLeft.getTraitSet(), call); + call.transformTo(new HashJoinPrel(join.getCluster(), traitSet, convertedLeft, convertedRight, joinCondition, join.getJoinType())); } else if (physicalJoinType == PhysicalJoinType.NESTEDLOOP_JOIN) { call.transformTo(new NestedLoopJoinPrel(join.getCluster(), convertedLeft.getTraitSet(), convertedLeft, @@ -245,5 +244,4 @@ public abstract class JoinPruleBase extends Prule { } } - } http://git-wip-us.apache.org/repos/asf/drill/blob/24a7acd4/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/PrelUtil.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/PrelUtil.java b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/PrelUtil.java index 67b3066..9c0ee40 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/PrelUtil.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/planner/physical/PrelUtil.java @@ -25,6 +25,7 @@ import java.util.Set; import org.apache.calcite.plan.RelOptCluster; import org.apache.calcite.plan.RelOptPlanner; import org.apache.calcite.plan.RelOptRuleCall; +import org.apache.calcite.plan.RelTrait; import org.apache.calcite.plan.RelTraitSet; import org.apache.calcite.rel.RelCollation; import org.apache.calcite.rel.RelFieldCollation; @@ -327,6 +328,20 @@ public class PrelUtil { } } + // DRILL-6089 make sure no collations are added to HashJoin + public static RelTraitSet removeCollation(RelTraitSet traitSet, RelOptRuleCall call) + { + RelTraitSet newTraitSet = call.getPlanner().emptyTraitSet(); + + for (RelTrait trait: traitSet) { + if (!trait.getTraitDef().getTraitClass().equals(RelCollation.class)) { + newTraitSet = newTraitSet.plus(trait); + } + } + + return newTraitSet; + } + public static class InputRefRemap { private int oldIndex; private int newIndex; http://git-wip-us.apache.org/repos/asf/drill/blob/24a7acd4/exec/java-exec/src/test/java/org/apache/drill/PlanTestBase.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/PlanTestBase.java b/exec/java-exec/src/test/java/org/apache/drill/PlanTestBase.java index 22b734b..47a8623 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/PlanTestBase.java +++ b/exec/java-exec/src/test/java/org/apache/drill/PlanTestBase.java @@ -80,28 +80,47 @@ public class PlanTestBase extends BaseTestQuery { * planning process throws an exception */ public static void testPlanMatchingPatterns(String query, String[] expectedPatterns, String[] excludedPatterns) - throws Exception { + throws Exception { + testPlanMatchingPatterns(query, stringsToPatterns(expectedPatterns), stringsToPatterns(excludedPatterns)); + } + + public static void testPlanMatchingPatterns(String query, Pattern[] expectedPatterns, Pattern[] excludedPatterns) + throws Exception { final String plan = getPlanInString("EXPLAIN PLAN for " + QueryTestUtil.normalizeQuery(query), OPTIQ_FORMAT); // Check and make sure all expected patterns are in the plan if (expectedPatterns != null) { - for (final String s : expectedPatterns) { - final Pattern p = Pattern.compile(s); - final Matcher m = p.matcher(plan); - assertTrue(EXPECTED_NOT_FOUND + s +"\n" + plan, m.find()); + for (final Pattern expectedPattern: expectedPatterns) { + final Matcher m = expectedPattern.matcher(plan); + assertTrue(EXPECTED_NOT_FOUND + expectedPattern.pattern() +"\n" + plan, m.find()); } } // Check and make sure all excluded patterns are not in the plan if (excludedPatterns != null) { - for (final String s : excludedPatterns) { - final Pattern p = Pattern.compile(s); - final Matcher m = p.matcher(plan); - assertFalse(UNEXPECTED_FOUND + s +"\n" + plan, m.find()); + for (final Pattern excludedPattern: excludedPatterns) { + final Matcher m = excludedPattern.matcher(plan); + assertFalse(UNEXPECTED_FOUND + excludedPattern.pattern() +"\n" + plan, m.find()); } } } + private static Pattern[] stringsToPatterns(String[] strings) + { + if (strings == null) { + return null; + } + + final Pattern[] patterns = new Pattern[strings.length]; + + for (int index = 0; index < strings.length; index++) { + final String string = strings[index]; + patterns[index] = Pattern.compile(string); + } + + return patterns; + } + /** * Runs an explain plan including attributes query and check for expected regex patterns * (in optiq text format), also ensure excluded patterns are not found. Either list can http://git-wip-us.apache.org/repos/asf/drill/blob/24a7acd4/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/join/TestHashJoinAdvanced.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/join/TestHashJoinAdvanced.java b/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/join/TestHashJoinAdvanced.java index b9b97c1..d4a7814 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/join/TestHashJoinAdvanced.java +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/join/TestHashJoinAdvanced.java @@ -18,7 +18,6 @@ package org.apache.drill.exec.physical.impl.join; - import org.apache.drill.categories.OperatorTest; import org.apache.drill.categories.UnlikelyTest; import org.apache.drill.exec.ExecConstants; @@ -31,8 +30,7 @@ import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.nio.file.Paths; -import java.util.concurrent.ExecutorService; - +import java.util.regex.Pattern; @Category(OperatorTest.class) public class TestHashJoinAdvanced extends JoinTestBase { @@ -41,6 +39,8 @@ public class TestHashJoinAdvanced extends JoinTestBase { @BeforeClass public static void disableMergeJoin() throws Exception { dirTestWatcher.copyResourceToRoot(Paths.get("join", "empty_part")); + dirTestWatcher.copyFileToRoot(Paths.get("sample-data", "region.parquet")); + dirTestWatcher.copyFileToRoot(Paths.get("sample-data", "nation.parquet")); test(DISABLE_MJ); } @@ -197,4 +197,14 @@ public class TestHashJoinAdvanced extends JoinTestBase { BaseTestQuery.resetSessionOption(ExecConstants.SLICE_TARGET); } } + + @Test // DRILL-6089 + public void testJoinOrdering() throws Exception { + final String query = "select * from dfs.`sample-data/nation.parquet` nation left outer join " + + "(select * from dfs.`sample-data/region.parquet`) " + + "as region on region.r_regionkey = nation.n_nationkey order by nation.n_name desc"; + + final Pattern sortHashJoinPattern = Pattern.compile(".*Sort.*HashJoin", Pattern.DOTALL); + testPlanMatchingPatterns(query, new Pattern[]{sortHashJoinPattern}, null); + } }