blob: 694edde1e9defb22346a29f15b0e890762686e42 [file] [log] [blame]
/*
* 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;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import nl.jqno.equalsverifier.EqualsVerifier;
import org.apache.druid.common.config.NullHandling;
import org.apache.druid.java.util.common.IAE;
import org.apache.druid.java.util.common.Intervals;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.java.util.common.granularity.Granularities;
import org.apache.druid.math.expr.ExprMacroTable;
import org.apache.druid.query.QueryContexts;
import org.apache.druid.query.expression.TestExprMacroTable;
import org.apache.druid.query.filter.BoundDimFilter;
import org.apache.druid.query.filter.ExpressionDimFilter;
import org.apache.druid.query.filter.Filter;
import org.apache.druid.query.filter.InDimFilter;
import org.apache.druid.segment.VirtualColumn;
import org.apache.druid.segment.VirtualColumns;
import org.apache.druid.segment.column.ValueType;
import org.apache.druid.segment.filter.AndFilter;
import org.apache.druid.segment.filter.BoundFilter;
import org.apache.druid.segment.filter.FalseFilter;
import org.apache.druid.segment.filter.Filters;
import org.apache.druid.segment.filter.OrFilter;
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.JoinFilterPreAnalysisKey;
import org.apache.druid.segment.join.filter.JoinFilterSplit;
import org.apache.druid.segment.join.filter.JoinableClauses;
import org.apache.druid.segment.join.filter.rewrite.JoinFilterRewriteConfig;
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;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
public class JoinFilterAnalyzerTest extends BaseHashJoinSegmentStorageAdapterTest
{
@Test
public void test_filterPushDown_factToRegionToCountryLeftFilterOnChannel()
{
Filter originalFilter = new SelectorFilter("channel", "#en.wikipedia");
List<JoinableClause> joinableClauses = ImmutableList.of(
factToRegion(JoinType.LEFT),
regionToCountry(JoinType.LEFT)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName",
REGION_TO_COUNTRY_PREFIX + "countryName"
),
ImmutableList.of(
new Object[]{"Talk:Oswald Tilghman", null, null},
new Object[]{"Peremptory norm", "New South Wales", "Australia"},
new Object[]{"President of India", "California", "United States"},
new Object[]{"Glasgow", "Kingston upon Hull", "United Kingdom"},
new Object[]{"Otjiwarongo Airport", "California", "United States"},
new Object[]{"Sarah Michelle Gellar", "Ontario", "Canada"},
new Object[]{"DirecTV", "North Carolina", "United States"},
new Object[]{"Carlo Curti", "California", "United States"},
new Object[]{"Giusy Ferreri discography", "Provincia di Varese", "Italy"},
new Object[]{"Roma-Bangkok", "Provincia di Varese", "Italy"},
new Object[]{"Old Anatolian Turkish", "Virginia", "United States"},
new Object[]{"Cream Soda", "Ainigriv", "States United"},
new Object[]{"Orange Soda", null, null},
new Object[]{"History of Fourems", "Fourems Province", "Fourems"}
)
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
new SelectorFilter("channel", "#en.wikipedia"),
null,
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToRegionExprToCountryLeftFilterOnCountryName()
{
Filter originalFilter = new SelectorFilter("rtc.countryName", "United States");
JoinableClause regionExprToCountry = new JoinableClause(
REGION_TO_COUNTRY_PREFIX,
new IndexedTableJoinable(countriesTable),
JoinType.LEFT,
JoinConditionAnalysis.forExpression(
StringUtils.format(
"reverse(\"%scountryIsoCode\") == \"%scountryIsoCode\"",
FACT_TO_REGION_PREFIX,
REGION_TO_COUNTRY_PREFIX
),
REGION_TO_COUNTRY_PREFIX,
ExprMacroTable.nil()
)
);
List<JoinableClause> joinableClauses = ImmutableList.of(
factToRegion(JoinType.LEFT),
regionExprToCountry
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName",
REGION_TO_COUNTRY_PREFIX + "countryName"
),
ImmutableList.of(
new Object[]{"Cream Soda", "Ainigriv", "United States"}
)
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
null,
new SelectorFilter("rtc.countryName", "United States"),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToRegionToCountryLeftFilterOnChannelAndCountryName()
{
Filter originalFilter = new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", "#en.wikipedia"),
new SelectorFilter("rtc.countryName", "United States")
)
);
List<JoinableClause> joinableClauses = ImmutableList.of(
factToRegion(JoinType.LEFT),
regionToCountry(JoinType.LEFT)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName",
REGION_TO_COUNTRY_PREFIX + "countryName"
),
ImmutableList.of(
new Object[]{"President of India", "California", "United States"},
new Object[]{"Otjiwarongo Airport", "California", "United States"},
new Object[]{"DirecTV", "North Carolina", "United States"},
new Object[]{"Carlo Curti", "California", "United States"},
new Object[]{"Old Anatolian Turkish", "Virginia", "United States"}
)
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", "#en.wikipedia"),
new InDimFilter("countryIsoCode", ImmutableSet.of("US"), null, null).toFilter()
)
),
new SelectorFilter("rtc.countryName", "United States"),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToRegionToCountryLeftFilterOnNullColumns()
{
Filter originalFilter = new AndFilter(
ImmutableList.of(
new SelectorFilter("countryIsoCode", null),
new SelectorFilter("countryNumber", null),
new SelectorFilter("rtc.countryName", null),
new SelectorFilter("r1.regionName", null)
)
);
List<JoinableClause> joinableClauses = ImmutableList.of(
factToRegion(JoinType.LEFT),
regionToCountry(JoinType.LEFT)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName",
REGION_TO_COUNTRY_PREFIX + "countryName"
),
NullHandling.sqlCompatible() ?
ImmutableList.of(
new Object[]{"Talk:Oswald Tilghman", null, null},
new Object[]{"Rallicula", null, null},
new Object[]{"Apamea abruzzorum", null, null},
new Object[]{"Atractus flammigerus", null, null},
new Object[]{"Agama mossambica", null, null}
) :
ImmutableList.of() // when not running in SQL compatible mode, countryNumber does not have nulls
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
null,
new AndFilter(
ImmutableList.of(
new SelectorFilter("countryIsoCode", null),
new SelectorFilter("countryNumber", null),
new SelectorFilter("rtc.countryName", null),
new SelectorFilter("r1.regionName", null)
)
),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToRegionToCountryLeftFilterOnInvalidColumns()
{
List<JoinableClause> joinableClauses = ImmutableList.of(
factToRegion(JoinType.LEFT),
regionToCountry(JoinType.LEFT)
);
Filter originalFilter = new AndFilter(
ImmutableList.of(
new SelectorFilter("baseTableInvalidColumn", "abcd"),
new SelectorFilter("baseTableInvalidColumn2", null),
new SelectorFilter("rtc.invalidColumn", "abcd"),
new SelectorFilter("r1.invalidColumn", "abcd")
)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName",
REGION_TO_COUNTRY_PREFIX + "countryName"
),
ImmutableList.of()
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
new SelectorFilter("baseTableInvalidColumn", "abcd"),
new AndFilter(
ImmutableList.of(
new SelectorFilter("baseTableInvalidColumn2", null),
new SelectorFilter("rtc.invalidColumn", "abcd"),
new SelectorFilter("r1.invalidColumn", "abcd")
)
),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToRegionToCountryLeftFilterOnChannelVirtualColumn()
{
List<JoinableClause> joinableClauses = ImmutableList.of(
factToRegion(JoinType.LEFT),
regionToCountry(JoinType.LEFT)
);
Filter originalFilter = new AndFilter(
ImmutableList.of(
new SelectorFilter("v1", "virtual-column-#en.wikipedia")
)
);
VirtualColumns virtualColumns = VirtualColumns.create(
ImmutableList.of(
new ExpressionVirtualColumn(
"v1",
"concat('virtual-column-', \"channel\")",
ValueType.STRING,
TestExprMacroTable.INSTANCE
)
)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
virtualColumns
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
virtualColumns,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName",
REGION_TO_COUNTRY_PREFIX + "countryName"
),
ImmutableList.of(
new Object[]{"Talk:Oswald Tilghman", null, null},
new Object[]{"Peremptory norm", "New South Wales", "Australia"},
new Object[]{"President of India", "California", "United States"},
new Object[]{"Glasgow", "Kingston upon Hull", "United Kingdom"},
new Object[]{"Otjiwarongo Airport", "California", "United States"},
new Object[]{"Sarah Michelle Gellar", "Ontario", "Canada"},
new Object[]{"DirecTV", "North Carolina", "United States"},
new Object[]{"Carlo Curti", "California", "United States"},
new Object[]{"Giusy Ferreri discography", "Provincia di Varese", "Italy"},
new Object[]{"Roma-Bangkok", "Provincia di Varese", "Italy"},
new Object[]{"Old Anatolian Turkish", "Virginia", "United States"},
new Object[]{"Cream Soda", "Ainigriv", "States United"},
new Object[]{"Orange Soda", null, null},
new Object[]{"History of Fourems", "Fourems Province", "Fourems"}
)
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
new SelectorFilter("v1", "virtual-column-#en.wikipedia"),
null,
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToRegionFilterOnRHSRegionNameExprVirtualColumn()
{
// If our query had a filter that uses expressions, such as upper(r1.regionName) == 'VIRGINIA', this plans into
// a selector filter on an ExpressionVirtualColumn
Filter originalFilter = new SelectorFilter("v0", "VIRGINIA");
VirtualColumns virtualColumns = VirtualColumns.create(
ImmutableList.of(
new ExpressionVirtualColumn(
"v0",
"upper(\"r1.regionName\")",
ValueType.STRING,
TestExprMacroTable.INSTANCE
)
)
);
JoinableClauses joinableClauses = JoinableClauses.fromList(ImmutableList.of(
factToRegion(JoinType.LEFT)
));
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses.getJoinableClauses(),
virtualColumns
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses.getJoinableClauses(),
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
virtualColumns,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
"v0"
),
ImmutableList.of(
new Object[]{"Old Anatolian Turkish", "VIRGINIA"}
)
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
null,
new SelectorFilter("v0", "VIRGINIA"),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToRegionToCountryLeftFilterNormalizedAlreadyPushDownVariety()
{
Filter originalFilter = new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", "#fr.wikipedia"),
new BoundFilter(new BoundDimFilter(
"page",
"Les Argonautes",
"Les Argonautes",
false,
false,
null,
null,
null
)),
new SelectorFilter("rtc.countryName", "Canada"),
new BoundFilter(new BoundDimFilter(
"rtc.countryName",
"Canada",
"Canada",
false,
false,
null,
null,
null
)),
new OrFilter(
ImmutableList.of(
new SelectorFilter("namespace", "main"),
new BoundFilter(new BoundDimFilter(
"user",
"24.122.168.111",
"24.122.168.111",
false,
false,
null,
null,
null
))
)
),
new OrFilter(
ImmutableList.of(
new SelectorFilter("namespace", "main"),
new BoundFilter(new BoundDimFilter(
"r1.regionName",
"Quebec",
"Quebec",
false,
false,
null,
null,
null
))
)
)
)
);
List<JoinableClause> joinableClauses = ImmutableList.of(
factToRegion(JoinType.LEFT),
regionToCountry(JoinType.LEFT)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName",
REGION_TO_COUNTRY_PREFIX + "countryName"
),
ImmutableList.of(
new Object[]{"Les Argonautes", "Quebec", "Canada"}
)
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", "#fr.wikipedia"),
new BoundFilter(new BoundDimFilter(
"page",
"Les Argonautes",
"Les Argonautes",
false,
false,
null,
null,
null
)),
new OrFilter(
ImmutableList.of(
new SelectorFilter("namespace", "main"),
new BoundFilter(new BoundDimFilter(
"user",
"24.122.168.111",
"24.122.168.111",
false,
false,
null,
null,
null
))
)
),
new InDimFilter("countryIsoCode", ImmutableSet.of("CA"), null, null).toFilter()
)
),
new AndFilter(
ImmutableList.of(
new SelectorFilter("rtc.countryName", "Canada"),
new BoundFilter(new BoundDimFilter(
"rtc.countryName",
"Canada",
"Canada",
false,
false,
null,
null,
null
)),
new OrFilter(
ImmutableList.of(
new SelectorFilter("namespace", "main"),
new BoundFilter(new BoundDimFilter(
"r1.regionName",
"Quebec",
"Quebec",
false,
false,
null,
null,
null
))
)
)
)
),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factExpressionsToRegionToCountryLeftFilterOnChannelAndCountryName()
{
JoinableClause factExprToRegon = new JoinableClause(
FACT_TO_REGION_PREFIX,
new IndexedTableJoinable(regionsTable),
JoinType.LEFT,
JoinConditionAnalysis.forExpression(
StringUtils.format(
"\"%sregionIsoCode\" == reverse(regionIsoCode) && \"%scountryIsoCode\" == reverse(countryIsoCode)",
FACT_TO_REGION_PREFIX,
FACT_TO_REGION_PREFIX
),
FACT_TO_REGION_PREFIX,
ExprMacroTable.nil()
)
);
List<JoinableClause> joinableClauses = ImmutableList.of(
factExprToRegon,
regionToCountry(JoinType.LEFT)
);
Filter originalFilter = new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", "#en.wikipedia"),
new SelectorFilter("rtc.countryName", "States United")
)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName",
REGION_TO_COUNTRY_PREFIX + "countryName"
),
ImmutableList.of(
new Object[]{"Old Anatolian Turkish", "Ainigriv", "States United"}
)
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", "#en.wikipedia"),
new InDimFilter("JOIN-FILTER-PUSHDOWN-VIRTUAL-COLUMN-0", ImmutableSet.of("SU"), null, null).toFilter()
)
),
new SelectorFilter("rtc.countryName", "States United"),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
ExpressionVirtualColumn expectedVirtualColumn = new ExpressionVirtualColumn(
"JOIN-FILTER-PUSHDOWN-VIRTUAL-COLUMN-0",
"reverse(countryIsoCode)",
ValueType.STRING,
ExprMacroTable.nil()
);
Assert.assertEquals(
expectedFilterSplit.getBaseTableFilter(),
actualFilterSplit.getBaseTableFilter()
);
Assert.assertEquals(
expectedFilterSplit.getJoinTableFilter(),
actualFilterSplit.getJoinTableFilter()
);
ExpressionVirtualColumn actualVirtualColumn = (ExpressionVirtualColumn) actualFilterSplit.getPushDownVirtualColumns()
.iterator().next();
compareExpressionVirtualColumns(expectedVirtualColumn, actualVirtualColumn);
}
@Test
public void test_filterPushDown_factToRegionToCountryNotEquiJoinLeftFilterOnChannelAndCountryName()
{
JoinableClause factExprToRegon = new JoinableClause(
FACT_TO_REGION_PREFIX,
new IndexedTableJoinable(regionsTable),
JoinType.LEFT,
JoinConditionAnalysis.forExpression(
StringUtils.format(
"\"%sregionIsoCode\" == regionIsoCode && reverse(\"%scountryIsoCode\") == countryIsoCode",
FACT_TO_REGION_PREFIX,
FACT_TO_REGION_PREFIX
),
FACT_TO_REGION_PREFIX,
ExprMacroTable.nil()
)
);
List<JoinableClause> joinableClauses = ImmutableList.of(
factExprToRegon,
regionToCountry(JoinType.LEFT)
);
Filter originalFilter = new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", "#en.wikipedia"),
new SelectorFilter("rtc.countryName", "States United")
)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage(
"Cannot build hash-join matcher on non-equi-join condition: \"r1.regionIsoCode\" == regionIsoCode && reverse(\"r1.countryIsoCode\") == countryIsoCode");
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName",
REGION_TO_COUNTRY_PREFIX + "countryName"
),
ImmutableList.of(
new Object[]{"Old Anatolian Turkish", "Ainigriv", "States United"}
)
);
}
@Test
public void test_filterPushDown_factToRegionToCountryLeftUnnormalizedFilter()
{
List<JoinableClause> joinableClauses = ImmutableList.of(
factToRegion(JoinType.LEFT),
regionToCountry(JoinType.LEFT)
);
Filter originalFilter = new OrFilter(
ImmutableList.of(
new SelectorFilter("channel", "#ko.wikipedia"),
new AndFilter(
ImmutableList.of(
new SelectorFilter("rtc.countryName", "United States"),
new SelectorFilter("r1.regionName", "Virginia")
)
)
)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName",
REGION_TO_COUNTRY_PREFIX + "countryName"
),
ImmutableList.of(
new Object[]{"유희왕 GX", "Seoul", "Republic of Korea"},
new Object[]{"Old Anatolian Turkish", "Virginia", "United States"}
)
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
new AndFilter(
ImmutableList.of(
new OrFilter(
ImmutableList.of(
new SelectorFilter("channel", "#ko.wikipedia"),
new InDimFilter("countryIsoCode", ImmutableSet.of("US"), null, null).toFilter()
)
),
new OrFilter(
ImmutableList.of(
new SelectorFilter("channel", "#ko.wikipedia"),
new AndFilter(
ImmutableList.of(
new InDimFilter("countryIsoCode", ImmutableSet.of("US"), null, null).toFilter(),
new InDimFilter("regionIsoCode", ImmutableSet.of("VA"), null, null).toFilter()
)
)
)
)
)
),
new AndFilter(
ImmutableList.of(
new OrFilter(
ImmutableList.of(
new SelectorFilter("channel", "#ko.wikipedia"),
new SelectorFilter("rtc.countryName", "United States")
)
),
new OrFilter(
ImmutableList.of(
new SelectorFilter("channel", "#ko.wikipedia"),
new SelectorFilter("r1.regionName", "Virginia")
)
)
)
),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factConcatExpressionToCountryLeftFilterOnChannelAndCountryName()
{
JoinableClause factExprToCountry = new JoinableClause(
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX,
new IndexedTableJoinable(countriesTable),
JoinType.LEFT,
JoinConditionAnalysis.forExpression(
StringUtils.format(
"\"%scountryIsoCode\" == 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.countryName", "Usca")
)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
filter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
filter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryName"
),
ImmutableList.of(
new Object[]{"President of India", "Usca"},
new Object[]{"Otjiwarongo Airport", "Usca"},
new Object[]{"Carlo Curti", "Usca"}
)
);
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.countryName", "Usca"),
ImmutableSet.of(
expectedVirtualColumn
)
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(
expectedFilterSplit.getBaseTableFilter(),
actualFilterSplit.getBaseTableFilter()
);
Assert.assertEquals(
expectedFilterSplit.getJoinTableFilter(),
actualFilterSplit.getJoinTableFilter()
);
ExpressionVirtualColumn actualVirtualColumn = (ExpressionVirtualColumn) actualFilterSplit.getPushDownVirtualColumns()
.iterator().next();
compareExpressionVirtualColumns(expectedVirtualColumn, actualVirtualColumn);
}
@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 = makeDefaultConfigPreAnalysis(
filter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
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"}
)
);
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"),
ImmutableSet.of(
expectedVirtualColumn
)
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(
expectedFilterSplit.getBaseTableFilter(),
actualFilterSplit.getBaseTableFilter()
);
Assert.assertEquals(
expectedFilterSplit.getJoinTableFilter(),
actualFilterSplit.getJoinTableFilter()
);
ExpressionVirtualColumn actualVirtualColumn = (ExpressionVirtualColumn) actualFilterSplit.getPushDownVirtualColumns()
.iterator().next();
compareExpressionVirtualColumns(expectedVirtualColumn, actualVirtualColumn);
}
@Test
public void test_filterPushDown_factToCountryRightWithFilterOnChannelAndJoinable()
{
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryOnIsoCode(JoinType.RIGHT));
Filter originalFilter = new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", "#de.wikipedia"),
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryName", "Germany")
)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
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 + "countryIsoCode",
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryName",
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryNumber"
),
ImmutableList.of(
new Object[]{"Diskussion:Sebastian Schulz", "DE", 3L, "DE", "Germany", 3L}
)
);
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 + "countryName", "Germany"),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@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 = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
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"}
)
);
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"),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToCountryRightWithFilterOnNullColumns()
{
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryOnIsoCode(JoinType.RIGHT));
Filter originalFilter = new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", null),
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryName", null)
)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
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 + "countryIsoCode",
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryName",
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryNumber"
),
ImmutableList.of()
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
null,
new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", null),
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryName", null)
)
),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToCountryRightWithFilterOnValueThatMatchesNothing()
{
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryOnIsoCode(JoinType.RIGHT));
Filter originalFilter = new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", null),
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryName", "NO MATCH")
)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
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 + "countryIsoCode",
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryName",
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryNumber"
),
ImmutableList.of()
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
FalseFilter.instance(),
new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", null),
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryName", "NO MATCH")
)
),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@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 = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
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()
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
null,
new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", null),
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v", null)
)
),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToCountryInnerUsingCountryNumberFilterOnChannelAndCountryName()
{
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryOnNumber(JoinType.INNER));
Filter originalFilter = new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", "#en.wikipedia"),
new SelectorFilter(FACT_TO_COUNTRY_ON_NUMBER_PREFIX + "countryName", "Australia")
)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
// 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 + "countryIsoCode",
FACT_TO_COUNTRY_ON_NUMBER_PREFIX + "countryName",
FACT_TO_COUNTRY_ON_NUMBER_PREFIX + "countryNumber"
),
NullHandling.sqlCompatible() ?
ImmutableList.of(
new Object[]{"Peremptory norm", "AU", "AU", "Australia", 0L}
) :
ImmutableList.of(
new Object[]{"Talk:Oswald Tilghman", null, "AU", "Australia", 0L},
new Object[]{"Peremptory norm", "AU", "AU", "Australia", 0L}
)
);
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 + "countryName", "Australia"),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@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 = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
// 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"}
)
);
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"),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToCountryInnerUsingCountryNumberFilterOnNulls()
{
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryOnNumber(JoinType.INNER));
Filter originalFilter = new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", null),
new SelectorFilter(FACT_TO_COUNTRY_ON_NUMBER_PREFIX + "countryName", null)
)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
"countryIsoCode",
FACT_TO_COUNTRY_ON_NUMBER_PREFIX + "countryIsoCode",
FACT_TO_COUNTRY_ON_NUMBER_PREFIX + "countryName",
FACT_TO_COUNTRY_ON_NUMBER_PREFIX + "countryNumber"
),
ImmutableList.of()
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
null,
new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", null),
new SelectorFilter(FACT_TO_COUNTRY_ON_NUMBER_PREFIX + "countryName", null)
)
),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@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 = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
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()
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
null,
new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", null),
new SelectorFilter(FACT_TO_COUNTRY_ON_NUMBER_PREFIX + "v", null)
)
),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToCountryFullWithFilterOnChannelAndCountryName()
{
Filter filter = new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", "#es.wikipedia"),
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryName", "El Salvador")
)
);
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryOnIsoCode(JoinType.FULL));
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
filter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
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 + "countryIsoCode",
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryName",
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryNumber"
),
ImmutableList.of(
new Object[]{"Wendigo", "SV", 12L, "SV", "El Salvador", 12L}
)
);
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 + "countryName", "El Salvador"),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@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 = makeDefaultConfigPreAnalysis(
filter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
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"}
)
);
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"),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToCountryFullWithFilterOnNulls()
{
List<JoinableClause> joinableClauses = ImmutableList.of(factToCountryOnIsoCode(JoinType.FULL));
Filter originalFilter = new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", null),
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryName", null)
)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
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 + "countryIsoCode",
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryName",
FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryNumber"
),
ImmutableList.of()
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
null,
new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", null),
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "countryName", null)
)
),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@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 = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
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()
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
null,
new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", null),
new SelectorFilter(FACT_TO_COUNTRY_ON_ISO_CODE_PREFIX + "v", null)
)
),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToRegionTwoColumnsToOneRHSColumnAndFilterOnRHS()
{
JoinableClause factExprToRegon = new JoinableClause(
FACT_TO_REGION_PREFIX,
new IndexedTableJoinable(regionsTable),
JoinType.LEFT,
JoinConditionAnalysis.forExpression(
StringUtils.format(
"\"%sregionIsoCode\" == regionIsoCode && \"%sregionIsoCode\" == countryIsoCode",
FACT_TO_REGION_PREFIX,
FACT_TO_REGION_PREFIX
),
FACT_TO_REGION_PREFIX,
ExprMacroTable.nil()
)
);
List<JoinableClause> joinableClauses = ImmutableList.of(
factExprToRegon
);
Filter originalFilter = new SelectorFilter("r1.regionName", "Fourems Province");
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName"
),
ImmutableList.of(
new Object[]{"History of Fourems", "Fourems Province"}
)
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
new AndFilter(
ImmutableList.of(
new InDimFilter("countryIsoCode", ImmutableSet.of("MMMM"), null, null).toFilter(),
new InDimFilter("regionIsoCode", ImmutableSet.of("MMMM"), null, null).toFilter()
)
),
new SelectorFilter("r1.regionName", "Fourems Province"),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToRegionOneColumnToTwoRHSColumnsAndFilterOnRHS()
{
JoinableClause factExprToRegon = new JoinableClause(
FACT_TO_REGION_PREFIX,
new IndexedTableJoinable(regionsTable),
JoinType.LEFT,
JoinConditionAnalysis.forExpression(
StringUtils.format(
"\"%sregionIsoCode\" == regionIsoCode && \"%scountryIsoCode\" == regionIsoCode",
FACT_TO_REGION_PREFIX,
FACT_TO_REGION_PREFIX
),
FACT_TO_REGION_PREFIX,
ExprMacroTable.nil()
)
);
List<JoinableClause> joinableClauses = ImmutableList.of(
factExprToRegon
);
Filter originalFilter = new OrFilter(
ImmutableList.of(
new SelectorFilter("r1.regionName", "Fourems Province"),
new SelectorFilter("r1.regionIsoCode", "AAAA")
)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName"
),
ImmutableList.of(
new Object[]{"History of Fourems", "Fourems Province"}
)
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
new OrFilter(
ImmutableList.of(
new InDimFilter("regionIsoCode", ImmutableSet.of("MMMM"), null, null).toFilter(),
new SelectorFilter("regionIsoCode", "AAAA")
)
),
originalFilter,
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToRegionThreeRHSColumnsAllDirectAndFilterOnRHS()
{
JoinableClause factExprToRegon = new JoinableClause(
FACT_TO_REGION_PREFIX,
new IndexedTableJoinable(regionsTable),
JoinType.LEFT,
JoinConditionAnalysis.forExpression(
StringUtils.format(
"\"%sregionIsoCode\" == regionIsoCode && \"%scountryIsoCode\" == regionIsoCode && \"%sregionName\" == user",
FACT_TO_REGION_PREFIX,
FACT_TO_REGION_PREFIX,
FACT_TO_REGION_PREFIX
),
FACT_TO_REGION_PREFIX,
ExprMacroTable.nil()
)
);
List<JoinableClause> joinableClauses = ImmutableList.of(
factExprToRegon
);
Filter originalFilter = new OrFilter(
ImmutableList.of(
new SelectorFilter("r1.regionName", "Fourems Province"),
new SelectorFilter("r1.regionIsoCode", "AAAA")
)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
// This query doesn't execute because regionName is not a key column, but we can still check the
// filter rewrites.
expectedException.expect(IAE.class);
expectedException.expectMessage(
"Cannot build hash-join matcher on non-key-based condition: Equality{leftExpr=user, rightColumn='regionName'}"
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName"
),
ImmutableList.of()
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
new OrFilter(
ImmutableList.of(
new SelectorFilter("user", "Fourems Province"),
new SelectorFilter("regionIsoCode", "AAAA")
)
),
null,
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToRegionToCountryLeftFilterOnPageDisablePushDown()
{
JoinableClauses joinableClauses = JoinableClauses.fromList(ImmutableList.of(
factToRegion(JoinType.LEFT),
regionToCountry(JoinType.LEFT)
));
Filter originalFilter = new SelectorFilter("page", "Peremptory norm");
JoinFilterPreAnalysis joinFilterPreAnalysis = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(
new JoinFilterPreAnalysisKey(
new JoinFilterRewriteConfig(
false,
true,
true,
QueryContexts.DEFAULT_ENABLE_REWRITE_JOIN_TO_FILTER,
QueryContexts.DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE
),
joinableClauses.getJoinableClauses(),
VirtualColumns.EMPTY,
originalFilter
)
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses.getJoinableClauses(),
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName",
REGION_TO_COUNTRY_PREFIX + "countryName"
),
ImmutableList.of(
new Object[]{"Peremptory norm", "New South Wales", "Australia"}
)
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
null,
new SelectorFilter("page", "Peremptory norm"),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToRegionToCountryLeftEnablePushDownDisableRewrite()
{
JoinableClauses joinableClauses = JoinableClauses.fromList(ImmutableList.of(
factToRegion(JoinType.LEFT),
regionToCountry(JoinType.LEFT)
));
Filter originalFilter = new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", "#en.wikipedia"),
new SelectorFilter("rtc.countryName", "United States"),
new OrFilter(
ImmutableList.of(
new SelectorFilter("page", "DirecTV"),
new SelectorFilter("rtc.countryIsoCode", "US")
)
),
new BoundFilter(new BoundDimFilter(
"namespace",
"Main",
"Main",
false,
false,
null,
null,
null
))
)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(
new JoinFilterPreAnalysisKey(
new JoinFilterRewriteConfig(
true,
false,
true,
QueryContexts.DEFAULT_ENABLE_REWRITE_JOIN_TO_FILTER,
QueryContexts.DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE
),
joinableClauses.getJoinableClauses(),
VirtualColumns.EMPTY,
originalFilter
)
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses.getJoinableClauses(),
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName",
REGION_TO_COUNTRY_PREFIX + "countryName"
),
ImmutableList.of(
new Object[]{"President of India", "California", "United States"},
new Object[]{"Otjiwarongo Airport", "California", "United States"},
new Object[]{"DirecTV", "North Carolina", "United States"},
new Object[]{"Carlo Curti", "California", "United States"},
new Object[]{"Old Anatolian Turkish", "Virginia", "United States"}
)
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
new AndFilter(
ImmutableList.of(
new SelectorFilter("channel", "#en.wikipedia"),
new BoundFilter(new BoundDimFilter(
"namespace",
"Main",
"Main",
false,
false,
null,
null,
null
))
)
),
new AndFilter(
ImmutableList.of(
new SelectorFilter("rtc.countryName", "United States"),
new OrFilter(
ImmutableList.of(
new SelectorFilter("page", "DirecTV"),
new SelectorFilter("rtc.countryIsoCode", "US")
)
)
)
),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToRegionToCountryLeftFilterOnRHSJoinConditionColumns()
{
test_filterPushDown_factToRegionToCountryLeftFilterOnRHSJoinConditionColumnsHelper(false);
}
@Test
public void test_filterPushDown_factToRegionToCountryLeftFilterOnRHSJoinConditionColumnsWithLhsExpr()
{
test_filterPushDown_factToRegionToCountryLeftFilterOnRHSJoinConditionColumnsHelper(true);
}
private void test_filterPushDown_factToRegionToCountryLeftFilterOnRHSJoinConditionColumnsHelper(boolean hasLhsExpressionInJoinCondition)
{
Filter expressionFilter = new ExpressionDimFilter(
"\"rtc.countryIsoCode\" == 'CA'",
ExprMacroTable.nil()
).toFilter();
Filter specialSelectorFilter = new SelectorFilter("rtc.countryIsoCode", "CA")
{
@Override
public boolean supportsRequiredColumnRewrite()
{
return false;
}
};
Filter originalFilter = new AndFilter(
ImmutableList.of(
new SelectorFilter("r1.regionIsoCode", "ON"),
new SelectorFilter("rtc.countryIsoCode", "CA"),
specialSelectorFilter,
new BoundFilter(new BoundDimFilter(
"rtc.countryIsoCode",
"CA",
"CB",
false,
false,
null,
null,
null
)),
expressionFilter,
new InDimFilter("rtc.countryIsoCode", ImmutableSet.of("CA", "CA2", "CA3"), null, null).toFilter(),
new OrFilter(
ImmutableList.of(
new SelectorFilter("channel", "#fr.wikipedia"),
new SelectorFilter("rtc.countryIsoCode", "QQQ"),
new BoundFilter(new BoundDimFilter(
"rtc.countryIsoCode",
"YYY",
"ZZZ",
false,
false,
null,
null,
null
))
)
),
new OrFilter(
ImmutableList.of(
new SelectorFilter("namespace", "Main"),
new SelectorFilter("rtc.countryIsoCode", "ABCDEF"),
new SelectorFilter("rtc.countryName", "Canada"),
new BoundFilter(new BoundDimFilter(
"rtc.countryIsoCode",
"XYZXYZ",
"XYZXYZ",
false,
false,
null,
null,
null
))
)
)
)
);
JoinableClause factToRegionClause;
if (hasLhsExpressionInJoinCondition) {
factToRegionClause = new JoinableClause(
FACT_TO_REGION_PREFIX,
new IndexedTableJoinable(regionsTable),
JoinType.LEFT,
JoinConditionAnalysis.forExpression(
StringUtils.format(
"\"%sregionIsoCode\" == upper(lower(regionIsoCode)) && \"%scountryIsoCode\" == upper(lower(countryIsoCode))",
FACT_TO_REGION_PREFIX,
FACT_TO_REGION_PREFIX
),
FACT_TO_REGION_PREFIX,
ExprMacroTable.nil()
)
);
} else {
factToRegionClause = factToRegion(JoinType.LEFT);
}
List<JoinableClause> joinableClauses = ImmutableList.of(
factToRegionClause,
regionToCountry(JoinType.LEFT)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
String rewrittenCountryIsoCodeColumnName = hasLhsExpressionInJoinCondition
? "JOIN-FILTER-PUSHDOWN-VIRTUAL-COLUMN-1"
: "countryIsoCode";
String rewrittenRegionIsoCodeColumnName = hasLhsExpressionInJoinCondition
? "JOIN-FILTER-PUSHDOWN-VIRTUAL-COLUMN-0"
: "regionIsoCode";
Set<VirtualColumn> expectedVirtualColumns;
if (hasLhsExpressionInJoinCondition) {
expectedVirtualColumns = ImmutableSet.of(
new ExpressionVirtualColumn(
rewrittenRegionIsoCodeColumnName,
"(upper [(lower [regionIsoCode])])",
ValueType.STRING,
ExprMacroTable.nil()
),
new ExpressionVirtualColumn(
rewrittenCountryIsoCodeColumnName,
"(upper [(lower [countryIsoCode])])",
ValueType.STRING,
ExprMacroTable.nil()
)
);
} else {
expectedVirtualColumns = ImmutableSet.of();
}
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName",
REGION_TO_COUNTRY_PREFIX + "countryName"
),
ImmutableList.of(
new Object[]{"Didier Leclair", "Ontario", "Canada"}
)
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
new AndFilter(
ImmutableList.of(
new SelectorFilter(rewrittenRegionIsoCodeColumnName, "ON"),
new SelectorFilter(rewrittenCountryIsoCodeColumnName, "CA"),
new InDimFilter(rewrittenCountryIsoCodeColumnName, ImmutableSet.of("CA"), null, null).toFilter(),
new BoundFilter(new BoundDimFilter(
rewrittenCountryIsoCodeColumnName,
"CA",
"CB",
false,
false,
null,
null,
null
)),
new InDimFilter(
rewrittenCountryIsoCodeColumnName,
ImmutableSet.of("CA", "CA2", "CA3"),
null,
null
).toFilter(),
new OrFilter(
ImmutableList.of(
new SelectorFilter("channel", "#fr.wikipedia"),
new SelectorFilter(rewrittenCountryIsoCodeColumnName, "QQQ"),
new BoundFilter(new BoundDimFilter(
rewrittenCountryIsoCodeColumnName,
"YYY",
"ZZZ",
false,
false,
null,
null,
null
))
)
),
new OrFilter(
ImmutableList.of(
new SelectorFilter("namespace", "Main"),
new SelectorFilter(rewrittenCountryIsoCodeColumnName, "ABCDEF"),
new InDimFilter(
rewrittenCountryIsoCodeColumnName,
ImmutableSet.of("CA"),
null,
null
).toFilter(),
new BoundFilter(new BoundDimFilter(
rewrittenCountryIsoCodeColumnName,
"XYZXYZ",
"XYZXYZ",
false,
false,
null,
null,
null
))
)
)
)
),
new AndFilter(
ImmutableList.of(
specialSelectorFilter,
expressionFilter,
new OrFilter(
ImmutableList.of(
new SelectorFilter("namespace", "Main"),
new SelectorFilter("rtc.countryIsoCode", "ABCDEF"),
new SelectorFilter("rtc.countryName", "Canada"),
new BoundFilter(new BoundDimFilter(
"rtc.countryIsoCode",
"XYZXYZ",
"XYZXYZ",
false,
false,
null,
null,
null
))
)
)
)
),
expectedVirtualColumns
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToRegionToCountryLeftFilterOnTwoRHSColumnsSameValue()
{
Filter originalFilter = new AndFilter(
ImmutableList.of(
new SelectorFilter("r1.regionName", "California"),
new SelectorFilter("r1.extraField", "California")
)
);
List<JoinableClause> joinableClauses = ImmutableList.of(
factToRegion(JoinType.LEFT),
regionToCountry(JoinType.LEFT)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName",
REGION_TO_COUNTRY_PREFIX + "countryName"
),
ImmutableList.of(
)
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
new AndFilter(
ImmutableList.of(
new InDimFilter("countryIsoCode", ImmutableSet.of("US"), null, null).toFilter(),
new InDimFilter("regionIsoCode", ImmutableSet.of("CA"), null, null).toFilter(),
new InDimFilter("countryIsoCode", ImmutableSet.of("MMMM", "AAAA"), null, null).toFilter(),
new InDimFilter("regionIsoCode", ImmutableSet.of("MMMM", "AAAA"), null, null).toFilter()
)
),
originalFilter,
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_filterPushDown_factToRegionExprToCountryLeftFilterOnCountryNameWithMultiLevelMode()
{
Filter originalFilter = new SelectorFilter("rtc.countryName", "United States");
JoinableClause regionExprToCountry = new JoinableClause(
REGION_TO_COUNTRY_PREFIX,
new IndexedTableJoinable(countriesTable),
JoinType.LEFT,
JoinConditionAnalysis.forExpression(
StringUtils.format(
"reverse(\"%scountryIsoCode\") == \"%scountryIsoCode\"",
FACT_TO_REGION_PREFIX,
REGION_TO_COUNTRY_PREFIX
),
REGION_TO_COUNTRY_PREFIX,
ExprMacroTable.nil()
)
);
List<JoinableClause> joinableClauses = ImmutableList.of(
factToRegion(JoinType.LEFT),
regionExprToCountry
);
JoinFilterPreAnalysis joinFilterPreAnalysis = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(
new JoinFilterPreAnalysisKey(
new JoinFilterRewriteConfig(
true,
true,
true,
QueryContexts.DEFAULT_ENABLE_REWRITE_JOIN_TO_FILTER,
QueryContexts.DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE
),
joinableClauses,
VirtualColumns.EMPTY,
originalFilter
)
);
HashJoinSegmentStorageAdapter adapter = new HashJoinSegmentStorageAdapter(
factSegment.asStorageAdapter(),
joinableClauses,
joinFilterPreAnalysis
);
JoinTestHelper.verifyCursors(
adapter.makeCursors(
originalFilter,
Intervals.ETERNITY,
VirtualColumns.EMPTY,
Granularities.ALL,
false,
null
),
ImmutableList.of(
"page",
FACT_TO_REGION_PREFIX + "regionName",
REGION_TO_COUNTRY_PREFIX + "countryName"
),
ImmutableList.of(
new Object[]{"Cream Soda", "Ainigriv", "United States"}
)
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
null,
new SelectorFilter("rtc.countryName", "United States"),
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
@Test
public void test_JoinFilterSplit_equals()
{
EqualsVerifier.forClass(JoinFilterSplit.class)
.usingGetClass()
.withNonnullFields("baseTableFilter", "pushDownVirtualColumns")
.verify();
}
@Test
public void test_joinFilterPreAnalysisKey_equals()
{
EqualsVerifier.forClass(JoinFilterPreAnalysisKey.class)
.usingGetClass()
.withNonnullFields("virtualColumns")
.verify();
}
@Test
public void test_filterPushDown_baseTableFilter()
{
Filter originalFilter = new SelectorFilter("channel", "#en.wikipedia");
Filter baseTableFilter = new SelectorFilter("countryIsoCode", "CA");
List<JoinableClause> joinableClauses = ImmutableList.of(
factToRegion(JoinType.LEFT),
regionToCountry(JoinType.LEFT)
);
JoinFilterPreAnalysis joinFilterPreAnalysis = makeDefaultConfigPreAnalysis(
originalFilter,
joinableClauses,
VirtualColumns.EMPTY
);
JoinFilterSplit expectedFilterSplit = new JoinFilterSplit(
Filters.and(Arrays.asList(originalFilter, baseTableFilter)),
null,
ImmutableSet.of()
);
JoinFilterSplit actualFilterSplit = JoinFilterAnalyzer.splitFilter(joinFilterPreAnalysis, baseTableFilter);
Assert.assertEquals(expectedFilterSplit, actualFilterSplit);
}
}