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

Extract GroupValues (#6969) #7016

Merged
merged 3 commits into from
Jul 19, 2023
Merged

Conversation

tustvold
Copy link
Contributor

Which issue does this PR close?

Part of #6969

Rationale for this change

Extracts the group key storage into a type-erased trait object so that it can then be specialized for different column types.

I have not been able to run the benchmarks on this yet, but I don't expect it to have a major material impact

What changes are included in this PR?

Are these changes tested?

Are there any user-facing changes?

@github-actions github-actions bot added the core Core DataFusion crate label Jul 19, 2023
}

// account for memory growth in scratch space
*allocated += self.scratch_space.size();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I couldn't see a reason to keep track of the delta and not just use try_resize at the end

Copy link
Contributor

Choose a reason for hiding this comment

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

Related response: #6932 (comment)

@alamb
Copy link
Contributor

alamb commented Jul 19, 2023

I am running benchmarks on this PR

@alamb
Copy link
Contributor

alamb commented Jul 19, 2023

My benchmark runs confirm what @tustvold suspected that there is no major performance change for this PR

--------------------
Benchmark tpch_mem.json
--------------------
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query        ┃ main_base ┃ extract-group-values ┃        Change ┃
┡━━━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 1     │  570.35ms │             567.53ms │     no change │
│ QQuery 2     │  166.07ms │             162.08ms │     no change │
│ QQuery 3     │  174.89ms │             170.65ms │     no change │
│ QQuery 4     │  115.82ms │             113.91ms │     no change │
│ QQuery 5     │  390.04ms │             388.49ms │     no change │
│ QQuery 6     │   39.12ms │              40.99ms │     no change │
│ QQuery 7     │  956.00ms │             925.58ms │     no change │
│ QQuery 8     │  239.53ms │             249.49ms │     no change │
│ QQuery 9     │  586.23ms │             586.65ms │     no change │
│ QQuery 10    │  331.74ms │             339.71ms │     no change │
│ QQuery 11    │  166.03ms │             155.13ms │ +1.07x faster │
│ QQuery 12    │  173.20ms │             174.27ms │     no change │
│ QQuery 13    │  305.51ms │             306.92ms │     no change │
│ QQuery 14    │   48.78ms │              51.24ms │  1.05x slower │
│ QQuery 15    │   52.68ms │              53.09ms │     no change │
│ QQuery 16    │  165.92ms │             172.41ms │     no change │
│ QQuery 17    │  981.34ms │             924.09ms │ +1.06x faster │
│ QQuery 18    │ 1644.03ms │            1696.96ms │     no change │
│ QQuery 19    │  169.66ms │             168.50ms │     no change │
│ QQuery 20    │  334.96ms │             329.97ms │     no change │
│ QQuery 21    │ 1161.63ms │            1189.21ms │     no change │
│ QQuery 22    │   87.75ms │              90.87ms │     no change │
└──────────────┴───────────┴──────────────────────┴───────────────┘

Copy link
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

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

This looks great to me -- thank you @tustvold

I am very excited to see what this looks like with a special case for single columns (I expect it to be screaming fast)

@@ -60,6 +60,151 @@ pub(crate) enum ExecutionState {

use super::AggregateExec;

/// An interning store for group keys
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// An interning store for group keys
/// Stores group key values and their mapping to group_index
///
/// This is a trait to allow special casing certain kinds of keys
/// like single column primitive arrays

fn flush(&mut self) -> Result<Vec<ArrayRef>>;
}

/// A [`GroupValues`] making use of [`Rows`]
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// A [`GroupValues`] making use of [`Rows`]
/// A [`GroupValues`] which stores group values using the arrow_row format [`Rows`]

///
/// keys: u64 hashes of the GroupValue
/// values: (hash, group_index)
map: RawTable<(u64, usize)>,
Copy link
Contributor

Choose a reason for hiding this comment

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

I am surprised to see the map in this structure -- I was expecting only the group values.

Is your idea to store the group keys inside the map, as shown to be so effective by @yahoNanJing in apache/arrow-rs#4524 (comment) ?

Copy link
Contributor

Choose a reason for hiding this comment

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

I also was thinking this structure will allow for an easy insertion of the FixedWidthRowFormat if that turns out to be better as well. So I think this PR is a step in the right direction regardless of which approach we choose to take

@@ -60,6 +60,151 @@ pub(crate) enum ExecutionState {

use super::AggregateExec;

/// An interning store for group keys
trait GroupValues: Send {
Copy link
Contributor

Choose a reason for hiding this comment

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

Eventually I would love to see this in its own module aggregates/group_values.rs but that can be a follow on PR for sure

batch_hashes.resize(n_rows, 0);
create_hashes(cols, &self.random_state, batch_hashes)?;

for (row, &hash) in batch_hashes.iter().enumerate() {
Copy link
Contributor

Choose a reason for hiding this comment

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

This change will likely conflict with #6932 (review) but I think it should be straightforward to update

/// └────────────┘ ││ └────────┘ ││ ││ └────────┘ ││
/// │└────────────┘│ │└────────────┘│
/// └──────────────┘ └──────────────┘
/// ┌────────────┐ ┌──────────────┐ ┌──────────────┐
Copy link
Contributor

Choose a reason for hiding this comment

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

If we choose to go with this approach, I can make some pictures for RowGroupValues as well

}

// account for memory growth in scratch space
*allocated += self.scratch_space.size();
Copy link
Contributor

Choose a reason for hiding this comment

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

Related response: #6932 (comment)

@tustvold tustvold merged commit a6dcd94 into apache:main Jul 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Core DataFusion crate
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants