This is an automated email from the ASF dual-hosted git repository.
alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git
The following commit(s) were added to refs/heads/main by this push:
new b4afa182e7 Add bench for data page statistics parquet extraction
(#10950)
b4afa182e7 is described below
commit b4afa182e76b4cded599c76a7a63627740549577
Author: Marvin Lanhenke <[email protected]>
AuthorDate: Wed Jul 3 23:47:03 2024 +0200
Add bench for data page statistics parquet extraction (#10950)
* feat: add data page bench
* chore: add comment
* fix: row_groups + shorten row_group_indices
---------
Co-authored-by: Andrew Lamb <[email protected]>
---
datafusion/core/benches/parquet_statistic.rs | 168 +++++++++++++++++++++------
1 file changed, 134 insertions(+), 34 deletions(-)
diff --git a/datafusion/core/benches/parquet_statistic.rs
b/datafusion/core/benches/parquet_statistic.rs
index b58ecc13ae..3595e8773b 100644
--- a/datafusion/core/benches/parquet_statistic.rs
+++ b/datafusion/core/benches/parquet_statistic.rs
@@ -18,20 +18,26 @@
//! Benchmarks of benchmark for extracting arrow statistics from parquet
use arrow::array::{ArrayRef, DictionaryArray, Float64Array, StringArray,
UInt64Array};
-use arrow_array::{Int32Array, RecordBatch};
+use arrow_array::{Int32Array, Int64Array, RecordBatch};
use arrow_schema::{
DataType::{self, *},
Field, Schema,
};
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use datafusion::datasource::physical_plan::parquet::StatisticsConverter;
-use parquet::arrow::{arrow_reader::ArrowReaderBuilder, ArrowWriter};
-use parquet::file::properties::WriterProperties;
+use parquet::{
+ arrow::arrow_reader::ArrowReaderOptions,
file::properties::WriterProperties,
+};
+use parquet::{
+ arrow::{arrow_reader::ArrowReaderBuilder, ArrowWriter},
+ file::properties::EnabledStatistics,
+};
use std::sync::Arc;
use tempfile::NamedTempFile;
#[derive(Debug, Clone)]
enum TestTypes {
UInt64,
+ Int64,
F64,
String,
Dictionary,
@@ -43,6 +49,7 @@ impl fmt::Display for TestTypes {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TestTypes::UInt64 => write!(f, "UInt64"),
+ TestTypes::Int64 => write!(f, "Int64"),
TestTypes::F64 => write!(f, "F64"),
TestTypes::String => write!(f, "String"),
TestTypes::Dictionary => write!(f, "Dictionary(Int32, String)"),
@@ -50,11 +57,18 @@ impl fmt::Display for TestTypes {
}
}
-fn create_parquet_file(dtype: TestTypes, row_groups: usize) -> NamedTempFile {
+fn create_parquet_file(
+ dtype: TestTypes,
+ row_groups: usize,
+ data_page_row_count_limit: &Option<usize>,
+) -> NamedTempFile {
let schema = match dtype {
TestTypes::UInt64 => {
Arc::new(Schema::new(vec![Field::new("col", DataType::UInt64,
true)]))
}
+ TestTypes::Int64 => {
+ Arc::new(Schema::new(vec![Field::new("col", DataType::Int64,
true)]))
+ }
TestTypes::F64 => Arc::new(Schema::new(vec![Field::new(
"col",
DataType::Float64,
@@ -70,7 +84,14 @@ fn create_parquet_file(dtype: TestTypes, row_groups: usize)
-> NamedTempFile {
)])),
};
- let props = WriterProperties::builder().build();
+ let mut props =
WriterProperties::builder().set_max_row_group_size(row_groups);
+ if let Some(limit) = data_page_row_count_limit {
+ props = props
+ .set_data_page_row_count_limit(*limit)
+ .set_statistics_enabled(EnabledStatistics::Page);
+ };
+ let props = props.build();
+
let file = tempfile::Builder::new()
.suffix(".parquet")
.tempfile()
@@ -82,11 +103,21 @@ fn create_parquet_file(dtype: TestTypes, row_groups:
usize) -> NamedTempFile {
for _ in 0..row_groups {
let batch = match dtype {
TestTypes::UInt64 => make_uint64_batch(),
+ TestTypes::Int64 => make_int64_batch(),
TestTypes::F64 => make_f64_batch(),
TestTypes::String => make_string_batch(),
TestTypes::Dictionary => make_dict_batch(),
};
- writer.write(&batch).unwrap();
+ if data_page_row_count_limit.is_some() {
+ // Send batches one at a time. This allows the
+ // writer to apply the page limit, that is only
+ // checked on RecordBatch boundaries.
+ for i in 0..batch.num_rows() {
+ writer.write(&batch.slice(i, 1)).unwrap();
+ }
+ } else {
+ writer.write(&batch).unwrap();
+ }
}
writer.close().unwrap();
file
@@ -109,6 +140,23 @@ fn make_uint64_batch() -> RecordBatch {
.unwrap()
}
+fn make_int64_batch() -> RecordBatch {
+ let array: ArrayRef = Arc::new(Int64Array::from(vec![
+ Some(1),
+ Some(2),
+ Some(3),
+ Some(4),
+ Some(5),
+ ]));
+ RecordBatch::try_new(
+ Arc::new(arrow::datatypes::Schema::new(vec![
+ arrow::datatypes::Field::new("col", Int64, false),
+ ])),
+ vec![array],
+ )
+ .unwrap()
+}
+
fn make_f64_batch() -> RecordBatch {
let array: ArrayRef = Arc::new(Float64Array::from(vec![1.0, 2.0, 3.0, 4.0,
5.0]));
RecordBatch::try_new(
@@ -150,36 +198,88 @@ fn make_dict_batch() -> RecordBatch {
fn criterion_benchmark(c: &mut Criterion) {
let row_groups = 100;
use TestTypes::*;
- let types = vec![UInt64, F64, String, Dictionary];
+ let types = vec![Int64, UInt64, F64, String, Dictionary];
+ let data_page_row_count_limits = vec![None, Some(1)];
for dtype in types {
- let file = create_parquet_file(dtype.clone(), row_groups);
- let file = file.reopen().unwrap();
- let reader = ArrowReaderBuilder::try_new(file).unwrap();
- let metadata = reader.metadata();
- let row_groups = metadata.row_groups();
-
- let mut group =
- c.benchmark_group(format!("Extract statistics for {}",
dtype.clone()));
- group.bench_function(
- BenchmarkId::new("extract_statistics", dtype.clone()),
- |b| {
- b.iter(|| {
- let converter = StatisticsConverter::try_new(
- "col",
- reader.schema(),
- reader.parquet_schema(),
- )
- .unwrap();
-
- let _ =
converter.row_group_mins(row_groups.iter()).unwrap();
- let _ =
converter.row_group_maxes(row_groups.iter()).unwrap();
- let _ =
converter.row_group_null_counts(row_groups.iter()).unwrap();
- let _ =
converter.row_group_row_counts(row_groups.iter()).unwrap();
- })
- },
- );
- group.finish();
+ for data_page_row_count_limit in &data_page_row_count_limits {
+ let file =
+ create_parquet_file(dtype.clone(), row_groups,
data_page_row_count_limit);
+ let file = file.reopen().unwrap();
+ let options = ArrowReaderOptions::new().with_page_index(true);
+ let reader = ArrowReaderBuilder::try_new_with_options(file,
options).unwrap();
+ let metadata = reader.metadata();
+ let row_groups = metadata.row_groups();
+ let row_group_indices: Vec<_> = (0..row_groups.len()).collect();
+
+ let statistic_type = if data_page_row_count_limit.is_some() {
+ "data page"
+ } else {
+ "row group"
+ };
+
+ let mut group = c.benchmark_group(format!(
+ "Extract {} statistics for {}",
+ statistic_type,
+ dtype.clone()
+ ));
+ group.bench_function(
+ BenchmarkId::new("extract_statistics", dtype.clone()),
+ |b| {
+ b.iter(|| {
+ let converter = StatisticsConverter::try_new(
+ "col",
+ reader.schema(),
+ reader.parquet_schema(),
+ )
+ .unwrap();
+
+ if data_page_row_count_limit.is_some() {
+ let column_page_index = reader
+ .metadata()
+ .column_index()
+ .expect("File should have column page
indices");
+
+ let column_offset_index = reader
+ .metadata()
+ .offset_index()
+ .expect("File should have column offset
indices");
+
+ let _ = converter.data_page_mins(
+ column_page_index,
+ column_offset_index,
+ &row_group_indices,
+ );
+ let _ = converter.data_page_maxes(
+ column_page_index,
+ column_offset_index,
+ &row_group_indices,
+ );
+ let _ = converter.data_page_null_counts(
+ column_page_index,
+ column_offset_index,
+ &row_group_indices,
+ );
+ let _ = converter.data_page_row_counts(
+ column_offset_index,
+ row_groups,
+ &row_group_indices,
+ );
+ } else {
+ let _ =
converter.row_group_mins(row_groups.iter()).unwrap();
+ let _ =
converter.row_group_maxes(row_groups.iter()).unwrap();
+ let _ = converter
+ .row_group_null_counts(row_groups.iter())
+ .unwrap();
+ let _ = converter
+ .row_group_row_counts(row_groups.iter())
+ .unwrap();
+ }
+ })
+ },
+ );
+ group.finish();
+ }
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]