use of org.apache.druid.segment.join.JoinableClause in project druid by druid-io.
the class JoinableClauses method createClauses.
/**
* Builds a list of {@link JoinableClause} corresponding to a list of {@link PreJoinableClause}. This will call
* {@link JoinableFactory#build} on each one and therefore may be an expensive operation.
*/
public static JoinableClauses createClauses(final List<PreJoinableClause> preClauses, final JoinableFactory joinableFactory) {
// Since building a JoinableClause can be expensive, check for prefix conflicts before building
checkPreJoinableClausesForDuplicatesAndShadowing(preClauses);
List<JoinableClause> joinableClauses = preClauses.stream().map(preJoinableClause -> {
final Optional<Joinable> joinable = joinableFactory.build(preJoinableClause.getDataSource(), preJoinableClause.getCondition());
return new JoinableClause(preJoinableClause.getPrefix(), joinable.orElseThrow(() -> new ISE("dataSource is not joinable: %s", preJoinableClause.getDataSource())), preJoinableClause.getJoinType(), preJoinableClause.getCondition());
}).collect(Collectors.toList());
return new JoinableClauses(joinableClauses);
}
use of org.apache.druid.segment.join.JoinableClause in project druid by druid-io.
the class JoinAndLookupBenchmark method setup.
@Setup()
public void setup() throws IOException {
tmpDir = FileUtils.createTempDir();
ColumnConfig columnConfig = () -> columnCacheSizeBytes;
index = JoinTestHelper.createFactIndexBuilder(columnConfig, tmpDir, rows).buildMMappedIndex();
final String prefix = "c.";
baseSegment = new QueryableIndexSegment(index, SegmentId.dummy("join"));
List<JoinableClause> joinableClausesLookupStringKey = ImmutableList.of(new JoinableClause(prefix, LookupJoinable.wrap(JoinTestHelper.createCountryIsoCodeToNameLookup()), JoinType.LEFT, JoinConditionAnalysis.forExpression(StringUtils.format("countryIsoCode == \"%sk\"", prefix), prefix, ExprMacroTable.nil())));
JoinFilterPreAnalysis preAnalysisLookupStringKey = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(new JoinFilterPreAnalysisKey(new JoinFilterRewriteConfig(false, false, false, false, 0), joinableClausesLookupStringKey, VirtualColumns.EMPTY, null));
hashJoinLookupStringKeySegment = new HashJoinSegment(ReferenceCountingSegment.wrapRootGenerationSegment(baseSegment), null, joinableClausesLookupStringKey, preAnalysisLookupStringKey);
List<JoinableClause> joinableClausesLookupLongKey = ImmutableList.of(new JoinableClause(prefix, LookupJoinable.wrap(JoinTestHelper.createCountryIsoCodeToNameLookup()), JoinType.LEFT, JoinConditionAnalysis.forExpression(StringUtils.format("countryIsoCode == \"%sk\"", prefix), prefix, ExprMacroTable.nil())));
JoinFilterPreAnalysis preAnalysisLookupLongKey = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(new JoinFilterPreAnalysisKey(new JoinFilterRewriteConfig(false, false, false, false, 0), joinableClausesLookupLongKey, VirtualColumns.EMPTY, null));
hashJoinLookupLongKeySegment = new HashJoinSegment(ReferenceCountingSegment.wrapRootGenerationSegment(baseSegment), null, joinableClausesLookupLongKey, preAnalysisLookupLongKey);
List<JoinableClause> joinableClausesIndexedTableStringKey = ImmutableList.of(new JoinableClause(prefix, new IndexedTableJoinable(JoinTestHelper.createCountriesIndexedTable()), JoinType.LEFT, JoinConditionAnalysis.forExpression(StringUtils.format("countryIsoCode == \"%scountryIsoCode\"", prefix), prefix, ExprMacroTable.nil())));
JoinFilterPreAnalysis preAnalysisIndexedStringKey = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(new JoinFilterPreAnalysisKey(new JoinFilterRewriteConfig(false, false, false, false, 0), joinableClausesLookupLongKey, VirtualColumns.EMPTY, null));
hashJoinIndexedTableStringKeySegment = new HashJoinSegment(ReferenceCountingSegment.wrapRootGenerationSegment(baseSegment), null, joinableClausesIndexedTableStringKey, preAnalysisIndexedStringKey);
List<JoinableClause> joinableClausesIndexedTableLongKey = ImmutableList.of(new JoinableClause(prefix, new IndexedTableJoinable(JoinTestHelper.createCountriesIndexedTable()), JoinType.LEFT, JoinConditionAnalysis.forExpression(StringUtils.format("countryNumber == \"%scountryNumber\"", prefix), prefix, ExprMacroTable.nil())));
JoinFilterPreAnalysis preAnalysisIndexedLongKey = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(new JoinFilterPreAnalysisKey(new JoinFilterRewriteConfig(false, false, false, false, 0), joinableClausesIndexedTableLongKey, VirtualColumns.EMPTY, null));
hashJoinIndexedTableLongKeySegment = new HashJoinSegment(ReferenceCountingSegment.wrapRootGenerationSegment(baseSegment), null, joinableClausesIndexedTableLongKey, preAnalysisIndexedLongKey);
final Map<String, String> countryCodeToNameMap = JoinTestHelper.createCountryIsoCodeToNameLookup().getMap();
final Map<String, String> countryNumberToNameMap = JoinTestHelper.createCountryNumberToNameLookup().getMap();
final ExprMacroTable exprMacroTable = new ExprMacroTable(ImmutableList.of(new LookupExprMacro(new LookupExtractorFactoryContainerProvider() {
@Override
public Set<String> getAllLookupNames() {
return ImmutableSet.of(LOOKUP_COUNTRY_CODE_TO_NAME, LOOKUP_COUNTRY_NUMBER_TO_NAME);
}
@Override
public Optional<LookupExtractorFactoryContainer> get(String lookupName) {
if (LOOKUP_COUNTRY_CODE_TO_NAME.equals(lookupName)) {
return Optional.of(new LookupExtractorFactoryContainer("0", new MapLookupExtractorFactory(countryCodeToNameMap, false)));
} else if (LOOKUP_COUNTRY_NUMBER_TO_NAME.equals(lookupName)) {
return Optional.of(new LookupExtractorFactoryContainer("0", new MapLookupExtractorFactory(countryNumberToNameMap, false)));
} else {
return Optional.empty();
}
}
})));
lookupVirtualColumns = VirtualColumns.create(ImmutableList.of(new ExpressionVirtualColumn(LOOKUP_COUNTRY_CODE_TO_NAME, "lookup(countryIsoCode, '" + LOOKUP_COUNTRY_CODE_TO_NAME + "')", ColumnType.STRING, exprMacroTable), new ExpressionVirtualColumn(LOOKUP_COUNTRY_NUMBER_TO_NAME, "lookup(countryNumber, '" + LOOKUP_COUNTRY_NUMBER_TO_NAME + "')", ColumnType.STRING, exprMacroTable)));
}
use of org.apache.druid.segment.join.JoinableClause in project druid by druid-io.
the class IndexedTableJoinCursorBenchmark method setup.
@Setup(Level.Trial)
public void setup() {
baseSegment = makeQueryableIndexSegment(closer, "regular", rowsPerSegment);
joinSegment = makeQueryableIndexSegment(closer, "join", rowsPerTableSegment);
table = closer.register(makeTable(indexedTableType, keyColumns, joinSegment));
final String prefix = "j0.";
projectionColumns = PROJECTIONS.get(projection);
final String[] split = joinColumns.split(",");
final String lhsJoinColumn = split[0];
final String rhsJoinColumn = split[1];
final List<JoinableClause> clauses = ImmutableList.of(new JoinableClause(prefix, new IndexedTableJoinable(table), JoinType.LEFT, JoinConditionAnalysis.forExpression(StringUtils.format("%s == \"%s%s\"", lhsJoinColumn, prefix, rhsJoinColumn), prefix, ExprMacroTable.nil())));
final JoinFilterPreAnalysis preAnalysis = JoinFilterAnalyzer.computeJoinFilterPreAnalysis(new JoinFilterPreAnalysisKey(new JoinFilterRewriteConfig(enableFilterPushdown, enableFilterRewrite, enableFilterRewriteValueFilters, QueryContexts.DEFAULT_ENABLE_REWRITE_JOIN_TO_FILTER, QueryContexts.DEFAULT_ENABLE_JOIN_FILTER_REWRITE_MAX_SIZE), clauses, VirtualColumns.EMPTY, null));
hashJoinSegment = closer.register(new HashJoinSegment(ReferenceCountingSegment.wrapRootGenerationSegment(baseSegment), null, clauses, preAnalysis));
}
use of org.apache.druid.segment.join.JoinableClause in project druid by druid-io.
the class JoinFilterCorrelations method findCorrelatedBaseTableColumns.
/**
* For each rhs column that appears in the equiconditions for a table's JoinableClause,
* we try to determine what base table columns are related to the rhs column through the total set of equiconditions.
* We do this by searching backwards through the chain of join equiconditions using the provided equicondition map.
* <p>
* For example, suppose we have 3 tables, A,B,C, joined with the following conditions, where A is the base table:
* A.joinColumn == B.joinColumn
* B.joinColum == C.joinColumnenableRewriteValueColumnFilters
* <p>
* We would determine that C.joinColumn is correlated with A.joinColumn: we first see that
* C.joinColumn is linked to B.joinColumn which in turn is linked to A.joinColumn
* <p>
* Suppose we had the following join conditions instead:
* f(A.joinColumn) == B.joinColumn
* B.joinColum == C.joinColumn
* In this case, the JoinFilterColumnCorrelationAnalysis for C.joinColumn would be linked to f(A.joinColumn).
* <p>
* Suppose we had the following join conditions instead:
* A.joinColumn == B.joinColumn
* f(B.joinColum) == C.joinColumn
* <p>
* Because we cannot reverse the function f() applied to the second table B in all cases,
* we cannot relate C.joinColumn to A.joinColumn, and we would not generate a correlation for C.joinColumn
*
* @param joinableClauses List of joinable clauses for the query
* @param tablePrefix Prefix for a join table
* @param rhsRewriteCandidate RHS rewrite candidate that we find correlated base table columns for
* @param equiConditions Map of equiconditions, keyed by the right hand columns
* @return A list of correlatation analyses for the equicondition RHS columns that reside in the table associated with
* the tablePrefix
*/
private static Optional<Map<String, JoinFilterColumnCorrelationAnalysis>> findCorrelatedBaseTableColumns(JoinableClauses joinableClauses, String tablePrefix, RhsRewriteCandidate rhsRewriteCandidate, Equiconditions equiConditions) {
JoinableClause clauseForTablePrefix = rhsRewriteCandidate.getJoinableClause();
JoinConditionAnalysis jca = clauseForTablePrefix.getCondition();
Set<String> rhsColumns = new HashSet<>();
if (rhsRewriteCandidate.isDirectRewrite()) {
// If we filter on a RHS join column, we only need to consider that column from the RHS side
rhsColumns.add(rhsRewriteCandidate.getRhsColumn());
} else {
for (Equality eq : jca.getEquiConditions()) {
rhsColumns.add(tablePrefix + eq.getRightColumn());
}
}
Map<String, JoinFilterColumnCorrelationAnalysis> correlations = new LinkedHashMap<>();
for (String rhsColumn : rhsColumns) {
Set<String> correlatedBaseColumns = new HashSet<>();
Set<Expr> correlatedBaseExpressions = new HashSet<>();
getCorrelationForRHSColumn(joinableClauses, equiConditions, rhsColumn, correlatedBaseColumns, correlatedBaseExpressions);
if (correlatedBaseColumns.isEmpty() && correlatedBaseExpressions.isEmpty()) {
continue;
}
correlations.put(rhsColumn, new JoinFilterColumnCorrelationAnalysis(rhsColumn, correlatedBaseColumns, correlatedBaseExpressions));
}
if (correlations.size() == 0) {
return Optional.empty();
} else {
return Optional.of(correlations);
}
}
use of org.apache.druid.segment.join.JoinableClause in project druid by druid-io.
the class RhsRewriteCandidates method determineRhsRewriteCandidatesForSingleFilter.
private static Optional<RhsRewriteCandidate> determineRhsRewriteCandidatesForSingleFilter(Filter orClause, Equiconditions equiconditions, JoinableClauses joinableClauses) {
// Currently, we only support rewrites of filters that operate on a single column for simplicity.
if (equiconditions.doesFilterSupportDirectJoinFilterRewrite(orClause)) {
String reqColumn = orClause.getRequiredColumns().iterator().next();
JoinableClause joinableClause = joinableClauses.getColumnFromJoinIfExists(reqColumn);
if (joinableClause != null) {
return Optional.of(new RhsRewriteCandidate(joinableClause, reqColumn, null, true));
}
} else if (orClause instanceof SelectorFilter) {
// this is a candidate for RHS filter rewrite, determine column correlations and correlated values
String reqColumn = ((SelectorFilter) orClause).getDimension();
String reqValue = ((SelectorFilter) orClause).getValue();
JoinableClause joinableClause = joinableClauses.getColumnFromJoinIfExists(reqColumn);
if (joinableClause != null) {
return Optional.of(new RhsRewriteCandidate(joinableClause, reqColumn, reqValue, false));
}
}
return Optional.empty();
}
Aggregations