Skip to content

ARROW-16807: [C++][R] count distinct incorrectly merges state - #13583

Merged
wesm merged 11 commits into
apache:masterfrom
drin:ARROW-16807-count-distinct
Jul 16, 2022
Merged

ARROW-16807: [C++][R] count distinct incorrectly merges state#13583
wesm merged 11 commits into
apache:masterfrom
drin:ARROW-16807-count-distinct

Conversation

@drin

@drindrin commented Jul 12, 2022

Copy link
Copy Markdown
Contributor

This addresses a bug where the count_distinct function simply added counts when merging state. The correct logic would be to return the number of distinct elements after both states have been merged.

State for count_distinct is backed by a MemoTable, which is then backed by a HashTable. To properly merge state, this PR adds 2 functions to each MemoTable: MaybeInsert and MergeTable. The MaybeInsert function handles simplified logic for inserting an element into the MemoTable. The MergeTable function handles iteration over elements in the MemoTable to be merged.

This PR also adds an R test and a C++ test. The R test mirrors what was provided in ARROW-16807. The C++ test, AllChunkedArrayTypesWithNulls, mirrors another C++ test, AllArrayTypesWithNulls, but uses chunked arrays for test data.

drin added 5 commits July 12, 2022 08:47
The bug described in ARROW-16807 is that when merging states for count
distinct, the non_null counts are simply added (no overload that I saw).
The fix was to change this into a proper merge of the data in the MemoTable.
There are 3 derived classes from MemoTable. This adds a `MaybeInsert`
and `MergeTable` function to each to support the merge logic.
This adds a unittest to run count_distinct on chunked arrays, which were
incorrectly handled before.
This is a test to reproduce the issue seen in ARROW-16807, which calls
`count_distinct` (via `n_distinct`) on a dataset with many chunks. If
`summarize` is called before `collect`, then count_distinct merges
distinct counts across chunks incorrectly. Calling collect before
summarize does not expose the bug.
Added an extra assert to be sure that collect and summarize produce the
same results when commuted.
@github-actions

Copy link
Copy Markdown

@drin

drin commented Jul 12, 2022

Copy link
Copy Markdown
ContributorAuthor

I just realized that this introduces (or maybe just exposes) a bug when calling this function on scalar inputs. If the input is a scalar, non_nulls is incremented without changing state. To address this "correctly," the code path for scalar inputs should also update the state by using GetOrInsert as is done for the code path for vector inputs.

I am working on figuring this out, given that the compiler has type conversion issues when attempting to just call GetOrInsert with a scalar reference.

@cyb70289cyb70289 changed the title ARROW-16807: count distinct incorrectly merges stateARROW-16807: [C++][R] count distinct incorrectly merges stateJul 13, 2022
Comment threadcpp/src/arrow/util/hashing.h Outdated
Comment threadr/tests/testthat/test-dplyr-summarize.R Outdated
Comment threadcpp/src/arrow/util/hashing.h Outdated
drin added 2 commits July 13, 2022 16:38
The path for count_distinct with scalar inputs didn't update state, and
instead only added a single count. To fix this, we use MaybeInsert and
UnboxScalar to insert the new value. The non_null count can then be set
the same way for both vector and scalar inputs
The UnboxScalar implementation that has `enable_if_has_string_view` is
also true for Decimal128 and Decimal256 types. Usually the
implementation templated for these types would be called, but The
BinaryMemoTable only has a type for BinaryTypes. This means that for
count_distinct with Decimal columns, the UnboxScalar implementation that
gets called is the one for string_view type
@drin

drin commented Jul 13, 2022

Copy link
Copy Markdown
ContributorAuthor

@wesm@westonpace previous pair of commits makes this work for scalar inputs. I tried putting some of the conditional logic ("if type is decimal") in CountDistinctImpl but it ended up being difficult to satisfy the compiler.

the current change to UnboxScalar tries to essentially use is_decimal, but then I realized that there isn't an easy way to call the appriopriate view function unless I know which decimal type I have. Additionally, the UnboxScalar implementations for Decimal types gets the value, which I think would be difficult to downcast/change back to string_view.

