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

Extend fast inequality join #630

Closed
wants to merge 6 commits into from
Closed

Conversation

anusudarsan
Copy link

@anusudarsan anusudarsan commented Jul 18, 2017

Follow up PR to extend functionality added in prestodb#7097. The tests result below. @losipiuk Please review.

PR branch

Benchmark                                                     (buckets)  (fastInequalityJoins)  (filterOutCoefficient)  Mode  Cnt     Score     Error  Units
BenchmarkInequalityJoin.benchmarkJoin                               100                   true                      10  avgt   30   234.191 ±  33.999  ms/op
BenchmarkInequalityJoin.benchmarkJoin                               100                  false                      10  avgt   30  2360.016 ± 189.837  ms/op
BenchmarkInequalityJoin.benchmarkJoin                              1000                   true                      10  avgt   30   187.426 ±  24.792  ms/op
BenchmarkInequalityJoin.benchmarkJoin                              1000                  false                      10  avgt   30   414.487 ±  27.297  ms/op
BenchmarkInequalityJoin.benchmarkJoin                             10000                   true                      10  avgt   30   198.977 ±  35.756  ms/op
BenchmarkInequalityJoin.benchmarkJoin                             10000                  false                      10  avgt   30   239.980 ±  18.026  ms/op
BenchmarkInequalityJoin.benchmarkJoin                             60000                   true                      10  avgt   30   173.009 ±   6.956  ms/op
BenchmarkInequalityJoin.benchmarkJoin                             60000                  false                      10  avgt   30   181.165 ±   8.649  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate        100                   true                      10  avgt   30   280.396 ±  17.991  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate        100                  false                      10  avgt   30  2376.180 ± 125.109  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate       1000                   true                      10  avgt   30   210.539 ±  11.744  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate       1000                  false                      10  avgt   30   471.721 ±  45.251  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate      10000                   true                      10  avgt   30   203.669 ±   9.373  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate      10000                  false                      10  avgt   30   259.281 ±  13.036  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate      60000                   true                      10  avgt   30   203.048 ±  10.953  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate      60000                  false                      10  avgt   30   199.349 ±   9.362  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate          100                   true                      10  avgt   30   216.786 ±  12.600  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate          100                  false                      10  avgt   30  2408.483 ±  97.140  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate         1000                   true                      10  avgt   30   195.763 ±  13.215  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate         1000                  false                      10  avgt   30   580.025 ± 120.265  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate        10000                   true                      10  avgt   30   226.885 ±  24.685  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate        10000                  false                      10  avgt   30   274.404 ±  18.313  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate        60000                   true                      10  avgt   30   197.643 ±  11.469  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate        60000                  false                      10  avgt   30   210.390 ±  15.268  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin                 100                   true                      10  avgt   30   247.428 ±  11.549  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin                 100                  false                      10  avgt   30  2487.442 ±  60.085  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin                1000                   true                      10  avgt   30   240.810 ±  14.584  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin                1000                  false                      10  avgt   30   527.124 ±  47.483  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin               10000                   true                      10  avgt   30   226.683 ±  11.559  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin               10000                  false                      10  avgt   30   270.130 ±  13.167  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin               60000                   true                      10  avgt   30   226.237 ±   8.305  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin               60000                  false                      10  avgt   30   218.149 ±   9.184  ms/op

sprint-59 branch

