@@ -34,13 +34,18 @@ use parquet::data_type::Decimal;
3434/// Parquet row groups and data pages based on the query predicate.
3535#[ derive( Debug , Clone , Default ) ]
3636pub ( crate ) struct BloomFilterStatistics {
37- /// Per-column Bloom filters
38- /// Key: predicate column name
39- /// Value:
40- /// * [`Sbbf`] (Bloom filter),
41- /// * Parquet physical [`Type`] needed to evaluate literals against the filter
42- /// * Type length from the Parquet column descriptor
43- column_sbbf : HashMap < String , ( Sbbf , Type , i32 ) > ,
37+ /// Per-column Bloom filters keyed by predicate column name.
38+ column_sbbf : HashMap < String , ColumnBloomFilter > ,
39+ }
40+
41+ #[ derive( Debug , Clone ) ]
42+ struct ColumnBloomFilter {
43+ /// [`Sbbf`] (Bloom filter).
44+ sbbf : Sbbf ,
45+ /// Parquet physical [`Type`] needed to evaluate literals against the filter.
46+ physical_type : Type ,
47+ /// Type length from the Parquet column descriptor.
48+ type_length : i32 ,
4449}
4550
4651impl BloomFilterStatistics {
@@ -64,8 +69,14 @@ impl BloomFilterStatistics {
6469 ty : Type ,
6570 type_length : i32 ,
6671 ) {
67- self . column_sbbf
68- . insert ( column. into ( ) , ( sbbf, ty, type_length) ) ;
72+ self . column_sbbf . insert (
73+ column. into ( ) ,
74+ ColumnBloomFilter {
75+ sbbf,
76+ physical_type : ty,
77+ type_length,
78+ } ,
79+ ) ;
6980 }
7081
7182 /// Helper function for checking if [`Sbbf`] filter contains [`ScalarValue`].
@@ -186,8 +197,7 @@ impl PruningStatistics for BloomFilterStatistics {
186197 column : & Column ,
187198 values : & HashSet < ScalarValue > ,
188199 ) -> Option < BooleanArray > {
189- let ( sbbf, parquet_type, type_length) =
190- self . column_sbbf . get ( column. name . as_str ( ) ) ?;
200+ let column_bloom_filter = self . column_sbbf . get ( column. name . as_str ( ) ) ?;
191201
192202 // Bloom filters are probabilistic data structures that can return false
193203 // positives (i.e. it might return true even if the value is not
@@ -198,10 +208,10 @@ impl PruningStatistics for BloomFilterStatistics {
198208 . iter ( )
199209 . map ( |value| {
200210 BloomFilterStatistics :: check_scalar (
201- sbbf,
211+ & column_bloom_filter . sbbf ,
202212 value,
203- parquet_type ,
204- * type_length,
213+ & column_bloom_filter . physical_type ,
214+ column_bloom_filter . type_length ,
205215 )
206216 } )
207217 // The row group doesn't contain any of the values if
@@ -413,7 +423,11 @@ mod tests {
413423 async fn test_row_group_bloom_filter_pruning_predicate_decimal128 ( ) {
414424 for precision in [ 19 , 20 , 21 , 28 , 38 ] {
415425 let scale = 2 ;
416- let data = parquet_decimal128_with_bloom_filter ( precision, scale) ;
426+ let data = parquet_decimal128_with_bloom_filter (
427+ precision,
428+ scale,
429+ vec ! [ 100 , 200 , 300 , 400 , 500 , 600 ] ,
430+ ) ;
417431 let schema = Schema :: new ( vec ! [ Field :: new(
418432 "decimal_col" ,
419433 DataType :: Decimal128 ( precision, scale) ,
@@ -443,6 +457,44 @@ mod tests {
443457 }
444458 }
445459
460+ #[ tokio:: test]
461+ async fn test_row_group_bloom_filter_pruning_predicate_negative_decimal128 ( ) {
462+ for precision in [ 19 , 20 , 21 , 28 , 38 ] {
463+ let scale = 2 ;
464+ let data = parquet_decimal128_with_bloom_filter (
465+ precision,
466+ scale,
467+ vec ! [ -100 , -200 , -300 , -400 , -500 , -600 ] ,
468+ ) ;
469+ let schema = Schema :: new ( vec ! [ Field :: new(
470+ "decimal_col" ,
471+ DataType :: Decimal128 ( precision, scale) ,
472+ true ,
473+ ) ] ) ;
474+ let expr = col ( "decimal_col" ) . eq ( Expr :: Literal (
475+ ScalarValue :: Decimal128 ( Some ( -500 ) , precision, scale) ,
476+ None ,
477+ ) ) ;
478+ let expr = logical2physical ( & expr, & schema) ;
479+ let pruning_predicate =
480+ PruningPredicate :: try_new ( expr, Arc :: new ( schema) ) . unwrap ( ) ;
481+
482+ let pruned_row_groups = test_row_group_bloom_filter_pruning_predicate (
483+ & format ! ( "negative-decimal128-{precision}.parquet" ) ,
484+ data,
485+ & pruning_predicate,
486+ )
487+ . await
488+ . unwrap ( ) ;
489+
490+ assert_eq ! (
491+ pruned_row_groups. access_plan( ) . row_group_indexes( ) ,
492+ vec![ 2 ] ,
493+ "precision {precision}"
494+ ) ;
495+ }
496+ }
497+
446498 struct BloomFilterTest {
447499 file_name : String ,
448500 schema : Schema ,
@@ -535,14 +587,18 @@ mod tests {
535587 }
536588 }
537589
538- fn parquet_decimal128_with_bloom_filter ( precision : u8 , scale : i8 ) -> bytes:: Bytes {
590+ fn parquet_decimal128_with_bloom_filter (
591+ precision : u8 ,
592+ scale : i8 ,
593+ values : Vec < i128 > ,
594+ ) -> bytes:: Bytes {
539595 let schema = Arc :: new ( Schema :: new ( vec ! [ Field :: new(
540596 "decimal_col" ,
541597 DataType :: Decimal128 ( precision, scale) ,
542598 true ,
543599 ) ] ) ) ;
544600 let array = Arc :: new (
545- Decimal128Array :: from ( vec ! [ 100 , 200 , 300 , 400 , 500 , 600 ] )
601+ Decimal128Array :: from ( values )
546602 . with_precision_and_scale ( precision, scale)
547603 . unwrap ( ) ,
548604 ) as ArrayRef ;
0 commit comments