Search in sources :

Example 11 with LookupDataSource

use of org.apache.druid.query.LookupDataSource in project druid by druid-io.

the class CalciteJoinQueryTest method testInnerJoinTwoLookupsToTableUsingNumericColumnInReverse.

@Test
@Parameters(source = QueryContextForJoinProvider.class)
public void testInnerJoinTwoLookupsToTableUsingNumericColumnInReverse(Map<String, Object> queryContext) throws Exception {
    // Like "testInnerJoinTwoLookupsToTableUsingNumericColumn", but the tables are specified backwards.
    cannotVectorize();
    testQuery("SELECT COUNT(*)\n" + "FROM lookup.lookyloo l1\n" + "INNER JOIN lookup.lookyloo l2 ON l1.k = l2.k\n" + "INNER JOIN foo on l2.k = foo.m1", queryContext, ImmutableList.of(Druids.newTimeseriesQueryBuilder().dataSource(join(join(new LookupDataSource("lookyloo"), new LookupDataSource("lookyloo"), "j0.", equalsCondition(makeColumnExpression("k"), makeColumnExpression("j0.k")), JoinType.INNER), new QueryDataSource(newScanQueryBuilder().dataSource(CalciteTests.DATASOURCE1).intervals(querySegmentSpec(Filtration.eternity())).columns("m1").context(QUERY_CONTEXT_DEFAULT).build()), "_j0.", equalsCondition(makeExpression(ColumnType.DOUBLE, "CAST(\"j0.k\", 'DOUBLE')"), DruidExpression.ofColumn(ColumnType.DOUBLE, "_j0.m1")), JoinType.INNER)).intervals(querySegmentSpec(Filtration.eternity())).granularity(Granularities.ALL).aggregators(new CountAggregatorFactory("a0")).context(QUERY_CONTEXT_DEFAULT).build()), ImmutableList.of(new Object[] { 1L }));
}
Also used : QueryDataSource(org.apache.druid.query.QueryDataSource) CountAggregatorFactory(org.apache.druid.query.aggregation.CountAggregatorFactory) LookupDataSource(org.apache.druid.query.LookupDataSource) Parameters(junitparams.Parameters) Test(org.junit.Test)

Example 12 with LookupDataSource

use of org.apache.druid.query.LookupDataSource in project druid by druid-io.

the class CalciteJoinQueryTest method testJoinUnionTablesOnLookup.

@Test
@Parameters(source = QueryContextForJoinProvider.class)
public void testJoinUnionTablesOnLookup(Map<String, Object> queryContext) throws Exception {
    // Cannot vectorize JOIN operator.
    cannotVectorize();
    testQuery("SELECT lookyloo.v, COUNT(*)\n" + "FROM\n" + "  (SELECT dim2 FROM foo UNION ALL SELECT dim2 FROM numfoo) u\n" + "  LEFT JOIN lookup.lookyloo ON u.dim2 = lookyloo.k\n" + "WHERE lookyloo.v <> 'xa'\n" + "GROUP BY lookyloo.v", queryContext, ImmutableList.of(GroupByQuery.builder().setDataSource(join(new UnionDataSource(ImmutableList.of(new TableDataSource(CalciteTests.DATASOURCE1), new TableDataSource(CalciteTests.DATASOURCE3))), new LookupDataSource("lookyloo"), "j0.", equalsCondition(makeColumnExpression("dim2"), makeColumnExpression("j0.k")), JoinType.LEFT)).setInterval(querySegmentSpec(Filtration.eternity())).setDimFilter(not(selector("j0.v", "xa", null))).setGranularity(Granularities.ALL).setDimensions(dimensions(new DefaultDimensionSpec("j0.v", "d0"))).setAggregatorSpecs(aggregators(new CountAggregatorFactory("a0"))).setContext(queryContext).build()), ImmutableList.of(new Object[] { NULL_STRING, 6L }, new Object[] { "xabc", 2L }));
}
Also used : GlobalTableDataSource(org.apache.druid.query.GlobalTableDataSource) TableDataSource(org.apache.druid.query.TableDataSource) CountAggregatorFactory(org.apache.druid.query.aggregation.CountAggregatorFactory) LookupDataSource(org.apache.druid.query.LookupDataSource) UnionDataSource(org.apache.druid.query.UnionDataSource) DefaultDimensionSpec(org.apache.druid.query.dimension.DefaultDimensionSpec) Parameters(junitparams.Parameters) Test(org.junit.Test)

Example 13 with LookupDataSource

use of org.apache.druid.query.LookupDataSource in project druid by druid-io.

the class DruidJoinRule method analyzeCondition.

/**
 * If this condition is an AND of some combination of (1) literals; (2) equality conditions of the form
 * {@code f(LeftRel) = RightColumn}, then return a {@link ConditionAnalysis}.
 */