Benchmark                                                     (buckets)  (fastInequalityJoins)  (filterOutCoefficient)  Mode  Cnt     Score     Error  Units
BenchmarkInequalityJoin.benchmarkJoin                               100                   true                      10  avgt   30   222.267 ±  36.490  ms/op
BenchmarkInequalityJoin.benchmarkJoin                               100                  false                      10  avgt   30  2409.789 ± 193.371  ms/op
BenchmarkInequalityJoin.benchmarkJoin                              1000                   true                      10  avgt   30   192.559 ±  25.289  ms/op
BenchmarkInequalityJoin.benchmarkJoin                              1000                  false                      10  avgt   30   458.951 ±  56.590  ms/op
BenchmarkInequalityJoin.benchmarkJoin                             10000                   true                      10  avgt   30   186.968 ±  31.170  ms/op
BenchmarkInequalityJoin.benchmarkJoin                             10000                  false                      10  avgt   30   191.897 ±  13.314  ms/op
BenchmarkInequalityJoin.benchmarkJoin                             60000                   true                      10  avgt   30   153.550 ±  12.891  ms/op
BenchmarkInequalityJoin.benchmarkJoin                             60000                  false                      10  avgt   30   168.607 ±  10.826  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate        100                   true                      10  avgt   30   279.125 ±  23.798  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate        100                  false                      10  avgt   30  2375.963 ±  78.662  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate       1000                   true                      10  avgt   30   208.635 ±  12.900  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate       1000                  false                      10  avgt   30   479.930 ±  54.966  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate      10000                   true                      10  avgt   30   191.762 ±  12.959  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate      10000                  false                      10  avgt   30   240.564 ±  18.699  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate      60000                   true                      10  avgt   30   182.319 ±  13.622  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate      60000                  false                      10  avgt   30   190.407 ±   8.862  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate          100                   true                      10  avgt   30   193.858 ±  12.845  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate          100                  false                      10  avgt   30  2288.445 ±  55.931  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate         1000                   true                      10  avgt   30   206.152 ±  10.544  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate         1000                  false                      10  avgt   30   479.045 ±  54.701  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate        10000                   true                      10  avgt   30   207.194 ±  12.368  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate        10000                  false                      10  avgt   30   252.875 ±  15.385  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate        60000                   true                      10  avgt   30   178.251 ±   6.402  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate        60000                  false                      10  avgt   30   201.308 ±  12.452  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin                 100                   true                      10  avgt   30  2435.688 ± 143.372  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin                 100                  false                      10  avgt   30  2433.708 ±  64.086  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin                1000                   true                      10  avgt   30   488.757 ±  33.252  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin                1000                  false                      10  avgt   30   507.685 ±  34.516  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin               10000                   true                      10  avgt   30   263.682 ±  14.438  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin               10000                  false                      10  avgt   30   261.671 ±  14.073  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin               60000                   true                      10  avgt   30   216.391 ±  11.229  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin               60000                  false                      10  avgt   30   217.869 ±  11.015  ms/op

The PR extends the functionality to speed up query with range predicates eg: benchmarkRangePredicateJoin . But I added benchmark tests for other queries which were already addressed by the optimization. So you can see the comparison below with and without this optimization.

								(buckets)  (fastInequalityJoins)     (sprint-59)	    (PR branch)
BenchmarkInequalityJoin.benchmarkJoin 				100		true		222.267 ±  36.490  ms/op   234.191 ±  33.999  ms/op
BenchmarkInequalityJoin.benchmarkJoin 				100		false	       2409.789 ± 193.371  ms/op  2360.016 ± 189.837  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate	100		true		279.125 ±  23.798  ms/op   280.396 ±  17.991  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate	100		false	       2375.963 ±  78.662  ms/op  2376.180 ± 125.109  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate	100		true		193.858 ±  12.845  ms/op   216.786 ±  12.600  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithFunctionPredicate	100		false	       2288.445 ±  55.931  ms/op  2408.483 ±  97.140  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin		100		true	      2435.688 ± 143.372  ms/op	   247.428 ±  11.549  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin		100		false	      2433.708 ±  64.086  ms/op   2487.442 ±  60.085  ms/op

@kokosing
Copy link

@anu can you post what performance results you had before applying your patch?

Copy link

@kokosing kokosing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just skimmed this so far. I need a closer look.

It is awesome that you worked on that!

