Search in sources :

Example 11 with StringComparator

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

the class LimitedBufferHashGrouperTest method makeGrouperWithOrderBy.

private static LimitedBufferHashGrouper<Integer> makeGrouperWithOrderBy(TestColumnSelectorFactory columnSelectorFactory, String orderByColumn, OrderByColumnSpec.Direction direction) {
    final StringComparator stringComparator = "value".equals(orderByColumn) ? StringComparators.LEXICOGRAPHIC : StringComparators.NUMERIC;
    final DefaultLimitSpec orderBy = DefaultLimitSpec.builder().orderBy(new OrderByColumnSpec(orderByColumn, direction, stringComparator)).limit(LIMIT).build();
    LimitedBufferHashGrouper<Integer> grouper = new LimitedBufferHashGrouper<>(Suppliers.ofInstance(ByteBuffer.allocate(12120)), new GroupByIshKeySerde(orderBy), AggregatorAdapters.factorizeBuffered(columnSelectorFactory, ImmutableList.of(new LongSumAggregatorFactory("valueSum", "value"), new CountAggregatorFactory("count"))), Integer.MAX_VALUE, 0.5f, 2, LIMIT, !orderBy.getColumns().get(0).getDimension().equals("value"));
    grouper.init();
    return grouper;
}
Also used : OrderByColumnSpec(org.apache.druid.query.groupby.orderby.OrderByColumnSpec) DefaultLimitSpec(org.apache.druid.query.groupby.orderby.DefaultLimitSpec) CountAggregatorFactory(org.apache.druid.query.aggregation.CountAggregatorFactory) LongSumAggregatorFactory(org.apache.druid.query.aggregation.LongSumAggregatorFactory) StringComparator(org.apache.druid.query.ordering.StringComparator)

Example 12 with StringComparator

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

the class Expressions method toSimpleLeafFilter.

/**
 * Translates to a simple leaf filter, i.e. not an "expression" type filter. Note that the filter may still
 * reference expression virtual columns, if and only if "virtualColumnRegistry" is defined.
 *
 * @param plannerContext        planner context
 * @param rowSignature          input row signature
 * @param virtualColumnRegistry re-usable virtual column references, may be null if virtual columns aren't allowed
 * @param rexNode               Calcite row expression
 */
@Nullable
private static DimFilter toSimpleLeafFilter(final PlannerContext plannerContext, final RowSignature rowSignature, @Nullable final VirtualColumnRegistry virtualColumnRegistry, final RexNode rexNode) {
    final SqlKind kind = rexNode.getKind();
    if (kind == SqlKind.IS_TRUE || kind == SqlKind.IS_NOT_FALSE) {
        return toSimpleLeafFilter(plannerContext, rowSignature, virtualColumnRegistry, Iterables.getOnlyElement(((RexCall) rexNode).getOperands()));
    } else if (kind == SqlKind.IS_FALSE || kind == SqlKind.IS_NOT_TRUE) {
        return new NotDimFilter(toSimpleLeafFilter(plannerContext, rowSignature, virtualColumnRegistry, Iterables.getOnlyElement(((RexCall) rexNode).getOperands())));
    } else if (kind == SqlKind.IS_NULL || kind == SqlKind.IS_NOT_NULL) {
        final RexNode operand = Iterables.getOnlyElement(((RexCall) rexNode).getOperands());
        final DruidExpression druidExpression = toDruidExpression(plannerContext, rowSignature, operand);
        if (druidExpression == null) {
            return null;
        }
        final DimFilter equalFilter;
        if (druidExpression.isSimpleExtraction()) {
            equalFilter = new SelectorDimFilter(druidExpression.getSimpleExtraction().getColumn(), NullHandling.defaultStringValue(), druidExpression.getSimpleExtraction().getExtractionFn());
        } else if (virtualColumnRegistry != null) {
            final String virtualColumn = virtualColumnRegistry.getOrCreateVirtualColumnForExpression(druidExpression, operand.getType());
            equalFilter = new SelectorDimFilter(virtualColumn, NullHandling.defaultStringValue(), null);
        } else {
            return null;
        }
        return kind == SqlKind.IS_NOT_NULL ? new NotDimFilter(equalFilter) : equalFilter;
    } else if (kind == SqlKind.EQUALS || kind == SqlKind.NOT_EQUALS || kind == SqlKind.GREATER_THAN || kind == SqlKind.GREATER_THAN_OR_EQUAL || kind == SqlKind.LESS_THAN || kind == SqlKind.LESS_THAN_OR_EQUAL) {
        final List<RexNode> operands = ((RexCall) rexNode).getOperands();
        Preconditions.checkState(operands.size() == 2, "Expected 2 operands, got[%,d]", operands.size());
        boolean flip = false;
        RexNode lhs = operands.get(0);
        RexNode rhs = operands.get(1);
        if (lhs.getKind() == SqlKind.LITERAL && rhs.getKind() != SqlKind.LITERAL) {
            // swap lhs, rhs
            RexNode x = lhs;
            lhs = rhs;
            rhs = x;
            flip = true;
        }
        // Flip operator, maybe.
        final SqlKind flippedKind;
        if (flip) {
            switch(kind) {
                case EQUALS:
                case NOT_EQUALS:
                    flippedKind = kind;
                    break;
                case GREATER_THAN:
                    flippedKind = SqlKind.LESS_THAN;
                    break;
                case GREATER_THAN_OR_EQUAL:
                    flippedKind = SqlKind.LESS_THAN_OR_EQUAL;
                    break;
                case LESS_THAN:
                    flippedKind = SqlKind.GREATER_THAN;
                    break;
                case LESS_THAN_OR_EQUAL:
                    flippedKind = SqlKind.GREATER_THAN_OR_EQUAL;
                    break;
                default:
                    throw new ISE("Kind[%s] not expected here", kind);
            }
        } else {
            flippedKind = kind;
        }
        // rhs must be a literal
        if (rhs.getKind() != SqlKind.LITERAL) {
            return null;
        }
        // Translate lhs to a DruidExpression.
        final DruidExpression lhsExpression = toDruidExpression(plannerContext, rowSignature, lhs);
        if (lhsExpression == null) {
            return null;
        }
        // Special handling for filters on FLOOR(__time TO granularity).
        final Granularity queryGranularity = toQueryGranularity(lhsExpression, plannerContext.getExprMacroTable());
        if (queryGranularity != null) {
            // lhs is FLOOR(__time TO granularity); rhs must be a timestamp
            final long rhsMillis = Calcites.calciteDateTimeLiteralToJoda(rhs, plannerContext.getTimeZone()).getMillis();
            return buildTimeFloorFilter(ColumnHolder.TIME_COLUMN_NAME, queryGranularity, flippedKind, rhsMillis);
        }
        final String column;
        final ExtractionFn extractionFn;
        if (lhsExpression.isSimpleExtraction()) {
            column = lhsExpression.getSimpleExtraction().getColumn();
            extractionFn = lhsExpression.getSimpleExtraction().getExtractionFn();
        } else if (virtualColumnRegistry != null) {
            column = virtualColumnRegistry.getOrCreateVirtualColumnForExpression(lhsExpression, lhs.getType());
            extractionFn = null;
        } else {
            return null;
        }
        if (column.equals(ColumnHolder.TIME_COLUMN_NAME) && extractionFn instanceof TimeFormatExtractionFn) {
            // Check if we can strip the extractionFn and convert the filter to a direct filter on __time.
            // This allows potential conversion to query-level "intervals" later on, which is ideal for Druid queries.
            final Granularity granularity = ExtractionFns.toQueryGranularity(extractionFn);
            if (granularity != null) {
                // lhs is FLOOR(__time TO granularity); rhs must be a timestamp
                final long rhsMillis = Calcites.calciteDateTimeLiteralToJoda(rhs, plannerContext.getTimeZone()).getMillis();
                final Interval rhsInterval = granularity.bucket(DateTimes.utc(rhsMillis));
                // Is rhs aligned on granularity boundaries?
                final boolean rhsAligned = rhsInterval.getStartMillis() == rhsMillis;
                // Create a BoundRefKey that strips the extractionFn and compares __time as a number.
                final BoundRefKey boundRefKey = new BoundRefKey(column, null, StringComparators.NUMERIC);
                return getBoundTimeDimFilter(flippedKind, boundRefKey, rhsInterval, rhsAligned);
            }
        }
        final String val;
        final RexLiteral rhsLiteral = (RexLiteral) rhs;
        if (SqlTypeName.NUMERIC_TYPES.contains(rhsLiteral.getTypeName())) {
            val = String.valueOf(RexLiteral.value(rhsLiteral));
        } else if (SqlTypeName.CHAR_TYPES.contains(rhsLiteral.getTypeName())) {
            val = String.valueOf(RexLiteral.stringValue(rhsLiteral));
        } else if (SqlTypeName.TIMESTAMP == rhsLiteral.getTypeName() || SqlTypeName.DATE == rhsLiteral.getTypeName()) {
            val = String.valueOf(Calcites.calciteDateTimeLiteralToJoda(rhsLiteral, plannerContext.getTimeZone()).getMillis());
        } else {
            // Don't know how to filter on this kind of literal.
            return null;
        }
        // Numeric lhs needs a numeric comparison.
        final StringComparator comparator = Calcites.getStringComparatorForRelDataType(lhs.getType());
        final BoundRefKey boundRefKey = new BoundRefKey(column, extractionFn, comparator);
        final DimFilter filter;
        // Always use BoundDimFilters, to simplify filter optimization later (it helps to remember the comparator).
        switch(flippedKind) {
            case EQUALS:
                filter = Bounds.equalTo(boundRefKey, val);
                break;
            case NOT_EQUALS:
                filter = new NotDimFilter(Bounds.equalTo(boundRefKey, val));
                break;
            case GREATER_THAN:
                filter = Bounds.greaterThan(boundRefKey, val);
                break;
            case GREATER_THAN_OR_EQUAL:
                filter = Bounds.greaterThanOrEqualTo(boundRefKey, val);
                break;
            case LESS_THAN:
                filter = Bounds.lessThan(boundRefKey, val);
                break;
            case LESS_THAN_OR_EQUAL:
                filter = Bounds.lessThanOrEqualTo(boundRefKey, val);
                break;
            default:
                throw new IllegalStateException("Shouldn't have got here");
        }
        return filter;
    } else if (rexNode instanceof RexCall) {
        final SqlOperator operator = ((RexCall) rexNode).getOperator();
        final SqlOperatorConversion conversion = plannerContext.getOperatorTable().lookupOperatorConversion(operator);
        if (conversion == null) {
            return null;
        } else {
            return conversion.toDruidFilter(plannerContext, rowSignature, virtualColumnRegistry, rexNode);
        }
    } else {
        return null;
    }
}
Also used : TimeFormatExtractionFn(org.apache.druid.query.extraction.TimeFormatExtractionFn) RexLiteral(org.apache.calcite.rex.RexLiteral) NotDimFilter(org.apache.druid.query.filter.NotDimFilter) SqlOperator(org.apache.calcite.sql.SqlOperator) SqlKind(org.apache.calcite.sql.SqlKind) Granularity(org.apache.druid.java.util.common.granularity.Granularity) StringComparator(org.apache.druid.query.ordering.StringComparator) RexCall(org.apache.calcite.rex.RexCall) ExtractionFn(org.apache.druid.query.extraction.ExtractionFn) TimeFormatExtractionFn(org.apache.druid.query.extraction.TimeFormatExtractionFn) SelectorDimFilter(org.apache.druid.query.filter.SelectorDimFilter) ArrayList(java.util.ArrayList) List(java.util.List) ISE(org.apache.druid.java.util.common.ISE) BoundRefKey(org.apache.druid.sql.calcite.filtration.BoundRefKey) SelectorDimFilter(org.apache.druid.query.filter.SelectorDimFilter) AndDimFilter(org.apache.druid.query.filter.AndDimFilter) NotDimFilter(org.apache.druid.query.filter.NotDimFilter) DimFilter(org.apache.druid.query.filter.DimFilter) OrDimFilter(org.apache.druid.query.filter.OrDimFilter) ExpressionDimFilter(org.apache.druid.query.filter.ExpressionDimFilter) RexNode(org.apache.calcite.rex.RexNode) Interval(org.joda.time.Interval) Nullable(javax.annotation.Nullable)

Aggregations

StringComparator (org.apache.druid.query.ordering.StringComparator)12 ArrayList (java.util.ArrayList)5 List (java.util.List)5 Nullable (javax.annotation.Nullable)5 ISE (org.apache.druid.java.util.common.ISE)4 OrderByColumnSpec (org.apache.druid.query.groupby.orderby.OrderByColumnSpec)4 ColumnType (org.apache.druid.segment.column.ColumnType)4 Preconditions (com.google.common.base.Preconditions)3 ImmutableList (com.google.common.collect.ImmutableList)3 ByteBuffer (java.nio.ByteBuffer)3 HashSet (java.util.HashSet)3 StringComparators (org.apache.druid.query.ordering.StringComparators)3 ComparableList (org.apache.druid.segment.data.ComparableList)3 ComparableStringArray (org.apache.druid.segment.data.ComparableStringArray)3 JsonCreator (com.fasterxml.jackson.annotation.JsonCreator)2 JsonInclude (com.fasterxml.jackson.annotation.JsonInclude)2 JsonProperty (com.fasterxml.jackson.annotation.JsonProperty)2 Function (com.google.common.base.Function)2 Functions (com.google.common.base.Functions)2 Ordering (com.google.common.collect.Ordering)2