-
Notifications
You must be signed in to change notification settings - Fork 28.9k
[SPARK-24076][SQL] Use different seed in HashAggregate to avoid hash conflict #21149
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
Conversation
|
oh... good catch. I think you'd be better to put the detailed info. (written in the jira) in the description above? |
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.
How about writing comments for the reason why we set the seed value here?
|
@maropu Thanks for comments, I have updated, could you help take a look at? |
|
cc: @hvanhovell |
|
Can you also show the screenshot after this change? |
|
Test build #89830 has finished for PR 21149 at commit
|
|
Test build #89839 has finished for PR 21149 at commit
|
|
ping @hvanhovell @gatorsmile |
|
LGTM - merging to master. Thanks! |
|
@maropu @hvanhovell thanks very much! |
| // SPARK-24076: HashAggregate uses the same hash algorithm on the same expressions | ||
| // as ShuffleExchange, it may lead to bad hash conflict when shuffle.partitions=8192*n, | ||
| // pick a different seed to avoid this conflict | ||
| val hashExpr = Murmur3Hash(groupingExpressions, 48) |
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.
can we just use UnsafeRow.hashCode here?
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.
@cloud-fan you mean unsafeRowKeys.hashCode(), right?
I think it is a good idea, unsafe row has [null bit set] etc., the result should be different, we don't need weird 48 also. Do you want me to create a followup PR?
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.
yes please, 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.
@cloud-fan would this perform slower since now we are moving to interpreted version for hashcode generation? If not then why didn't we use unsafeRowKeys.hashCode() in the first place?
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.
it should be faster, as unsafeRowKeys.hashCode() is just one function call. I don't know why we didn't do it in the first place, the code is pretty old.
…n HashAggregate ## What changes were proposed in this pull request? This is a followup PR for #21149. New way uses unsafeRow.hashCode() as hash value in HashAggregate. The unsafe row has [null bit set] etc., so the hash should be different from shuffle hash, and then we don't need a special seed. ## How was this patch tested? UTs. Closes #23821 from yucai/unsafe_hash. Authored-by: yucai <[email protected]> Signed-off-by: Wenchen Fan <[email protected]>
What changes were proposed in this pull request?
HashAggregate uses the same hash algorithm and seed as ShuffleExchange, it may lead to bad hash conflict when shuffle.partitions=8192*n.
Considering below example:
In the shuffle stage, if user sets the shuffle.partition = 8192, all tuples in the same partition will meet the following relationship:
Then in the next HashAggregate stage, all tuples from the same partition need be put into a 16K BytesToBytesMap (unsafeRowAggBuffer).
Here, the HashAggregate uses the same hash algorithm on the same expression as shuffle, and uses the same seed, and 16K = 8192 * 2, so actually, all tuples in the same parititon will only be hashed to 2 different places in the BytesToBytesMap. It is bad hash conflict. With BytesToBytesMap growing, the conflict will always exist.
Before change:

After change:

How was this patch tested?
Unit tests and production cases.