mirror of https://github.com/apache/druid.git
Add equivalent test coverage for all RHS join impls (#9831)
* Add equivalent test coverage for all RHS join impls * address comments
This commit is contained in:
parent
6674d721bc
commit
accd710115
|
@ -364,6 +364,74 @@ public class HashJoinSegmentStorageAdapterTest extends BaseHashJoinSegmentStorag
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToCountryLeftUsingLookup()
|
||||
{
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryNameUsingIsoCodeLookup(JoinType.LEFT));
|
||||
|
||||
JoinFilterPreAnalysis preAnalysis = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(
|
||||
joinableClauses,
|
||||
VirtualColumns.EMPTY,
|
||||
null,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
QueryContexts.DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE
|
||||
);
|
||||
|
||||
JoinTestHelper.verifyCursors(
|
||||
new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
preAnalysis
|
||||
).makeCursors(
|
||||
null,
|
||||
Intervals.ETERNITY,
|
||||
VirtualColumns.EMPTY,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of(
|
||||
"page",
|
||||
"countryIsoCode",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "k",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v"
|
||||
),
|
||||
ImmutableList.of(
|
||||
new Object[]{"Talk:Oswald Tilghman", null, null, null},
|
||||
new Object[]{"Rallicula", null, null, null},
|
||||
new Object[]{"Peremptory norm", "AU", "AU", "Australia"},
|
||||
new Object[]{"Apamea abruzzorum", null, null, null},
|
||||
new Object[]{"Atractus flammigerus", null, null, null},
|
||||
new Object[]{"Agama mossambica", null, null, null},
|
||||
new Object[]{"Mathis Bolly", "MX", "MX", "Mexico"},
|
||||
new Object[]{"유희왕 GX", "KR", "KR", "Republic of Korea"},
|
||||
new Object[]{"青野武", "JP", "JP", "Japan"},
|
||||
new Object[]{"Golpe de Estado en Chile de 1973", "CL", "CL", "Chile"},
|
||||
new Object[]{"President of India", "US", "US", "United States"},
|
||||
new Object[]{"Diskussion:Sebastian Schulz", "DE", "DE", "Germany"},
|
||||
new Object[]{"Saison 9 de Secret Story", "FR", "FR", "France"},
|
||||
new Object[]{"Glasgow", "GB", "GB", "United Kingdom"},
|
||||
new Object[]{"Didier Leclair", "CA", "CA", "Canada"},
|
||||
new Object[]{"Les Argonautes", "CA", "CA", "Canada"},
|
||||
new Object[]{"Otjiwarongo Airport", "US", "US", "United States"},
|
||||
new Object[]{"Sarah Michelle Gellar", "CA", "CA", "Canada"},
|
||||
new Object[]{"DirecTV", "US", "US", "United States"},
|
||||
new Object[]{"Carlo Curti", "US", "US", "United States"},
|
||||
new Object[]{"Giusy Ferreri discography", "IT", "IT", "Italy"},
|
||||
new Object[]{"Roma-Bangkok", "IT", "IT", "Italy"},
|
||||
new Object[]{"Wendigo", "SV", "SV", "El Salvador"},
|
||||
new Object[]{"Алиса в Зазеркалье", "NO", "NO", "Norway"},
|
||||
new Object[]{"Gabinete Ministerial de Rafael Correa", "EC", "EC", "Ecuador"},
|
||||
new Object[]{"Old Anatolian Turkish", "US", "US", "United States"},
|
||||
new Object[]{"Cream Soda", "SU", "SU", "States United"},
|
||||
new Object[]{"Orange Soda", "MatchNothing", null, null},
|
||||
new Object[]{"History of Fourems", "MMMM", "MMMM", "Fourems"}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToCountryInner()
|
||||
{
|
||||
|
@ -666,6 +734,46 @@ public class HashJoinSegmentStorageAdapterTest extends BaseHashJoinSegmentStorag
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToCountryLeftWithFilterOnFactsUsingLookup()
|
||||
{
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryNameUsingIsoCodeLookup(JoinType.LEFT));
|
||||
Filter filter = new SelectorDimFilter("channel", "#de.wikipedia", null).toFilter();
|
||||
JoinFilterPreAnalysis preAnalysis = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(
|
||||
joinableClauses,
|
||||
VirtualColumns.EMPTY,
|
||||
filter,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
QueryContexts.DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE
|
||||
);
|
||||
|
||||
JoinTestHelper.verifyCursors(
|
||||
new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
preAnalysis
|
||||
).makeCursors(
|
||||
filter,
|
||||
Intervals.ETERNITY,
|
||||
VirtualColumns.EMPTY,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of(
|
||||
"page",
|
||||
"countryIsoCode",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "k",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v"
|
||||
),
|
||||
ImmutableList.of(
|
||||
new Object[]{"Diskussion:Sebastian Schulz", "DE", "DE", "Germany"}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToCountryRightWithFilterOnLeftIsNull()
|
||||
{
|
||||
|
@ -709,6 +817,48 @@ public class HashJoinSegmentStorageAdapterTest extends BaseHashJoinSegmentStorag
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToCountryRightWithFilterOnLeftIsNullUsingLookup()
|
||||
{
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryNameUsingIsoCodeLookup(JoinType.RIGHT));
|
||||
Filter filter = new SelectorDimFilter("channel", null, null).toFilter();
|
||||
JoinFilterPreAnalysis preAnalysis = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(
|
||||
joinableClauses,
|
||||
VirtualColumns.EMPTY,
|
||||
filter,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
QueryContexts.DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE
|
||||
);
|
||||
|
||||
JoinTestHelper.verifyCursors(
|
||||
new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
preAnalysis
|
||||
).makeCursors(
|
||||
filter,
|
||||
Intervals.ETERNITY,
|
||||
VirtualColumns.EMPTY,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of(
|
||||
"page",
|
||||
"countryIsoCode",
|
||||
"countryNumber",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "k",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v"
|
||||
),
|
||||
ImmutableList.of(
|
||||
new Object[]{null, null, NullHandling.sqlCompatible() ? null : 0L, "AX", "Atlantis"},
|
||||
new Object[]{null, null, NullHandling.sqlCompatible() ? null : 0L, "USCA", "Usca"}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToCountryFullWithFilterOnLeftIsNull()
|
||||
{
|
||||
|
@ -752,6 +902,48 @@ public class HashJoinSegmentStorageAdapterTest extends BaseHashJoinSegmentStorag
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToCountryFullWithFilterOnLeftIsNullUsingLookup()
|
||||
{
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryNameUsingIsoCodeLookup(JoinType.FULL));
|
||||
Filter filter = new SelectorDimFilter("channel", null, null).toFilter();
|
||||
JoinFilterPreAnalysis preAnalysis = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(
|
||||
joinableClauses,
|
||||
VirtualColumns.EMPTY,
|
||||
filter,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
QueryContexts.DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE
|
||||
);
|
||||
|
||||
JoinTestHelper.verifyCursors(
|
||||
new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
preAnalysis
|
||||
).makeCursors(
|
||||
filter,
|
||||
Intervals.ETERNITY,
|
||||
VirtualColumns.EMPTY,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of(
|
||||
"page",
|
||||
"countryIsoCode",
|
||||
"countryNumber",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "k",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v"
|
||||
),
|
||||
ImmutableList.of(
|
||||
new Object[]{null, null, NullHandling.sqlCompatible() ? null : 0L, "AX", "Atlantis"},
|
||||
new Object[]{null, null, NullHandling.sqlCompatible() ? null : 0L, "USCA", "Usca"}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToCountryRightWithFilterOnJoinable()
|
||||
{
|
||||
|
@ -799,6 +991,52 @@ public class HashJoinSegmentStorageAdapterTest extends BaseHashJoinSegmentStorag
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToCountryRightWithFilterOnJoinableUsingLookup()
|
||||
{
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryNameUsingIsoCodeLookup(JoinType.RIGHT));
|
||||
Filter filter = new SelectorDimFilter(
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v",
|
||||
"Germany",
|
||||
null
|
||||
).toFilter();
|
||||
|
||||
JoinFilterPreAnalysis preAnalysis = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(
|
||||
joinableClauses,
|
||||
VirtualColumns.EMPTY,
|
||||
filter,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
QueryContexts.DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE
|
||||
);
|
||||
|
||||
JoinTestHelper.verifyCursors(
|
||||
new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
preAnalysis
|
||||
).makeCursors(
|
||||
filter,
|
||||
Intervals.ETERNITY,
|
||||
VirtualColumns.EMPTY,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of(
|
||||
"page",
|
||||
"countryIsoCode",
|
||||
"countryNumber",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "k",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v"
|
||||
),
|
||||
ImmutableList.of(
|
||||
new Object[]{"Diskussion:Sebastian Schulz", "DE", 3L, "DE", "Germany"}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToCountryLeftWithFilterOnJoinable()
|
||||
{
|
||||
|
@ -975,6 +1213,87 @@ public class HashJoinSegmentStorageAdapterTest extends BaseHashJoinSegmentStorag
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToCountryInnerWithFilterInsteadOfRealJoinConditionUsingLookup()
|
||||
{
|
||||
// Join condition => always true.
|
||||
// Filter => Fact to countries on countryIsoCode.
|
||||
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(
|
||||
new JoinableClause(
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX,
|
||||
LookupJoinable.wrap(countryIsoCodeToNameLookup),
|
||||
JoinType.INNER,
|
||||
JoinConditionAnalysis.forExpression(
|
||||
"1",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX,
|
||||
ExprMacroTable.nil()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
Filter filter = new ExpressionDimFilter(
|
||||
StringUtils.format("\"%sk\" == countryIsoCode", FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX),
|
||||
ExprMacroTable.nil()
|
||||
).toFilter();
|
||||
|
||||
JoinFilterPreAnalysis preAnalysis = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(
|
||||
joinableClauses,
|
||||
VirtualColumns.EMPTY,
|
||||
filter,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
QueryContexts.DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE
|
||||
);
|
||||
|
||||
JoinTestHelper.verifyCursors(
|
||||
new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
preAnalysis
|
||||
).makeCursors(
|
||||
filter,
|
||||
Intervals.ETERNITY,
|
||||
VirtualColumns.EMPTY,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of(
|
||||
"page",
|
||||
"countryIsoCode",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "k",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v"
|
||||
),
|
||||
ImmutableList.of(
|
||||
new Object[]{"Peremptory norm", "AU", "AU", "Australia"},
|
||||
new Object[]{"Mathis Bolly", "MX", "MX", "Mexico"},
|
||||
new Object[]{"유희왕 GX", "KR", "KR", "Republic of Korea"},
|
||||
new Object[]{"青野武", "JP", "JP", "Japan"},
|
||||
new Object[]{"Golpe de Estado en Chile de 1973", "CL", "CL", "Chile"},
|
||||
new Object[]{"President of India", "US", "US", "United States"},
|
||||
new Object[]{"Diskussion:Sebastian Schulz", "DE", "DE", "Germany"},
|
||||
new Object[]{"Saison 9 de Secret Story", "FR", "FR", "France"},
|
||||
new Object[]{"Glasgow", "GB", "GB", "United Kingdom"},
|
||||
new Object[]{"Didier Leclair", "CA", "CA", "Canada"},
|
||||
new Object[]{"Les Argonautes", "CA", "CA", "Canada"},
|
||||
new Object[]{"Otjiwarongo Airport", "US", "US", "United States"},
|
||||
new Object[]{"Sarah Michelle Gellar", "CA", "CA", "Canada"},
|
||||
new Object[]{"DirecTV", "US", "US", "United States"},
|
||||
new Object[]{"Carlo Curti", "US", "US", "United States"},
|
||||
new Object[]{"Giusy Ferreri discography", "IT", "IT", "Italy"},
|
||||
new Object[]{"Roma-Bangkok", "IT", "IT", "Italy"},
|
||||
new Object[]{"Wendigo", "SV", "SV", "El Salvador"},
|
||||
new Object[]{"Алиса в Зазеркалье", "NO", "NO", "Norway"},
|
||||
new Object[]{"Gabinete Ministerial de Rafael Correa", "EC", "EC", "Ecuador"},
|
||||
new Object[]{"Old Anatolian Turkish", "US", "US", "United States"},
|
||||
new Object[]{"Cream Soda", "SU", "SU", "States United"},
|
||||
new Object[]{"History of Fourems", "MMMM", "MMMM", "Fourems"}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToRegionToCountryLeft()
|
||||
{
|
||||
|
@ -1347,6 +1666,72 @@ public class HashJoinSegmentStorageAdapterTest extends BaseHashJoinSegmentStorag
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToCountryUsingVirtualColumnUsingLookup()
|
||||
{
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(
|
||||
new JoinableClause(
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX,
|
||||
LookupJoinable.wrap(countryIsoCodeToNameLookup),
|
||||
JoinType.INNER,
|
||||
JoinConditionAnalysis.forExpression(
|
||||
StringUtils.format("\"%sk\" == virtual", FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX),
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX,
|
||||
ExprMacroTable.nil()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
VirtualColumns virtualColumns = VirtualColumns.create(
|
||||
Collections.singletonList(
|
||||
new ExpressionVirtualColumn(
|
||||
"virtual",
|
||||
"concat(substring(countryIsoCode, 0, 1),'L')",
|
||||
ValueType.STRING,
|
||||
ExprMacroTable.nil()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
JoinFilterPreAnalysis preAnalysis = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(
|
||||
joinableClauses,
|
||||
virtualColumns,
|
||||
null,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
QueryContexts.DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE
|
||||
);
|
||||
|
||||
JoinTestHelper.verifyCursors(
|
||||
new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
preAnalysis
|
||||
).makeCursors(
|
||||
null,
|
||||
Intervals.ETERNITY,
|
||||
virtualColumns,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of(
|
||||
"page",
|
||||
"countryIsoCode",
|
||||
"virtual",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "k",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v"
|
||||
),
|
||||
ImmutableList.of(
|
||||
new Object[]{"Golpe de Estado en Chile de 1973", "CL", "CL", "CL", "Chile"},
|
||||
new Object[]{"Didier Leclair", "CA", "CL", "CL", "Chile"},
|
||||
new Object[]{"Les Argonautes", "CA", "CL", "CL", "Chile"},
|
||||
new Object[]{"Sarah Michelle Gellar", "CA", "CL", "CL", "Chile"}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToCountryUsingExpression()
|
||||
{
|
||||
|
@ -1404,6 +1789,63 @@ public class HashJoinSegmentStorageAdapterTest extends BaseHashJoinSegmentStorag
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToCountryUsingExpressionUsingLookup()
|
||||
{
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(
|
||||
new JoinableClause(
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX,
|
||||
LookupJoinable.wrap(countryIsoCodeToNameLookup),
|
||||
JoinType.INNER,
|
||||
JoinConditionAnalysis.forExpression(
|
||||
StringUtils.format(
|
||||
"\"%sk\" == concat(substring(countryIsoCode, 0, 1),'L')",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX
|
||||
),
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX,
|
||||
ExprMacroTable.nil()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
JoinFilterPreAnalysis preAnalysis = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(
|
||||
joinableClauses,
|
||||
VirtualColumns.EMPTY,
|
||||
null,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
QueryContexts.DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE
|
||||
);
|
||||
|
||||
JoinTestHelper.verifyCursors(
|
||||
new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
preAnalysis
|
||||
).makeCursors(
|
||||
null,
|
||||
Intervals.ETERNITY,
|
||||
VirtualColumns.EMPTY,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of(
|
||||
"page",
|
||||
"countryIsoCode",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "k",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v"
|
||||
),
|
||||
ImmutableList.of(
|
||||
new Object[]{"Golpe de Estado en Chile de 1973", "CL", "CL", "Chile"},
|
||||
new Object[]{"Didier Leclair", "CA", "CL", "Chile"},
|
||||
new Object[]{"Les Argonautes", "CA", "CL", "Chile"},
|
||||
new Object[]{"Sarah Michelle Gellar", "CA", "CL", "Chile"}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToRegionTheWrongWay()
|
||||
{
|
||||
|
@ -1513,6 +1955,52 @@ public class HashJoinSegmentStorageAdapterTest extends BaseHashJoinSegmentStorag
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_errorOnNonEquiJoinUsingLookup()
|
||||
{
|
||||
expectedException.expect(IllegalArgumentException.class);
|
||||
expectedException.expectMessage("Cannot join lookup with non-equi condition: x == y");
|
||||
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(
|
||||
new JoinableClause(
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX,
|
||||
LookupJoinable.wrap(countryIsoCodeToNameLookup),
|
||||
JoinType.LEFT,
|
||||
JoinConditionAnalysis.forExpression(
|
||||
"x == y",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX,
|
||||
ExprMacroTable.nil()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
JoinFilterPreAnalysis preAnalysis = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(
|
||||
joinableClauses,
|
||||
VirtualColumns.EMPTY,
|
||||
null,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
QueryContexts.DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE
|
||||
);
|
||||
|
||||
JoinTestHelper.readCursors(
|
||||
new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
preAnalysis
|
||||
).makeCursors(
|
||||
null,
|
||||
Intervals.ETERNITY,
|
||||
VirtualColumns.EMPTY,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_errorOnNonKeyBasedJoin()
|
||||
{
|
||||
|
@ -1559,6 +2047,51 @@ public class HashJoinSegmentStorageAdapterTest extends BaseHashJoinSegmentStorag
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_errorOnNonKeyBasedJoinUsingLookup()
|
||||
{
|
||||
expectedException.expect(IllegalArgumentException.class);
|
||||
expectedException.expectMessage("Cannot join lookup with condition referring to non-key column: x == \"c1.countryName");
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(
|
||||
new JoinableClause(
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX,
|
||||
LookupJoinable.wrap(countryIsoCodeToNameLookup),
|
||||
JoinType.LEFT,
|
||||
JoinConditionAnalysis.forExpression(
|
||||
StringUtils.format("x == \"%scountryName\"", FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX),
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX,
|
||||
ExprMacroTable.nil()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
JoinFilterPreAnalysis preAnalysis = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(
|
||||
joinableClauses,
|
||||
VirtualColumns.EMPTY,
|
||||
null,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
QueryContexts.DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE
|
||||
);
|
||||
|
||||
JoinTestHelper.readCursors(
|
||||
new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
preAnalysis
|
||||
).makeCursors(
|
||||
null,
|
||||
Intervals.ETERNITY,
|
||||
VirtualColumns.EMPTY,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToCountryLeft_filterExcludesAllLeftRows()
|
||||
{
|
||||
|
@ -1598,4 +2131,43 @@ public class HashJoinSegmentStorageAdapterTest extends BaseHashJoinSegmentStorag
|
|||
ImmutableList.of()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_makeCursors_factToCountryLeft_filterExcludesAllLeftRowsUsingLookup()
|
||||
{
|
||||
Filter originalFilter = new SelectorFilter("page", "this matches nothing");
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryNameUsingIsoCodeLookup(JoinType.LEFT));
|
||||
|
||||
JoinFilterPreAnalysis preAnalysis = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(
|
||||
joinableClauses,
|
||||
VirtualColumns.EMPTY,
|
||||
originalFilter,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
QueryContexts.DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE
|
||||
);
|
||||
|
||||
JoinTestHelper.verifyCursors(
|
||||
new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
preAnalysis
|
||||
).makeCursors(
|
||||
originalFilter,
|
||||
Intervals.ETERNITY,
|
||||
VirtualColumns.EMPTY,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of(
|
||||
"page",
|
||||
"countryIsoCode",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "k",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v"
|
||||
),
|
||||
ImmutableList.of()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ import org.apache.druid.segment.filter.SelectorFilter;
|
|||
import org.apache.druid.segment.join.filter.JoinFilterAnalyzer;
|
||||
import org.apache.druid.segment.join.filter.JoinFilterPreAnalysis;
|
||||
import org.apache.druid.segment.join.filter.JoinFilterSplit;
|
||||
import org.apache.druid.segment.join.lookup.LookupJoinable;
|
||||
import org.apache.druid.segment.join.table.IndexedTableJoinable;
|
||||
import org.apache.druid.segment.virtual.ExpressionVirtualColumn;
|
||||
import org.junit.Assert;
|
||||
|
@ -1001,6 +1002,95 @@ public class JoinFilterAnalyzerTest extends BaseHashJoinSegmentStorageAdapterTes
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterPushDown_factConcatExpressionToCountryLeftFilterOnChannelAndCountryNameUsingLookup()
|
||||
{
|
||||
JoinableClause factExprToCountry = new JoinableClause(
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX,
|
||||
LookupJoinable.wrap(countryIsoCodeToNameLookup),
|
||||
JoinType.LEFT,
|
||||
JoinConditionAnalysis.forExpression(
|
||||
StringUtils.format(
|
||||
"\"%sk\" == concat(countryIsoCode, regionIsoCode)",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX
|
||||
),
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX,
|
||||
ExprMacroTable.nil()
|
||||
)
|
||||
);
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(
|
||||
factExprToCountry
|
||||
);
|
||||
Filter filter = new AndFilter(
|
||||
ImmutableList.of(
|
||||
new SelectorFilter("channel", "#en.wikipedia"),
|
||||
new SelectorFilter("c1.v", "Usca")
|
||||
)
|
||||
);
|
||||
|
||||
JoinFilterPreAnalysis joinFilterPreAnalysis = simplePreAnalysis(
|
||||
joinableClauses,
|
||||
filter
|
||||
);
|
||||
|
||||
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
joinFilterPreAnalysis
|
||||
);
|
||||
|
||||
ExpressionVirtualColumn expectedVirtualColumn = new ExpressionVirtualColumn(
|
||||
"JOIN-FILTER-PUSHDOWN-VIRTUAL-COLUMN-0",
|
||||
"concat(countryIsoCode, regionIsoCode)",
|
||||
ValueType.STRING,
|
||||
ExprMacroTable.nil()
|
||||
);
|
||||
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
|
||||
new AndFilter(
|
||||
ImmutableList.of(
|
||||
new SelectorFilter("channel", "#en.wikipedia"),
|
||||
new InDimFilter("JOIN-FILTER-PUSHDOWN-VIRTUAL-COLUMN-0", ImmutableSet.of("USCA"), null, null).toFilter()
|
||||
)
|
||||
),
|
||||
new SelectorFilter("c1.v", "Usca"),
|
||||
ImmutableList.of(
|
||||
expectedVirtualColumn
|
||||
)
|
||||
);
|
||||
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
|
||||
Assert.assertEquals(
|
||||
expectedFilterSplit.getBaseTableFilter(),
|
||||
actualFilterSplit.getBaseTableFilter()
|
||||
);
|
||||
Assert.assertEquals(
|
||||
expectedFilterSplit.getJoinTableFilter(),
|
||||
actualFilterSplit.getJoinTableFilter()
|
||||
);
|
||||
ExpressionVirtualColumn actualVirtualColumn = (ExpressionVirtualColumn) actualFilterSplit.getPushDownVirtualColumns()
|
||||
.get(0);
|
||||
compareExpressionVirtualColumns(expectedVirtualColumn, actualVirtualColumn);
|
||||
|
||||
JoinTestHelper.verifyCursors(
|
||||
adapter.makeCursors(
|
||||
filter,
|
||||
Intervals.ETERNITY,
|
||||
VirtualColumns.EMPTY,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of(
|
||||
"page",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v"
|
||||
),
|
||||
ImmutableList.of(
|
||||
new Object[]{"President of India", "Usca"},
|
||||
new Object[]{"Otjiwarongo Airport", "Usca"},
|
||||
new Object[]{"Carlo Curti", "Usca"}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterPushDown_factToCountryRightWithFilterOnChannelAndJoinable()
|
||||
{
|
||||
|
@ -1057,6 +1147,61 @@ public class JoinFilterAnalyzerTest extends BaseHashJoinSegmentStorageAdapterTes
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterPushDown_factToCountryRightWithFilterOnChannelAndJoinableUsingLookup()
|
||||
{
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryNameUsingIsoCodeLookup(JoinType.RIGHT));
|
||||
Filter originalFilter = new AndFilter(
|
||||
ImmutableList.of(
|
||||
new SelectorFilter("channel", "#de.wikipedia"),
|
||||
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v", "Germany")
|
||||
)
|
||||
);
|
||||
JoinFilterPreAnalysis joinFilterPreAnalysis = simplePreAnalysis(
|
||||
joinableClauses,
|
||||
originalFilter
|
||||
);
|
||||
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
joinFilterPreAnalysis
|
||||
);
|
||||
|
||||
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
|
||||
new AndFilter(
|
||||
ImmutableList.of(
|
||||
new SelectorFilter("channel", "#de.wikipedia"),
|
||||
new InDimFilter("countryIsoCode", ImmutableSet.of("DE"), null, null).toFilter()
|
||||
)
|
||||
),
|
||||
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v", "Germany"),
|
||||
ImmutableList.of()
|
||||
);
|
||||
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
|
||||
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
|
||||
|
||||
JoinTestHelper.verifyCursors(
|
||||
adapter.makeCursors(
|
||||
originalFilter,
|
||||
Intervals.ETERNITY,
|
||||
VirtualColumns.EMPTY,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of(
|
||||
"page",
|
||||
"countryIsoCode",
|
||||
"countryNumber",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "k",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v"
|
||||
),
|
||||
ImmutableList.of(
|
||||
new Object[]{"Diskussion:Sebastian Schulz", "DE", 3L, "DE", "Germany"}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterPushDown_factToCountryRightWithFilterOnNullColumns()
|
||||
{
|
||||
|
@ -1111,6 +1256,59 @@ public class JoinFilterAnalyzerTest extends BaseHashJoinSegmentStorageAdapterTes
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterPushDown_factToCountryRightWithFilterOnNullColumnsUsingLookup()
|
||||
{
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryNameUsingIsoCodeLookup(JoinType.RIGHT));
|
||||
Filter originalFilter = new AndFilter(
|
||||
ImmutableList.of(
|
||||
new SelectorFilter("channel", null),
|
||||
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v", null)
|
||||
)
|
||||
);
|
||||
JoinFilterPreAnalysis joinFilterPreAnalysis = simplePreAnalysis(
|
||||
joinableClauses,
|
||||
originalFilter
|
||||
);
|
||||
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
joinFilterPreAnalysis
|
||||
);
|
||||
|
||||
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
|
||||
null,
|
||||
new AndFilter(
|
||||
ImmutableList.of(
|
||||
new SelectorFilter("channel", null),
|
||||
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v", null)
|
||||
)
|
||||
),
|
||||
ImmutableList.of()
|
||||
);
|
||||
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
|
||||
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
|
||||
|
||||
JoinTestHelper.verifyCursors(
|
||||
adapter.makeCursors(
|
||||
originalFilter,
|
||||
Intervals.ETERNITY,
|
||||
VirtualColumns.EMPTY,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of(
|
||||
"page",
|
||||
"countryIsoCode",
|
||||
"countryNumber",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "k",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v"
|
||||
),
|
||||
ImmutableList.of()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterPushDown_factToCountryInnerUsingCountryNumberFilterOnChannelAndCountryName()
|
||||
{
|
||||
|
@ -1173,6 +1371,67 @@ public class JoinFilterAnalyzerTest extends BaseHashJoinSegmentStorageAdapterTes
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterPushDown_factToCountryInnerUsingCountryNumberFilterOnChannelAndCountryNameUsingLookup()
|
||||
{
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryNameUsingNumberLookup(JoinType.INNER));
|
||||
Filter originalFilter = new AndFilter(
|
||||
ImmutableList.of(
|
||||
new SelectorFilter("channel", "#en.wikipedia"),
|
||||
new SelectorFilter(FACT_TO_COUNTRY_ON_NUMBER_PREFIX + "v", "Australia")
|
||||
)
|
||||
);
|
||||
JoinFilterPreAnalysis joinFilterPreAnalysis = simplePreAnalysis(
|
||||
joinableClauses,
|
||||
originalFilter
|
||||
);
|
||||
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
joinFilterPreAnalysis
|
||||
);
|
||||
|
||||
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
|
||||
new AndFilter(
|
||||
ImmutableList.of(
|
||||
new SelectorFilter("channel", "#en.wikipedia"),
|
||||
new InDimFilter("countryNumber", ImmutableSet.of("0"), null, null).toFilter()
|
||||
)
|
||||
),
|
||||
new SelectorFilter(FACT_TO_COUNTRY_ON_NUMBER_PREFIX + "v", "Australia"),
|
||||
ImmutableList.of()
|
||||
);
|
||||
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
|
||||
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
|
||||
|
||||
// In non-SQL-compatible mode, we get an extra row, since the 'null' countryNumber for "Talk:Oswald Tilghman"
|
||||
// is interpreted as 0 (a.k.a. Australia).
|
||||
JoinTestHelper.verifyCursors(
|
||||
adapter.makeCursors(
|
||||
originalFilter,
|
||||
Intervals.ETERNITY,
|
||||
VirtualColumns.EMPTY,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of(
|
||||
"page",
|
||||
"countryIsoCode",
|
||||
FACT_TO_COUNTRY_ON_NUMBER_PREFIX + "k",
|
||||
FACT_TO_COUNTRY_ON_NUMBER_PREFIX + "v"
|
||||
),
|
||||
NullHandling.sqlCompatible() ?
|
||||
ImmutableList.of(
|
||||
new Object[]{"Peremptory norm", "AU", "0", "Australia"}
|
||||
) :
|
||||
ImmutableList.of(
|
||||
new Object[]{"Talk:Oswald Tilghman", null, "0", "Australia"},
|
||||
new Object[]{"Peremptory norm", "AU", "0", "Australia"}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterPushDown_factToCountryInnerUsingCountryNumberFilterOnNulls()
|
||||
{
|
||||
|
@ -1226,6 +1485,58 @@ public class JoinFilterAnalyzerTest extends BaseHashJoinSegmentStorageAdapterTes
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterPushDown_factToCountryInnerUsingCountryNumberFilterOnNullsUsingLookup()
|
||||
{
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryNameUsingIsoCodeLookup(JoinType.INNER));
|
||||
Filter originalFilter = new AndFilter(
|
||||
ImmutableList.of(
|
||||
new SelectorFilter("channel", null),
|
||||
new SelectorFilter(FACT_TO_COUNTRY_ON_NUMBER_PREFIX + "v", null)
|
||||
)
|
||||
);
|
||||
JoinFilterPreAnalysis joinFilterPreAnalysis = simplePreAnalysis(
|
||||
joinableClauses,
|
||||
originalFilter
|
||||
);
|
||||
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
joinFilterPreAnalysis
|
||||
);
|
||||
|
||||
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
|
||||
null,
|
||||
new AndFilter(
|
||||
ImmutableList.of(
|
||||
new SelectorFilter("channel", null),
|
||||
new SelectorFilter(FACT_TO_COUNTRY_ON_NUMBER_PREFIX + "v", null)
|
||||
)
|
||||
),
|
||||
ImmutableList.of()
|
||||
);
|
||||
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
|
||||
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
|
||||
|
||||
JoinTestHelper.verifyCursors(
|
||||
adapter.makeCursors(
|
||||
originalFilter,
|
||||
Intervals.ETERNITY,
|
||||
VirtualColumns.EMPTY,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of(
|
||||
"page",
|
||||
"countryIsoCode",
|
||||
FACT_TO_COUNTRY_ON_NUMBER_PREFIX + "k",
|
||||
FACT_TO_COUNTRY_ON_NUMBER_PREFIX + "v"
|
||||
),
|
||||
ImmutableList.of()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterPushDown_factToCountryFullWithFilterOnChannelAndCountryName()
|
||||
{
|
||||
|
@ -1282,6 +1593,61 @@ public class JoinFilterAnalyzerTest extends BaseHashJoinSegmentStorageAdapterTes
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterPushDown_factToCountryFullWithFilterOnChannelAndCountryNameUsingLookup()
|
||||
{
|
||||
Filter filter = new AndFilter(
|
||||
ImmutableList.of(
|
||||
new SelectorFilter("channel", "#es.wikipedia"),
|
||||
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v", "El Salvador")
|
||||
)
|
||||
);
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryNameUsingIsoCodeLookup(JoinType.FULL));
|
||||
JoinFilterPreAnalysis joinFilterPreAnalysis = simplePreAnalysis(
|
||||
joinableClauses,
|
||||
filter
|
||||
);
|
||||
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
joinFilterPreAnalysis
|
||||
);
|
||||
|
||||
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
|
||||
new AndFilter(
|
||||
ImmutableList.of(
|
||||
new SelectorFilter("channel", "#es.wikipedia"),
|
||||
new InDimFilter("countryIsoCode", ImmutableSet.of("SV"), null, null).toFilter()
|
||||
)
|
||||
),
|
||||
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v", "El Salvador"),
|
||||
ImmutableList.of()
|
||||
);
|
||||
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
|
||||
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
|
||||
|
||||
JoinTestHelper.verifyCursors(
|
||||
adapter.makeCursors(
|
||||
filter,
|
||||
Intervals.ETERNITY,
|
||||
VirtualColumns.EMPTY,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of(
|
||||
"page",
|
||||
"countryIsoCode",
|
||||
"countryNumber",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "k",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v"
|
||||
),
|
||||
ImmutableList.of(
|
||||
new Object[]{"Wendigo", "SV", 12L, "SV", "El Salvador"}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterPushDown_factToCountryFullWithFilterOnNulls()
|
||||
{
|
||||
|
@ -1336,6 +1702,59 @@ public class JoinFilterAnalyzerTest extends BaseHashJoinSegmentStorageAdapterTes
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterPushDown_factToCountryFullWithFilterOnNullsUsingLookup()
|
||||
{
|
||||
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryNameUsingIsoCodeLookup(JoinType.FULL));
|
||||
Filter originalFilter = new AndFilter(
|
||||
ImmutableList.of(
|
||||
new SelectorFilter("channel", null),
|
||||
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v", null)
|
||||
)
|
||||
);
|
||||
JoinFilterPreAnalysis joinFilterPreAnalysis = simplePreAnalysis(
|
||||
joinableClauses,
|
||||
originalFilter
|
||||
);
|
||||
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
|
||||
factSegment.asStorageAdapter(),
|
||||
joinableClauses,
|
||||
joinFilterPreAnalysis
|
||||
);
|
||||
|
||||
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
|
||||
null,
|
||||
new AndFilter(
|
||||
ImmutableList.of(
|
||||
new SelectorFilter("channel", null),
|
||||
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v", null)
|
||||
)
|
||||
),
|
||||
ImmutableList.of()
|
||||
);
|
||||
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
|
||||
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
|
||||
|
||||
JoinTestHelper.verifyCursors(
|
||||
adapter.makeCursors(
|
||||
originalFilter,
|
||||
Intervals.ETERNITY,
|
||||
VirtualColumns.EMPTY,
|
||||
Granularities.ALL,
|
||||
false,
|
||||
null
|
||||
),
|
||||
ImmutableList.of(
|
||||
"page",
|
||||
"countryIsoCode",
|
||||
"countryNumber",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "k",
|
||||
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v"
|
||||
),
|
||||
ImmutableList.of()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_filterPushDown_factToRegionTwoColumnsToOneRHSColumnAndFilterOnRHS()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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 org.apache.druid.segment.join.table;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.apache.druid.java.util.common.StringUtils;
|
||||
import org.apache.druid.math.expr.ExprMacroTable;
|
||||
import org.apache.druid.query.dimension.DefaultDimensionSpec;
|
||||
import org.apache.druid.query.dimension.DimensionSpec;
|
||||
import org.apache.druid.query.lookup.LookupExtractor;
|
||||
import org.apache.druid.segment.ColumnSelectorFactory;
|
||||
import org.apache.druid.segment.DimensionSelector;
|
||||
import org.apache.druid.segment.data.SingleIndexedInt;
|
||||
import org.apache.druid.segment.join.JoinConditionAnalysis;
|
||||
import org.apache.druid.segment.join.lookup.LookupJoinMatcher;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class LookupJoinMatcherTest
|
||||
{
|
||||
private final Map<String, String> lookupMap =
|
||||
ImmutableMap.of("foo", "bar", "null", "", "empty String", "", "", "empty_string");
|
||||
private static final String PREFIX = "j.";
|
||||
|
||||
@Mock
|
||||
private LookupExtractor extractor;
|
||||
|
||||
@Mock
|
||||
private ColumnSelectorFactory leftSelectorFactory;
|
||||
|
||||
@Mock
|
||||
private DimensionSelector dimensionSelector;
|
||||
|
||||
private LookupJoinMatcher target;
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
Mockito.doReturn(true).when(extractor).canIterate();
|
||||
Mockito.doReturn(lookupMap.entrySet()).when(extractor).iterable();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateConditionAlwaysFalseShouldReturnSuccessfullyAndNotThrowException()
|
||||
{
|
||||
JoinConditionAnalysis condition = JoinConditionAnalysis.forExpression("0", PREFIX, ExprMacroTable.nil());
|
||||
target = LookupJoinMatcher.create(extractor, leftSelectorFactory, condition, false);
|
||||
Assert.assertNotNull(target);
|
||||
target = LookupJoinMatcher.create(extractor, leftSelectorFactory, condition, true);
|
||||
Assert.assertNotNull(target);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateConditionAlwaysTrueShouldReturnSuccessfullyAndNotThrowException()
|
||||
{
|
||||
JoinConditionAnalysis condition = JoinConditionAnalysis.forExpression("1", PREFIX, ExprMacroTable.nil());
|
||||
Mockito.doReturn(true).when(extractor).canIterate();
|
||||
target = LookupJoinMatcher.create(extractor, leftSelectorFactory, condition, false);
|
||||
Assert.assertNotNull(target);
|
||||
target = LookupJoinMatcher.create(extractor, leftSelectorFactory, condition, true);
|
||||
Assert.assertNotNull(target);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchConditionAlwaysTrue()
|
||||
{
|
||||
JoinConditionAnalysis condition = JoinConditionAnalysis.forExpression("1", PREFIX, ExprMacroTable.nil());
|
||||
target = LookupJoinMatcher.create(extractor, leftSelectorFactory, condition, true);
|
||||
// Test match first
|
||||
target.matchCondition();
|
||||
Assert.assertTrue(target.hasMatch());
|
||||
verifyMatch("foo", "bar");
|
||||
// Test match second
|
||||
target.nextMatch();
|
||||
Assert.assertTrue(target.hasMatch());
|
||||
verifyMatch("null", "");
|
||||
// Test match third
|
||||
target.nextMatch();
|
||||
Assert.assertTrue(target.hasMatch());
|
||||
verifyMatch("empty String", "");
|
||||
// Test match forth
|
||||
target.nextMatch();
|
||||
Assert.assertTrue(target.hasMatch());
|
||||
verifyMatch("", "empty_string");
|
||||
// Test no more
|
||||
target.nextMatch();
|
||||
Assert.assertFalse(target.hasMatch());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchConditionAlwaysFalse()
|
||||
{
|
||||
JoinConditionAnalysis condition = JoinConditionAnalysis.forExpression("0", PREFIX, ExprMacroTable.nil());
|
||||
target = LookupJoinMatcher.create(extractor, leftSelectorFactory, condition, true);
|
||||
// Test match first
|
||||
target.matchCondition();
|
||||
Assert.assertFalse(target.hasMatch());
|
||||
verifyMatch(null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatchConditionSometimesTrueSometimesFalse()
|
||||
{
|
||||
final int index = 1;
|
||||
SingleIndexedInt row = new SingleIndexedInt();
|
||||
row.setValue(index);
|
||||
Mockito.doReturn(dimensionSelector).when(leftSelectorFactory).makeDimensionSelector(ArgumentMatchers.any(DimensionSpec.class));
|
||||
Mockito.doReturn(row).when(dimensionSelector).getRow();
|
||||
Mockito.doReturn("foo").when(dimensionSelector).lookupName(index);
|
||||
Mockito.doReturn("bar").when(extractor).apply("foo");
|
||||
|
||||
JoinConditionAnalysis condition = JoinConditionAnalysis.forExpression(
|
||||
StringUtils.format("\"%sk\" == foo", PREFIX),
|
||||
PREFIX,
|
||||
ExprMacroTable.nil()
|
||||
);
|
||||
target = LookupJoinMatcher.create(extractor, leftSelectorFactory, condition, true);
|
||||
// Test match
|
||||
target.matchCondition();
|
||||
Assert.assertTrue(target.hasMatch());
|
||||
verifyMatch("foo", "bar");
|
||||
// Test no more
|
||||
target.nextMatch();
|
||||
Assert.assertFalse(target.hasMatch());
|
||||
}
|
||||
|
||||
private void verifyMatch(String expectedKey, String expectedValue)
|
||||
{
|
||||
DimensionSelector selector = target.getColumnSelectorFactory()
|
||||
.makeDimensionSelector(DefaultDimensionSpec.of("k"));
|
||||
Assert.assertEquals(-1, selector.getValueCardinality());
|
||||
Assert.assertEquals(expectedKey, selector.lookupName(0));
|
||||
Assert.assertEquals(expectedKey, selector.lookupName(0));
|
||||
Assert.assertNull(selector.idLookup());
|
||||
|
||||
selector = target.getColumnSelectorFactory()
|
||||
.makeDimensionSelector(DefaultDimensionSpec.of("v"));
|
||||
Assert.assertEquals(-1, selector.getValueCardinality());
|
||||
Assert.assertEquals(expectedValue, selector.lookupName(0));
|
||||
Assert.assertEquals(expectedValue, selector.lookupName(0));
|
||||
Assert.assertNull(selector.idLookup());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue