1use std::collections::{HashMap, HashSet};
2use std::sync::Arc;
3
4use arrow_array::{
5 Array, ArrayRef, Int64Array, RecordBatch, RecordBatchOptions, UInt64Array, new_empty_array,
6};
7use arrow_row::{RowConverter, Rows, SortField};
8use arrow_schema::{ArrowError, DataType, Field, Schema};
9use arrow_select::concat::concat;
10use arrow_select::interleave::interleave;
11use arrow_select::take::take;
12use rayon::prelude::*;
13use runlength::How;
14
15use crate::error::{Error, Result};
16use crate::kernels::Kernel;
17use crate::rle::{ArrowRle, default_fill};
18
19#[derive(Clone, Debug)]
27pub struct ArrowRleBatch {
28 keys: RecordBatch,
29 offsets: Vec<usize>,
30 ends: Vec<i64>,
31 values: ArrayRef,
32}
33
34pub(crate) fn single_key_column(name: &str, column: ArrayRef) -> RecordBatch {
36 let schema = Schema::new(vec![Field::new(
37 name,
38 column.data_type().clone(),
39 column.is_nullable(),
40 )]);
41 RecordBatch::try_new(Arc::new(schema), vec![column]).expect("one column matches its own schema")
42}
43
44pub(crate) fn key_rows(converter: &RowConverter, keys: &RecordBatch) -> Result<Rows> {
46 Ok(converter.convert_columns(keys.columns())?)
47}
48
49pub(crate) fn key_converter(keys: &RecordBatch) -> Result<RowConverter> {
50 let fields = keys
51 .schema()
52 .fields()
53 .iter()
54 .map(|f| SortField::new(f.data_type().clone()))
55 .collect();
56 Ok(RowConverter::new(fields)?)
57}
58
59fn concat_values(rles: &[ArrowRle], data_type: &DataType) -> Result<ArrayRef> {
60 if rles.is_empty() {
61 return Ok(new_empty_array(data_type));
62 }
63 let arrays: Vec<&dyn Array> = rles.iter().map(|r| r.values.as_ref()).collect();
64 Ok(concat(&arrays)?)
65}
66
67impl ArrowRleBatch {
68 pub fn try_new(
71 keys: RecordBatch,
72 offsets: Vec<usize>,
73 ends: Vec<i64>,
74 values: ArrayRef,
75 ) -> Result<Self> {
76 let n = keys.num_rows();
77 if offsets.len() != n + 1 {
78 return Err(runlength::Error::LengthMismatch {
79 what: "offsets and keys + 1",
80 left: offsets.len(),
81 right: n + 1,
82 }
83 .into());
84 }
85 if ends.len() != values.len() {
86 return Err(runlength::Error::LengthMismatch {
87 what: "ends and values",
88 left: ends.len(),
89 right: values.len(),
90 }
91 .into());
92 }
93 if offsets[0] != 0 || offsets[n] != ends.len() || offsets.windows(2).any(|w| w[0] > w[1]) {
94 return Err(runlength::Error::InvalidOffsets.into());
95 }
96 for (position, w) in offsets.windows(2).enumerate() {
97 let rle_ends = ends[w[0]..w[1]].to_vec();
98 let values = values.slice(w[0], w[1] - w[0]);
99 ArrowRle::try_new(rle_ends, values).map_err(|e| e.in_key(position))?;
100 }
101 let converter = key_converter(&keys)?;
102 let rows = key_rows(&converter, &keys)?;
103 let mut seen = HashSet::with_capacity(n);
104 for (position, row) in rows.iter().enumerate() {
105 if !seen.insert(row) {
106 return Err(runlength::Error::DuplicateKey { position }.into());
107 }
108 }
109 Ok(ArrowRleBatch {
110 keys,
111 offsets,
112 ends,
113 values,
114 })
115 }
116
117 pub(crate) fn from_parts_unchecked(
118 keys: RecordBatch,
119 offsets: Vec<usize>,
120 ends: Vec<i64>,
121 values: ArrayRef,
122 ) -> Result<Self> {
123 debug_assert_eq!(offsets.len(), keys.num_rows() + 1);
124 Ok(ArrowRleBatch {
125 keys,
126 offsets,
127 ends,
128 values,
129 })
130 }
131
132 pub fn from_rles(keys: RecordBatch, rles: Vec<ArrowRle>, data_type: &DataType) -> Result<Self> {
135 if keys.num_rows() != rles.len() {
136 return Err(runlength::Error::LengthMismatch {
137 what: "keys and sequences",
138 left: keys.num_rows(),
139 right: rles.len(),
140 }
141 .into());
142 }
143 let mut offsets = Vec::with_capacity(rles.len() + 1);
144 offsets.push(0);
145 let mut ends = Vec::new();
146 for rle in &rles {
147 ends.extend_from_slice(&rle.ends);
148 offsets.push(ends.len());
149 }
150 let values = concat_values(&rles, data_type)?;
151 Self::try_new(keys, offsets, ends, values)
152 }
153
154 pub fn len(&self) -> usize {
156 self.keys.num_rows()
157 }
158
159 pub fn is_empty(&self) -> bool {
160 self.len() == 0
161 }
162
163 pub fn keys(&self) -> &RecordBatch {
165 &self.keys
166 }
167
168 pub fn offsets(&self) -> &[usize] {
169 &self.offsets
170 }
171
172 pub fn ends(&self) -> &[i64] {
174 &self.ends
175 }
176
177 pub fn values(&self) -> &ArrayRef {
179 &self.values
180 }
181
182 pub fn get_index(&self, position: usize) -> Option<ArrowRle> {
184 (position < self.len()).then(|| self.rle_at(position))
185 }
186
187 fn rle_at(&self, position: usize) -> ArrowRle {
188 let (start, end) = (self.offsets[position], self.offsets[position + 1]);
189 ArrowRle {
190 ends: self.ends[start..end].to_vec(),
191 values: self.values.slice(start, end - start),
192 }
193 }
194
195 pub fn iter(&self) -> impl Iterator<Item = ArrowRle> + '_ {
197 (0..self.len()).map(|i| self.rle_at(i))
198 }
199
200 pub fn positions(&self, keys: &RecordBatch) -> Result<Vec<Option<usize>>> {
203 self.check_key_schema(keys)?;
204 let converter = key_converter(&self.keys)?;
205 let mine = key_rows(&converter, &self.keys)?;
206 let index: HashMap<_, _> = mine.iter().enumerate().map(|(i, row)| (row, i)).collect();
207 let theirs = key_rows(&converter, keys)?;
208 Ok(theirs.iter().map(|row| index.get(&row).copied()).collect())
209 }
210
211 pub(crate) fn check_key_schema(&self, keys: &RecordBatch) -> Result<()> {
212 let (mine, theirs) = (self.keys.schema(), keys.schema());
213 let same = mine.fields().len() == theirs.fields().len()
214 && mine
215 .fields()
216 .iter()
217 .zip(theirs.fields())
218 .all(|(a, b)| a.name() == b.name() && a.data_type() == b.data_type());
219 if same {
220 Ok(())
221 } else {
222 Err(Error::KeySchemaMismatch)
223 }
224 }
225
226 #[allow(clippy::type_complexity)]
229 fn join(
230 &self,
231 other: &ArrowRleBatch,
232 how: How,
233 ) -> Result<(Vec<(usize, usize)>, Vec<(Option<usize>, Option<usize>)>)> {
234 self.check_key_schema(&other.keys)?;
235 let converter = key_converter(&self.keys)?;
236 let (rows_a, rows_b) = (
237 key_rows(&converter, &self.keys)?,
238 key_rows(&converter, &other.keys)?,
239 );
240 let index_a: HashMap<_, _> = rows_a.iter().enumerate().map(|(i, row)| (row, i)).collect();
241 let index_b: HashMap<_, _> = rows_b.iter().enumerate().map(|(j, row)| (row, j)).collect();
242
243 let (mut sources, mut pairs) = (Vec::new(), Vec::new());
244 for (i, row) in rows_a.iter().enumerate() {
245 let j = index_b.get(&row).copied();
246 if j.is_some() || matches!(how, How::Outer | How::Left) {
247 sources.push((0, i));
248 pairs.push((Some(i), j));
249 }
250 }
251 if matches!(how, How::Outer | How::Right) {
252 for (j, row) in rows_b.iter().enumerate() {
253 if !index_a.contains_key(&row) {
254 sources.push((1, j));
255 pairs.push((None, Some(j)));
256 }
257 }
258 }
259 Ok((sources, pairs))
260 }
261
262 pub fn zip_with<F>(
270 &self,
271 other: &ArrowRleBatch,
272 how: How,
273 fill_a: Option<&dyn Array>,
274 fill_b: Option<&dyn Array>,
275 f: F,
276 ) -> Result<ArrowRleBatch>
277 where
278 F: Fn(&dyn Array, &dyn Array) -> std::result::Result<ArrayRef, ArrowError> + Sync,
279 {
280 let (sources, pairs) = self.join(other, how)?;
281 let rles = pairs
282 .par_iter()
283 .enumerate()
284 .map(|(position, &(i, j))| {
285 let a = i.map_or_else(
286 || ArrowRle::empty(self.values.data_type()),
287 |i| self.rle_at(i),
288 );
289 let b = j.map_or_else(
290 || ArrowRle::empty(other.values.data_type()),
291 |j| other.rle_at(j),
292 );
293 a.zip_with(&b, fill_a, fill_b, &f)
294 .map_err(|e| e.in_key(position))
295 })
296 .collect::<Result<Vec<_>>>()?;
297
298 let columns = (0..self.keys.num_columns())
299 .map(|c| {
300 interleave(
301 &[self.keys.column(c).as_ref(), other.keys.column(c).as_ref()],
302 &sources,
303 )
304 })
305 .collect::<std::result::Result<Vec<_>, _>>()?;
306 let keys = RecordBatch::try_new_with_options(
307 self.keys.schema(),
308 columns,
309 &RecordBatchOptions::new().with_row_count(Some(sources.len())),
310 )?;
311 let data_type = rles
312 .first()
313 .map_or(DataType::Null, |r| r.data_type().clone());
314 let mut offsets = Vec::with_capacity(rles.len() + 1);
315 offsets.push(0);
316 let mut ends = Vec::new();
317 for rle in &rles {
318 ends.extend_from_slice(&rle.ends);
319 offsets.push(ends.len());
320 }
321 let values = concat_values(&rles, &data_type)?;
322 Self::from_parts_unchecked(keys, offsets, ends, values)
323 }
324
325 pub fn to_record_batch(&self) -> Result<RecordBatch> {
329 let mut key_index = Vec::with_capacity(self.ends.len());
330 let mut starts = Vec::with_capacity(self.ends.len());
331 for (k, w) in self.offsets.windows(2).enumerate() {
332 let mut prev = 0;
333 for &end in &self.ends[w[0]..w[1]] {
334 key_index.push(k as u64);
335 starts.push(prev);
336 prev = end;
337 }
338 }
339 let key_index = UInt64Array::from(key_index);
340 let mut fields: Vec<Field> = self
341 .keys
342 .schema()
343 .fields()
344 .iter()
345 .map(|f| f.as_ref().clone())
346 .collect();
347 let mut columns = self
348 .keys
349 .columns()
350 .iter()
351 .map(|c| take(c.as_ref(), &key_index, None))
352 .collect::<std::result::Result<Vec<_>, _>>()?;
353 fields.push(Field::new("start", DataType::Int64, false));
354 fields.push(Field::new("end", DataType::Int64, false));
355 fields.push(Field::new("value", self.values.data_type().clone(), true));
356 columns.push(Arc::new(Int64Array::from(starts)));
357 columns.push(Arc::new(Int64Array::from(self.ends.clone())));
358 columns.push(self.values.clone());
359 Ok(RecordBatch::try_new_with_options(
360 Arc::new(Schema::new(fields)),
361 columns,
362 &RecordBatchOptions::new().with_row_count(Some(self.ends.len())),
363 )?)
364 }
365
366 pub fn zip_with_default(&self, other: &ArrowRleBatch, f: Kernel) -> Result<ArrowRleBatch> {
369 self.op(other, f)
370 }
371
372 fn op(&self, other: &ArrowRleBatch, f: Kernel) -> Result<ArrowRleBatch> {
373 let fill_a = default_fill(self.values.data_type());
374 let fill_b = default_fill(other.values.data_type());
375 self.zip_with(other, How::Outer, fill_a.as_deref(), fill_b.as_deref(), f)
376 }
377}
378
379crate::kernels::kernel_methods!(
380 ArrowRleBatch,
381 " Keys are outer-joined and shorter sides padded with [`default_fill`]."
382);
383
384impl PartialEq for ArrowRleBatch {
385 fn eq(&self, other: &Self) -> bool {
387 self.keys == other.keys && self.iter().zip(other.iter()).all(|(a, b)| a == b)
388 }
389}