Skip to content

Commit febcf28

Browse files
committed
Decode dictionary-encoded arrays before bucket transform
1 parent 2c75523 commit febcf28

2 files changed

Lines changed: 40 additions & 2 deletions

File tree

pyiceberg/transforms.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,17 @@ def _cast_if_needed(arr: "ArrayLike") -> "ArrayLike":
145145
else:
146146
return arr
147147

148+
def _decode_if_dict(arr: "pa.Array") -> "pa.Array":
149+
if isinstance(arr.type, pa.DictionaryType):
150+
return arr.dictionary_decode()
151+
return arr
152+
148153
if isinstance(array, pa.Array):
149-
return _cast_if_needed(transform_func(array, *args))
154+
return _cast_if_needed(transform_func(_decode_if_dict(array), *args))
150155
elif isinstance(array, pa.ChunkedArray):
151156
result_chunks = []
152157
for arr in array.iterchunks():
153-
result_chunks.append(_cast_if_needed(transform_func(arr, *args)))
158+
result_chunks.append(_cast_if_needed(transform_func(_decode_if_dict(arr), *args)))
154159
return pa.chunked_array(result_chunks)
155160
else:
156161
raise ValueError(f"PyArrow array can only be of type pa.Array or pa.ChunkedArray, but found {type(array)}")

tests/test_transforms.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1682,6 +1682,39 @@ def test_bucket_pyarrow_void_transform() -> None:
16821682
assert output_arr == VoidTransform().pyarrow_transform(IntegerType())(input_arr)
16831683

16841684

1685+
# Regression test for https://github.com/apache/iceberg-python/issues/3633
1686+
@pytest.mark.parametrize(
1687+
"source_type, input_arr, expected, num_buckets",
1688+
[
1689+
(
1690+
StringType(),
1691+
pa.array(["foo", "bar", "foo"], type=pa.dictionary(pa.int32(), pa.utf8())),
1692+
pa.array([6, 7, 6], type=pa.int32()),
1693+
10,
1694+
),
1695+
(
1696+
StringType(),
1697+
pa.chunked_array(
1698+
[
1699+
pa.array(["foo", "bar"], type=pa.dictionary(pa.int32(), pa.utf8())),
1700+
pa.array(["baz"], type=pa.dictionary(pa.int32(), pa.utf8())),
1701+
]
1702+
),
1703+
pa.chunked_array([pa.array([6, 7], type=pa.int32()), pa.array([4], type=pa.int32())]),
1704+
10,
1705+
),
1706+
],
1707+
)
1708+
def test_bucket_pyarrow_transform_dictionary_encoded(
1709+
source_type: PrimitiveType,
1710+
input_arr: pa.Array | pa.ChunkedArray,
1711+
expected: pa.Array | pa.ChunkedArray,
1712+
num_buckets: int,
1713+
) -> None:
1714+
transform: Transform[Any, Any] = BucketTransform(num_buckets=num_buckets)
1715+
assert expected == transform.pyarrow_transform(source_type)(input_arr)
1716+
1717+
16851718
@pytest.mark.parametrize(
16861719
"source_type, input_arr, expected, width",
16871720
[

0 commit comments

Comments
 (0)