@@ -121,6 +121,13 @@ public void setUp()
.execute("SELECT count(*) FROM t1 JOIN t2 on (t1.bucket = t2.bucket) AND t1.val1 < sin(t2.val2)");
}

@Benchmark

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should not it belong to previous commit?

@@ -90,9 +91,13 @@ public JoinHash get()
// are not thread safe...
Optional<JoinFilterFunction> filterFunction =
filterFunctionFactory.map(factory -> factory.create(session.toConnectorSession(), addresses, channels));
List<JoinFilterFunction> filterExpressions = filterFunctionFactory.isPresent() ?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Optional.map as in the statement above instead of ternary operator

@@ -81,6 +82,61 @@ public void testGetSortExpression()
ComparisonExpressionType.GREATER_THAN,
new FunctionCall(QualifiedName.of("sin"), ImmutableList.of(new SymbolReference("b1"))),
new SymbolReference("p1")));

assertGetSortExpression(
new LogicalBinaryExpression(LogicalBinaryExpression.Type.OR,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of creating expressions by hand you can use something like:

expression("b1 > p1 OR b2 <= p1")

where expression is:

private Expression expression(String sql) {
 return rewriteIdentifiersToSymbolReferences(new SqlParser().createExpression(sql));
}

@losipiuk
Copy link

Why is that targeted for sprint-59 instead master

Copy link

@losipiuk losipiuk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can not grasp this PR. Could we meet so you explain to me what is happening here?

@@ -107,6 +107,20 @@ public void setUp()
.execute("SELECT count(*) FROM t1 JOIN t2 on (t1.bucket = t2.bucket) WHERE t1.val1 < t2.val2");
}

@Benchmark
public List<Page> benchmarkJoinWithExpressionPredicate(Context context)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would explicitly state we are talking about arithmetics here. Maybe call method benchmarkJoinWithArithmeticInPredicate

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems you renamed the wrong test method. The one with sin(). But left original name for test method with arithmetic.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

@@ -2279,6 +2279,8 @@ public void testJoinWithLessThanInJoinClause()
"VALUES -1");
// test with only null value in build side
assertQuery("SELECT b FROM nation n, (VALUES (0, NULL)) t(a, b) WHERE n.regionkey - 100 < t.b AND n.nationkey = t.a", "SELECT 1 WHERE FALSE");
// test with filter expression

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't comment here be sth like:
// test with function calls in predicate

@@ -2298,6 +2300,8 @@ public void testJoinWithGreaterThanInJoinClause()
"VALUES -1");
// test with only null value in build side
assertQuery("SELECT b FROM nation n, (VALUES (0, NULL)) t(a, b) WHERE n.regionkey + 100 > t.b AND n.nationkey = t.a", "SELECT 1 WHERE FALSE");
// test with filter expression

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

return new SortExpressionVisitor(buildSymbols).process(filter);
}

private static class SortExpressionVisitor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed the fixup commit 518d7ea to PR branch which simplifies the extractor. See what you think.
I found the visitExpression logic with HashSet hard to follow. You can naturally put logic of supporting just AND with matching sort expressions within visitLogicalBinaryExpression.

Take a look at commit and see what you think.

return new FilterExpressions().process(expression);
}

private static class FilterExpressions

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name it FilterExpressionsVisitor