private Optional<ConditionAnalysis> analyzeCondition(final RexNode condition, final RelDataType leftRowType, DruidRel<?> right) {
    final List<RexNode> subConditions = decomposeAnd(condition);
    final List<Pair<RexNode, RexInputRef>> equalitySubConditions = new ArrayList<>();
    final List<RexLiteral> literalSubConditions = new ArrayList<>();
    final int numLeftFields = leftRowType.getFieldCount();
    final Set<RexInputRef> rightColumns = new HashSet<>();
    for (RexNode subCondition : subConditions) {
        if (RexUtil.isLiteral(subCondition, true)) {
            if (subCondition.isA(SqlKind.CAST)) {
                // This is CAST(literal) which is always OK.
                // We know that this is CAST(literal) as it passed the check from RexUtil.isLiteral
                RexCall call = (RexCall) subCondition;
                // are different, then skipping the cast might change the meaning of the subcondition.
                if (call.getType().getSqlTypeName().equals(call.getOperands().get(0).getType().getSqlTypeName())) {
                    // If the types are the same, unwrap the cast and use the underlying literal.
                    literalSubConditions.add((RexLiteral) call.getOperands().get(0));
                } else {
                    // If the types are not the same, return Optional.empty() indicating the condition is not supported.
                    return Optional.empty();
                }
            } else {
                // Literals are always OK.
                literalSubConditions.add((RexLiteral) subCondition);
            }
            continue;
        }
        if (!subCondition.isA(SqlKind.EQUALS)) {
            // If it's not EQUALS, it's not supported.
            plannerContext.setPlanningError("SQL requires a join with '%s' condition that is not supported.", subCondition.getKind());
            return Optional.empty();
        }
        final List<RexNode> operands = ((RexCall) subCondition).getOperands();
        Preconditions.checkState(operands.size() == 2, "Expected 2 operands, got[%,d]", operands.size());
        if (isLeftExpression(operands.get(0), numLeftFields) && isRightInputRef(operands.get(1), numLeftFields)) {
            equalitySubConditions.add(Pair.of(operands.get(0), (RexInputRef) operands.get(1)));
            rightColumns.add((RexInputRef) operands.get(1));
        } else if (isRightInputRef(operands.get(0), numLeftFields) && isLeftExpression(operands.get(1), numLeftFields)) {
            equalitySubConditions.add(Pair.of(operands.get(1), (RexInputRef) operands.get(0)));
            rightColumns.add((RexInputRef) operands.get(0));
        } else {
            // Cannot handle this condition.
            plannerContext.setPlanningError("SQL is resulting in a join that has unsupported operand types.");
            return Optional.empty();
        }
    }
    // thereby allowing join conditions on both k and v columns of the lookup
    if (right != null && !DruidJoinQueryRel.computeRightRequiresSubquery(DruidJoinQueryRel.getSomeDruidChild(right)) && right instanceof DruidQueryRel) {
        DruidQueryRel druidQueryRel = (DruidQueryRel) right;
        if (druidQueryRel.getDruidTable().getDataSource() instanceof LookupDataSource) {
            long distinctRightColumns = rightColumns.stream().map(RexSlot::getIndex).distinct().count();
            if (distinctRightColumns > 1) {
                // it means that the join's right side is lookup and the join condition contains both key and value columns of lookup.
                // currently, the lookup datasource in the native engine doesn't support using value column in the join condition.
                plannerContext.setPlanningError("SQL is resulting in a join involving lookup where value column is used in the condition.");
                return Optional.empty();
            }
        }
    }
    return Optional.of(new ConditionAnalysis(numLeftFields, equalitySubConditions, literalSubConditions));
}
Also used : RexLiteral(org.apache.calcite.rex.RexLiteral) ArrayList(java.util.ArrayList) DruidQueryRel(org.apache.druid.sql.calcite.rel.DruidQueryRel) RexCall(org.apache.calcite.rex.RexCall) LookupDataSource(org.apache.druid.query.LookupDataSource) RexInputRef(org.apache.calcite.rex.RexInputRef) RexSlot(org.apache.calcite.rex.RexSlot) RexNode(org.apache.calcite.rex.RexNode) Pair(org.apache.druid.java.util.common.Pair) HashSet(java.util.HashSet)

Example 14 with LookupDataSource

use of org.apache.druid.query.LookupDataSource in project druid by druid-io.

the class JoinableFactoryWrapperTest method test_createSegmentMapFn_usableClause.

