Tpt opened a new issue, #11792:
URL: https://github.com/apache/arrow-rs/issues/11792

   ### Describe the bug
   
   `ArrowWriter` only splits an incoming batch on `max_row_group_bytes` when 
the in-progress row group already has buffered rows, because it extrapolates 
from their average size. The first batch written to a row group is therefore 
always accepted whole, and the row group is flushed afterwards.
   
   When a single batch is larger than the limit, every row group ends up 
holding exactly one batch, whatever its size. In practice this hits wide rows 
(images, embeddings, documents), which is precisely where a byte limit matters 
most: we see 128 MB row groups with a 16 MB limit, one per 128-row batch.
   
   ### To Reproduce
   
   ```rust
   use std::sync::Arc;
   use arrow_array::{BinaryArray, RecordBatch};
   use parquet::arrow::ArrowWriter;
   use parquet::file::properties::WriterProperties;
   
   fn main() {
       // 128 rows of 1 MB each
       let values: Vec<Vec<u8>> = (0..128u64)
           .map(|i| {
               let mut v = vec![0u8; 1_000_000];
               v[..8].copy_from_slice(&i.to_le_bytes());
               v
           })
           .collect();
       let batch = RecordBatch::try_from_iter([(
           "b",
           Arc::new(BinaryArray::from_iter_values(&values)) as _,
       )])
       .unwrap();
   
       let props = WriterProperties::builder()
           .set_max_row_group_bytes(Some(16_000_000))
           .set_dictionary_enabled(false)
           .build();
       let mut writer = ArrowWriter::try_new(Vec::new(), batch.schema(), 
Some(props)).unwrap();
       for _ in 0..4 {
           writer.write(&batch).unwrap();
       }
       for rg in writer.close().unwrap().row_groups() {
           println!("{} rows, {} bytes", rg.num_rows(), rg.total_byte_size());
       }
   }
   ```
   
   Output: four row groups of 128 rows and ~128 MB each.
   
   The same happens through DataFusion with 
`datafusion.execution.parquet.max_row_group_bytes` (and 
`allow_single_file_parallelism = false`, which it requires): once 
`execution.batch_size` rows exceed the limit, row groups are exactly 
`batch_size` rows.
   
   ### Expected behavior
   
   Row groups of roughly 16 MB (15 rows each here), as when batches are smaller 
than the limit: with 100 KB rows the same writer correctly produces ~16 MB 
groups of 159 rows.
   
   ### Additional context
   
   The relevant check is `if let Some(max_bytes) = self.max_row_group_bytes && 
buffered_rows > 0` in `ArrowWriter::write`. Other projects have hit this 
through parquet-rs and worked around it in their own writers, e.g. 
https://github.com/apache/paimon-rust/pull/1072 and 
https://github.com/duckdb/duckdb/pull/25060


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to