@Override
protected List<Expression> visitExpression(Expression expression, Void context)
{
List<Expression> filters = new ArrayList<>();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can do it in more functional way (IMO more a bit more readable) as:

                return expression.getChildren().stream()
                        .flatMap(child -> process(child).stream())
                        .collect(toImmutableList());

@@ -152,13 +153,14 @@ public Factory build()
return new Factory()
{
@Override
public PositionLinks create(Optional<JoinFilterFunction> lessThanFunction)
public PositionLinks create(Optional<JoinFilterFunction> lessThanFunction, List<JoinFilterFunction> filterFunctions)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand why we keep old lessThanFunction and add a list of filterFunctions.

Would lessThanFunction not be on of the functions in filterFunctions list?

Copy link
Author

@anusudarsan anusudarsan Jul 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use the lessThanFunction (a<b AND b< a+10 in case of range predicates), for the next() method. I can get rid of it and use filterFunctions ({a< b, b< a+10}) in a loop in next() method too (like I do in start()).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rename filterFunctions to inequalityFilterConjuncts or inequalityFilterExpressions and then either remove lessThanFunction.
Or rename it to combinedIneqalityFIlterExpressions and ensure that it is clear when this is constructed that it is just a conjunction of function passed in the other parameter.

@anusudarsan
Copy link
Author

This is not going to sprint-59. I had the PR branch locally rebased on that. I will change it once the review is done

@Override
protected List<Expression> visitLogicalBinaryExpression(LogicalBinaryExpression expression, Void context)
{
return extractConjuncts(expression);
Copy link

@losipiuk losipiuk Jul 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not seem good.
It will work correctly for case like this
a < x AND a < x +10

But what if we have other conjuncts in filter function. Which are not in shape of
[sort_symbol] [<=|>=|<|>] [expression using probe side symbols>].

Then those conjuncts will be used as filter functions in SortedPositionLInks.start(). And they will not work fine when passed as lessThanFunction to binary search.

Am I right?
For sure we need tests for that.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as discussed added test in ATQ.

@anusudarsan anusudarsan force-pushed the extend-fast-inequality-join branch 3 times, most recently from cbc96f1 to ce681df Compare July 20, 2017 22:02
@anusudarsan
Copy link
Author

addressed comments. @losipiuk @kokosing

@kokosing
Copy link

Can you please squash fixup commits?

@anusudarsan
Copy link
Author

@kokosing done

Copy link

@losipiuk losipiuk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Some minor comments. Mostly concerning clarifications in tests.

@@ -107,6 +107,20 @@ public void setUp()
.execute("SELECT count(*) FROM t1 JOIN t2 on (t1.bucket = t2.bucket) WHERE t1.val1 < t2.val2");
}

@Benchmark
public List<Page> benchmarkJoinWithExpressionPredicate(Context context)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems you renamed the wrong test method. The one with sin(). But left original name for test method with arithmetic.

@@ -2279,6 +2279,8 @@ public void testJoinWithLessThanInJoinClause()
"VALUES -1");
// test with only null value in build side
assertQuery("SELECT b FROM nation n, (VALUES (0, NULL)) t(a, b) WHERE n.regionkey - 100 < t.b AND n.nationkey = t.a", "SELECT 1 WHERE FALSE");
// test with function calls in predicate

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please explain in the comment what are you testing here. This is not supported case for inequality fast joins.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This case is supported by this optimization since the non-equi join condition occurs in the ON clause. updated the comment.

@@ -2305,6 +2305,22 @@ public void testJoinWithGreaterThanInJoinClause()
}

@Test
public void testJoinWithRangePredicatesinJoinClause()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In should be upper case.

@@ -2305,6 +2305,22 @@ public void testJoinWithGreaterThanInJoinClause()
}

@Test
public void testJoinWithRangePredicatesinJoinClause()
{
assertQuery("SELECT COUNT(*)\n" +

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please format the queries so every condition is in separate line. This is hard to read in this shape.

Also add comment what is this test testing.
I understand that it for testing regression in fast inequality join code.
And the code is working for this query because expressions used in equality conditions are rewritten to symbols. So actual expression in join is in shape of build_symbol < probe_expression.

What about seconde query?

@@ -43,7 +42,8 @@
*
* filterFunction_1(...) OR filterFunction_2(....) OR ... OR filterFunction_n(...)
*
* To use lessThanFunction in this class, it must be an expression in form of:
* To use the elements in the list of filters inequalityJoinFilterConjuncts in this class,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this Javadoc is out of sync with the codebase. As we are not supporting g(build_column, ....) but only build_column as sort expression. Maybe add a commit which puts that javadoc in sync with current implementation?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do support g(build_column) as sort expression, provided the expression is pushed to the Scan node (eg: when the expression appears in the ON clause). Updated the doc accordingly.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah - but in this case it is essentially a symbol when it comes to filter function in join.
I would rather keep in javadoc that g(b_symbol) is not supported. As this javadoc is describing what is supported locally.
It should not need to be updated anytime we add some optimizer in other place which transforms expression which does not have supported shape to one which has.

Then this Javadoc would be unmaintainble (if it is not such already :) )

return startingPosition;
}

