-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Fix Spark WeekFunction on long years #10713
Conversation
Hi @zml1206! Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks! |
✅ Deploy Preview for meta-velox canceled.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the fix. Looks like the implementation is nearly the same with Presto's except for the return type (seeing #5941). To improve code maintainability, any chance to extract a template function into 'velox/functions/lib' and use it for both Presto and Spark?
I recently vendored another part of external/date library that let you calculate weeks of year. Could you just use it here instead? I provides the exact ISO semantic, which I guess is what Spark expects? https://github.com/facebookincubator/velox/pull/10686/files Cc: @kevinwilfong |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. Added some comments.
|
Fair enough, but I feel like even the narrower min/max provided by external/date should be enough to cover any realistic date ranges. IMHO the value of consolidating this logic is probably larger; we could also always look into relaxing the date restrictions in external/date (I think @gggrace14 did something similar in the past) if this becomes a must. |
@@ -488,7 +488,7 @@ TEST_F(DateTimeFunctionsTest, week) { | |||
VELOX_USER_FAIL("{}", status.message()); | |||
}); | |||
auto timestamp = | |||
std::make_optional(Timestamp(ts.getSeconds() * 100'000'000, 0)); | |||
std::make_optional(Timestamp(ts.getSeconds() * 100'000, 0)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change it avoid year range error.
Can you help take a look again, thanks @pedroerp |
EXPECT_EQ(33, weekTimestamp("T06:01:01")); | ||
EXPECT_EQ(44, weekTimestamp("T06:59:59")); | ||
EXPECT_EQ(47, weekTimestamp("T12:00:01")); | ||
EXPECT_EQ(16, weekTimestamp("T12:59:59")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zml1206 Wondering why we are getting different results with this change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the timestamp becomes 1/1000 of the original value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As long as we have a way to verify externally that these are in fact the correct values for year 100k
Whether regression is accidental and has nothing to do with pr? @rui-mo |
We may need a Meta employee to help check the details. |
FOLLY_ALWAYS_INLINE void call(int32_t& result, const arg_type<Date>& date) { | ||
result = getWeek(getDateTime(date)); | ||
int64_t seconds = (int64_t)date * kSecondsInDay; | ||
result = getWeek(Timestamp(seconds, 0), nullptr, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering if overflow can happen when the date is very large, and what is the Spark's behavior when an overflow occurs? Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the late reply, I'm on vacation for a few days. Spark will returns null
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few small comments, but overall looks good.
velox/functions/lib/TimeUtils.h
Outdated
@@ -92,6 +94,23 @@ FOLLY_ALWAYS_INLINE int32_t getDayOfYear(const std::tm& time) { | |||
return time.tm_yday + 1; | |||
} | |||
|
|||
FOLLY_ALWAYS_INLINE unsigned getWeek( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: could we use something like uint32_t to make the type length more explicit?
} | ||
|
||
FOLLY_ALWAYS_INLINE void call(int64_t& result, const arg_type<Date>& date) { | ||
result = getWeek(getDateTime(date)); | ||
int64_t seconds = (int64_t)date * kSecondsInDay; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems like here we could add another factory method on Timestamp to encapsulate this logic, like:
result = getWeek(Timestamp::fromDate(date), nullptr, false);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated, thank you.
EXPECT_EQ(33, weekTimestamp("T06:01:01")); | ||
EXPECT_EQ(44, weekTimestamp("T06:59:59")); | ||
EXPECT_EQ(47, weekTimestamp("T12:00:01")); | ||
EXPECT_EQ(16, weekTimestamp("T12:59:59")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As long as we have a way to verify externally that these are in fact the correct values for year 100k
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you
@@ -117,6 +117,9 @@ struct Timestamp { | |||
/// and the number of nanoseconds. | |||
static Timestamp fromDaysAndNanos(int32_t days, int64_t nanos); | |||
|
|||
// date is since unix epoch. | |||
static Timestamp fromDate(int32_t date); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you also add a quick comment explaining what date represents?
Failure CI seems unrelated to PR. |
Thank you @zml1206 . Looks good to me. |
@pedroerp has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
@zml1206 looks like Spark fuzzer is failing. Could you check? |
87af294
to
54cad4b
Compare
@@ -69,6 +69,9 @@ int main(int argc, char** argv) { | |||
// timestamp_millis(bigint) can generate timestamps out of the supported | |||
// range that make other functions throw VeloxRuntimeErrors. | |||
"timestamp_millis(bigint) -> timestamp", | |||
// week_of_year throws VeloxRuntimeError when the year is out of the | |||
// supported range. | |||
"week_of_year", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to #10928.
@zml1206 Skipping the function means we won't be testing it at all. @kagamiori what is the right way of leaving this enabled? |
Hi
Hi @zml1206, do you have a link of the spark and expression fuzzer failure in CI because of the week_of_year function? I can take a look to see why it's not suppressed by #10993. |
@kagamiori Thank you. |
…hrown from one eval path Summary: Velox throws VeloxRuntimeError at a few places intentionally to fail the query instead of generating wrong results, e.g., when timestamp is outside the supported range. These VeloxRuntimeErrors caused failures in expression fuzzer, hence an attempt was made to tolerate such runtime errors in fuzzer so that fuzzer can still test the relevant functions (facebookincubator#10993). However, it turns out that that attempt was not enough. The reason is that VeloxRuntimeError doesn't work well with the existing mechanism of masking error by default nulls. So the expression fuzzer still occasionally fails because of only one of the common and simple evaluation path throwing the error. (If we later want to make those VeloxRuntimeError not suppressable by TRY but suppressable by the mask-error-by-default-null mechanism, we'll need to extend the EvalErrors struct with an additional buffer to track whether the error at an index can be suppressed by Try and check that in TryExpr.) This diff relaxes the fuzzer check to make fuzzer not fail when only one of the common and simple eval path throw the UNSUPPORTED_INPUT_UNCATCHABLE runtime error. This should unblock facebookincubator#10713. Differential Revision: D63421914
…hrown from one eval path (#11096) Summary: Pull Request resolved: #11096 Velox throws VeloxRuntimeError at a few places intentionally to fail the query instead of generating wrong results, e.g., when timestamp is outside the supported range. These VeloxRuntimeErrors caused failures in expression fuzzer, hence an attempt was made to tolerate such runtime errors in fuzzer so that fuzzer can still test the relevant functions (#10993). However, it turns out that that attempt was not enough. The reason is that VeloxRuntimeError doesn't work well with the existing mechanism of masking error by default nulls. So the expression fuzzer still occasionally fails because of only one of the common and simple evaluation path throwing the error. (If we later want to make those VeloxRuntimeError not suppressable by TRY but suppressable by the mask-error-by-default-null mechanism, we'll need to extend the EvalErrors struct with an additional buffer to track whether the error at an index can be suppressed by Try and check that in TryExpr.) This diff relaxes the fuzzer check to make fuzzer not fail when only one of the common and simple eval path throw the UNSUPPORTED_INPUT_UNCATCHABLE runtime error. This should unblock #10713. Reviewed By: kevinwilfong Differential Revision: D63421914 fbshipit-source-id: 54d01f7a5e7ea887018659d0eec8070fd0922b50
Hi @zml1206, the fix for the fuzzer test has been merged. Could you rebase the PR on top of the latest main and remove week_of_year from the skip-function list to see if there is still any failure? Thanks! |
extract getWeek update fix fix fix fix DateTimeFunctionsTest.week fix update update update comment
It is resolved, thanks @kagamiori . cc @pedroerp |
Conbench analyzed the 1 benchmark run on commit There were no benchmark performance regressions. 🎉 The full Conbench report has more details. |
…hrown from one eval path (facebookincubator#11096) Summary: Pull Request resolved: facebookincubator#11096 Velox throws VeloxRuntimeError at a few places intentionally to fail the query instead of generating wrong results, e.g., when timestamp is outside the supported range. These VeloxRuntimeErrors caused failures in expression fuzzer, hence an attempt was made to tolerate such runtime errors in fuzzer so that fuzzer can still test the relevant functions (facebookincubator#10993). However, it turns out that that attempt was not enough. The reason is that VeloxRuntimeError doesn't work well with the existing mechanism of masking error by default nulls. So the expression fuzzer still occasionally fails because of only one of the common and simple evaluation path throwing the error. (If we later want to make those VeloxRuntimeError not suppressable by TRY but suppressable by the mask-error-by-default-null mechanism, we'll need to extend the EvalErrors struct with an additional buffer to track whether the error at an index can be suppressed by Try and check that in TryExpr.) This diff relaxes the fuzzer check to make fuzzer not fail when only one of the common and simple eval path throw the UNSUPPORTED_INPUT_UNCATCHABLE runtime error. This should unblock facebookincubator#10713. Reviewed By: kevinwilfong Differential Revision: D63421914 fbshipit-source-id: 54d01f7a5e7ea887018659d0eec8070fd0922b50
Summary: Similar to facebookincubator#10599, in Spark, a long year is any year ending on Thursday and any leap year ending on Friday. Since the only difference between Presto and Spark is on return type, this PR extracts the 'getWeek' function to functions/lib and changed to use 'weeknum' from external/date library for the week calculation. Pull Request resolved: facebookincubator#10713 Reviewed By: DanielHunte Differential Revision: D63269551 Pulled By: pedroerp fbshipit-source-id: cf8cf8b4f2a917d7a7c16a03cc8feed5f3fed5d8
Similar to #10599, in Spark, a long year is any year ending on Thursday and any
leap year ending on Friday. Since the only difference between Presto and Spark
is on return type, this PR extracts the 'getWeek' function to functions/lib and
changed to use 'weeknum' from external/date library for the week calculation.