JoinFilterPushDown extends LogicalOperatorTransform { @Override public OperatorNode<SequenceOperator> visitSequenceOperator(OperatorNode<SequenceOperator> node) { if (node.getOperator() != SequenceOperator.FILTER) { return super.visitSequenceOperator(node); } OperatorNode<SequenceOperator> target = node.getArgument(0); OperatorNode<ExpressionOperator> filter = node.getArgument(1); if (target.getOperator() == SequenceOperator.JOIN || target.getOperator() == SequenceOperator.LEFT_JOIN) { List<OperatorNode<ExpressionOperator>> top = Lists.newArrayList(); List<OperatorNode<ExpressionOperator>> leftFilter = Lists.newArrayList(); List<OperatorNode<ExpressionOperator>> rightFilter = Lists.newArrayList(); OperatorNode<SequenceOperator> leftSide = target.getArgument(0); OperatorNode<SequenceOperator> rightSide = target.getArgument(1); OperatorNode<ExpressionOperator> joinExpr = target.getArgument(2); if (filter.getOperator() == ExpressionOperator.AND) { flatten(top, (List<OperatorNode<ExpressionOperator>>) filter.getArgument(0)); } else { top.add(filter); } Iterator<OperatorNode<ExpressionOperator>> topIterator = top.iterator(); while (topIterator.hasNext()) { OperatorNode<ExpressionOperator> clause = topIterator.next(); Set<String> left = findSources(leftSide); Set<String> right = findSources(rightSide); Set<String> referencedFilter = findReferencedSources(clause); boolean useLeft = !Sets.intersection(referencedFilter, left).isEmpty(); boolean useRight = !Sets.intersection(referencedFilter, right).isEmpty(); if (useLeft && useRight) { } else if (useLeft) { leftFilter.add(clause); topIterator.remove(); } else if (useRight) { rightFilter.add(clause); topIterator.remove(); } } OperatorNode<SequenceOperator> result = node; if (rightFilter.size() > 0) { rightSide = visitSequenceOperator(new MergeFilters().visitSequenceOperator(OperatorNode.create(node.getLocation(), SequenceOperator.FILTER, rightSide, createFilter(rightFilter)))); } if (leftFilter.size() > 0) { leftSide = visitSequenceOperator(new MergeFilters().visitSequenceOperator(OperatorNode.create(node.getLocation(), SequenceOperator.FILTER, leftSide, createFilter(leftFilter)))); } if (rightFilter.size() > 0 || leftFilter.size() > 0) { result = OperatorNode.create(target.getLocation(), target.getAnnotations(), target.getOperator(), leftSide, rightSide, joinExpr); if (top.size() > 0) { result = OperatorNode.create(node.getLocation(), node.getAnnotations(), node.getOperator(), result, createFilter(top)); } else { for (Map.Entry<String, Object> e : node.getAnnotations().entrySet()) { result.putAnnotation(e.getKey(), e.getValue()); } } } return super.visitSequenceOperator(result); } return node; }  @Override OperatorNode<SequenceOperator> visitSequenceOperator(OperatorNode<SequenceOperator> node);  }
@Test public void testLeftPush() throws IOException { OperatorNode<SequenceOperator> query = OperatorNode.create(SequenceOperator.FILTER, OperatorNode.create(SequenceOperator.JOIN, OperatorNode.create(SequenceOperator.SCAN, ImmutableList.of("left"), Lists.newArrayList()).putAnnotation("alias", "left"), OperatorNode.create(SequenceOperator.SCAN, ImmutableList.of("right"), Lists.newArrayList()).putAnnotation("alias", "right"), OperatorNode.create(ExpressionOperator.EQ, OperatorNode.create(ExpressionOperator.PROPREF, OperatorNode.create(ExpressionOperator.READ_RECORD, "left"), "id"), OperatorNode.create(ExpressionOperator.PROPREF, OperatorNode.create(ExpressionOperator.READ_RECORD, "right"), "id")) ), OperatorNode.create(ExpressionOperator.EQ, OperatorNode.create(ExpressionOperator.PROPREF, OperatorNode.create(ExpressionOperator.READ_RECORD, "left"), "id"), OperatorNode.create(ExpressionOperator.LITERAL, "1")) ); OperatorNode<SequenceOperator> transformed = new JoinFilterPushDown().visitSequenceOperator(query); Assert.assertEquals(transformed.getOperator(), SequenceOperator.JOIN); Assert.assertEquals(((OperatorNode) transformed.getArgument(0)).getOperator(), SequenceOperator.FILTER); Assert.assertEquals(((OperatorNode) transformed.getArgument(1)).getOperator(), SequenceOperator.SCAN); }
@Test public void testRightPush() throws IOException { OperatorNode<SequenceOperator> query = OperatorNode.create(SequenceOperator.FILTER, OperatorNode.create(SequenceOperator.JOIN, OperatorNode.create(SequenceOperator.SCAN, ImmutableList.of("left"), Lists.newArrayList()).putAnnotation("alias", "left"), OperatorNode.create(SequenceOperator.SCAN, ImmutableList.of("right"), Lists.newArrayList()).putAnnotation("alias", "right"), OperatorNode.create(ExpressionOperator.EQ, OperatorNode.create(ExpressionOperator.PROPREF, OperatorNode.create(ExpressionOperator.READ_RECORD, "left"), "id"), OperatorNode.create(ExpressionOperator.PROPREF, OperatorNode.create(ExpressionOperator.READ_RECORD, "right"), "id")) ), OperatorNode.create(ExpressionOperator.EQ, OperatorNode.create(ExpressionOperator.PROPREF, OperatorNode.create(ExpressionOperator.READ_RECORD, "right"), "id"), OperatorNode.create(ExpressionOperator.LITERAL, "1")) ); OperatorNode<SequenceOperator> transformed = new JoinFilterPushDown().visitSequenceOperator(query); Assert.assertEquals(transformed.getOperator(), SequenceOperator.JOIN); Assert.assertEquals(((OperatorNode) transformed.getArgument(0)).getOperator(), SequenceOperator.SCAN); Assert.assertEquals(((OperatorNode) transformed.getArgument(1)).getOperator(), SequenceOperator.FILTER); }
@Test public void testNoPush() throws IOException, RecognitionException { ProgramParser parser = new ProgramParser(); OperatorNode<SequenceOperator> query = parser.parseQuery("SELECT * FROM left JOIN right ON left.id = right.id WHERE left.id = 1 OR right.id = 1"); OperatorNode<SequenceOperator> transformed = new JoinFilterPushDown().visitSequenceOperator(query); Assert.assertEquals(transformed.getOperator(), SequenceOperator.FILTER); Assert.assertEquals(((OperatorNode) transformed.getArgument(0)).getOperator(), SequenceOperator.JOIN); }
@Test public void testClausePush() throws IOException, RecognitionException { ProgramParser parser = new ProgramParser(); OperatorNode<SequenceOperator> query = parser.parseQuery("SELECT * FROM left JOIN right ON left.id = right.id WHERE left.category = 1 AND right.woeid = 2"); OperatorNode<SequenceOperator> transformed = new JoinFilterPushDown().visitSequenceOperator(query); Assert.assertEquals(transformed.getOperator(), SequenceOperator.JOIN); Assert.assertEquals(((OperatorNode) transformed.getArgument(0)).getOperator(), SequenceOperator.FILTER); Assert.assertEquals(((OperatorNode) transformed.getArgument(1)).getOperator(), SequenceOperator.FILTER); }
@Test public void testClausePushWithExpression() throws IOException, RecognitionException { ProgramParser parser = new ProgramParser(); OperatorNode<SequenceOperator> query = parser.parseQuery("SELECT * FROM left JOIN right ON left.id = right.id WHERE false AND left.category = 1 AND right.woeid = 2 AND true"); OperatorNode<SequenceOperator> transformed = new JoinFilterPushDown().visitSequenceOperator(query); Assert.assertEquals(transformed.getOperator(), SequenceOperator.FILTER); Assert.assertEquals(((OperatorNode) transformed.getArgument(0)).getOperator(), SequenceOperator.JOIN); Assert.assertEquals(((OperatorNode) transformed.getArgument(1)).getOperator(), ExpressionOperator.AND); }
@Test public void testMultiClausePush() throws IOException, RecognitionException { ProgramParser parser = new ProgramParser(); OperatorNode<SequenceOperator> query = parser.parseQuery( "SELECT * " + "FROM left " + "JOIN right ON left.id = right.id " + "JOIN middle ON right.id = middle.id " + "WHERE left.category = 1 AND right.woeid = 2 AND middle.id = 1" ); OperatorNode<SequenceOperator> transformed = new JoinFilterPushDown().visitSequenceOperator(query); Assert.assertEquals(transformed.getOperator(), SequenceOperator.JOIN); Assert.assertEquals(((OperatorNode) transformed.getArgument(0)).getOperator(), SequenceOperator.JOIN); Assert.assertEquals(((OperatorNode) transformed.getArgument(1)).getOperator(), SequenceOperator.FILTER); }