private int findStartPositionForFunction(int startingPosition, int probePosition, Page allProbeChannelsPage, JoinFilterFunction filterFunction)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make paremeter ordering consistent with applyLessThanFunction. I.e. make filterFunction first parameter.

}

@Override
public int start(int startingPosition, int probePosition, Page allProbeChannelsPage)
{
int count = inequalityJoinFilterConjuncts.size();
while (count > 0) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use for loop here, too.

@@ -112,7 +114,14 @@ public JoinFilterFunctionFactory compileJoinFilterFunction(RowExpression filter,
private JoinFilterFunctionFactory internalCompileFilterFunctionFactory(RowExpression filterExpression, int leftBlocksSize, Optional<SortExpression> sortChannel)
{
Class<? extends InternalJoinFilterFunction> internalJoinFilterFunction = compileInternalJoinFilterFunction(filterExpression, leftBlocksSize);
return new IsolatedJoinFilterFunctionFactory(internalJoinFilterFunction, sortChannel);

List<Class<? extends InternalJoinFilterFunction>> internalInequalityJoinFilterConjuncts = new ArrayList<>();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about using Optional.map()

List<Class<? extends InternalJoinFilterFunction>> internalInequalityJoinFilterConjuncts = 
   sortChannel.map(channel -> channel.getInequalityJoinFilterConjuncts().stream()
                                  .map(rowExpression -> compileInternalJoinFilterFunction(rowExpression, leftBlocksSize))
                                  .collect(toImmutableList()))
              .orElse(ImmutableMap.of());

If you do not like this please at least use ImmutableMap.of() instead new ArrayList(). We use ImmutableMap.of() as empty list by convention.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tried this, but had to change the type of internalInequalityJoinFilterConjuncts to ImmutableList which also needs changing the constructor of IsolatedJoinFilterFunctionFactory. So keeping it as-is.

@@ -71,6 +72,7 @@
import static com.facebook.presto.sql.gen.TryCodeGenerator.defineTryMethod;
import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Verify.verify;
import static com.google.common.collect.ImmutableList.toImmutableList;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JoinFilterCacheKey currently has sortChannel field?
It seems unnecessary to me. Anyway, it should either be removed. Or taken into consideration in equals and hashCode.

It is not related strictly to this PR but maybe you could fix that that along the way as you are working on this class anyway. As a separate commit of course :).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sortChannel is still being used to call internalCompileFilterFunctionFactory. So added it to equals and hashcode

import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static java.util.Objects.requireNonNull;

/**
* Currently this class handles only simple expressions like:
*
* <p>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not up to date. Probe side expression can be aribtrary one. Not just symbol.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a new javadoc commit to reflect what was supported, and later added info about range predicate support.

@losipiuk
Copy link

And one more question. How did evaluating conjuncts one by one influence performance?

@anusudarsan
Copy link
Author

no regression after evaluating conjuncts one by one . Here is the result:

Benchmark                                                       (buckets)  (fastInequalityJoins)  (filterOutCoefficient)  Mode  Cnt     Score     Error  Units
BenchmarkInequalityJoin.benchmarkJoin                                 100                   true                      10  avgt   30   187.515 ±   9.338  ms/op
BenchmarkInequalityJoin.benchmarkJoin                                 100                  false                      10  avgt   30  2372.887 ±  75.762  ms/op
BenchmarkInequalityJoin.benchmarkJoin                                1000                   true                      10  avgt   30   174.968 ±  10.317  ms/op
BenchmarkInequalityJoin.benchmarkJoin                                1000                  false                      10  avgt   30   431.399 ±  43.748  ms/op
BenchmarkInequalityJoin.benchmarkJoin                               10000                   true                      10  avgt   30   173.501 ±   7.109  ms/op
BenchmarkInequalityJoin.benchmarkJoin                               10000                  false                      10  avgt   30   209.469 ±  13.789  ms/op
BenchmarkInequalityJoin.benchmarkJoin                               60000                   true                      10  avgt   30   169.522 ±   6.670  ms/op
BenchmarkInequalityJoin.benchmarkJoin                               60000                  false                      10  avgt   30   180.787 ±  18.943  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithArithmeticInPredicate        100                   true                      10  avgt   30   224.066 ±  30.257  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithArithmeticInPredicate        100                  false                      10  avgt   30  2468.211 ± 119.020  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithArithmeticInPredicate       1000                   true                      10  avgt   30   210.219 ±   9.918  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithArithmeticInPredicate       1000                  false                      10  avgt   30   457.773 ±  47.746  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithArithmeticInPredicate      10000                   true                      10  avgt   30   204.778 ±   8.744  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithArithmeticInPredicate      10000                  false                      10  avgt   30   268.531 ±  39.687  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithArithmeticInPredicate      60000                   true                      10  avgt   30   208.116 ±  16.148  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithArithmeticInPredicate      60000                  false                      10  avgt   30   201.309 ±  10.366  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate          100                   true                      10  avgt   30   273.970 ±  19.601  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate          100                  false                      10  avgt   30  2431.654 ±  86.431  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate         1000                   true                      10  avgt   30   216.315 ±  11.381  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate         1000                  false                      10  avgt   30   465.993 ±  28.393  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate        10000                   true                      10  avgt   30   208.250 ±  12.453  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate        10000                  false                      10  avgt   30   248.567 ±  15.304  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate        60000                   true                      10  avgt   30   198.138 ±   9.732  ms/op
BenchmarkInequalityJoin.benchmarkJoinWithExpressionPredicate        60000                  false                      10  avgt   30   201.292 ±   8.834  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin                   100                   true                      10  avgt   30   254.792 ±  14.055  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin                   100                  false                      10  avgt   30  2528.831 ±  48.746  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin                  1000                   true                      10  avgt   30   234.692 ±   9.586  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin                  1000                  false                      10  avgt   30   473.772 ±  33.844  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin                 10000                   true                      10  avgt   30   226.928 ±   8.116  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin                 10000                  false                      10  avgt   30   284.204 ±  18.327  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin                 60000                   true                      10  avgt   30   221.052 ±   6.519  ms/op
BenchmarkInequalityJoin.benchmarkRangePredicateJoin                 60000                  false                      10  avgt   30   215.020 ±   9.656  ms/op

I will address the rest of the comments.

@anusudarsan anusudarsan force-pushed the extend-fast-inequality-join branch 2 times, most recently from f7e97a4 to 1c62815 Compare July 25, 2017 21:35
Copy link
Author

@anusudarsan anusudarsan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed comments @losipiuk

@@ -43,7 +42,8 @@
*
* filterFunction_1(...) OR filterFunction_2(....) OR ... OR filterFunction_n(...)
*
* To use lessThanFunction in this class, it must be an expression in form of:
* To use the elements in the list of filters inequalityJoinFilterConjuncts in this class,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do support g(build_column) as sort expression, provided the expression is pushed to the Scan node (eg: when the expression appears in the ON clause). Updated the doc accordingly.

@@ -107,6 +107,20 @@ public void setUp()
.execute("SELECT count(*) FROM t1 JOIN t2 on (t1.bucket = t2.bucket) WHERE t1.val1 < t2.val2");
}

@Benchmark
public List<Page> benchmarkJoinWithExpressionPredicate(Context context)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static java.util.Objects.requireNonNull;

/**
* Currently this class handles only simple expressions like:
*
* <p>
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a new javadoc commit to reflect what was supported, and later added info about range predicate support.

@@ -71,6 +72,7 @@
import static com.facebook.presto.sql.gen.TryCodeGenerator.defineTryMethod;
import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Verify.verify;
import static com.google.common.collect.ImmutableList.toImmutableList;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sortChannel is still being used to call internalCompileFilterFunctionFactory. So added it to equals and hashcode

@@ -2279,6 +2279,8 @@ public void testJoinWithLessThanInJoinClause()
"VALUES -1");
// test with only null value in build side
assertQuery("SELECT b FROM nation n, (VALUES (0, NULL)) t(a, b) WHERE n.regionkey - 100 < t.b AND n.nationkey = t.a", "SELECT 1 WHERE FALSE");
// test with function calls in predicate
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This case is supported by this optimization since the non-equi join condition occurs in the ON clause. updated the comment.

@@ -112,7 +114,14 @@ public JoinFilterFunctionFactory compileJoinFilterFunction(RowExpression filter,
private JoinFilterFunctionFactory internalCompileFilterFunctionFactory(RowExpression filterExpression, int leftBlocksSize, Optional<SortExpression> sortChannel)
{
Class<? extends InternalJoinFilterFunction> internalJoinFilterFunction = compileInternalJoinFilterFunction(filterExpression, leftBlocksSize);
return new IsolatedJoinFilterFunctionFactory(internalJoinFilterFunction, sortChannel);

List<Class<? extends InternalJoinFilterFunction>> internalInequalityJoinFilterConjuncts = new ArrayList<>();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tried this, but had to change the type of internalInequalityJoinFilterConjuncts to ImmutableList which also needs changing the constructor of IsolatedJoinFilterFunctionFactory. So keeping it as-is.

@@ -211,17 +210,35 @@ public int next(int position, int probePosition, Page allProbeChannelsPage)
return -1;
}
// break a position links chain if next position should be filtered out
if (applyLessThanFunction(nextPosition, probePosition, allProbeChannelsPage)) {
return nextPosition;
int count = inequalityJoinFilterConjuncts.size();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

.map(rowExpression -> compileInternalJoinFilterFunction(rowExpression, leftBlocksSize))
.collect(toImmutableList());
}
List<? extends Class<? extends InternalJoinFilterFunction>> internalInequalityJoinFilterConjuncts = sortChannel.map(channel -> channel.getInequalityJoinFilterConjuncts().stream()
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated. thanks @findepi

@losipiuk
Copy link

losipiuk commented Jul 26, 2017

Travis is red. Please change base of the PR to prestodb/master. I think you can do it without creating new one.

@anusudarsan anusudarsan changed the base branch from sprint-59 to master July 26, 2017 19:30
@anusudarsan
Copy link
Author

travis is green. rebased on master and squashed the commits.

@losipiuk
Copy link

losipiuk commented Jul 26, 2017

Thanks, I will do one last pass tomorrow and merge if everything looks good.

@Teradata Teradata deleted a comment from kokosing Jul 26, 2017
@@ -151,13 +152,10 @@ public Factory build()
}
}

return lessThanFunction -> {
checkState(lessThanFunction.isPresent(), "Using SortedPositionLinks without lessThanFunction");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please reintroduce the check in new code checking if provided List is not empty.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or actually it can be moved to SortedPositionLinks constructor.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done. closing this and opening a PR upstream

anusudarsan added 2 commits July 27, 2017 09:18
The sorted position links is searched for each of the expression in the
range predicate. Thus this optimization works only for predicates with AND (conjuncts).
The iteration over the position links is stopped as soon as each of the
filter expression is false.
@anusudarsan
Copy link
Author

prestodb#8614 created. closing this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants