@@ -1097,60 +1097,26 @@ mod tests {
10971097 // +-----------+
10981098 #[ tokio:: test]
10991099 async fn test_row_group_bloom_filter_pruning_predicate_simple_expr ( ) {
1100- // load parquet file
1101- let testdata = datafusion_common:: test_util:: parquet_test_data ( ) ;
1102- let file_name = "data_index_bloom_encoding_stats.parquet" ;
1103- let path = format ! ( "{testdata}/{file_name}" ) ;
1104- let data = bytes:: Bytes :: from ( std:: fs:: read ( path) . unwrap ( ) ) ;
1105-
1106- // generate pruning predicate `(String = "Hello_Not_exists")`
1107- let schema = Schema :: new ( vec ! [ Field :: new( "String" , DataType :: Utf8 , false ) ] ) ;
1108- let expr = col ( r#""String""# ) . eq ( lit ( "Hello_Not_Exists" ) ) ;
1109- let expr = logical2physical ( & expr, & schema) ;
1110- let pruning_predicate =
1111- PruningPredicate :: try_new ( expr, Arc :: new ( schema) ) . unwrap ( ) ;
1112-
1113- let row_groups = vec ! [ 0 ] ;
1114- let pruned_row_groups = test_row_group_bloom_filter_pruning_predicate (
1115- file_name,
1116- data,
1117- & pruning_predicate,
1118- & row_groups,
1119- )
1120- . await
1121- . unwrap ( ) ;
1122- assert ! ( pruned_row_groups. is_empty( ) ) ;
1100+ BloomFilterTest :: new_data_index_bloom_encoding_stats ( )
1101+ . with_expect_all_pruned ( )
1102+ // generate pruning predicate `(String = "Hello_Not_exists")`
1103+ . run ( col ( r#""String""# ) . eq ( lit ( "Hello_Not_Exists" ) ) )
1104+ . await
11231105 }
11241106
11251107 #[ tokio:: test]
11261108 async fn test_row_group_bloom_filter_pruning_predicate_mutiple_expr ( ) {
1127- // load parquet file
1128- let testdata = datafusion_common:: test_util:: parquet_test_data ( ) ;
1129- let file_name = "data_index_bloom_encoding_stats.parquet" ;
1130- let path = format ! ( "{testdata}/{file_name}" ) ;
1131- let data = bytes:: Bytes :: from ( std:: fs:: read ( path) . unwrap ( ) ) ;
1132-
1133- // generate pruning predicate `(String = "Hello_Not_exists" OR String = "Hello_Not_exists2")`
1134- let schema = Schema :: new ( vec ! [ Field :: new( "String" , DataType :: Utf8 , false ) ] ) ;
1135- let expr = lit ( "1" ) . eq ( lit ( "1" ) ) . and (
1136- col ( r#""String""# )
1137- . eq ( lit ( "Hello_Not_Exists" ) )
1138- . or ( col ( r#""String""# ) . eq ( lit ( "Hello_Not_Exists2" ) ) ) ,
1139- ) ;
1140- let expr = logical2physical ( & expr, & schema) ;
1141- let pruning_predicate =
1142- PruningPredicate :: try_new ( expr, Arc :: new ( schema) ) . unwrap ( ) ;
1143-
1144- let row_groups = vec ! [ 0 ] ;
1145- let pruned_row_groups = test_row_group_bloom_filter_pruning_predicate (
1146- file_name,
1147- data,
1148- & pruning_predicate,
1149- & row_groups,
1150- )
1151- . await
1152- . unwrap ( ) ;
1153- assert ! ( pruned_row_groups. is_empty( ) ) ;
1109+ BloomFilterTest :: new_data_index_bloom_encoding_stats ( )
1110+ . with_expect_all_pruned ( )
1111+ // generate pruning predicate `(String = "Hello_Not_exists" OR String = "Hello_Not_exists2")`
1112+ . run (
1113+ lit ( "1" ) . eq ( lit ( "1" ) ) . and (
1114+ col ( r#""String""# )
1115+ . eq ( lit ( "Hello_Not_Exists" ) )
1116+ . or ( col ( r#""String""# ) . eq ( lit ( "Hello_Not_Exists2" ) ) ) ,
1117+ ) ,
1118+ )
1119+ . await
11541120 }
11551121
11561122 #[ tokio:: test]
@@ -1186,144 +1152,140 @@ mod tests {
11861152
11871153 #[ tokio:: test]
11881154 async fn test_row_group_bloom_filter_pruning_predicate_with_exists_value ( ) {
1189- // load parquet file
1190- let testdata = datafusion_common:: test_util:: parquet_test_data ( ) ;
1191- let file_name = "data_index_bloom_encoding_stats.parquet" ;
1192- let path = format ! ( "{testdata}/{file_name}" ) ;
1193- let data = bytes:: Bytes :: from ( std:: fs:: read ( path) . unwrap ( ) ) ;
1194-
1195- // generate pruning predicate `(String = "Hello")`
1196- let schema = Schema :: new ( vec ! [ Field :: new( "String" , DataType :: Utf8 , false ) ] ) ;
1197- let expr = col ( r#""String""# ) . eq ( lit ( "Hello" ) ) ;
1198- let expr = logical2physical ( & expr, & schema) ;
1199- let pruning_predicate =
1200- PruningPredicate :: try_new ( expr, Arc :: new ( schema) ) . unwrap ( ) ;
1201-
1202- let row_groups = vec ! [ 0 ] ;
1203- let pruned_row_groups = test_row_group_bloom_filter_pruning_predicate (
1204- file_name,
1205- data,
1206- & pruning_predicate,
1207- & row_groups,
1208- )
1209- . await
1210- . unwrap ( ) ;
1211- assert_eq ! ( pruned_row_groups, row_groups) ;
1155+ BloomFilterTest :: new_data_index_bloom_encoding_stats ( )
1156+ . with_expect_none_pruned ( )
1157+ // generate pruning predicate `(String = "Hello")`
1158+ . run ( col ( r#""String""# ) . eq ( lit ( "Hello" ) ) )
1159+ . await
12121160 }
12131161
12141162 #[ tokio:: test]
12151163 async fn test_row_group_bloom_filter_pruning_predicate_with_exists_2_values ( ) {
1216- // load parquet file
1217- let testdata = datafusion_common:: test_util:: parquet_test_data ( ) ;
1218- let file_name = "data_index_bloom_encoding_stats.parquet" ;
1219- let path = format ! ( "{testdata}/{file_name}" ) ;
1220- let data = bytes:: Bytes :: from ( std:: fs:: read ( path) . unwrap ( ) ) ;
1221-
1222- // generate pruning predicate `(String = "Hello") OR (String = "the quick")`
1223- let schema = Schema :: new ( vec ! [ Field :: new( "String" , DataType :: Utf8 , false ) ] ) ;
1224- let expr = col ( r#""String""# )
1225- . eq ( lit ( "Hello" ) )
1226- . or ( col ( r#""String""# ) . eq ( lit ( "the quick" ) ) ) ;
1227- let expr = logical2physical ( & expr, & schema) ;
1228- let pruning_predicate =
1229- PruningPredicate :: try_new ( expr, Arc :: new ( schema) ) . unwrap ( ) ;
1230-
1231- let row_groups = vec ! [ 0 ] ;
1232- let pruned_row_groups = test_row_group_bloom_filter_pruning_predicate (
1233- file_name,
1234- data,
1235- & pruning_predicate,
1236- & row_groups,
1237- )
1238- . await
1239- . unwrap ( ) ;
1240- assert_eq ! ( pruned_row_groups, row_groups) ;
1164+ BloomFilterTest :: new_data_index_bloom_encoding_stats ( )
1165+ . with_expect_none_pruned ( )
1166+ // generate pruning predicate `(String = "Hello") OR (String = "the quick")`
1167+ . run (
1168+ col ( r#""String""# )
1169+ . eq ( lit ( "Hello" ) )
1170+ . or ( col ( r#""String""# ) . eq ( lit ( "the quick" ) ) ) ,
1171+ )
1172+ . await
12411173 }
12421174
12431175 #[ tokio:: test]
12441176 async fn test_row_group_bloom_filter_pruning_predicate_with_exists_3_values ( ) {
1245- // load parquet file
1246- let testdata = datafusion_common:: test_util:: parquet_test_data ( ) ;
1247- let file_name = "data_index_bloom_encoding_stats.parquet" ;
1248- let path = format ! ( "{testdata}/{file_name}" ) ;
1249- let data = bytes:: Bytes :: from ( std:: fs:: read ( path) . unwrap ( ) ) ;
1250-
1251- // generate pruning predicate `(String = "Hello") OR (String = "the quick") OR (String = "are you")`
1252- let schema = Schema :: new ( vec ! [ Field :: new( "String" , DataType :: Utf8 , false ) ] ) ;
1253- let expr = col ( r#""String""# )
1254- . eq ( lit ( "Hello" ) )
1255- . or ( col ( r#""String""# ) . eq ( lit ( "the quick" ) ) )
1256- . or ( col ( r#""String""# ) . eq ( lit ( "are you" ) ) ) ;
1257- let expr = logical2physical ( & expr, & schema) ;
1258- let pruning_predicate =
1259- PruningPredicate :: try_new ( expr, Arc :: new ( schema) ) . unwrap ( ) ;
1260-
1261- let row_groups = vec ! [ 0 ] ;
1262- let pruned_row_groups = test_row_group_bloom_filter_pruning_predicate (
1263- file_name,
1264- data,
1265- & pruning_predicate,
1266- & row_groups,
1267- )
1268- . await
1269- . unwrap ( ) ;
1270- assert_eq ! ( pruned_row_groups, row_groups) ;
1177+ BloomFilterTest :: new_data_index_bloom_encoding_stats ( )
1178+ . with_expect_none_pruned ( )
1179+ // generate pruning predicate `(String = "Hello") OR (String = "the quick") OR (String = "are you")`
1180+ . run (
1181+ col ( r#""String""# )
1182+ . eq ( lit ( "Hello" ) )
1183+ . or ( col ( r#""String""# ) . eq ( lit ( "the quick" ) ) )
1184+ . or ( col ( r#""String""# ) . eq ( lit ( "are you" ) ) ) ,
1185+ )
1186+ . await
12711187 }
12721188
12731189 #[ tokio:: test]
12741190 async fn test_row_group_bloom_filter_pruning_predicate_with_or_not_eq ( ) {
1275- // load parquet file
1276- let testdata = datafusion_common:: test_util:: parquet_test_data ( ) ;
1277- let file_name = "data_index_bloom_encoding_stats.parquet" ;
1278- let path = format ! ( "{testdata}/{file_name}" ) ;
1279- let data = bytes:: Bytes :: from ( std:: fs:: read ( path) . unwrap ( ) ) ;
1280-
1281- // generate pruning predicate `(String = "foo") OR (String != "bar")`
1282- let schema = Schema :: new ( vec ! [ Field :: new( "String" , DataType :: Utf8 , false ) ] ) ;
1283- let expr = col ( r#""String""# )
1284- . not_eq ( lit ( "foo" ) )
1285- . or ( col ( r#""String""# ) . not_eq ( lit ( "bar" ) ) ) ;
1286- let expr = logical2physical ( & expr, & schema) ;
1287- let pruning_predicate =
1288- PruningPredicate :: try_new ( expr, Arc :: new ( schema) ) . unwrap ( ) ;
1289-
1290- let row_groups = vec ! [ 0 ] ;
1291- let pruned_row_groups = test_row_group_bloom_filter_pruning_predicate (
1292- file_name,
1293- data,
1294- & pruning_predicate,
1295- & row_groups,
1296- )
1297- . await
1298- . unwrap ( ) ;
1299- assert_eq ! ( pruned_row_groups, row_groups) ;
1191+ BloomFilterTest :: new_data_index_bloom_encoding_stats ( )
1192+ . with_expect_none_pruned ( )
1193+ // generate pruning predicate `(String = "foo") OR (String != "bar")`
1194+ . run (
1195+ col ( r#""String""# )
1196+ . not_eq ( lit ( "foo" ) )
1197+ . or ( col ( r#""String""# ) . not_eq ( lit ( "bar" ) ) ) ,
1198+ )
1199+ . await
13001200 }
13011201
13021202 #[ tokio:: test]
13031203 async fn test_row_group_bloom_filter_pruning_predicate_without_bloom_filter ( ) {
1304- // load parquet file
1305- let testdata = datafusion_common:: test_util:: parquet_test_data ( ) ;
1306- let file_name = "alltypes_plain.parquet" ;
1307- let path = format ! ( "{testdata}/{file_name}" ) ;
1308- let data = bytes:: Bytes :: from ( std:: fs:: read ( path) . unwrap ( ) ) ;
1309-
13101204 // generate pruning predicate on a column without a bloom filter
1311- let schema = Schema :: new ( vec ! [ Field :: new ( "string_col" , DataType :: Utf8 , false ) ] ) ;
1312- let expr = col ( r#""string_col""# ) . eq ( lit ( "0" ) ) ;
1313- let expr = logical2physical ( & expr , & schema ) ;
1314- let pruning_predicate =
1315- PruningPredicate :: try_new ( expr , Arc :: new ( schema ) ) . unwrap ( ) ;
1205+ BloomFilterTest :: new_all_types ( )
1206+ . with_expect_none_pruned ( )
1207+ . run ( col ( r#""string_col""# ) . eq ( lit ( "0" ) ) )
1208+ . await
1209+ }
13161210
1317- let row_groups = vec ! [ 0 ] ;
1318- let pruned_row_groups = test_row_group_bloom_filter_pruning_predicate (
1319- file_name,
1320- data,
1321- & pruning_predicate,
1322- & row_groups,
1323- )
1324- . await
1325- . unwrap ( ) ;
1326- assert_eq ! ( pruned_row_groups, row_groups) ;
1211+ struct BloomFilterTest {
1212+ file_name : String ,
1213+ schema : Schema ,
1214+ // which row groups should be attempted to prune
1215+ row_groups : Vec < usize > ,
1216+ // which row groups are expected to be left after pruning. Must be set
1217+ // otherwise will panic on run()
1218+ post_pruning_row_groups : Option < Vec < usize > > ,
1219+ }
1220+
1221+ impl BloomFilterTest {
1222+ /// Return a test for data_index_bloom_encoding_stats.parquet
1223+ fn new_data_index_bloom_encoding_stats ( ) -> Self {
1224+ Self {
1225+ file_name : String :: from ( "data_index_bloom_encoding_stats.parquet" ) ,
1226+ schema : Schema :: new ( vec ! [ Field :: new( "String" , DataType :: Utf8 , false ) ] ) ,
1227+ row_groups : vec ! [ 0 ] ,
1228+ post_pruning_row_groups : None ,
1229+ }
1230+ }
1231+
1232+ // Return a test for alltypes_plain.parquet
1233+ fn new_all_types ( ) -> Self {
1234+ Self {
1235+ file_name : String :: from ( "alltypes_plain.parquet" ) ,
1236+ schema : Schema :: new ( vec ! [ Field :: new(
1237+ "string_col" ,
1238+ DataType :: Utf8 ,
1239+ false ,
1240+ ) ] ) ,
1241+ row_groups : vec ! [ 0 ] ,
1242+ post_pruning_row_groups : None ,
1243+ }
1244+ }
1245+
1246+ /// Expect all row groups to be pruned
1247+ pub fn with_expect_all_pruned ( mut self ) -> Self {
1248+ self . post_pruning_row_groups = Some ( vec ! [ ] ) ;
1249+ self
1250+ }
1251+
1252+ /// Expect all row groups not to be pruned
1253+ pub fn with_expect_none_pruned ( mut self ) -> Self {
1254+ self . post_pruning_row_groups = Some ( self . row_groups . clone ( ) ) ;
1255+ self
1256+ }
1257+
1258+ /// Prune this file using the specified expression and check that the expected row groups are left
1259+ async fn run ( self , expr : Expr ) {
1260+ let Self {
1261+ file_name,
1262+ schema,
1263+ row_groups,
1264+ post_pruning_row_groups,
1265+ } = self ;
1266+
1267+ let post_pruning_row_groups =
1268+ post_pruning_row_groups. expect ( "post_pruning_row_groups must be set" ) ;
1269+
1270+ let testdata = datafusion_common:: test_util:: parquet_test_data ( ) ;
1271+ let path = format ! ( "{testdata}/{file_name}" ) ;
1272+ let data = bytes:: Bytes :: from ( std:: fs:: read ( path) . unwrap ( ) ) ;
1273+
1274+ // generate pruning predicate on a column without a bloom filter
1275+ let expr = logical2physical ( & expr, & schema) ;
1276+ let pruning_predicate =
1277+ PruningPredicate :: try_new ( expr, Arc :: new ( schema) ) . unwrap ( ) ;
1278+
1279+ let pruned_row_groups = test_row_group_bloom_filter_pruning_predicate (
1280+ & file_name,
1281+ data,
1282+ & pruning_predicate,
1283+ & row_groups,
1284+ )
1285+ . await
1286+ . unwrap ( ) ;
1287+ assert_eq ! ( pruned_row_groups, post_pruning_row_groups) ;
1288+ }
13271289 }
13281290
13291291 async fn test_row_group_bloom_filter_pruning_predicate (
0 commit comments