1use std::collections::HashMap;
2use std::sync::Arc;
3
4use arrow_array::cast::AsArray;
5use arrow_array::types::Int64Type;
6use arrow_array::{
7 Array, ArrayRef, ArrowPrimitiveType, Int64Array, LargeListArray, PrimitiveArray, RecordBatch,
8 RecordBatchOptions, StringArray, UInt64Array,
9};
10use arrow_buffer::{OffsetBuffer, ScalarBuffer};
11use arrow_schema::{DataType, Field, Schema};
12use arrow_select::take::take;
13use rayon::prelude::*;
14use runlength::{Rle, RleBatch};
15
16use crate::batch::{ArrowRleBatch, key_converter, key_rows};
17use crate::error::{Error, Result};
18use crate::numeric::with_numeric_type;
19use crate::rle::ArrowRle;
20
21fn to_array<T: ArrowPrimitiveType>(values: Vec<T::Native>) -> ArrayRef {
22 Arc::new(PrimitiveArray::<T>::new(ScalarBuffer::from(values), None))
23}
24
25fn native<T: ArrowPrimitiveType>(values: &dyn Array) -> Result<&[T::Native]> {
26 if values.null_count() > 0 {
27 return Err(Error::UnexpectedNulls);
28 }
29 Ok(values.as_primitive::<T>().values())
30}
31
32pub fn coverage(
39 starts: &[i64],
40 ends: &[i64],
41 values: Option<&dyn Array>,
42 length: Option<i64>,
43) -> Result<ArrowRle> {
44 let Some(values) = values else {
45 let rle = runlength::coverage_count(starts, ends, length)?;
46 return Ok(ArrowRle::from_rle::<Int64Type>(&rle));
47 };
48 with_numeric_type!(values, |T| {
49 let rle = runlength::coverage_sum(starts, ends, native::<T>(values)?, length)?;
50 Ok(ArrowRle::from_rle::<T>(&rle))
51 })
52}
53
54#[derive(Clone, Copy, Debug, PartialEq, Eq)]
56pub enum Agg {
57 Sum,
59 Count,
61 Max,
63 Min,
65}
66
67fn from_options<T: ArrowPrimitiveType>(rle: Rle<Option<T::Native>>) -> ArrowRle {
68 let (ends, values) = rle.into_parts();
69 ArrowRle::try_new(
70 ends,
71 Arc::new(values.into_iter().collect::<PrimitiveArray<T>>()),
72 )
73 .expect("a core sequence has valid ends")
74}
75
76fn strings_from_options(rle: Rle<Option<&str>>) -> ArrowRle {
77 let (ends, values) = rle.into_parts();
78 ArrowRle::try_new(ends, Arc::new(values.into_iter().collect::<StringArray>()))
79 .expect("a core sequence has valid ends")
80}
81
82fn core_extreme<V>(
84 starts: &[i64],
85 ends: &[i64],
86 values: &[V],
87 length: Option<i64>,
88 max: bool,
89) -> runlength::Result<Rle<Option<V>>>
90where
91 V: PartialOrd + Clone + runlength::Identical,
92{
93 if max {
94 runlength::coverage_max(starts, ends, values, length)
95 } else {
96 runlength::coverage_min(starts, ends, values, length)
97 }
98}
99
100fn extreme(
102 starts: &[i64],
103 ends: &[i64],
104 values: &dyn Array,
105 length: Option<i64>,
106 max: bool,
107) -> Result<ArrowRle> {
108 if let Some(strings) = values.as_string_opt::<i32>() {
109 if strings.null_count() > 0 {
110 return Err(Error::UnexpectedNulls);
111 }
112 let strings: Vec<&str> = strings.iter().map(|s| s.expect("no nulls")).collect();
113 return Ok(strings_from_options(core_extreme(
114 starts, ends, &strings, length, max,
115 )?));
116 }
117 with_numeric_type!(values, |T| {
118 Ok(from_options::<T>(core_extreme(
119 starts,
120 ends,
121 native::<T>(values)?,
122 length,
123 max,
124 )?))
125 })
126}
127
128pub fn coverage_agg(
134 starts: &[i64],
135 ends: &[i64],
136 values: Option<&dyn Array>,
137 length: Option<i64>,
138 agg: Agg,
139) -> Result<ArrowRle> {
140 let values = match (agg, values) {
141 (Agg::Count, _) => return coverage(starts, ends, None, length),
142 (_, Some(values)) => values,
143 (_, None) => return Err(Error::MissingValues),
144 };
145 match agg {
146 Agg::Sum => with_numeric_type!(values, |T| {
147 let rle = runlength::coverage_sum_opt(starts, ends, native::<T>(values)?, length)?;
148 Ok(from_options::<T>(rle))
149 }),
150 Agg::Max => extreme(starts, ends, values, length, true),
151 Agg::Min => extreme(starts, ends, values, length, false),
152 Agg::Count => unreachable!("handled above"),
153 }
154}
155
156pub fn coverage_agg_by_key(
159 keys: &RecordBatch,
160 starts: &[i64],
161 ends: &[i64],
162 values: Option<&dyn Array>,
163 agg: Agg,
164) -> Result<ArrowRleBatch> {
165 if agg == Agg::Count {
166 return coverage_by_key(keys, starts, ends, None);
167 }
168 let values = values.ok_or(Error::MissingValues)?;
169 let (ids, first_rows) = group_rows(keys)?;
170 let groups = group_indices(&ids, first_rows.len());
171 let rles = groups
172 .par_iter()
173 .map(|idx| {
174 let starts: Vec<i64> = idx.iter().map(|&i| starts[i]).collect();
175 let ends: Vec<i64> = idx.iter().map(|&i| ends[i]).collect();
176 let indices = UInt64Array::from_iter_values(idx.iter().map(|&i| i as u64));
177 let values = take(values, &indices, None)?;
178 coverage_agg(&starts, &ends, Some(values.as_ref()), None, agg)
179 })
180 .collect::<Result<Vec<_>>>()?;
181 let first_rows = UInt64Array::from(first_rows);
182 let columns = keys
183 .columns()
184 .iter()
185 .map(|c| take(c.as_ref(), &first_rows, None))
186 .collect::<std::result::Result<Vec<_>, _>>()?;
187 let keys = RecordBatch::try_new(keys.schema(), columns)?;
188 let data_type = rles
189 .first()
190 .map_or(DataType::Null, |r| r.data_type().clone());
191 ArrowRleBatch::from_rles(keys, rles, &data_type)
192}
193
194fn group_indices(ids: &[usize], n: usize) -> Vec<Vec<usize>> {
195 let mut groups = vec![Vec::new(); n];
196 for (i, &g) in ids.iter().enumerate() {
197 groups[g].push(i);
198 }
199 groups
200}
201
202fn group_rows(keys: &RecordBatch) -> Result<(Vec<usize>, Vec<u64>)> {
205 let converter = key_converter(keys)?;
206 let rows = key_rows(&converter, keys)?;
207 let mut groups = HashMap::new();
208 let mut first_rows = Vec::new();
209 let ids = rows
210 .iter()
211 .enumerate()
212 .map(|(i, row)| {
213 *groups.entry(row).or_insert_with(|| {
214 first_rows.push(i as u64);
215 first_rows.len() - 1
216 })
217 })
218 .collect();
219 Ok((ids, first_rows))
220}
221
222fn into_arrow_batch<T: ArrowPrimitiveType>(
223 keys: &RecordBatch,
224 first_rows: Vec<u64>,
225 batch: RleBatch<usize, T::Native>,
226) -> Result<ArrowRleBatch> {
227 let first_rows = UInt64Array::from(first_rows);
228 let columns = keys
229 .columns()
230 .iter()
231 .map(|c| take(c.as_ref(), &first_rows, None))
232 .collect::<std::result::Result<Vec<_>, _>>()?;
233 let keys = RecordBatch::try_new(keys.schema(), columns)?;
234 let (_, offsets, ends, values) = batch.into_parts();
235 ArrowRleBatch::from_parts_unchecked(keys, offsets, ends, to_array::<T>(values))
236}
237
238pub fn coverage_by_key(
244 keys: &RecordBatch,
245 starts: &[i64],
246 ends: &[i64],
247 values: Option<&dyn Array>,
248) -> Result<ArrowRleBatch> {
249 let (ids, first_rows) = group_rows(keys)?;
250 let Some(values) = values else {
251 let batch = runlength::coverage_count_by_key(&ids, starts, ends)?;
252 return into_arrow_batch::<Int64Type>(keys, first_rows, batch);
253 };
254 with_numeric_type!(values, |T| {
255 let batch = runlength::coverage_sum_by_key(&ids, starts, ends, native::<T>(values)?)?;
256 into_arrow_batch::<T>(keys, first_rows, batch)
257 })
258}
259
260pub fn overlap_plan_by_key(
269 keys: &RecordBatch,
270 starts: &[i64],
271 ends: &[i64],
272) -> Result<RecordBatch> {
273 let (ids, first_rows) = group_rows(keys)?;
274 let (groups, plans) = runlength::overlap_plan_by_key(&ids, starts, ends)?;
275 debug_assert!(groups.iter().enumerate().all(|(i, &g)| i == g));
276 let segments: usize = plans.iter().map(|p| p.num_segments()).sum();
277 let mut key_rows = Vec::with_capacity(segments);
278 let mut seg_starts = Vec::with_capacity(segments);
279 let mut seg_ends = Vec::with_capacity(segments);
280 let mut list_offsets = Vec::with_capacity(segments + 1);
281 list_offsets.push(0i64);
282 let mut items = Vec::new();
283 for (plan, &row) in plans.iter().zip(&first_rows) {
284 let mut prev = 0;
285 for s in 0..plan.num_segments() {
286 key_rows.push(row);
287 seg_starts.push(prev);
288 seg_ends.push(plan.ends[s]);
289 prev = plan.ends[s];
290 items.extend(plan.ids(s).iter().map(|&i| i as i64));
291 list_offsets.push(items.len() as i64);
292 }
293 }
294 let key_rows = UInt64Array::from(key_rows);
295 let mut columns = keys
296 .columns()
297 .iter()
298 .map(|c| take(c.as_ref(), &key_rows, None))
299 .collect::<std::result::Result<Vec<_>, _>>()?;
300 let mut fields: Vec<Field> = keys
301 .schema()
302 .fields()
303 .iter()
304 .map(|f| f.as_ref().clone())
305 .collect();
306 let item = Arc::new(Field::new("item", DataType::Int64, false));
307 fields.push(Field::new("start", DataType::Int64, false));
308 fields.push(Field::new("end", DataType::Int64, false));
309 fields.push(Field::new("ids", DataType::LargeList(item.clone()), false));
310 columns.push(Arc::new(Int64Array::from(seg_starts)));
311 columns.push(Arc::new(Int64Array::from(seg_ends)));
312 columns.push(Arc::new(LargeListArray::new(
313 item,
314 OffsetBuffer::new(ScalarBuffer::from(list_offsets)),
315 Arc::new(Int64Array::from(items)),
316 None,
317 )));
318 Ok(RecordBatch::try_new_with_options(
319 Arc::new(Schema::new(fields)),
320 columns,
321 &RecordBatchOptions::new().with_row_count(Some(segments)),
322 )?)
323}