Add javadocs and small improvements to join code. (#9196)

A follow-up to #9111.
This commit is contained in:
Gian Merlino 2020-01-16 15:25:38 -08:00 committed by GitHub
parent 42359c93dd
commit bfcb30e48f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 70 additions and 4 deletions

View File

@ -41,6 +41,9 @@ public interface ColumnProcessorFactory<T>
{
/**
* This default type will be used when the underlying column has an unknown type.
*
* This allows a column processor factory to specify what type it prefers to deal with (the most 'natural' type for
* whatever it is doing) when all else is equal.
*/
ValueType defaultType();

View File

@ -45,8 +45,11 @@ public class HashJoinEngine
* 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.
*
* Ensuing that the joinable clause's prefix does not conflict with any columns from "leftCursor" is the
* responsibility of the caller.
* 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)
{

View File

@ -62,6 +62,14 @@ public class JoinConditionAnalysis
this.nonEquiConditions = nonEquiConditions;
}
/**
* Analyze a join condition.
*
* @param condition the condition expression
* @param rightPrefix prefix for the right-hand side of the join; will be used to determine which identifiers in
* the condition come from the right-hand side and which come from the left-hand side
* @param macroTable macro table for parsing the condition expression
*/
public static JoinConditionAnalysis forExpression(
final String condition,
final String rightPrefix,

View File

@ -48,7 +48,15 @@ public class JoinableClause
}
/**
* The prefix to apply to all columns from the Joinable.
* The prefix to apply to all columns from the Joinable. The idea is that during a join, any columns that start with
* this prefix should be retrieved from our Joinable's {@link JoinMatcher#getColumnSelectorFactory()}. Any other
* columns should be returned from the left-hand side of the join.
*
* The prefix can be any string, as long as it is nonempty and not itself a prefix of the reserved column name
* {@code __time}.
*
* @see #getAvailableColumnsPrefixed() the list of columns from our {@link Joinable} with prefixes attached
* @see #unprefix a method for removing prefixes
*/
public String getPrefix()
{

View File

@ -26,6 +26,10 @@ import org.apache.druid.segment.ColumnValueSelector;
import javax.annotation.Nullable;
import java.util.function.BooleanSupplier;
/**
* A {@link ColumnValueSelector} that wraps a base selector but might also generate null values on demand. This
* is used for "righty" joins (see {@link JoinType#isRighty()}), which may need to generate nulls on the left-hand side.
*/
public class PossiblyNullColumnValueSelector<T> implements ColumnValueSelector<T>
{
private final ColumnValueSelector<T> baseSelector;

View File

@ -26,27 +26,67 @@ import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;
/**
* An interface to a table where some columns (the 'key columns') have indexes that enable fast lookups.
*
* The main user of this class is {@link IndexedTableJoinable}, and its main purpose is to participate in joins.
*/
public interface IndexedTable
{
/**
* Returns the columns of this table that have indexes.
*/
List<String> keyColumns();
/**
* Returns all columns of this table, including the key and non-key columns.
*/
List<String> allColumns();
/**
* Returns the signature of this table: a map where each key is a column from {@link #allColumns()} and each value
* is a type code.
*/
Map<String, ValueType> rowSignature();
/**
* Returns the number of rows in this table. It must not change over time, since it is used for things like algorithm
* selection and reporting of cardinality metadata.
*/
int numRows();
/**
* Returns the index for a particular column. The provided column number must be that column's position in
* {@link #allColumns()}.
*/
Index columnIndex(int column);
/**
* Returns a reader for a particular column. The provided column number must be that column's position in
* {@link #allColumns()}.
*/
Reader columnReader(int column);
/**
* Indexes support fast lookups on key columns.
*/
interface Index
{
/**
* Returns the list of row numbers where the column this Reader is based on contains 'key'.
*/
IntList find(Object key);
}
/**
* Readers support reading values out of any column.
*/
interface Reader
{
/**
* Read the value at a particular row number. Throws an exception if the row is out of bounds (must be between zero
* and {@link #numRows()}).
*/
@Nullable
Object read(int row);
}

View File

@ -75,7 +75,7 @@ public class IndexedTableJoinMatcher implements JoinMatcher
if (condition.isAlwaysTrue()) {
this.conditionMatchers = Collections.singletonList(() -> IntIterators.fromTo(0, table.numRows()));
} else if (condition.isAlwaysFalse()) {
this.conditionMatchers = Collections.singletonList(() -> IntIterators.fromTo(0, 0));
this.conditionMatchers = Collections.singletonList(() -> IntIterators.EMPTY_ITERATOR);
} else if (condition.getNonEquiConditions().isEmpty()) {
this.conditionMatchers = condition.getEquiConditions()
.stream()