@Test
public void test_createSegmentMapFn_usableClause() {
    final LookupDataSource lookupDataSource = new LookupDataSource("lookyloo");
    final JoinConditionAnalysis conditionAnalysis = JoinConditionAnalysis.forExpression("x == \"j.x\"", "j.", ExprMacroTable.nil());
    final PreJoinableClause clause = new PreJoinableClause("j.", lookupDataSource, JoinType.LEFT, conditionAnalysis);
    JoinableFactoryWrapper joinableFactoryWrapper = new JoinableFactoryWrapper(new JoinableFactory() {

        @Override
        public boolean isDirectlyJoinable(DataSource dataSource) {
            return dataSource.equals(lookupDataSource);
        }

        @Override
        public Optional<Joinable> build(DataSource dataSource, JoinConditionAnalysis condition) {
            if (dataSource.equals(lookupDataSource) && condition.equals(conditionAnalysis)) {
                return Optional.of(LookupJoinable.wrap(new MapLookupExtractor(ImmutableMap.of("k", "v"), false)));
            } else {
                return Optional.empty();
            }
        }
    });
    final Function<SegmentReference, SegmentReference> segmentMapFn = joinableFactoryWrapper.createSegmentMapFn(null, ImmutableList.of(clause), new AtomicLong(), new TestQuery(new TableDataSource("test"), new MultipleIntervalSegmentSpec(ImmutableList.of(Intervals.of("0/100"))), false, new HashMap()));
    Assert.assertNotSame(Function.identity(), segmentMapFn);
}
Also used : TestQuery(org.apache.druid.query.TestQuery) PreJoinableClause(org.apache.druid.query.planning.PreJoinableClause) Optional(java.util.Optional) HashMap(java.util.HashMap) SegmentReference(org.apache.druid.segment.SegmentReference) MultipleIntervalSegmentSpec(org.apache.druid.query.spec.MultipleIntervalSegmentSpec) GlobalTableDataSource(org.apache.druid.query.GlobalTableDataSource) LookupDataSource(org.apache.druid.query.LookupDataSource) DataSource(org.apache.druid.query.DataSource) TableDataSource(org.apache.druid.query.TableDataSource) AtomicLong(java.util.concurrent.atomic.AtomicLong) GlobalTableDataSource(org.apache.druid.query.GlobalTableDataSource) TableDataSource(org.apache.druid.query.TableDataSource) LookupDataSource(org.apache.druid.query.LookupDataSource) MapLookupExtractor(org.apache.druid.query.extraction.MapLookupExtractor) NullHandlingTest(org.apache.druid.common.config.NullHandlingTest) Test(org.junit.Test)

Example 15 with LookupDataSource

use of org.apache.druid.query.LookupDataSource in project druid by druid-io.

the class JoinableFactoryWrapperTest method test_computeJoinDataSourceCacheKey_cachingUnsupported.

@Test
public void test_computeJoinDataSourceCacheKey_cachingUnsupported() {
    PreJoinableClause clause1 = makeGlobalPreJoinableClause("dataSource_1", "x == \"j.x\"", "j.");
    DataSource dataSource = new LookupDataSource("lookup");
    PreJoinableClause clause2 = makePreJoinableClause(dataSource, "x == \"h.x\"", "h.", JoinType.LEFT);
    DataSourceAnalysis analysis = EasyMock.mock(DataSourceAnalysis.class);
    EasyMock.expect(analysis.getPreJoinableClauses()).andReturn(Arrays.asList(clause1, clause2)).anyTimes();
    EasyMock.expect(analysis.getJoinBaseTableFilter()).andReturn(Optional.of(TrueDimFilter.instance())).anyTimes();
    EasyMock.replay(analysis);
    JoinableFactoryWrapper joinableFactoryWrapper = new JoinableFactoryWrapper(new JoinableFactoryWithCacheKey());
    Optional<byte[]> cacheKey = joinableFactoryWrapper.computeJoinDataSourceCacheKey(analysis);
    Assert.assertFalse(cacheKey.isPresent());
}
Also used : PreJoinableClause(org.apache.druid.query.planning.PreJoinableClause) LookupDataSource(org.apache.druid.query.LookupDataSource) DataSourceAnalysis(org.apache.druid.query.planning.DataSourceAnalysis) GlobalTableDataSource(org.apache.druid.query.GlobalTableDataSource) LookupDataSource(org.apache.druid.query.LookupDataSource) DataSource(org.apache.druid.query.DataSource) TableDataSource(org.apache.druid.query.TableDataSource) NullHandlingTest(org.apache.druid.common.config.NullHandlingTest) Test(org.junit.Test)

Aggregations

LookupDataSource (org.apache.druid.query.LookupDataSource)27 Test (org.junit.Test)25 Parameters (junitparams.Parameters)19 GlobalTableDataSource (org.apache.druid.query.GlobalTableDataSource)19 TableDataSource (org.apache.druid.query.TableDataSource)19 CountAggregatorFactory (org.apache.druid.query.aggregation.CountAggregatorFactory)14 DefaultDimensionSpec (org.apache.druid.query.dimension.DefaultDimensionSpec)14 QueryDataSource (org.apache.druid.query.QueryDataSource)12 NullHandlingTest (org.apache.druid.common.config.NullHandlingTest)3 DataSource (org.apache.druid.query.DataSource)3 PreJoinableClause (org.apache.druid.query.planning.PreJoinableClause)3 Optional (java.util.Optional)2 AtomicLong (java.util.concurrent.atomic.AtomicLong)2 DoubleSumAggregatorFactory (org.apache.druid.query.aggregation.DoubleSumAggregatorFactory)2 ExtractionDimensionSpec (org.apache.druid.query.dimension.ExtractionDimensionSpec)2 SubstringDimExtractionFn (org.apache.druid.query.extraction.SubstringDimExtractionFn)2 DefaultLimitSpec (org.apache.druid.query.groupby.orderby.DefaultLimitSpec)2 OrderByColumnSpec (org.apache.druid.query.groupby.orderby.OrderByColumnSpec)2 SegmentReference (org.apache.druid.segment.SegmentReference)2 Inject (com.google.inject.Inject)1