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

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


The following commit(s) were added to refs/heads/main by this push:
     new 5574d707 fix(scan): preserve Data Evolution file order in row-id 
groups (#717)
5574d707 is described below

commit 5574d707f023a10099085c30165508fc321e3190
Author: XiaoHongbo <[email protected]>
AuthorDate: Sun Aug 16 22:46:20 2026 +0800

    fix(scan): preserve Data Evolution file order in row-id groups (#717)
---
 crates/paimon/src/table/stats_filter.rs | 46 ++++++++++++++++++++-------------
 crates/paimon/src/table/table_scan.rs   | 10 +++----
 2 files changed, 33 insertions(+), 23 deletions(-)

diff --git a/crates/paimon/src/table/stats_filter.rs 
b/crates/paimon/src/table/stats_filter.rs
index 8e2f06b0..010a2344 100644
--- a/crates/paimon/src/table/stats_filter.rs
+++ b/crates/paimon/src/table/stats_filter.rs
@@ -571,29 +571,39 @@ fn data_evolution_predicate_must_match(
 
 /// Groups data files by overlapping `row_id_range` for data evolution.
 ///
-/// Files are sorted by `(first_row_id, -max_sequence_number)`. Files whose 
row ID ranges
-/// overlap are merged into the same group (they contain different columns for 
the same rows).
-/// Files without `first_row_id` become their own group.
+/// Groups are sorted by row ID range. Files whose row ID ranges overlap are 
merged into
+/// the same group while preserving their input order. Files without 
`first_row_id` become
+/// their own group.
 ///
-/// Reference: 
[DataEvolutionSplitGenerator](https://github.com/apache/paimon/blob/master/paimon-core/src/main/java/org/apache/paimon/table/source/splitread/DataEvolutionSplitGenerator.java)
-pub(crate) fn group_by_overlapping_row_id(mut files: Vec<DataFileMeta>) -> 
Vec<Vec<DataFileMeta>> {
-    files.sort_by(|a, b| {
-        let a_row_id = a.first_row_id.unwrap_or(i64::MIN);
-        let b_row_id = b.first_row_id.unwrap_or(i64::MIN);
-        a_row_id
-            .cmp(&b_row_id)
-            .then_with(|| b.max_sequence_number.cmp(&a.max_sequence_number))
+/// Reference: 
[DataEvolutionSplitGenerator](https://github.com/apache/paimon/blob/master/paimon-core/src/main/java/org/apache/paimon/table/source/DataEvolutionSplitGenerator.java)
+pub(crate) fn group_by_overlapping_row_id(files: Vec<DataFileMeta>) -> 
Vec<Vec<DataFileMeta>> {
+    let mut indexed_files: Vec<(usize, DataFileMeta)> = 
files.into_iter().enumerate().collect();
+    indexed_files.sort_by(|(a_index, a), (b_index, b)| {
+        match (a.row_id_range(), b.row_id_range()) {
+            (None, None) => a_index.cmp(b_index),
+            (None, Some(_)) => std::cmp::Ordering::Less,
+            (Some(_), None) => std::cmp::Ordering::Greater,
+            (Some((a_start, a_end)), Some((b_start, b_end))) => a_start
+                .cmp(&b_start)
+                .then_with(|| a_end.cmp(&b_end))
+                .then_with(|| a_index.cmp(b_index)),
+        }
     });
 
     let mut result: Vec<Vec<DataFileMeta>> = Vec::new();
-    let mut current_group: Vec<DataFileMeta> = Vec::new();
+    let mut current_group: Vec<(usize, DataFileMeta)> = Vec::new();
     let mut current_range_end: i64 = i64::MIN;
 
-    for file in files {
+    let restore_input_order = |mut group: Vec<(usize, DataFileMeta)>| {
+        group.sort_by_key(|(index, _)| *index);
+        group.into_iter().map(|(_, file)| file).collect()
+    };
+
+    for (index, file) in indexed_files {
         match file.row_id_range() {
             None => {
                 if !current_group.is_empty() {
-                    result.push(std::mem::take(&mut current_group));
+                    result.push(restore_input_order(std::mem::take(&mut 
current_group)));
                     current_range_end = i64::MIN;
                 }
                 result.push(vec![file]);
@@ -603,17 +613,17 @@ pub(crate) fn group_by_overlapping_row_id(mut files: 
Vec<DataFileMeta>) -> Vec<V
                     if end > current_range_end {
                         current_range_end = end;
                     }
-                    current_group.push(file);
+                    current_group.push((index, file));
                 } else {
-                    result.push(std::mem::take(&mut current_group));
+                    result.push(restore_input_order(std::mem::take(&mut 
current_group)));
                     current_range_end = end;
-                    current_group.push(file);
+                    current_group.push((index, file));
                 }
             }
         }
     }
     if !current_group.is_empty() {
-        result.push(current_group);
+        result.push(restore_input_order(current_group));
     }
     result
 }
diff --git a/crates/paimon/src/table/table_scan.rs 
b/crates/paimon/src/table/table_scan.rs
index e4cd60ef..35b8b1a8 100644
--- a/crates/paimon/src/table/table_scan.rs
+++ b/crates/paimon/src/table/table_scan.rs
@@ -2899,7 +2899,7 @@ mod tests {
             make_evo_file("b", 10, 100, 2, None),
         ];
         let groups = group_by_overlapping_row_id(files);
-        assert_eq!(file_names(&groups), vec![vec!["b"], vec!["a"]]);
+        assert_eq!(file_names(&groups), vec![vec!["a"], vec!["b"]]);
     }
 
     #[test]
@@ -3247,8 +3247,8 @@ mod tests {
     #[test]
     fn test_group_by_overlapping_row_id_non_overlapping() {
         let files = vec![
-            make_evo_file("a", 10, 100, 1, Some(0)),
             make_evo_file("b", 10, 100, 2, Some(100)),
+            make_evo_file("a", 10, 100, 1, Some(0)),
         ];
         let groups = group_by_overlapping_row_id(files);
         assert_eq!(groups.len(), 2);
@@ -3266,12 +3266,12 @@ mod tests {
         let groups = group_by_overlapping_row_id(files);
         assert_eq!(
             file_names(&groups),
-            vec![vec!["c"], vec!["b", "a"], vec!["d"]]
+            vec![vec!["c"], vec!["a", "b"], vec!["d"]]
         );
     }
 
     #[test]
-    fn test_group_by_overlapping_row_id_sorted_by_seq() {
+    fn test_group_by_overlapping_row_id_preserves_input_order() {
         let files = vec![
             make_evo_file("a", 10, 100, 1, Some(0)),
             make_evo_file("b", 10, 100, 3, Some(0)),
@@ -3279,7 +3279,7 @@ mod tests {
         ];
         let groups = group_by_overlapping_row_id(files);
         assert_eq!(groups.len(), 1);
-        assert_eq!(file_names(&groups), vec![vec!["b", "c", "a"]]);
+        assert_eq!(file_names(&groups), vec![vec!["a", "b", "c"]]);
     }
 
     #[test]

Reply via email to