ashishjayamohan commented on code in PR #14385: URL: https://github.com/apache/pinot/pull/14385#discussion_r1970474848
########## pinot-core/src/main/java/org/apache/pinot/core/query/optimizer/filter/TimePredicateFilterOptimizer.java: ########## @@ -411,6 +427,94 @@ && isStringLiteral(dateTimeConvertOperands.get(3)), } } + private void optimizeDateTrunc(Function filterFunction, FilterKind filterKind) { + List<Expression> filterOperands = filterFunction.getOperands(); + List<Expression> dateTruncOperands = filterOperands.get(0).getFunctionCall().getOperands(); + + if (dateTruncOperands.get(1).isSetLiteral()) { + return; + } + + Long lowerMillis = null; + Long upperMillis = null; + boolean lowerInclusive = true; + boolean upperInclusive = true; + List<Expression> operands = new ArrayList<>(dateTruncOperands); + String unit = operands.get(0).getLiteral().getStringValue(); + String inputTimeUnit = (operands.size() >= 3) ? operands.get(2).getLiteral().getStringValue() + : TimeUnit.MILLISECONDS.name(); + if (operands.size() >= 4) { + if (!operands.get(3).getLiteral().getStringValue().equals("UTC")) { + // Leave query unoptimized if working with non-UTC time zones + return; + } + } + ISOChronology chronology = ISOChronology.getInstanceUTC(); + String outputTimeUnit = (operands.size() == 5) ? operands.get(4).getLiteral().getStringValue() + : TimeUnit.MILLISECONDS.name(); + switch (filterKind) { + case EQUALS: + operands.set(1, getExpression(getLongValue(filterOperands.get(1)), new DateTimeFormatSpec("TIMESTAMP"))); + upperMillis = dateTruncCeil(operands); + lowerMillis = dateTruncFloor(operands); + if (lowerMillis != DateTimeUtils.getTimestampField(chronology, unit).roundFloor(lowerMillis)) { + lowerMillis = Long.MAX_VALUE; + upperMillis = Long.MIN_VALUE; + String rangeString = new Range(lowerMillis, lowerInclusive, upperMillis, upperInclusive).getRangeString(); + rewriteToRange(filterFunction, dateTruncOperands.get(1), rangeString); + return; + } + break; + case GREATER_THAN: + operands.set(1, getExpression(getLongValue(filterOperands.get(1)), new DateTimeFormatSpec("TIMESTAMP"))); + lowerMillis = dateTruncCeil(operands); + lowerInclusive = false; + upperMillis = Long.MAX_VALUE; + break; + case GREATER_THAN_OR_EQUAL: + operands.set(1, getExpression(getLongValue(filterOperands.get(1)), new DateTimeFormatSpec("TIMESTAMP"))); + lowerMillis = dateTruncFloor(operands); + upperMillis = Long.MAX_VALUE; + if (lowerMillis != DateTimeUtils.getTimestampField(chronology, unit).roundFloor(lowerMillis)) { Review Comment: I've left some comments on each check that should explain why these checks is necessary. That being said, for "less than or equal" filters, we don't need to check if because the ceiling of the inverse function (inclusive) will always truncate to a value that is less than or equal to the literal, regardless of whether the literal is aligned to the unit's stride or not. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org For additional commands, e-mail: commits-h...@pinot.apache.org