yggdrasil.data.record¶
record ¶
Single-row materialization with a singleton :class:Schema reference.
A :class:Record is a :class:collections.abc.Mapping over one row's
values, keyed by field name. The schema is shared by reference
across sibling rows — a stream of N records carries one
:class:Schema and N value tuples, not N (Schema, values) pairs.
That keeps row materialization cheap when the same schema repeats
across millions of rows (the only real use case).
:class:Record is the natural unit returned by
:meth:Tabular.read_records and consumed by
:meth:Tabular.write_records. Subclasses with a richer row shape
(SQL row, Spark Row, etc.) should still satisfy the Mapping contract
so callers don't need to know the concrete origin.
Record ¶
Bases: Mapping[str, Any]
Single row, keyed by field name, sharing a :class:Schema.
The Mapping protocol gives callers record[name],
record.get(name, default), in, keys(), values(),
items(), and len() without any extra surface. Positional
integer access (record[0]) is supported as a convenience for
fast-path callers that already know the field index.
Construction:
Record((v0, v1, v2), schema)— values aligned withschema.fieldsorder.Record({"a": 1, "b": 2}, schema)— dict re-aligned toschema.fieldsorder; missing keys land asNone.
The schema is taken by reference — pass the same :class:Schema
instance across a stream of rows to keep allocation flat.
from_arrow_batches
classmethod
¶
from_arrow_batches(
batches: Iterable[RecordBatch], *, schema: "Schema | None" = None
) -> Iterator["Record"]
Yield :class:Record s from an Arrow-batch stream.
The first batch's schema becomes the singleton :class:Schema
all yielded records share, unless one is passed explicitly.
Per-row values are materialized via column[i].as_py() —
cheap for primitive columns, expensive for nested types. If
you only need a few columns, project the batch first.
from_spark_frame
classmethod
¶
from_spark_frame(
frame: "SparkDataFrame", *, schema: "Schema | None" = None
) -> Iterator["Record"]
Yield :class:Record s from a Spark DataFrame.
Rows stream lazily through frame.toLocalIterator() — the
DataFrame is never collected as a whole, so the driver stays
memory-bounded for large frames. The :class:Schema is
derived once from :meth:Field.from_spark (or taken
explicitly) and shared by reference across every yielded
record.
Per-row values come from row.asDict(recursive=True) so
nested structs land as plain Python dicts / lists, matching
the Arrow-batch path's as_py() conventions instead of
leaving Spark Row objects in the field values.