Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PHOENIX-6823 calling Joda-based round() function on temporal PK field… #1537

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import org.apache.phoenix.expression.Expression;
import org.joda.time.DateTime;
import org.joda.time.chrono.GJChronology;

/**
*
Expand All @@ -41,4 +42,16 @@ public long roundDateTime(DateTime dateTime) {
return dateTime.monthOfYear().roundCeilingCopy().getMillis();
}

@Override
public long rangeLower(long time) {
// floor(time - 1) + 1
return (new DateTime(time - 1, GJChronology.getInstanceUTC())).monthOfYear()
.roundFloorCopy().getMillis() + 1;
}

@Override
public long rangeUpper(long time) {
// ceil
return roundDateTime(new DateTime(time, GJChronology.getInstanceUTC()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import org.apache.phoenix.expression.Expression;
import org.joda.time.DateTime;
import org.joda.time.chrono.GJChronology;

/**
*
Expand All @@ -41,4 +42,16 @@ public long roundDateTime(DateTime dateTime) {
return dateTime.weekOfWeekyear().roundCeilingCopy().getMillis();
}

@Override
public long rangeLower(long time) {
// floor(time - 1) + 1
return (new DateTime(time - 1, GJChronology.getInstanceUTC())).weekOfWeekyear()
.roundFloorCopy().getMillis() + 1;
}

@Override
public long rangeUpper(long time) {
// ceil
return roundDateTime(new DateTime(time, GJChronology.getInstanceUTC()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import org.apache.phoenix.expression.Expression;
import org.joda.time.DateTime;
import org.joda.time.chrono.GJChronology;

/**
*
Expand All @@ -41,4 +42,16 @@ public long roundDateTime(DateTime dateTime) {
return dateTime.year().roundCeilingCopy().getMillis();
}

@Override
public long rangeLower(long time) {
// floor(time - 1) + 1
return (new DateTime(time - 1, GJChronology.getInstanceUTC())).year().roundFloorCopy()
.getMillis() + 1;
}

@Override
public long rangeUpper(long time) {
// ceil
return roundDateTime(new DateTime(time, GJChronology.getInstanceUTC()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import org.apache.phoenix.expression.Expression;
import org.joda.time.DateTime;
import org.joda.time.chrono.GJChronology;

/**
*
Expand All @@ -41,4 +42,16 @@ public long roundDateTime(DateTime datetime) {
return datetime.monthOfYear().roundFloorCopy().getMillis();
}

@Override
public long rangeLower(long time) {
// floor
return roundDateTime(new DateTime(time, GJChronology.getInstanceUTC()));
}

@Override
public long rangeUpper(long time) {
// ceil(time + 1) -1
return (new DateTime(time + 1, GJChronology.getInstanceUTC())).monthOfYear()
.roundCeilingCopy().getMillis() - 1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import org.apache.phoenix.expression.Expression;
import org.joda.time.DateTime;
import org.joda.time.chrono.GJChronology;

/**
* Floor function that rounds up the {@link DateTime} to start of week.
Expand All @@ -40,4 +41,16 @@ public long roundDateTime(DateTime datetime) {
return datetime.weekOfWeekyear().roundFloorCopy().getMillis();
}

@Override
public long rangeLower(long time) {
// floor
return roundDateTime(new DateTime(time, GJChronology.getInstanceUTC()));
}

@Override
public long rangeUpper(long time) {
// ceil(time + 1) -1
return (new DateTime(time + 1, GJChronology.getInstanceUTC())).weekOfWeekyear()
.roundCeilingCopy().getMillis() - 1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import org.apache.phoenix.expression.Expression;
import org.joda.time.DateTime;
import org.joda.time.chrono.GJChronology;

/**
*
Expand All @@ -41,4 +42,16 @@ public long roundDateTime(DateTime datetime) {
return datetime.year().roundFloorCopy().getMillis();
}

@Override
public long rangeLower(long time) {
// floor
return roundDateTime(new DateTime(time, GJChronology.getInstanceUTC()));
}

@Override
public long rangeUpper(long time) {
// ceil(time + 1) -1
return (new DateTime(time + 1, GJChronology.getInstanceUTC())).year().roundCeilingCopy()
.getMillis() - 1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@
import org.apache.phoenix.schema.types.PDate;
import org.apache.phoenix.schema.types.PInteger;
import org.apache.phoenix.schema.types.PVarchar;
import org.apache.phoenix.util.ByteUtil;

import org.apache.phoenix.thirdparty.com.google.common.annotations.VisibleForTesting;
import org.apache.phoenix.thirdparty.com.google.common.collect.Lists;
import org.apache.phoenix.util.ByteUtil;

/**
* Function used to bucketize date/time values by rounding them to
Expand Down Expand Up @@ -105,7 +105,7 @@ public static Expression create(Expression expr, TimeUnit timeUnit, int multipli

public static Expression create(List<Expression> children) throws SQLException {
int numChildren = children.size();
if(numChildren < 2 || numChildren > 3) {
if (numChildren < 2 || numChildren > 3) {
throw new IllegalArgumentException("Wrong number of arguments : " + numChildren);
}
Object timeUnitValue = ((LiteralExpression)children.get(1)).getValue();
Expand Down Expand Up @@ -138,7 +138,7 @@ public RoundDateExpression(List<Expression> children) {
Object multiplierValue = numChildren > 2 ? ((LiteralExpression)children.get(2)).getValue() : null;
int multiplier = multiplierValue == null ? 1 :((Number)multiplierValue).intValue();
TimeUnit timeUnit = TimeUnit.getTimeUnit(timeUnitValue != null ? timeUnitValue.toString() : null);
if(timeUnit.ordinal() < TIME_UNIT_MS.length) {
if (timeUnit.ordinal() < TIME_UNIT_MS.length) {
divBy = multiplier * TIME_UNIT_MS[timeUnit.ordinal()];
}
}
Expand All @@ -148,8 +148,8 @@ protected long getRoundUpAmount() {
return divBy/2;
}


protected long roundTime(long time) {
@VisibleForTesting
public long roundTime(long time) {
long value;
long roundUpAmount = getRoundUpAmount();
if (time <= Long.MAX_VALUE - roundUpAmount) { // If no overflow, add
Expand All @@ -159,7 +159,21 @@ protected long roundTime(long time) {
}
return value * divBy;
}


@VisibleForTesting
public long rangeLower(long time) {
// This is for the ms based intervals. This needs to be separately implemented for the
// joda based intervals
return roundTime(time) - getRoundUpAmount();
}

@VisibleForTesting
public long rangeUpper(long time) {
// This is for the ms based intervals. This needs to be separately implemented for the
// joda based intervals
return roundTime(time) + (divBy - getRoundUpAmount()) - 1;
}

@Override
public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
if (children.get(0).evaluate(tuple, ptr)) {
Expand Down Expand Up @@ -260,7 +274,8 @@ public KeyRange getKeyRange(CompareOp op, Expression rhs) {
PDataCodec codec = getKeyRangeCodec(type);
int offset = ByteUtil.isInclusive(op) ? 1 : 0;
long value = codec.decodeLong(key, 0, SortOrder.getDefault());
byte[] nextKey = new byte[type.getByteSize()];
byte[] lowerKey = new byte[type.getByteSize()];
byte[] upperKey = new byte[type.getByteSize()];
KeyRange range;
switch (op) {
case EQUAL:
Expand All @@ -269,21 +284,58 @@ public KeyRange getKeyRange(CompareOp op, Expression rhs) {
// had ROUND(dateCol,'DAY') = TO_DATE('2013-01-01 23:00:00')
// it could never be equal, since date constant isn't at a day
// boundary.
if (value % divBy != 0) {
if (value != roundTime(value)) {
return KeyRange.EMPTY_RANGE;
}
codec.encodeLong(value + divBy, nextKey, 0);
range = type.getKeyRange(key, true, nextKey, false);
codec.encodeLong(rangeLower(value), lowerKey, 0);
codec.encodeLong(rangeUpper(value), upperKey, 0);
range = type.getKeyRange(lowerKey, true, upperKey, true);
break;
// a simple number example (with half up rounding):
// round(x) = 10 ==> [9.5, 10.5)
// round(x) <= 10 ==> [-inf, 10.5)
// round(x) <= 10.1 === round(x) <= 10 => [-inf, 10.5)
// round(x) <= 9.9 === round(x) <= 9 => [-inf, 9.5)
// round(x) < 10 ==> round(x) <= 9 ==> [-inf, 9.5)
case GREATER:
if (value == roundTime(value)) {
codec.encodeLong(rangeUpper(value), lowerKey, 0);
range = type.getKeyRange(lowerKey, false, KeyRange.UNBOUND, false);
break;
}
//fallthrough intended
case GREATER_OR_EQUAL:
codec.encodeLong((value + divBy - offset)/divBy*divBy, nextKey, 0);
range = type.getKeyRange(nextKey, true, KeyRange.UNBOUND, false);
codec.encodeLong(rangeLower(value), lowerKey, 0);
range = type.getKeyRange(lowerKey, true, KeyRange.UNBOUND, false);
if (value <= roundTime(value)) {
//always true for ceil
codec.encodeLong(rangeLower(value), lowerKey, 0);
range = type.getKeyRange(lowerKey, true, KeyRange.UNBOUND, false);
} else {
//always true for floor, except when exact
codec.encodeLong(rangeUpper(value), lowerKey, 0);
range = type.getKeyRange(lowerKey, false, KeyRange.UNBOUND, false);
}
break;
case LESS:
if (value == roundTime(value)) {
codec.encodeLong(rangeLower(value), upperKey, 0);
range = type.getKeyRange(KeyRange.UNBOUND, false, upperKey, false);
break;
}
//fallthrough intended
case LESS_OR_EQUAL:
codec.encodeLong((value + divBy - (1 -offset))/divBy*divBy, nextKey, 0);
range = type.getKeyRange(KeyRange.UNBOUND, false, nextKey, false);
codec.encodeLong(rangeUpper(value), upperKey, 0);
range = type.getKeyRange(KeyRange.UNBOUND, false, upperKey, true);
if (value >= roundTime(value)) {
//always true for floor
codec.encodeLong(rangeUpper(value), upperKey, 0);
range = type.getKeyRange(KeyRange.UNBOUND, false, upperKey, true);
} else {
//always true for ceil, except when exact
codec.encodeLong(rangeLower(value), upperKey, 0);
range = type.getKeyRange(KeyRange.UNBOUND, false, upperKey, false);
}
break;
default:
return childPart.getKeyRange(op, rhs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import org.apache.phoenix.schema.tuple.Tuple;
import org.apache.phoenix.schema.types.PDataType;
import org.joda.time.DateTime;
import org.joda.time.chrono.ISOChronology;
import org.joda.time.chrono.GJChronology;

/**
*
Expand All @@ -48,7 +48,7 @@ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
}
PDataType dataType = getDataType();
long time = dataType.getCodec().decodeLong(ptr, children.get(0).getSortOrder());
DateTime dt = new DateTime(time, ISOChronology.getInstanceUTC());
DateTime dt = new DateTime(time, GJChronology.getInstanceUTC());
long value = roundDateTime(dt);
Date d = new Date(value);
byte[] byteValue = dataType.toBytes(d);
Expand All @@ -63,4 +63,10 @@ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
* @return Time in millis.
*/
public abstract long roundDateTime(DateTime dateTime);

