yggdrasil.spark.cast¶
cast ¶
Spark <-> Arrow casting helpers and converters.
This module provides bidirectional type-mapping and data-casting between
Apache Spark (PySpark) and Apache Arrow (PyArrow). Every public function
accepts an optional CastOptions argument that carries the target schema
and a safe flag:
safe=True(default) – best-effort: invalid casts becomenull/ empty values; missing columns are filled with type-appropriate defaults.safe=False– strict: any type mismatch or missing column raises immediately.
The module is structured in three layers:
- Type converters – stateless, pure functions that map Arrow ↔ Spark type objects without touching any data.
- Field / schema converters – wrap type converters to also carry name, nullability, and metadata.
- Data converters – operate on live Spark DataFrames / Columns using the type information from layers 1-2.
JSON decoding for compound targets¶
When the source column is StringType or BinaryType and the target
type is a compound type (struct, array, or map), the casters automatically
attempt to parse the column as JSON using from_json before applying
field-level / element-level casting. This handles the common commodity-data
pattern where nested structures are stored as JSON strings in a flat column
(e.g. a STRING column containing '{"bid":99.5,"ask":100.0}').
BinaryTypesources are decoded to UTF-8 string first viaCAST(... AS STRING).- Spark's
from_jsonsilently returnsnullfor rows whose JSON is malformed or structurally incompatible — consistent withsafe=Truesemantics. Insafe=Falsemode callers can enforce non-nullability on the result via the standard null-fill machinery.
spark_dataframe_to_arrow ¶
Materialize df as a pa.Table, working on PySpark 3 and 4.
PySpark 4.x added the native :meth:pyspark.sql.DataFrame.toArrow
helper that we prefer when available — single driver-side collect
that round-trips through Arrow IPC. Older releases (3.x) don't
expose it; we fall back to the streaming
:meth:toArrowBatchIterator API when present, and finally to a
pandas round-trip.
Both Arrow paths can fail at the JVM level on Java 17+ when the
cluster JVM was started without the sun.misc.Unsafe /
java.nio.DirectByteBuffer --add-opens flags
(IllegalAccessException deep inside the Spark allocator). We
catch that and fall back to toPandas so callers see a working
table instead of a JVM stack trace. The pandas path itself
benefits from Spark's Arrow optimization when the session has
spark.sql.execution.arrow.pyspark.enabled=true.
Centralizing the polyfill here keeps callers from sprinkling
hasattr(df, "toArrow") and exception-handling boilerplate
throughout the codebase.
spark_dataframe_to_pandas ¶
Public alias for :func:_to_pandas_no_arrow.
Same JVM-Arrow-bypass behavior; exposed so tests and callers that just want a pandas DataFrame don't have to round-trip through Arrow or hand-roll the same conf-toggle dance.