Skip to content

Add was_valid parameter to NullState callbacks - #11592

Closed
joroKr21 wants to merge 3 commits into
apache:mainfrom
coralogix:null-state/is-null
Closed

Add was_valid parameter to NullState callbacks#11592
joroKr21 wants to merge 3 commits into
apache:mainfrom
coralogix:null-state/is-null

Conversation

@joroKr21

@joroKr21joroKr21 commented Jul 22, 2024

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Closes#11591.

Rationale for this change

Provide more flexibility for implementing GroupsAccumulator which often make use of NullState.

What changes are included in this PR?

Add was_valid parameter to NullState callbacks. In this way implementations can handle nulls differently.

Are these changes tested?

Yes, extended existing tests.

Are there any user-facing changes?

Yes, changes the signatures of NullState::accumulate and NullState::accumulate_boolean.

Comment on lines +327 to +331
/// Check if the accumulated value for the group at the given `index` is valid,
/// meaning that there was at least one value passing the filter for this group.
pub fn is_valid(&self, index: usize) -> bool {
self.seen_values.get_bit(index)
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ahh I can't use it in accumulate due to mutable vs immutable borrow. This API is pretty difficult to use.

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.

I don't understand this comment 🤔

@joroKr21joroKr21Jul 22, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This is the signature of accumulate:

pubfnaccumulate<T,F>(&mutself,group_indices:&[usize],values:&PrimitiveArray<T>,opt_filter:Option<&BooleanArray>,total_num_groups:usize,mutvalue_fn:F,)whereT:ArrowPrimitiveType + Send,F:FnMut(usize,T::Native) + Send

But I can't use is_null inside value_fn because the NullState is already borrowed as mutable

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Ideally BooleanBufferBuilder::set_bit should return the previous value and we can pass it along to the callback. That's in arrow I guess.

@alambalamb 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.

Do you still think we should add this API @joroKr21 ? or perhaps we should mark the PR as draft while we work on other options?

@joroKr21
joroKr21 marked this pull request as draft July 22, 2024 19:29
@joroKr21

Copy link
Copy Markdown
ContributorAuthor

Yeah good point, I converted it to a draft. I'm not sure what to do. Adding a boolean flag to the callback is not great either...

@joroKr21

Copy link
Copy Markdown
ContributorAuthor

@alamb I implemented the version with an additional callback parameter, LMK what you think?

@alambalamb 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.

The code looks good to me @joroKr21

I think this PR needs:

  1. Update the docs
  2. A functional test
  3. Run the clickbench performance benchmarks to ensure we don't see a regression

I can help with the benchmarks if necessary

cc @Dandandan

|group_index, new_value| {
let value = &mut self.values[group_index];
(self.prim_fn)(value, new_value);
|group_index, was_valid, new_value| {

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.

It would be nice to add a test that covered this, if possible

) where
T: ArrowPrimitiveType + Send,
F: FnMut(usize, T::Native) + Send,
F: FnMut(usize, bool, T::Native) + Send,

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.

Can we please update the documentation to reflect this new argument and explains what it means

@joroKr21
joroKr21force-pushed the null-state/is-null branch from 13601c8 to 477eadaCompareJuly 23, 2024 05:48
@joroKr21joroKr21 changed the title Add NullState::is_valid and NullState::is_nullAdd was_valid parameter to NullState callbacksJul 23, 2024
@joroKr21

Copy link
Copy Markdown
ContributorAuthor

/benchmark

|group_index, new_value| {
let value = &mut self.values[group_index];
(self.prim_fn)(value, new_value);
|group_index, was_valid, new_value| {

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.

I don't think the existing implementation have to change, or do they?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Perhaps not, although conceptually an accumulator is just a map-reduce-map via some monoid or semigroup. The current implementation supports only monoids (need an empty value) but it doesn't support semigroups (no empty value). We could use this for something like FirstValue or AnyValue but I guess we could also implement it specifically for that use case.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

We could even drop the initial value parameter since it doesn't matter in this case.

@joroKr21

Copy link
Copy Markdown
ContributorAuthor

@alamb the benchmark didn't trigger on comment

@Dandandan

Copy link
Copy Markdown
Contributor

@alamb the benchmark didn't trigger on comment

That support has been dropped (as it was a potential security risk and wasn't super reliable).
#11165

Can you run the benchmarks and post the results here?

@joroKr21

Copy link
Copy Markdown
ContributorAuthor

Can you run the benchmarks and post the results here?

Sure, it might be some time until I do that though

@joroKr21

Copy link
Copy Markdown
ContributorAuthor

I don't like this API at all

@joroKr21
joroKr21 deleted the null-state/is-null branch November 7, 2025 20:46
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add NullState::is_null public method

3 participants

@joroKr21@Dandandan@alamb