use of org.apache.druid.query.dimension.DimensionSpec in project druid by druid-io.
the class HashJoinEngine method makeJoinCursor.
/**
* Creates a cursor that represents the join of {@param leftCursor} with {@param joinableClause}. The resulting
* cursor may generate nulls on the left-hand side (for righty joins; see {@link JoinType#isRighty()}) or on
* the right-hand side (for lefty joins; see {@link JoinType#isLefty()}). Columns that start with the
* joinable clause's prefix (see {@link JoinableClause#getPrefix()}) will come from the Joinable's column selector
* factory, and all other columns will come from the leftCursor's column selector factory.
*
* Ensuring that the joinable clause's prefix does not conflict with any columns from "leftCursor" is the
* responsibility of the caller. If there is such a conflict (for example, if the joinable clause's prefix is "j.",
* and the leftCursor has a field named "j.j.abrams"), then the field from the leftCursor will be shadowed and will
* not be queryable through the returned Cursor. This happens even if the right-hand joinable doesn't actually have a
* column with this name.
*/
public static Cursor makeJoinCursor(final Cursor leftCursor, final JoinableClause joinableClause, final boolean descending, final Closer closer) {
final ColumnSelectorFactory leftColumnSelectorFactory = leftCursor.getColumnSelectorFactory();
final JoinMatcher joinMatcher = joinableClause.getJoinable().makeJoinMatcher(leftColumnSelectorFactory, joinableClause.getCondition(), joinableClause.getJoinType().isRighty(), descending, closer);
class JoinColumnSelectorFactory implements ColumnSelectorFactory {
@Override
public DimensionSelector makeDimensionSelector(DimensionSpec dimensionSpec) {
if (joinableClause.includesColumn(dimensionSpec.getDimension())) {
return joinMatcher.getColumnSelectorFactory().makeDimensionSelector(dimensionSpec.withDimension(joinableClause.unprefix(dimensionSpec.getDimension())));
} else {
final DimensionSelector leftSelector = leftColumnSelectorFactory.makeDimensionSelector(dimensionSpec);
if (!joinableClause.getJoinType().isRighty()) {
return leftSelector;
} else {
return new PossiblyNullDimensionSelector(leftSelector, joinMatcher::matchingRemainder);
}
}
}
@Override
public ColumnValueSelector makeColumnValueSelector(String column) {
if (joinableClause.includesColumn(column)) {
return joinMatcher.getColumnSelectorFactory().makeColumnValueSelector(joinableClause.unprefix(column));
} else {
final ColumnValueSelector<?> leftSelector = leftColumnSelectorFactory.makeColumnValueSelector(column);
if (!joinableClause.getJoinType().isRighty()) {
return leftSelector;
} else {
return new PossiblyNullColumnValueSelector<>(leftSelector, joinMatcher::matchingRemainder);
}
}
}
@Nullable
@Override
public ColumnCapabilities getColumnCapabilities(String column) {
if (joinableClause.includesColumn(column)) {
return joinMatcher.getColumnSelectorFactory().getColumnCapabilities(joinableClause.unprefix(column));
} else {
return leftColumnSelectorFactory.getColumnCapabilities(column);
}
}
}
final JoinColumnSelectorFactory joinColumnSelectorFactory = new JoinColumnSelectorFactory();
class JoinCursor implements Cursor {
public void initialize() {
matchCurrentPosition();
if (!joinableClause.getJoinType().isLefty()) {
while (!joinMatcher.hasMatch() && !isDone()) {
advance();
matchCurrentPosition();
}
}
}
@Override
@Nonnull
public ColumnSelectorFactory getColumnSelectorFactory() {
return joinColumnSelectorFactory;
}
@Override
@Nonnull
public DateTime getTime() {
return leftCursor.getTime();
}
@Override
public void advance() {
advanceUninterruptibly();
BaseQuery.checkInterrupted();
}
private void matchCurrentPosition() {
if (leftCursor.isDone()) {
if (joinableClause.getJoinType().isRighty() && !joinMatcher.matchingRemainder()) {
// Warning! The way this engine handles "righty" joins is flawed: it generates the 'remainder' rows
// per-segment, but this should really be done globally. This should be improved in the future.
joinMatcher.matchRemainder();
}
} else {
joinMatcher.matchCondition();
}
}
@Override
public void advanceUninterruptibly() {
if (joinMatcher.hasMatch()) {
joinMatcher.nextMatch();
if (joinMatcher.hasMatch()) {
return;
}
}
assert !joinMatcher.hasMatch();
if (leftCursor.isDone()) {
// No right-hand matches and nothing on the left cursor. We're done; return.
assert isDone();
return;
}
do {
// No more right-hand side matches; advance the left-hand side.
leftCursor.advanceUninterruptibly();
// Update joinMatcher state to match new cursor position.
matchCurrentPosition();
// If this is not a left/full join, and joinMatcher didn't match anything, then keep advancing until we find
// left rows that have matching right rows.
} while (!joinableClause.getJoinType().isLefty() && !joinMatcher.hasMatch() && !leftCursor.isDone());
}
@Override
public boolean isDone() {
return leftCursor.isDone() && !joinMatcher.hasMatch();
}
@Override
public boolean isDoneOrInterrupted() {
return isDone() || Thread.currentThread().isInterrupted();
}
@Override
public void reset() {
leftCursor.reset();
joinMatcher.reset();
}
}
final JoinCursor joinCursor = new JoinCursor();
joinCursor.initialize();
return joinCursor;
}
use of org.apache.druid.query.dimension.DimensionSpec in project druid by druid-io.
the class ExpressionVirtualColumnTest method testMultiObjectSelector.
@Test
public void testMultiObjectSelector() {
DimensionSpec spec = new DefaultDimensionSpec("expr", "expr");
final BaseObjectColumnValueSelector selectorImplicit = SCALE_LIST_IMPLICIT.makeDimensionSelector(spec, COLUMN_SELECTOR_FACTORY);
CURRENT_ROW.set(ROWMULTI);
Assert.assertEquals(ImmutableList.of("2.0", "4.0", "6.0"), selectorImplicit.getObject());
CURRENT_ROW.set(ROWMULTI2);
Assert.assertEquals(ImmutableList.of("6.0", "8.0", "10.0"), selectorImplicit.getObject());
CURRENT_ROW.set(ROWMULTI3);
Assert.assertEquals(Arrays.asList("6.0", NullHandling.replaceWithDefault() ? "0.0" : null, "10.0"), selectorImplicit.getObject());
final BaseObjectColumnValueSelector selectorExplicit = SCALE_LIST_EXPLICIT.makeDimensionSelector(spec, COLUMN_SELECTOR_FACTORY);
CURRENT_ROW.set(ROWMULTI);
Assert.assertEquals(ImmutableList.of("2.0", "4.0", "6.0"), selectorExplicit.getObject());
CURRENT_ROW.set(ROWMULTI2);
Assert.assertEquals(ImmutableList.of("6.0", "8.0", "10.0"), selectorExplicit.getObject());
CURRENT_ROW.set(ROWMULTI3);
Assert.assertEquals(Arrays.asList("6.0", NullHandling.replaceWithDefault() ? "0.0" : null, "10.0"), selectorExplicit.getObject());
}
use of org.apache.druid.query.dimension.DimensionSpec in project druid by druid-io.
the class LookupSerdeModuleTest method testExtractionDimensionSerde.
@Test
public void testExtractionDimensionSerde() throws Exception {
final ExtractionDimensionSpec dimensionSpec = new ExtractionDimensionSpec("xxx", "d", new RegisteredLookupExtractionFn(null, "beep", false, null, null, null));
Assert.assertEquals(dimensionSpec, objectMapper.readValue(objectMapper.writeValueAsBytes(dimensionSpec), DimensionSpec.class));
}
Aggregations