This is an automated email from the ASF dual-hosted git repository.
Jefffrey pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git
The following commit(s) were added to refs/heads/main by this push:
new c8aff1ef5f Support Utf8View and BinaryView Ranking (#10559)
c8aff1ef5f is described below
commit c8aff1ef5ff804b94cbc38d71ff9135f862efb81
Author: Dhruv Vaishnav <[email protected]>
AuthorDate: Wed Aug 5 19:13:07 2026 +0530
Support Utf8View and BinaryView Ranking (#10559)
# Which issue does this PR close?
- Closes #7859.
# Rationale for this change
`rank` supports the standard UTF-8 and binary array representations, but
not their view variants. Adding support makes ranking available for
`Utf8View` and `BinaryView` arrays as well.
# What changes are included in this PR?
- Add `Utf8View` and `BinaryView` to the rankable data types.
- Dispatch both view types through a shared `GenericByteViewArray`
ranking path.
- Add coverage for inline values, out-of-line values, duplicates, and
null handling.
# Are these changes tested?
Yes. The following checks pass:
- `cargo fmt --all -- --check`
- `cargo test -p arrow-ord`
- `cargo clippy -p arrow-ord --all-targets --all-features -- -D
warnings`
- `git diff --check`
# Are there any user-facing changes?
`Utf8View` and `BinaryView` arrays can now be passed to `rank`. There
are no breaking API changes.
# AI assistance
OpenAI Codex assisted with codebase inspection, implementation, test
creation, and validation. The submitter remains responsible for
reviewing, understanding, and maintaining the contribution.
---------
Co-authored-by: Jeffrey Vo <[email protected]>
---
arrow-ord/src/rank.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 57 insertions(+), 2 deletions(-)
diff --git a/arrow-ord/src/rank.rs b/arrow-ord/src/rank.rs
index 252a41a4da..a4808b93fb 100644
--- a/arrow-ord/src/rank.rs
+++ b/arrow-ord/src/rank.rs
@@ -20,7 +20,8 @@
use arrow_array::cast::AsArray;
use arrow_array::types::*;
use arrow_array::{
- Array, ArrowNativeTypeOp, BooleanArray, GenericByteArray,
downcast_primitive_array,
+ Array, ArrowNativeTypeOp, BooleanArray, GenericByteArray,
GenericByteViewArray,
+ downcast_primitive_array,
};
use arrow_buffer::NullBuffer;
use arrow_schema::{ArrowError, DataType, SortOptions};
@@ -36,6 +37,8 @@ pub(crate) fn can_rank(data_type: &DataType) -> bool {
| DataType::LargeUtf8
| DataType::Binary
| DataType::LargeBinary
+ | DataType::Utf8View
+ | DataType::BinaryView
)
}
@@ -60,6 +63,8 @@ pub fn rank(array: &dyn Array, options: Option<SortOptions>)
-> Result<Vec<u32>,
DataType::LargeUtf8 => bytes_rank(array.as_bytes::<LargeUtf8Type>(),
options),
DataType::Binary => bytes_rank(array.as_bytes::<BinaryType>(),
options),
DataType::LargeBinary =>
bytes_rank(array.as_bytes::<LargeBinaryType>(), options),
+ DataType::Utf8View => byte_view_rank(array.as_string_view(), options),
+ DataType::BinaryView => byte_view_rank(array.as_binary_view(),
options),
d => return Err(ArrowError::ComputeError(format!("{d:?} not supported
in rank")))
};
Ok(ranks)
@@ -96,6 +101,23 @@ fn bytes_rank<T: ByteArrayType>(array:
&GenericByteArray<T>, options: SortOption
rank_impl(array.len(), to_sort, options, Ord::cmp, PartialEq::eq)
}
+#[inline(never)]
+fn byte_view_rank<T: ByteViewType>(
+ array: &GenericByteViewArray<T>,
+ options: SortOptions,
+) -> Vec<u32> {
+ let to_sort: Vec<(&[u8], u32)> = match array.nulls().filter(|n|
n.null_count() > 0) {
+ Some(n) => n
+ .valid_indices()
+ .map(|idx| (array.value(idx).as_ref(), idx as u32))
+ .collect(),
+ None => (0..array.len())
+ .map(|idx| (array.value(idx).as_ref(), idx as u32))
+ .collect(),
+ };
+ rank_impl(array.len(), to_sort, options, Ord::cmp, PartialEq::eq)
+}
+
fn rank_impl<T, C, E>(
len: usize,
mut valid: Vec<(T, u32)>,
@@ -349,13 +371,46 @@ mod tests {
let res = rank(&values, None).unwrap();
assert_eq!(res, &[4, 3, 2, 2]);
+ let values = StringViewArray::from(v);
+ let res = rank(&values, None).unwrap();
+ assert_eq!(res, &[4, 3, 2, 2]);
+
let v: Vec<&[u8]> = vec![&[1, 2], &[0], &[1, 2, 3], &[1, 2]];
let values = LargeBinaryArray::from(v.clone());
let res = rank(&values, None).unwrap();
assert_eq!(res, &[3, 1, 4, 3]);
- let values = BinaryArray::from(v);
+ let values = BinaryArray::from(v.clone());
let res = rank(&values, None).unwrap();
assert_eq!(res, &[3, 1, 4, 3]);
+
+ let values = BinaryViewArray::from_iter_values(v);
+ let res = rank(&values, None).unwrap();
+ assert_eq!(res, &[3, 1, 4, 3]);
+ }
+
+ #[test]
+ fn test_string_view_with_nulls() {
+ let values = StringViewArray::from(vec![
+ Some("a string longer than twelve bytes"),
+ Some("bar"),
+ None,
+ Some("a string longer than twelve bytes"),
+ ]);
+ let res = rank(&values, None).unwrap();
+ assert_eq!(res, &[3, 4, 1, 3]);
+ }
+
+ #[test]
+ fn test_binary_view_with_nulls() {
+ let long_value = b"a binary value longer than twelve bytes".as_ref();
+ let values = BinaryViewArray::from_iter([
+ Some(long_value),
+ Some(b"bar".as_ref()),
+ None,
+ Some(long_value),
+ ]);
+ let res = rank(&values, None).unwrap();
+ assert_eq!(res, &[3, 4, 1, 3]);
}
}