all in all, this was the only approach I could get to work and it seemed semi reasonable. Feedback would be much appreciated though.

Comment threadcpp/src/arrow/util/hashing.h Outdated
Comment threadcpp/src/arrow/util/hashing.h Outdated
@wesm

wesm commented Jul 14, 2022

Copy link
Copy Markdown
Member

@drin I pushed a simpler solution for the UnboxScalar change and removed MaybeInsert. We should probably open a follow up Jira to improve error handling in hash table merges but I don't think it's necessary to do that in this PR

@drin

drin commented Jul 14, 2022

Copy link
Copy Markdown
ContributorAuthor

I made a JIRA to track error handling improvements for hash table merge: ARROW-17074

I specifically made the priority minor, but feel free to change it (I don't know the protocol for priority assignment)

@drin
drin marked this pull request as ready for review July 14, 2022 16:15
@drin
drin requested a review from cyb70289July 14, 2022 16:16

@cyb70289cyb70289 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great. Only some minor comments.
Thanks @drin !

Comment threadcpp/src/arrow/util/hashing.h Outdated
Comment threadcpp/src/arrow/util/hashing.h Outdated
Comment threadcpp/src/arrow/util/hashing.h Outdated
Comment threadcpp/src/arrow/util/hashing.h Outdated
Comment threadcpp/src/arrow/util/hashing.h Outdated
@drin

drin commented Jul 15, 2022

Copy link
Copy Markdown
ContributorAuthor

thanks for the reviews @cyb70289 and Wes!

@drin
drin requested a review from cyb70289July 15, 2022 16:53

@westonpacewestonpace left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good from my perspective. Thanks for adding the tests. I'll let others confirm before merging.

@wesm

wesm commented Jul 16, 2022

Copy link
Copy Markdown
Member

@cyb70289 these CI failures don't seem related — R has some lint failures and there are these otel protobuf linkage issues. I'll go ahead to merge this

@wesm
wesm merged commit af4db77 into apache:masterJul 16, 2022
@nealrichardson

Copy link
Copy Markdown
Member

R issues are likely a combination of transient upstream issues and stuff that has been fixed in master. If things persist I'll follow up.

@ursabot

Copy link
Copy Markdown

Benchmark runs are scheduled for baseline = afc6840 and contender = af4db77. af4db77 is a master commit associated with this PR. Results will be available as each benchmark for each run completes.
Conbench compare runs links:
[Failed ⬇️0.0% ⬆️0.0%] ec2-t3-xlarge-us-east-2
[Failed ⬇️1.18% ⬆️0.03%] test-mac-arm
[Failed ⬇️0.0% ⬆️0.0%] ursa-i9-9960x
[Finished ⬇️1.36% ⬆️0.14%] ursa-thinkcentre-m75q
Buildkite builds:
[Failed] af4db773 ec2-t3-xlarge-us-east-2
[Failed] af4db773 test-mac-arm
[Failed] af4db773 ursa-i9-9960x
[Finished] af4db773 ursa-thinkcentre-m75q
[Finished] afc6840c ec2-t3-xlarge-us-east-2
[Failed] afc6840c test-mac-arm
[Failed] afc6840c ursa-i9-9960x
[Finished] afc6840c ursa-thinkcentre-m75q
Supported benchmarks:
ec2-t3-xlarge-us-east-2: Supported benchmark langs: Python, R. Runs only benchmarks with cloud = True
test-mac-arm: Supported benchmark langs: C++, Python, R
ursa-i9-9960x: Supported benchmark langs: Python, R, JavaScript
ursa-thinkcentre-m75q: Supported benchmark langs: C++, Java

@drin
drin deleted the ARROW-16807-count-distinct branch July 18, 2022 19:36
kou pushed a commit that referenced this pull request Feb 20, 2023
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@drin@wesm@cyb70289@nealrichardson@ursabot@westonpace