@Override
// We need a working roundTime() for the RowKey pushdown logic.
public long roundTime(long time) {
return roundDateTime(new DateTime(time, GJChronology.getInstanceUTC()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
import java.util.List;

import org.apache.phoenix.expression.Expression;
import org.apache.phoenix.util.DateUtil;
import org.joda.time.DateTime;
import org.joda.time.DateTimeFieldType;
import org.joda.time.chrono.GJChronology;

/**
*
Expand All @@ -39,4 +42,22 @@ public long roundDateTime(DateTime dateTime) {
return dateTime.monthOfYear().roundHalfEvenCopy().getMillis();
}

@Override
public long rangeLower(long epochMs) {
// We're doing unnecessary conversions here, but this is not perf sensitive
DateTime rounded =
new DateTime(roundDateTime(new DateTime(epochMs, GJChronology.getInstanceUTC())),
GJChronology.getInstanceUTC());
DateTime prev = rounded.minusMonths(1);
return DateUtil.rangeJodaHalfEven(rounded, prev, DateTimeFieldType.monthOfYear());
}

@Override
public long rangeUpper(long epochMs) {
DateTime rounded =
new DateTime(roundDateTime(new DateTime(epochMs, GJChronology.getInstanceUTC())),
GJChronology.getInstanceUTC());
DateTime next = rounded.plusMonths(1);
return DateUtil.rangeJodaHalfEven(rounded, next, DateTimeFieldType.monthOfYear());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
import java.util.List;

import org.apache.phoenix.expression.Expression;
import org.apache.phoenix.util.DateUtil;
import org.joda.time.DateTime;
import org.joda.time.DateTimeFieldType;
import org.joda.time.chrono.GJChronology;

/**
*
Expand All @@ -38,4 +41,23 @@ public RoundWeekExpression(List<Expression> children) {
public long roundDateTime(DateTime dateTime) {
return dateTime.weekOfWeekyear().roundHalfEvenCopy().getMillis();
}

@Override
public long rangeLower(long epochMs) {
// We're doing unnecessary conversions here, but this is NOT perf sensitive
DateTime rounded =
new DateTime(roundDateTime(new DateTime(epochMs, GJChronology.getInstanceUTC())),
GJChronology.getInstanceUTC());
DateTime prev = rounded.minusWeeks(1);
return DateUtil.rangeJodaHalfEven(rounded, prev, DateTimeFieldType.weekOfWeekyear());
}

@Override
public long rangeUpper(long epochMs) {
DateTime rounded =
new DateTime(roundDateTime(new DateTime(epochMs, GJChronology.getInstanceUTC())),
GJChronology.getInstanceUTC());
DateTime next = rounded.plusWeeks(1);
return DateUtil.rangeJodaHalfEven(rounded, next, DateTimeFieldType.weekOfWeekyear());
}
}
Loading