You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iceberg.apache.org by li...@apache.org on 2025/03/20 02:20:23 UTC

(iceberg-rust) branch main updated: feat: cache `calc_row_counts` (#1107)

This is an automated email from the ASF dual-hosted git repository.

liurenjie1024 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-rust.git


The following commit(s) were added to refs/heads/main by this push:
     new 5690615e feat: cache `calc_row_counts` (#1107)
5690615e is described below

commit 5690615e59c5a2150b7ad66405db5988a2e5dc63
Author: Jonathan Chen <ch...@gmail.com>
AuthorDate: Wed Mar 19 22:20:18 2025 -0400

    feat: cache `calc_row_counts` (#1107)
    
    
    ## What changes are included in this PR?
    Caches row counts when encountering columns multiple times.
---
 .../src/expr/visitors/page_index_evaluator.rs      | 37 +++++++++++++++-------
 1 file changed, 25 insertions(+), 12 deletions(-)

diff --git a/crates/iceberg/src/expr/visitors/page_index_evaluator.rs b/crates/iceberg/src/expr/visitors/page_index_evaluator.rs
index 2151bd98..35b03118 100644
--- a/crates/iceberg/src/expr/visitors/page_index_evaluator.rs
+++ b/crates/iceberg/src/expr/visitors/page_index_evaluator.rs
@@ -64,6 +64,7 @@ pub(crate) struct PageIndexEvaluator<'a> {
     row_group_metadata: &'a RowGroupMetaData,
     iceberg_field_id_to_parquet_column_index: &'a HashMap<i32, usize>,
     snapshot_schema: &'a Schema,
+    row_count_cache: HashMap<usize, Vec<usize>>,
 }
 
 impl<'a> PageIndexEvaluator<'a> {
@@ -80,6 +81,7 @@ impl<'a> PageIndexEvaluator<'a> {
             row_group_metadata,
             iceberg_field_id_to_parquet_column_index: field_id_map,
             snapshot_schema,
+            row_count_cache: HashMap::new(),
         }
     }
 
@@ -126,7 +128,7 @@ impl<'a> PageIndexEvaluator<'a> {
     }
 
     fn calc_row_selection<F>(
-        &self,
+        &mut self,
         field_id: i32,
         predicate: F,
         missing_col_behavior: MissingColBehavior,
@@ -168,17 +170,28 @@ impl<'a> PageIndexEvaluator<'a> {
             return self.select_all_rows();
         };
 
-        let Some(offset_index) = self.offset_index.get(parquet_column_index) else {
-            // if we have a column index, we should always have an offset index.
-            return Err(Error::new(
-                ErrorKind::Unexpected,
-                format!("Missing offset index for field id {}", field_id),
-            ));
-        };
+        let row_counts = {
+            // Caches row count calculations for columns that appear multiple times in
+            // the predicate
+            match self.row_count_cache.get(&parquet_column_index) {
+                Some(count) => count.clone(),
+                None => {
+                    let Some(offset_index) = self.offset_index.get(parquet_column_index) else {
+                        // if we have a column index, we should always have an offset index.
+                        return Err(Error::new(
+                            ErrorKind::Unexpected,
+                            format!("Missing offset index for field id {}", field_id),
+                        ));
+                    };
+
+                    let count = self.calc_row_counts(offset_index);
+                    self.row_count_cache
+                        .insert(parquet_column_index, count.clone());
 
-        // TODO: cache row_counts to avoid recalcing if the same column
-        //       appears multiple times in the filter predicate
-        let row_counts = self.calc_row_counts(offset_index);
+                    count
+                }
+            }
+        };
 
         let Some(page_filter) = Self::apply_predicate_to_column_index(
             predicate,
@@ -205,7 +218,7 @@ impl<'a> PageIndexEvaluator<'a> {
         Ok(row_selectors.into())
     }
 
-    /// returns a list of row counts per page
+    /// Returns a list of row counts per page
     fn calc_row_counts(&self, offset_index: &OffsetIndexMetaData) -> Vec<usize> {
         let mut remaining_rows = self.row_group_metadata.num_rows() as usize;
         let mut row_counts = Vec::with_capacity(self.offset_index.len());