Documentation
¶
Overview ¶
Package gobi is a geospatial dataframe library for Go, built on Apache Arrow.
A DataFrame is a set of named, equal-length Series backed by Arrow columns. Geometry columns are stored as Well-Known Binary (WKB) in Arrow Binary arrays and marked as geometries in the schema metadata (following the GeoParquet convention). This keeps gobi interoperable with other Arrow- aware tools without a custom extension type registry.
Reading data ¶
df, err := gobi.ReadCSV("cities.csv", nil)
df, err := gobi.ReadParquet("cities.parquet")
Selecting columns and rows ¶
col, _ := df.Column("name")
head, _ := df.Head(10)
Working with geometries ¶
geom, _ := df.Geometry("geometry", 0) // decode the WKB at row 0
See the subpackages for more:
- geometry: 2D primitives, WKB/WKT, CRS, area/distance/hull
- csvio: typed CSV read/write
- parquetio: Parquet + GeoParquet read/write, LazyFrame scan
- geojsonio: GeoJSON encoding/decoding for individual features
- gpkgio: OGC GeoPackage read/write with RTree spatial index
- kmlio: KML read/write with ExtendedData attributes
- shpio: ESRI Shapefile read/write
Index ¶
- Constants
- Variables
- func Aligned(meta *PartitionMetadata, columns []string) bool
- func AlignedWith(l, r *PartitionMetadata) bool
- func CanPossiblyMatch(pred Expr, stats Stats) bool
- func ExprToSQL(e Expr) (string, []any, bool)
- func GeoParquetSchemaWithMetadata(schema *arrow.Schema, meta *GeoParquetMetadata) (*arrow.Schema, error)
- func GeometryField(name string, epsg int32) arrow.Field
- func MarshalGeoParquetMetadata(meta *GeoParquetMetadata) (string, error)
- func MaxParallelism() int
- func SetMaxParallelism(n int)
- func ToStructs[T any](f *Frame) ([]T, error)
- type AggKind
- type Aggregation
- type Aggregator
- type CalendarUnit
- type ExecOperator
- type Expr
- func Coalesce(exprs ...Expr) Expr
- func Col(name string) Expr
- func Custom(node ExprNode) Expr
- func HaversineExpr(lat1, lon1, lat2, lon2 Expr, u geometry.Unit) Expr
- func If(cond, a, b Expr) Expr
- func Lit(v any) Expr
- func LitEmptyList(elemType arrow.DataType) Expr
- func LitNull(dtype arrow.DataType) Expr
- func SplitConjuncts(e Expr) []Expr
- func (e Expr) Add(o Expr) Expr
- func (e Expr) Alias(name string) Expr
- func (e Expr) And(o Expr) Expr
- func (e Expr) BitAnd(o Expr) Expr
- func (e Expr) BitOr(o Expr) Expr
- func (e Expr) BitXor(o Expr) Expr
- func (e Expr) Cast(target arrow.DataType) Expr
- func (e Expr) Count() Expr
- func (e Expr) Div(o Expr) Expr
- func (e Expr) Eq(o Expr) Expr
- func (e Expr) Ge(o Expr) Expr
- func (e Expr) Gt(o Expr) Expr
- func (e Expr) IsNotNull() Expr
- func (e Expr) IsNull() Expr
- func (e Expr) Le(o Expr) Expr
- func (e Expr) ListContains(elem any) Expr
- func (e Expr) ListFirst() Expr
- func (e Expr) ListGet(i int) Expr
- func (e Expr) ListLast() Expr
- func (e Expr) ListLen() Expr
- func (e Expr) ListMax() Expr
- func (e Expr) ListMean() Expr
- func (e Expr) ListMin() Expr
- func (e Expr) ListSlice(start, stop int) Expr
- func (e Expr) ListSum() Expr
- func (e Expr) ListUnion(other Expr) Expr
- func (e Expr) Lt(o Expr) Expr
- func (e Expr) MaxAgg() Expr
- func (e Expr) Mean() Expr
- func (e Expr) Median() Expr
- func (e Expr) MinAgg() Expr
- func (e Expr) Mode() Expr
- func (e Expr) Mul(o Expr) Expr
- func (e Expr) Ne(o Expr) Expr
- func (e Expr) Node() ExprNode
- func (e Expr) Not() Expr
- func (e Expr) Or(o Expr) Expr
- func (e Expr) Over(partitionCols ...string) Expr
- func (e Expr) OverOrdered(partitionCols []string, orderBy ...SortKey) Expr
- func (e Expr) Shift(n int) Expr
- func (e Expr) String() string
- func (e Expr) Sub(o Expr) Expr
- func (e Expr) Sum() Expr
- func (e Expr) UnixNano() Expr
- type ExprNode
- type Frame
- func (f *Frame) Column(name string) (Series, error)
- func (f *Frame) ColumnAt(i int) (Series, error)
- func (f *Frame) ColumnNames() []string
- func (f *Frame) Concat(others ...*Frame) (*Frame, error)
- func (f *Frame) Difference(other *Frame, cols ...string) (*Frame, error)
- func (f *Frame) DropColumn(name string) (*Frame, error)
- func (f *Frame) Explode(col string) (*Frame, error)
- func (f *Frame) Filter(mask Series) (*Frame, error)
- func (f *Frame) FilterExpr(e Expr) (*Frame, error)
- func (f *Frame) Geometry(colName string, row int) (any, error)
- func (f *Frame) GroupBy(keys ...string) (*GroupBy, error)
- func (f *Frame) Head(n int) *Frame
- func (f *Frame) Intersect(other *Frame, cols ...string) (*Frame, error)
- func (f *Frame) Join(right *Frame, leftKey, rightKey string, kind JoinType) (*Frame, error)
- func (f *Frame) Lazy() *LazyFrame
- func (f *Frame) NumCols() int
- func (f *Frame) NumRows() int
- func (f *Frame) PartitionMetadata() *PartitionMetadata
- func (f *Frame) Pivot(index, columns, values string, agg AggKind) (*Frame, error)
- func (f *Frame) Release()
- func (f *Frame) Rename(old, new string) (*Frame, error)
- func (f *Frame) ResampleEvery(timeCol string, interval time.Duration) (*Resampler, error)
- func (f *Frame) Retain()
- func (f *Frame) RollingBy(timeCol string, period time.Duration) (*TimeRolling, error)
- func (f *Frame) Row(i int) (*Frame, error)
- func (f *Frame) SJoin(right *Frame, leftGeomCol, rightGeomCol string, pred SpatialPredicate, ...) (*Frame, error)
- func (f *Frame) Schema() *arrow.Schema
- func (f *Frame) SelectCols(names ...string) (*Frame, error)
- func (f *Frame) Shape() (rows, cols int)
- func (f *Frame) SortBy(keys ...SortKey) (*Frame, error)
- func (f *Frame) String() string
- func (f *Frame) Table() arrow.Table
- func (f *Frame) Tail(n int) *Frame
- func (f *Frame) Take(indexes []int) (*Frame, error)
- func (f *Frame) Union(other *Frame, cols ...string) (*Frame, error)
- func (f *Frame) Unique(cols ...string) (*Frame, error)
- func (f *Frame) ValueCounts(col string) (*Frame, error)
- func (f *Frame) WithColumn(name string, s Series) (*Frame, error)
- func (f *Frame) WithColumnExpr(name string, e Expr) (*Frame, error)
- func (f *Frame) WithPartitionMeta(meta *PartitionMetadata) *Frame
- type GeoParquetColumnMeta
- type GeoParquetMetadata
- type GroupBy
- type IncrementalAggregator
- type JoinType
- type LazyFrame
- func (lf *LazyFrame) Collect() (*Frame, error)
- func (lf *LazyFrame) CollectRaw() (*Frame, error)
- func (lf *LazyFrame) DropColumn(name string) *LazyFrame
- func (lf *LazyFrame) Explain() string
- func (lf *LazyFrame) ExplainOptimized() string
- func (lf *LazyFrame) ExplainPhysical() string
- func (lf *LazyFrame) Explode(col string) *LazyFrame
- func (lf *LazyFrame) Filter(cond Expr) *LazyFrame
- func (lf *LazyFrame) GroupBy(keys ...string) *LazyGroupBy
- func (lf *LazyFrame) Head(n int) *LazyFrame
- func (lf *LazyFrame) Join(right *LazyFrame, leftKey, rightKey string, kind JoinType) *LazyFrame
- func (lf *LazyFrame) Limit(n int) *LazyFrame
- func (lf *LazyFrame) Optimize() LogicalPlan
- func (lf *LazyFrame) PartitionMetadata() *PartitionMetadata
- func (lf *LazyFrame) Plan() LogicalPlan
- func (lf *LazyFrame) Rename(old, new string) *LazyFrame
- func (lf *LazyFrame) Schema() *arrow.Schema
- func (lf *LazyFrame) Select(exprs ...Expr) *LazyFrame
- func (lf *LazyFrame) SelectCols(names ...string) *LazyFrame
- func (lf *LazyFrame) SortBy(keys ...SortKey) *LazyFrame
- func (lf *LazyFrame) Tail(n int) *LazyFrame
- func (lf *LazyFrame) WithColumn(name string, e Expr) *LazyFrame
- func (lf *LazyFrame) WithPartitionAssertion(assertion *PartitionMetadata) (*LazyFrame, error)
- type LazyGroupBy
- type LogicalPlan
- type Namer
- type Option
- type PartitionMetadata
- type PredicateSink
- type ProjectableScan
- type Resampler
- type Rule
- type ScanOption
- func WithColumnProjection(fn func(cols []string) LogicalPlan) ScanOption
- func WithParallelStreamReads(fn func() []func(cb func(*Frame) error) error) ScanOption
- func WithPartitionMetadata(meta *PartitionMetadata) ScanOption
- func WithPredicatePushdown(fn func(pred Expr) LogicalPlan) ScanOption
- func WithStreamRead(fn func(cb func(*Frame) error) error) ScanOption
- type Series
- func (s Series) Add(o Series) (Series, error)
- func (s Series) AddDuration(d time.Duration) (Series, error)
- func (s Series) AddScalar(v float64) (Series, error)
- func (s Series) Bools() ([]bool, error)
- func (s Series) Column() *arrow.Column
- func (s Series) Concat(others ...Series) (Series, error)
- func (s Series) Count() int
- func (s Series) DataType() arrow.DataType
- func (s Series) Day() (Series, error)
- func (s Series) DayOfYear() (Series, error)
- func (s Series) Diff(n int) (Series, error)
- func (s Series) DiffDuration(other Series) (Series, error)
- func (s Series) Difference(other Series) (Series, error)
- func (s Series) Div(o Series) (Series, error)
- func (s Series) DivScalar(v float64) (Series, error)
- func (s Series) Eq(o Series) (Series, error)
- func (s Series) EqScalar(v float64) (Series, error)
- func (s Series) EqTime(t time.Time) (Series, error)
- func (s Series) Float32Values() ([]float32, bool)
- func (s Series) Float32s() ([]float32, error)
- func (s Series) Float64Values() ([]float64, bool)
- func (s Series) Float64s() ([]float64, error)
- func (s Series) Ge(o Series) (Series, error)
- func (s Series) GeTime(t time.Time) (Series, error)
- func (s Series) GeomArea(u geometry.Unit) (Series, error)
- func (s Series) GeomBounds() (*Frame, error)
- func (s Series) GeomCentroid() (Series, error)
- func (s Series) GeomLength(u geometry.Unit) (Series, error)
- func (s Series) Geometry(i int) (geometry.Geometry, error)
- func (s Series) Gt(o Series) (Series, error)
- func (s Series) GtScalar(v float64) (Series, error)
- func (s Series) GtTime(t time.Time) (Series, error)
- func (s Series) HasNulls() bool
- func (s Series) Head(n int) Series
- func (s Series) Hour() (Series, error)
- func (s Series) Int32Values() ([]int32, bool)
- func (s Series) Int32s() ([]int32, error)
- func (s Series) Int64Values() ([]int64, bool)
- func (s Series) Int64s() ([]int64, error)
- func (s Series) Intersect(other Series) (Series, error)
- func (s Series) IsDateTime() bool
- func (s Series) IsGeometry() bool
- func (s Series) Le(o Series) (Series, error)
- func (s Series) LeTime(t time.Time) (Series, error)
- func (s Series) Len() int
- func (s Series) Lt(o Series) (Series, error)
- func (s Series) LtScalar(v float64) (Series, error)
- func (s Series) LtTime(t time.Time) (Series, error)
- func (s Series) Max() (float64, error)
- func (s Series) Mean() (float64, error)
- func (s Series) Min() (float64, error)
- func (s Series) Minute() (Series, error)
- func (s Series) Month() (Series, error)
- func (s Series) Mul(o Series) (Series, error)
- func (s Series) MulScalar(v float64) (Series, error)
- func (s Series) NUnique() (int64, error)
- func (s Series) Name() string
- func (s Series) Ne(o Series) (Series, error)
- func (s Series) NeTime(t time.Time) (Series, error)
- func (s Series) NullCount() int
- func (s Series) Nulls() []bool
- func (s Series) RollingCount(window int) (Series, error)
- func (s Series) RollingMax(window int) (Series, error)
- func (s Series) RollingMean(window int) (Series, error)
- func (s Series) RollingMin(window int) (Series, error)
- func (s Series) RollingSum(window int) (Series, error)
- func (s Series) Row(i int) (Series, error)
- func (s Series) Second() (Series, error)
- func (s Series) Shift(n int) (Series, error)
- func (s Series) Strings() ([]string, error)
- func (s Series) Sub(o Series) (Series, error)
- func (s Series) SubDuration(d time.Duration) (Series, error)
- func (s Series) SubScalar(v float64) (Series, error)
- func (s Series) Sum() (float64, error)
- func (s Series) Tail(n int) Series
- func (s Series) TimeAt(i int) (time.Time, bool, error)
- func (s Series) Timestamps() ([]arrow.Timestamp, error)
- func (s Series) Timezone() string
- func (s Series) TruncateTo(unit TimeUnit) (Series, error)
- func (s Series) TruncateToCalendar(unit CalendarUnit) (Series, error)
- func (s Series) Uint32Values() ([]uint32, bool)
- func (s Series) Uint32s() ([]uint32, error)
- func (s Series) Uint64Values() ([]uint64, bool)
- func (s Series) Uint64s() ([]uint64, error)
- func (s Series) Union(other Series) (Series, error)
- func (s Series) Unique() (Series, error)
- func (s Series) Weekday() (Series, error)
- func (s Series) WithTimezone(tz string) (Series, error)
- func (s Series) Year() (Series, error)
- type SortKey
- type SpatialPredicate
- type Stats
- type TimeRolling
- type TimeUnit
Constants ¶
const ( GeoParquetVersion = "1.1.0" // GeoParquetMetadataKey is the file-level metadata key used by GeoParquet. GeoParquetMetadataKey = "geo" )
GeoParquetVersion is the GeoParquet spec version this package emits.
const ( MetaGeometryType = "gobi:geometry_type" MetaGeometryCRS = "gobi:crs_epsg" )
Schema metadata keys used by gobi to tag geometry columns. This follows the GeoParquet convention closely enough that files written by gobi should be readable by other GeoParquet-aware tools for primitive geometry types.
const SJoinMinParallelRows = 1024
SJoinMinParallelRows is the smallest left-frame size at which SJoin will spawn goroutines. Below this, the sequential path is used to avoid scheduling overhead swamping the useful work.
Variables ¶
var ( ErrColumnNotFound = errors.New("gobi: column not found") ErrColumnLenMismatch = errors.New("gobi: column length mismatch") ErrColumnTypeMismatch = errors.New("gobi: column type mismatch") ErrRowOutOfRange = errors.New("gobi: row index out of range") ErrEmptyFrame = errors.New("gobi: empty dataframe") ErrNotGeometry = errors.New("gobi: column is not a geometry column") ErrExprTypeMismatch = errors.New("gobi: expression type mismatch") ErrUnsupportedLiteral = errors.New("gobi: unsupported literal type") )
var ErrMaskNotBoolean = fmt.Errorf("gobi: filter mask must be a boolean series")
ErrMaskNotBoolean is returned when Filter receives a non-boolean Series.
var ErrNotDateTime = fmt.Errorf("gobi: series is not a datetime column")
ErrNotDateTime is returned when a time-only op is attempted on a Series that is not a Timestamp / Date32 / Date64 column.
var ErrNotMonotonic = fmt.Errorf("gobi: time column must be monotonically non-decreasing")
ErrNotMonotonic is returned by ops that require a time column sorted in non-decreasing order (currently: Frame.RollingBy).
var ErrNotNumeric = fmt.Errorf("gobi: series is not numeric")
ErrNotNumeric is returned when arithmetic is attempted on a non-numeric Series. Only int64/int32/float64/float32 are currently supported.
var ErrUnsupportedStructField = errors.New("gobi: unsupported struct field type")
ErrUnsupportedStructField is returned when FromStructs / ToStructs encounters a struct field type it can't map to an arrow column. The error is wrap-friendly: errors.Is(err, ErrUnsupportedStructField) is true for every type-mapping failure.
Functions ¶
func Aligned ¶ added in v0.2.0
func Aligned(meta *PartitionMetadata, columns []string) bool
Aligned reports whether meta's partition claim colocates rows by the given columns — the shape the optimizer needs to prove that .Over(K) / GroupBy(K) / hash-partition-aware Aggregate can skip the cross-worker shuffle.
First-cut rule (v1): exact match only. meta must be non-nil, meta.Columns must equal columns in order, and meta's HashFn is otherwise unconstrained (any hash — including "" for value partitioning — is fine for a single-source alignment check; two-source alignment for partition-wise join uses AlignedWith).
Refuses aliasing (via FDs), subset matching (Over("A") on a hash(A, B) partition), and column-order permutations. Users who need looser matches go through LazyFrame.WithPartitionAssertion and own correctness.
func AlignedWith ¶ added in v0.2.0
func AlignedWith(l, r *PartitionMetadata) bool
AlignedWith reports whether two partition claims describe the same physical partitioning — same ordered Columns AND same HashFn. Consumed by the partition-wise Join rule (both sides must be partitioned on the join key by a byte-equal hash for a shuffle-free join to be safe).
Both metas must be non-nil with non-empty Columns; empty-Columns claims explicitly represent "no partitioning" and never align with anything.
func CanPossiblyMatch ¶
CanPossiblyMatch reports whether pred could be satisfied by any row in the range described by stats. Returns true when uncertain — false positives are safe (over-read); false negatives break correctness.
Supported predicate shapes:
- AND / OR of shapes below
- col == literal, col != literal
- col <, <=, >, >= literal
- literal on either side (auto-normalized)
Anything else (NOT, arithmetic, custom nodes) is treated as "possibly matches." Used by parquetio for row-group skipping; callable by any source package that can produce column stats.
func ExprToSQL ¶
ExprToSQL translates a gobi.Expr into a SQL fragment + a slice of bind arguments suitable for parameterized SQL queries (SQLite, PostgreSQL / PostGIS, DuckDB, etc.).
Returns ok=false when the expression contains a node the translator can't represent: custom nodes (Custom), aliased sub-expressions inside a predicate, or any binary op that doesn't map cleanly to SQL. Callers that get ok=false should fall back to evaluating the expression in the executor rather than pushing it into SQL.
The emitted SQL uses positional `?` placeholders for every literal, matching the SQLite driver contract that gpkgio uses. Drivers that expect `$1`/`$2` (pgx) or `:name` (Oracle) can rewrite the placeholders trivially since the args slice is 1:1 with `?` order.
Column names are double-quoted per SQL:2016 identifier rules; any embedded double-quote in a name is escaped by doubling. NULL comparisons (`x = NULL`) are rewritten to `IS NULL` / `IS NOT NULL` to match SQL's null-safe semantics.
Example:
e := gobi.Col("price").Mul(gobi.Lit(1.08)).Gt(gobi.Lit(100.0))
sql, args, ok := gobi.ExprToSQL(e)
// sql = `(("price" * ?) > ?)`
// args = []any{1.08, 100.0}
// ok = true
func GeoParquetSchemaWithMetadata ¶
func GeoParquetSchemaWithMetadata(schema *arrow.Schema, meta *GeoParquetMetadata) (*arrow.Schema, error)
GeoParquetSchemaWithMetadata returns a copy of schema with the given GeoParquet metadata injected under the "geo" key at the file level.
func GeometryField ¶
GeometryField returns a schema field tagged as a WKB geometry column. Pass epsg=0 to leave the CRS unset.
func MarshalGeoParquetMetadata ¶
func MarshalGeoParquetMetadata(meta *GeoParquetMetadata) (string, error)
MarshalGeoParquetMetadata serializes meta to JSON.
func MaxParallelism ¶
func MaxParallelism() int
MaxParallelism returns the current package-level default worker count. Returns 0 if unset (in which case operations use GOMAXPROCS).
func SetMaxParallelism ¶
func SetMaxParallelism(n int)
SetMaxParallelism sets the default max worker count for every parallel gobi operation across the process. Pass 0 (the default) to defer to GOMAXPROCS. Individual calls can override with the Workers option.
Negative values are treated as zero.
func ToStructs ¶ added in v0.1.1
ToStructs converts a Frame back to a slice of Go structs, using the same struct-tag conventions as FromStructs.
Columns are matched to fields by name (resolved via the `csv:"..."` tag or field name). A struct field with no matching column stays at its zero value. A frame column with no matching struct field is ignored.
Null cells populate the zero value for non-pointer fields, or nil for pointer fields. Type mismatches between column and field return an error.
Geometry columns (Binary with the geometry metadata) can be written back to a string field tagged `geom:"true"` (emits WKT via geometry.WKT()) or a []byte field tagged `geom:"true"` (raw WKB pass-through).
Types ¶
type AggKind ¶
type AggKind uint8
AggKind identifies an aggregation operation.
const ( AggCount AggKind = iota AggSum AggMean AggMin AggMax // AggFirst / AggLast: first (or last) non-null value in the // group, in the group's row order. Output type matches the source // column (preserved via the Frame's schema). AggFirst AggLast // AggStd / AggVar: sample standard deviation / variance // (Bessel-corrected, n-1 denominator). Streaming path uses // Welford's online algorithm. Empty or single-row groups emit // null. AggStd AggVar // AggNUnique: count of distinct non-null values per group. Output // is Int64, always non-null (empty group counts as 0). AggNUnique // AggMedian: 50th-percentile value. Output is Float64 (Bessel- // style interpolation between the two middle values on even // group sizes). Empty groups emit null. Buffers all non-null // values per group, so memory is proportional to input size. AggMedian // AggMode: most frequent non-null value. Output preserves the // source column's arrow type. Ties broken by first-seen order. // Empty groups (or all-null groups) emit null. AggMode )
type Aggregation ¶
type Aggregation struct {
Column string
Kind AggKind
Alias string
Fn Aggregator
// Filter is an optional predicate expression. When non-zero
// (Filter.node != nil), only rows where Filter evaluates to
// TRUE (non-null) participate in this aggregation. Different
// aggregations in the same Agg call may carry different
// filters — each is applied independently to that agg's row
// set. Polars-parity `pl.col("x").sum().filter(cond)`.
//
// Filtered aggregations currently route through the eager
// GroupBy.Agg path (the streaming aggregate rejects them via
// allBuiltInAggs, forcing the materializing fallback). This
// keeps the streaming hot path unchanged for filter-free
// workloads.
Filter Expr
}
Aggregation names a column to aggregate and how to aggregate it. The resulting column in the aggregated frame is named Alias (or, if empty, "<column>_<kind>" for built-in kinds, "<column>_<Fn.Name()>" for custom aggregators).
When Fn is non-nil, it takes precedence over Kind: the aggregation is user-defined and Fn is called once per group. Otherwise Kind selects a built-in aggregation.
type Aggregator ¶
type Aggregator interface {
Aggregate(s Series, rows []int) (any, error)
Merge(other Aggregator) error
Type() arrow.DataType
Name() string
}
Aggregator is a user-defined aggregation function called once per group during GroupBy.Agg. Implementations reduce the rows of a Series to a single scalar value.
Typical implementations:
weighted mean, mode, percentile / quantile, log-sum-exp, first / last, geospatial reductions (H3 cell of the centroid, dominant hex), string aggregations (concat, longest common prefix).
Return nil from Aggregate to emit an Arrow null for the group. The declared Type must match the concrete Go type Aggregate returns:
Float64 → float64 Uint64 → uint64 String → string Float32 → float32 Uint32 → uint32 Binary → []byte Int64 → int64 Boolean → bool Timestamp → arrow.Timestamp Int32 → int32
If the returned dynamic type doesn't match Type, Agg reports an error naming the offending Aggregation.
Aggregate is called sequentially per group; the same Aggregator instance is reused across groups. Implementations that need per-group scratch space should allocate it inside Aggregate rather than as receiver fields.
Merge combines the state of a peer Aggregator (one that has been fed a disjoint subset of the same group's rows via Aggregate) into the receiver. It exists so future parallel modes — rolling windows, pipeline-parallel executors, task parallelism — can partition a group's rows across workers and still assemble a correct result. gobi's v0.2 hash-partitioned executor never splits a group across workers, so Merge is not called on the current parallel path; it is still required so users don't have to guess whether they'll need it later. Implementations that don't carry state across Aggregate calls (e.g. stateless "return first non-null") can implement Merge as a no-op returning nil.
State lifecycle: the eager engine reuses a single Aggregator instance across every group, so implementations must reset internal state at the start of Aggregate — the receiver is fresh-per-group from the caller's perspective. Merge is called by parallel/window executors that deliberately hand the receiver a peer instance whose state should be combined; the framework never mixes state across groups.
func NewInt32SetAggregator ¶ added in v0.2.4
func NewInt32SetAggregator() Aggregator
NewInt32SetAggregator returns an Aggregator that collects distinct non-null int32 values per group into a `List<Int32>` column. Input column must be `arrow.INT32`.
func NewInt64SetAggregator ¶ added in v0.2.4
func NewInt64SetAggregator() Aggregator
NewInt64SetAggregator returns an Aggregator that collects distinct non-null int64 values per group into a `List<Int64>` column. Input column must be `arrow.INT64`.
func NewStringSetAggregator ¶ added in v0.2.4
func NewStringSetAggregator() Aggregator
NewStringSetAggregator returns an Aggregator that collects distinct non-null string values per group into a `List<String>` column. Input column must be `arrow.STRING`.
func NewUint32SetAggregator ¶ added in v0.2.4
func NewUint32SetAggregator() Aggregator
NewUint32SetAggregator returns an Aggregator that collects distinct non-null uint32 values per group into a `List<Uint32>` column. Input column must be `arrow.UINT32`.
func NewUint64SetAggregator ¶ added in v0.2.4
func NewUint64SetAggregator() Aggregator
NewUint64SetAggregator returns an Aggregator that collects distinct non-null uint64 values per group into a `List<Uint64>` column. Input column must be `arrow.UINT64`. Common h3 cell-id shape.
type CalendarUnit ¶
type CalendarUnit uint8
CalendarUnit selects a calendar-aware truncation granularity for Series.TruncateToCalendar.
const ( CalendarWeek CalendarUnit = iota // ISO week: truncate to the previous Monday 00:00 CalendarMonth // truncate to the first day of the month at 00:00 CalendarYear // truncate to Jan 1 at 00:00 )
type ExecOperator ¶
type ExecOperator interface {
// Next returns the next batch. When no more batches are available
// it returns (nil, io.EOF). Callers must Release the returned
// batch when done.
Next(ctx context.Context) (arrow.RecordBatch, error)
// Schema is the operator's output schema. Stable across all
// batches; safe to call before Next has been called.
Schema() *arrow.Schema
// Close releases resources held by the operator AND its upstream
// operators. Idempotent — safe to call multiple times. Called by
// Execute at the end of a plan, so hand-written test drivers
// usually don't need to call it explicitly.
Close() error
}
ExecOperator is a pull-based iterator over arrow record batches. Each call to Next produces the next batch of rows (or io.EOF when the operator has exhausted its input); the returned batch is owned by the caller and must be Released when no longer needed.
Operators can be composed into a tree: `filterExec` wraps another ExecOperator as its input and yields filtered batches; `scanFrameExec` is a leaf that produces batches from a source Frame. The plan compiler (Compile) turns a LogicalPlan into such a tree.
Layer 6 (vectorized execution) is the migration from the whole- Frame-per-node dispatch in lazy.go's collectPlan to batch-streaming through operators. Slice 1 lands the interface + streaming filter / project / limit / with-column / drop and a materializing fallback for blocking ops (Sort, Aggregate, Join, Tail); those still route to the eager engine internally but see one input Frame instead of a per-step re-materialization.
func Compile ¶
func Compile(p LogicalPlan) (ExecOperator, error)
Compile translates a LogicalPlan tree into a tree of ExecOperators ready for streaming execution via Execute.
The mapping is one-to-one for streaming operators (Filter → filterExec, Project → projectExec, and so on). Blocking operators (Sort, Aggregate, Join, Tail) compile to a materializeExec that pulls its upstream to a Frame and delegates the actual computation to the existing eager engine. This keeps Layer 6 slice 1 focused on the execution model itself; later slices can replace each materializeExec with a native streaming implementation.
Compile itself does no I/O and starts no goroutines. Scan operators that use a background producer (scanFileExec) start their goroutine on construction, so callers should always follow Compile with Execute or the operator's Close to avoid leaks.
type Expr ¶
type Expr struct {
// contains filtered or unexported fields
}
Expr is an expression tree — a value that describes a computation without performing it. Build expressions with the package-level constructors (Col, Lit, Custom) and combine them with the fluent methods on Expr (Add, Mul, Gt, And, etc.).
Expressions evaluate lazily: nothing runs until Frame.FilterExpr or Frame.WithColumnExpr consumes them. Because the tree is data, it can be inspected, printed, and (in a future release) rewritten by an optimizer before evaluation.
Example:
// (price * 1.08) > 100
e := gobi.Col("price").Mul(gobi.Lit(1.08)).Gt(gobi.Lit(100.0))
filtered, err := df.FilterExpr(e)
func Coalesce ¶ added in v0.2.5
Coalesce returns an expression that evaluates to the first non-null value among exprs, per row. Matches SQL COALESCE / polars `coalesce()`. All operands must produce the same arrow type — no automatic widening; cast explicitly or match Lit types.
If every operand is null at a given row, the output at that row is null too. Zero operands or a single operand each error at construction time (zero) or degenerate to a passthrough (single).
Common use — fill nulls on either side of a Full outer join before running ListUnion:
segSafe := gobi.Coalesce(gobi.Col("seg"), gobi.LitEmptyList(arrow.BinaryTypes.String))
pingSafe := gobi.Coalesce(gobi.Col("ping"), gobi.LitEmptyList(arrow.BinaryTypes.String))
merged := segSafe.ListUnion(pingSafe)
Not short-circuit: every operand is evaluated in full. If short- circuit matters (e.g. an expensive right-hand operand you only want on rows where the left is null), split into filtered pipelines.
func Custom ¶
Custom wraps a user-defined ExprNode into an Expr. This is the entry point for extending gobi with your own expression types.
func HaversineExpr ¶ added in v0.2.10
HaversineExpr returns an expression that computes the great-circle distance between two lon/lat point columns, in the requested unit. Composes with Shift(1).Over(K) for prev-row coordinate lookups, so per-segment ground-track distance is expressible entirely in LazyFrame land:
speedKMH := HaversineExpr(
Col("lat"), Col("lon"),
Col("lat").Shift(1).Over("eid"),
Col("lon").Shift(1).Over("eid"),
geometry.UnitKilometers,
).Div(Col("delta_hours"))
Argument order is (lat1, lon1, lat2, lon2) — the pair-per-side grouping matches how coordinates are usually named in a source dataset. Internally the call routes to geometry.Haversine (which takes lon first), so a mistake in ordering here surfaces as silently-wrong distances, not an error. Types are checked at Compile time (all four operands must be Float64).
Nulls in any of the four inputs propagate to a null output. Errors at Eval time if a column isn't Float64.
func If ¶ added in v0.2.4
If returns an expression that evaluates to a where cond is true, to b where cond is false, and to null where cond is null (SQL CASE-WHEN semantics). All three arguments are evaluated in full — this is not short-circuit. If short-circuit evaluation matters (e.g. one branch would error on rows the other branch handles), split into two filtered pipelines.
cond must produce a Boolean column. a and b must have the same arrow output type — no automatic numeric widening in v1. To combine mixed numeric types write `gobi.If(cond, gobi.Lit(1.0), gobi.Col("x"))` where "x" is Float64, or add a Cast on one side.
Example — mean-fill a nullable column:
gobi.If(gobi.Col("x").IsNull(), gobi.Col("x_mean"), gobi.Col("x"))
Nested else-if via chained If is supported:
gobi.If(
gobi.Col("region").Eq(gobi.Lit("EU")), gobi.Lit(1.08),
gobi.If(
gobi.Col("region").Eq(gobi.Lit("NA")), gobi.Lit(1.10),
gobi.Lit(1.0), // default
),
)
func Lit ¶
Lit returns an expression that evaluates to a constant value. The value's arrow type is inferred from its Go type; the following are supported:
bool → Boolean int, int32, int64 → Int64 float32, float64 → Float64 string → String
Other Go types return an Expr whose Eval reports a type-inference error. For a typed-null literal (e.g. a null-of-type-String column), use LitNull.
func LitEmptyList ¶ added in v0.2.5
LitEmptyList returns an expression that broadcasts a non-null empty list of the given element type to every input row. Companion to LitNull for the "coalesce null-list to empty-list" pattern that makes ListUnion usable across a full outer join:
segSafe := gobi.Coalesce(gobi.Col("seg_providers"), gobi.LitEmptyList(arrow.BinaryTypes.String))
pingSafe := gobi.Coalesce(gobi.Col("ping_providers"), gobi.LitEmptyList(arrow.BinaryTypes.String))
merged := segSafe.ListUnion(pingSafe)
LitNull(ListOf(t)) produces all-NULL lists per row; LitEmptyList(t) produces all-non-null empty lists per row. Different — the latter gets ListUnion past its null-propagation gate.
func LitNull ¶ added in v0.2.4
LitNull returns an expression that broadcasts a null value of the given arrow type to every input row. Useful for filling a column with typed nulls (e.g. when unioning two branches where one side legitimately lacks a value):
pings.WithColumn("provider", gobi.LitNull(arrow.BinaryTypes.String))
The type must be one that builderForType supports (every primitive gobi handles today plus List / Struct). Passing an unsupported type surfaces the error at Eval, not at construction.
func SplitConjuncts ¶
SplitConjuncts breaks an expression at top-level AND boundaries so callers can push the pieces that translate to SQL individually and keep the rest for post-scan filtering.
Example: given `(a > 5 AND custom_fn(b) AND c = "x")`, SplitConjuncts yields `[a > 5, custom_fn(b), c = "x"]`. The custom_fn part won't translate; the other two will, and the caller can push `a > 5 AND c = "x"` into SQL while leaving `custom_fn(b)` in the executor.
Non-AND expressions come back as a single-element slice — a top-level OR isn't safe to split (both sides must match), so we don't try.
func (Expr) Alias ¶
Alias renames the output column produced by e. Only used by Frame.WithColumnExpr and future SelectExpr — has no effect inside FilterExpr.
func (Expr) BitAnd ¶ added in v0.2.10
BitAnd returns the bitwise AND of two integer columns (or an integer column and an integer literal). Both operands must be integer-typed (Int32/Int64/Uint32/Uint64); errors at Type-check time otherwise. Common shape: unpacking a packed-flags Int64 column into per-bit indicator columns, e.g.
Col("flags").BitAnd(Lit(int64(1 << 3))).Ne(Lit(int64(0)))
func (Expr) BitOr ¶ added in v0.2.10
BitOr returns the bitwise OR of two integer columns / literals. Same type rules as BitAnd.
func (Expr) BitXor ¶ added in v0.2.10
BitXor returns the bitwise XOR of two integer columns / literals. Same type rules as BitAnd.
func (Expr) Cast ¶ added in v0.2.9
Cast returns an expression that converts the inner column to the given arrow data type. Numeric-to-numeric conversions are supported today; string / boolean / date-time conversions are follow-ups.
Supported source→target combinations (v1, numeric-to-numeric only):
- Float64 ← {Float32, Int64, Int32, Uint64, Uint32}
- Int64 ← {Float64, Float32, Int32, Uint32}
- Float32 ← {Float64, Int64, Int32}
- Int32 ← {Int64, Float64, Float32}
- Uint64 ← {Int64, Uint32}
- Uint32 ← {Uint64, Int64}
Same-type is a no-op (returns the input). Unsupported combinations error at Eval with a clear message.
Numeric widening carries values exactly. Narrowing (Int64→Int32, Float64→Int64, etc.) truncates without overflow-checking — mirrors Go's numeric conversion semantics. Nulls propagate: a null row in the source produces a null row in the output.
Primary motivating use case is unlocking numeric widening in If / Coalesce, which require exact type match otherwise:
gobi.If(cond, gobi.Col("int_col").Cast(arrow.PrimitiveTypes.Float64),
gobi.Lit(1.5))
func (Expr) Count ¶ added in v0.2.0
Count returns an expression that evaluates to the count of e's non-null values, broadcast to every input row. Output is Int64.
func (Expr) IsNotNull ¶ added in v0.2.3
IsNotNull returns a Boolean expression that is true where e evaluates to a non-null value. Semantic complement of IsNull.
func (Expr) IsNull ¶ added in v0.2.3
IsNull returns a Boolean expression that is true where e evaluates to null, false everywhere else. The returned column itself is never null.
Composes with Filter / WithColumn / Select and with the boolean combinators (And, Or, Not):
// Rows where price is missing.
f.FilterExpr(gobi.Col("price").IsNull())
// Rows where price is set AND qty is missing.
f.FilterExpr(gobi.Col("price").IsNotNull().And(gobi.Col("qty").IsNull()))
func (Expr) ListContains ¶ added in v0.2.0
ListContains returns an expression that reports whether each row's list contains elem. Null lists → null; otherwise Boolean. elem is a Go scalar (bool, int/int64, float32/float64, string) matching the list's element type.
func (Expr) ListFirst ¶ added in v0.2.0
ListFirst returns the first element of each row's list. Alias for ListGet(0) — kept as a distinct constructor to match polars/pandas naming conventions.
func (Expr) ListGet ¶ added in v0.2.0
ListGet returns an expression that reads the element at index i from each row's list. Negative i counts from the end (-1 = last). Out-of-range indices, null lists, and null elements all evaluate to null. The result type is the list's element type.
func (Expr) ListLast ¶ added in v0.2.0
ListLast returns the last element of each row's list. Alias for ListGet(-1).
func (Expr) ListLen ¶ added in v0.2.0
ListLen returns an expression that evaluates each row's list length. e must produce a List column. Null lists → null; empty lists → 0.
func (Expr) ListMax ¶ added in v0.2.0
ListMax returns the maximum non-null element of each row's list. Output widens like ListMin.
func (Expr) ListMean ¶ added in v0.2.0
ListMean returns the arithmetic mean of each row's non-null list elements. Always Float64. Null / empty lists produce null.
func (Expr) ListMin ¶ added in v0.2.0
ListMin returns the minimum non-null element of each row's list. Output widens to Int64 / Uint64 / Float64 per element category. Null / empty lists produce null.
func (Expr) ListSlice ¶ added in v0.2.0
ListSlice returns an expression that slices each row's list to [start, stop). Python-style semantics: negative indices count from the end; out-of-range endpoints clamp to the list bounds. The result is still a List column.
func (Expr) ListSum ¶ added in v0.2.0
ListSum returns an expression that sums each row's list elements. Null lists and empty lists produce null. Null elements are skipped (polars-parity). Signed integer element types widen to Int64; unsigned to Uint64; floats to Float64.
func (Expr) ListUnion ¶ added in v0.2.4
ListUnion returns an expression that unions each row's list with the corresponding row of other's list, deduplicating elements. Both e and other must be List<T> columns with the same element type.
Order semantics: first-seen order preserved. Elements from e come first (in their order), then any new elements from other in their order.
Null semantics: null elements inside a list are skipped. A null list itself (either side) makes the whole row null — polars / Spark array_union parity. Users who want "treat null as empty set" should wrap with a coalesce-to-empty step upstream.
Polars parity: pl.col("a").list.set_union(pl.col("b")). Spark parity: array_union(a, b).
func (Expr) MaxAgg ¶ added in v0.2.0
MaxAgg returns an expression that evaluates to the maximum of e's non-null values, broadcast to every input row.
func (Expr) Mean ¶ added in v0.2.0
Mean returns an expression that evaluates to the arithmetic mean of e's non-null values, broadcast to every input row.
func (Expr) Median ¶ added in v0.2.9
Median returns an expression that evaluates to the sample median of e's non-null numeric values, broadcast to every input row. Output is Float64. Even-sized groups interpolate between the two middle values.
func (Expr) MinAgg ¶ added in v0.2.0
MinAgg returns an expression that evaluates to the minimum of e's non-null values, broadcast to every input row. Named MinAgg to avoid clashing with Series.Min-shaped methods that already exist.
func (Expr) Mode ¶ added in v0.2.9
Mode returns an expression that evaluates to the most-frequent non-null value of e, broadcast to every input row. Ties are broken by first-seen order. Output type matches the source column.
func (Expr) Node ¶
Node returns the underlying ExprNode. Rarely needed unless you're implementing your own tree walker or optimizer.
func (Expr) Over ¶ added in v0.2.0
Over wraps an expression with partition keys.
Two shapes are supported depending on the inner:
**Scalar aggregate inner** (Sum/Mean/Min/Max/Count on a column): the aggregate is computed per unique partition-key combination and broadcast to every row in that group. This is the reduce- and-scatter shape gobi has had since v0.2.0.
**Shape-preserving inner** (Shift, arithmetic chains like `Col("v").Add(Lit(1.0))`, and other row-order-preserving ExprNodes): the inner is evaluated separately on each partition's rows and the per-row output is scattered back to the original row positions. Input row order is preserved within each partition (polars-parity default).
If the shape-preserving transform is row-order sensitive (e.g. Shift) and you need a specific within-partition order, use OverOrdered — this variant does not sort within partitions.
func (Expr) OverOrdered ¶ added in v0.2.2
OverOrdered is Over with an explicit within-partition sort order. Rows in each partition are sorted by orderBy (multi-key, stable, nulls-last, per-key Descending) before the shape-preserving inner runs on them. Output row order matches input row order — the sort only affects what "previous row" / "next row" mean inside each partition.
For scalar aggregate inners the orderBy is ignored (Sum, Mean, Min, Max, Count are order-invariant).
Example: previous v within each K, ordered by t.
Col("v").Shift(1).OverOrdered([]string{"K"}, gobi.SortKey{Column: "t"})
func (Expr) Shift ¶ added in v0.2.1
Shift returns an expression that shifts the values of e by n positions. Positive n shifts forward (the first n rows become null, each output row i takes the source value from row i-n). Negative n shifts backward. Matches Series.Shift semantics.
Composes naturally with WithColumn / Select for lag / lead computations:
// prior period's price
lf.WithColumn("prev_price", Col("price").Shift(1))
// running delta
lf.WithColumn("delta", Col("price").Sub(Col("price").Shift(1)))
Per-group shifts via .Over(K) are on the roadmap; today Over requires a scalar aggregate as its immediate inner, so shift-then-partition isn't wired up (see CLAUDE.md's Track 3 note on ordered-partition windows).
func (Expr) Sum ¶ added in v0.2.0
Sum returns an expression that evaluates to the sum of e's non-null values, broadcast to every input row. Combine with Over to get per-partition sums.
func (Expr) UnixNano ¶ added in v0.2.10
UnixNano returns an expression that converts a Timestamp column to Int64 nanoseconds since the Unix epoch, normalizing across the source column's TimeUnit (Second / Millisecond / Microsecond / Nanosecond). Distinct from `Cast(Int64)` on a Timestamp — that returns the raw underlying value in the source unit; UnixNano always scales to nanoseconds.
Combines with arithmetic to derive time-delta expressions inline without leaving LazyFrame land:
// ts_hours = float64 hours-since-epoch
Col("ts").UnixNano().Cast(arrow.PrimitiveTypes.Float64).
Div(Lit(float64(time.Hour)))
Nulls propagate. Errors at Eval time if the source isn't a Timestamp column.
type ExprNode ¶
type ExprNode interface {
// Eval evaluates the expression against input, returning a Series
// whose values are the result. The returned Series should have
// length equal to input.NumRows(). Scalar broadcasts are handled
// by the caller for built-in nodes; custom nodes may either
// broadcast internally or emit a length-1 Series.
Eval(input *Frame) (Series, error)
// Type returns the arrow data type of the result given the input
// schema. Called by type-inference passes before evaluation.
Type(schema *arrow.Schema) (arrow.DataType, error)
// Children returns the sub-expressions of this node in
// deterministic order (empty for leaves). Used by tree walkers.
Children() []Expr
// String returns a human-readable representation of the node.
String() string
}
ExprNode is the interface every expression node implements. Users extending gobi with custom expression types (H3 encoding, hashes, ML inference, etc.) implement this and wrap the result with Custom.
type Frame ¶
type Frame struct {
// contains filtered or unexported fields
}
Frame is a columnar dataset: an Arrow schema plus a set of named Series.
The API mirrors GeoPandas / Polars in shape: Shape, Head, Tail, Row, Column, and geometry helpers.
func Concat ¶
Concat is the package-level counterpart to Frame.Concat: stacks rows from every frame in-order, no dedupe. Useful when the caller holds a []*Frame and doesn't want the `frames[0].Concat(frames[1:]...)` dance the method form requires.
Errors when frames is empty (there's nothing to return a schema from) or when any two frames have incompatible schemas — same rules as Frame.Concat.
func Execute ¶
func Execute(ctx context.Context, op ExecOperator) (*Frame, error)
Execute drives op to EOF, gathers every batch, and assembles them into a single-chunk *Frame. Closes op unconditionally.
This is the terminal entry point for the streaming executor: LazyFrame.Collect calls Compile + Execute. Callers that want to consume batches directly (streaming ETL) should walk op.Next in a loop themselves — but that's a lower-level API not yet exposed.
func FromStructs ¶ added in v0.1.1
FromStructs builds a Frame from a slice of Go structs. Column order follows struct-field declaration order; unexported fields are ignored.
Struct-tag conventions (shared with csvio):
csv:"col" override the column name (default: field name)
geom:"true" geometry column — see below for value handling
time:"2006-01-02" parse string field as time.Time using the layout;
ignored for time.Time-typed fields
Geometry handling. A field tagged `geom:"true"` becomes a Binary arrow column tagged with GeometryField metadata:
- string field: value is parsed as WKT via geometry.ParseWKT and emitted as WKB bytes.
- []byte field: value is emitted as-is (assumed already WKB).
- other field types: error.
Nulls. Pointer-typed fields (*string, *int64, ...) emit null when the pointer is nil. Non-pointer fields never emit null — their zero value goes in.
Supported non-tagged field types:
string, bool int, int8, int16, int32, int64 uint, uint8, uint16, uint32, uint64 float32, float64 []byte (arrow Binary) time.Time (arrow Timestamp[ns]) *T of any above (nullable)
func NewFrame ¶
NewFrame builds a Frame from a schema and a set of arrow columns. The number of columns must match the schema.
func NewFrameFromTable ¶
NewFrameFromTable adopts the columns of t.
func (*Frame) ColumnNames ¶
ColumnNames returns the column names in order.
func (*Frame) Concat ¶
Concat returns a new Frame with rows from f followed by the rows of each frame in others, in the order given. No deduplication — this is a pure row stack (SQL UNION ALL / polars vstack / pandas `concat(axis=0)`).
All frames must share the exact same schema: matching column count, order, names, and arrow types. Fingerprint mismatches return an error naming the offending column with both types so the caller can decide how to cast.
Each frame's Arrow buffers are kept alive as separate chunks of the output — no memcpy of the underlying data. The resulting Frame's columns are multi-chunk; downstream ops that assume single-chunk (like some numeric fast paths) will fall back to the general path. Call `.Coalesce()` (planned) if you need a single-chunk output.
func (*Frame) Difference ¶
Difference returns rows in f that do not appear in other, deduplicated over cols. cols nil/empty → all columns. Nulls are treated as equal.
Equivalent to SQL EXCEPT / polars' `df.filter(~col.is_in(other))` generalized to whole-row membership.
Both frames must share the exact same schema.
func (*Frame) DropColumn ¶
DropColumn returns a new Frame with the named column removed. Returns ErrColumnNotFound if no column matches. Every retained column is independently ref-counted so the caller can Release either Frame without affecting the other's buffers.
func (*Frame) Explode ¶
Explode returns a new Frame where each row of col has been split into one row per component.
Two column shapes are accepted:
- Geometry column: multi-part geometries (MultiPoint, MultiLineString, MultiPolygon, GeometryCollection) expand to one row per contained geometry. Single geometries pass through unchanged. Null rows are kept as a single null row.
- List<T> column: each element becomes its own row. The exploded column's arrow type becomes the list's element type. Null lists and empty lists both produce a single output row with a null value in the exploded column (polars-parity).
All other columns are duplicated across the exploded rows so per-row attributes propagate to every component.
func (*Frame) Filter ¶
Filter returns a new Frame containing only the rows where mask is true. Null mask entries are treated as false.
The mask length must equal the frame's row count.
func (*Frame) FilterExpr ¶
FilterExpr returns a new Frame containing the rows for which e evaluates to true. e must produce a Boolean Series; null entries in the mask are treated as false (SQL-style — matches Frame.Filter).
Example:
// Keep rows where (price * 1.08) > 100.
e := gobi.Col("price").Mul(gobi.Lit(1.08)).Gt(gobi.Lit(100.0))
out, err := df.FilterExpr(e)
func (*Frame) Geometry ¶
Geometry decodes the geometry at (row, colName). Returns ErrNotGeometry if the column is not a geometry column.
func (*Frame) Intersect ¶
Intersect returns rows that exist in both f and other, deduplicated over cols. cols nil/empty → all columns. Nulls are treated as equal (see Union for the semantics rationale).
The result draws rows + column values from f (not from other) — so if other has a row with the same key columns but different non-key values, you get f's version. This matches SQL INTERSECT and polars behavior.
Both frames must share the exact same schema.
func (*Frame) Join ¶
Join returns a new Frame formed by combining rows of f (the left frame) and right, where the left column named leftKey equals the right column named rightKey. The join key must be a hashable type (String, Int64, Int32, Bool, Uint32, Uint64, Float64, Timestamp).
The result contains all columns from the left frame followed by all columns from the right frame except the join key. Right-side columns whose names collide with left-side columns are renamed with a "_right" suffix. For JoinSemi and JoinAnti, only left-side columns appear in the output.
Null keys never match (SQL semantics). In JoinLeft, JoinFull, and JoinAnti a null-keyed left row still appears in the output; in JoinRight and JoinFull a null-keyed right row still appears; in JoinSemi and JoinInner it is filtered out.
func (*Frame) Lazy ¶
Lazy wraps f in a LazyFrame anchored at a Scan[frame] leaf. Fluent operations on the returned LazyFrame append nodes to the plan; Collect() replays them against f.
func (*Frame) NumRows ¶
NumRows returns the number of rows in the frame (0 if there are no columns).
func (*Frame) PartitionMetadata ¶ added in v0.2.0
func (f *Frame) PartitionMetadata() *PartitionMetadata
PartitionMetadata returns the partition claim carried through by Collect from the source plan node, or nil if no claim was made. Runtime consumers (Over's aligned fast path, future partition-wise join / GroupBy dispatch) check this to decide whether shuffle-skip optimizations apply.
Users constructing Frames via NewFrame get a nil claim by default. The LazyFrame → Collect path attaches whatever the root plan node's PartitionMetadata() reports. Attach explicitly via Frame.WithPartitionMeta for hand-built frames that carry a claim.
func (*Frame) Pivot ¶
Pivot reshapes a long-form Frame into a wide-form one.
- index: column whose distinct values become the rows.
- columns: column whose distinct values become the new columns.
- values: column supplying the cell values.
- agg: how to reduce when multiple input rows map to the same (index, columns) cell. Use AggFirst / AggLast if you're sure there's no collision; use AggSum / AggMean / etc. to reduce. Any built-in AggKind is accepted.
The output schema is:
<index column> | <col_value_1> | <col_value_2> | ...
Column values are stringified for use as arrow field names — the header row is always a string. The value column's arrow type follows aggOutputType(Aggregation{Kind: agg, ...}); it's Int64 for Count/NUnique and Float64 for the rest, matching what GroupBy.Agg would produce.
Cells with no matching input rows are emitted as null. Output rows are ordered by the sorted index value; output columns are ordered by the sorted distinct columns-column value so the shape is deterministic across runs.
Equivalent to `pandas.DataFrame.pivot_table(index, columns, values, aggfunc)` / polars' `DataFrame.pivot`. Multi-column pivot indices aren't supported yet — pass a single index column.
func (*Frame) Release ¶
func (f *Frame) Release()
Release decrements the reference count of the underlying Arrow columns. Callers should match every Retain (including the implicit one at construction) with exactly one Release.
func (*Frame) Rename ¶ added in v0.2.4
Rename returns a new Frame with the column named old renamed to new. Column order and buffers are preserved (the underlying arrow arrays are shared via ref-count; only the arrow.Field's Name changes).
Returns ErrColumnNotFound if old doesn't exist. If new already exists on the Frame under a different index, the returned Frame has two columns with the same name — usually an error at downstream operators. Callers who want swap-safety should DropColumn(new) first.
func (*Frame) ResampleEvery ¶
ResampleEvery returns a Resampler that will group f's rows into interval-wide buckets by the values in timeCol. The interval must be positive.
func (*Frame) Retain ¶
func (f *Frame) Retain()
Retain increments the reference count of the underlying Arrow columns.
func (*Frame) RollingBy ¶
RollingBy returns a TimeRolling. The time column must be a Timestamp series in non-decreasing order.
func (*Frame) SJoin ¶
func (f *Frame) SJoin(right *Frame, leftGeomCol, rightGeomCol string, pred SpatialPredicate, opts ...Option) (*Frame, error)
SJoin performs a spatial join of f (left) and right by evaluating pred on each pair of geometries from leftGeomCol and rightGeomCol. Only rows where pred holds are emitted. The output frame contains all columns from the left frame, followed by all columns from the right frame except its geometry column (analogous to Frame.Join dropping the right join key). Right-side column names that collide with left-side names get a "_right" suffix.
Under the hood, an R-tree is built over the right frame's geometry bounds so each left row scans only overlapping candidates. Parallelism follows the priority order documented on resolveWorkers: Workers(n) > package SetMaxParallelism > GOMAXPROCS.
func (*Frame) SelectCols ¶ added in v0.2.4
SelectCols returns a Frame containing only the named columns, in the given order. Buffers are shared with the source Frame — the returned Frame owns its own field/schema structure but the underlying arrow arrays are ref-counted.
Also handles reordering: SelectCols("b", "a") returns a Frame whose output has "b" before "a". Zero names produce an empty Frame with the same row count and no columns. Missing columns error with ErrColumnNotFound.
func (*Frame) SortBy ¶
SortBy returns a new Frame with rows arranged according to keys. The sort is stable: rows that compare equal on every key retain their input order.
Supported key column types: String, Bool, Int32, Int64, Uint32, Uint64, Float64, Float32, Timestamp. Nulls sort last.
Example:
// Chronologically by date; break ties by value descending.
out, err := df.SortBy(
gobi.SortKey{Column: "date"},
gobi.SortKey{Column: "value", Descending: true},
)
func (*Frame) String ¶
String returns a debug representation of the frame. Not intended for pretty printing at scale.
func (*Frame) Table ¶
Table returns an arrow.Table view of the frame. The returned table shares buffers with the frame — releasing one releases the other.
func (*Frame) Take ¶
Take returns a new Frame consisting of rows selected by the given indexes, in the order given. Duplicates are allowed. Out-of-range indexes produce an error.
func (*Frame) Union ¶
Union returns rows in either f or other, deduplicated over cols. When cols is nil or empty, uniqueness is determined over every column. Uses the same composite-key encoding as GroupBy so null-vs-null comparisons collide (nulls are treated as equal for set membership — pandas / polars semantics, not SQL semantics).
Both frames must share the exact same schema — see Concat for the compatibility rules and error format.
Equivalent to `f.Concat(other).Unique(cols...)` but bundled for clarity of intent.
func (*Frame) Unique ¶
Unique returns a Frame with duplicate rows removed. Uniqueness is determined by the columns listed in cols; other columns come along for the ride from the first occurrence of each distinct key.
When cols is empty, distinctness is computed over every column (SQL `DISTINCT *`). Any listed column must be a hashable arrow type (String, LargeString, Int64, Int32, Uint64, Uint32, Float64, Bool, Timestamp) — the same set GroupBy accepts.
Semantics match pandas' `df.drop_duplicates(subset=cols)` and polars' `df.unique(subset=cols)`: the result preserves the full input schema and first-occurrence order. If you only want the distinct values of a single column, use `df.Column(name).Unique()` which returns a Series.
This is the whole-frame `distinct` primitive. For per-group distinct counts, use `GroupBy(...).Agg(Aggregation{Kind: AggNUnique})`.
func (*Frame) ValueCounts ¶
ValueCounts returns a two-column Frame of (value, count) pairs counting the occurrences of each distinct value of col, sorted descending by count. Ties are broken by the value itself ascending — makes the output stable / deterministic even when several distinct values share a frequency.
The output columns are named `col` (matching the input) and `count` (Int64). Null values in the source column are counted as their own group under the null value slot — the count row for null contains a null in the value column and its count in the count column.
Equivalent to pandas' `Series.value_counts()` / polars' `Series.value_counts()`. For per-group value counts (e.g. count of role per department), you want a nested output that gobi doesn't have a schema for yet — build it via two-level GroupBy today or wait for list-typed columns.
func (*Frame) WithColumn ¶
WithColumn returns a new Frame with s appended (or replaced, if a column already exists with that name). The returned Frame independently ref-counts every column, so the caller can Release either Frame without affecting the other's buffers.
s.Len() must equal f.NumRows() unless f has zero columns.
The Series' arrow.Field is carried over — its Nullable flag, geometry metadata, and any other field-level attributes — with only the Name replaced by name. This preserves geometry-column identification when swapping in a WKB Binary column derived from a user function.
func (*Frame) WithColumnExpr ¶
WithColumnExpr returns a new Frame with e evaluated and attached under name. If a column named name already exists, it is replaced in place; otherwise it is appended.
Example:
// Add a computed column: usd_price = eur_price * 1.08
out, err := df.WithColumnExpr("usd_price",
gobi.Col("eur_price").Mul(gobi.Lit(1.08)),
)
func (*Frame) WithPartitionMeta ¶ added in v0.2.0
func (f *Frame) WithPartitionMeta(meta *PartitionMetadata) *Frame
WithPartitionMeta returns f with the given partition claim attached. Used by collectPlan to propagate plan-node metadata onto the emitted Frame; also available for hand-built frames that carry a claim (rare — most callers should compose a LazyFrame + WithPartitionAssertion instead).
Returns the same Frame receiver — this is a mutating helper on a value that's already immutable-by-convention, so callers should only call it once immediately after construction.
type GeoParquetColumnMeta ¶
type GeoParquetColumnMeta struct {
Encoding string `json:"encoding"`
GeometryTypes []string `json:"geometry_types"`
CRS map[string]any `json:"crs,omitempty"`
Bbox []float64 `json:"bbox,omitempty"`
}
GeoParquetColumnMeta is the per-column entry inside GeoParquetMetadata.
type GeoParquetMetadata ¶
type GeoParquetMetadata struct {
Version string `json:"version"`
PrimaryColumn string `json:"primary_column"`
Columns map[string]GeoParquetColumnMeta `json:"columns"`
}
GeoParquetMetadata is the JSON payload written under the "geo" key of a GeoParquet file's Arrow-level metadata.
func BuildGeoParquetMetadata ¶
func BuildGeoParquetMetadata(f *Frame) (*GeoParquetMetadata, error)
BuildGeoParquetMetadata scans f and produces a GeoParquet metadata blob describing its geometry columns. Every column tagged as a geometry column (via GeometryField) is scanned once to compute its bounding box and the set of geometry types it contains.
func ParseGeoParquetMetadata ¶
func ParseGeoParquetMetadata(raw string) (*GeoParquetMetadata, error)
ParseGeoParquetMetadata decodes the JSON blob under the "geo" key.
type GroupBy ¶
type GroupBy struct {
// contains filtered or unexported fields
}
GroupBy partitions a Frame by the values in one or more key columns. The keys must be of a hashable Arrow type (String, Int64, Int32, Bool, Float64).
func (*GroupBy) Agg ¶
func (g *GroupBy) Agg(aggs ...Aggregation) (*Frame, error)
Agg computes the requested aggregations over each group, returning a Frame whose first N columns are the group keys (in the order passed to GroupBy) and whose remaining columns are the aggregations in order.
When the group-by uses exactly one hashable key column with a single Arrow chunk and every aggregation column is a single-chunk primitive numeric type, the fast path (aggFast) is taken — it avoids the per-row byte-slice hashing and chunk walks that dominate the general path. All other shapes fall back to the multi-key path below.
type IncrementalAggregator ¶ added in v0.2.7
type IncrementalAggregator interface {
Aggregator
Clone() IncrementalAggregator
Update(col Series, rows []int) error
Finalize() any
}
IncrementalAggregator is the optional extension that opts a custom aggregator into the streaming aggregate executor. Implementers process a group's rows incrementally across batches instead of receiving the whole row set at once via Aggregate, avoiding the materialize-both-sides concat that plain Aggregator triggers.
Contract:
- Clone returns a fresh instance with empty per-group state. The streaming executor calls Clone once per group at first-touch; each group's Update / Finalize / Merge run on its own clone. Callers never share a clone across groups.
- Update adds col[rows] to this instance's state. Called at most once per input batch per group. Must be additive — do not reset internal state at the top of Update.
- Finalize returns the group's aggregated value. Called once per group after all Updates. Should not mutate state.
- Aggregate (inherited from Aggregator) is still called by the eager path; implementers should keep it consistent with the Clone → Update → Finalize sequence. A typical implementation of Aggregate is just: reset state, call Update, return Finalize's value.
Custom aggregators that implement only Aggregator (not this interface) continue to work — they route through the materializing fallback exactly as before.
type JoinType ¶
type JoinType uint8
JoinType selects the join behavior.
const ( // JoinInner returns rows where the key exists on both sides. JoinInner JoinType = iota // JoinLeft returns every row from the left frame, with nulls where the // right side has no matching key. JoinLeft // JoinRight returns every row from the right frame, with nulls where // the left side has no matching key. Row order follows the right // frame's row order. JoinRight // JoinFull (a.k.a. FULL OUTER) returns the union of JoinLeft and // JoinRight: every row from both frames, matched where possible and // null-padded on the missing side otherwise. Left rows come first // (in left-row order), followed by unmatched right rows in right-row // order. JoinFull // JoinSemi returns each left row that has at least one match on the // right, without duplication when there are multiple matches. Only // left-side columns are emitted. JoinSemi // JoinAnti returns each left row that has NO match on the right. // Only left-side columns are emitted. Left rows with a null key are // treated as unmatched. JoinAnti )
type LazyFrame ¶
type LazyFrame struct {
// contains filtered or unexported fields
}
LazyFrame is a Frame that hasn't been computed yet — a chain of operations expressed as a plan tree. Building a LazyFrame does no work; each fluent method appends a node to the plan. Call Collect() to actually run it.
Today (Slice 1 of Layer 2-3) Collect() dispatches each plan node to the existing eager Frame methods. There is no optimizer yet — a LazyFrame chain runs at exactly the same speed as the equivalent eager code. The value here is API shape:
- Inspect a plan without running it: Explain() / Schema().
- Compose complex pipelines without naming intermediate Frames.
- Ready surface for Layer 4 optimizer passes and Layer 6 vectorized executor.
func NewLazyFrame ¶
func NewLazyFrame(plan LogicalPlan) *LazyFrame
NewLazyFrame constructs a LazyFrame from an arbitrary LogicalPlan. Reserved for advanced users building their own plan trees (custom scan nodes, plan-tree rewrites). Most callers should use Frame.Lazy() and the fluent builders.
func (*LazyFrame) Collect ¶
Collect materializes the LazyFrame into a concrete *Frame. Runs the default optimizer, compiles the plan into a tree of ExecOperators, and drives execution via the streaming executor.
Streaming operators (Filter, Project, WithColumn, Drop, Limit) pull one batch at a time; blocking operators (Sort, Aggregate, Join, Tail) buffer their input to a Frame and delegate to the eager engine. Peak memory is bounded to one batch per streaming node plus the accumulated Frame at each blocking node.
This is where errors surface: bad expressions, type mismatches, unknown columns, scan failures.
func (*LazyFrame) CollectRaw ¶
CollectRaw skips both the optimizer AND the streaming executor, executing the plan tree via the bottom-up whole-Frame walker used before Layer 6. Useful for debugging optimizer bugs, for benchmarks that isolate the eager engine's cost, and as a correctness oracle for the executor's tests. Prefer Collect for real use.
func (*LazyFrame) DropColumn ¶
DropColumn appends a Drop node. If the named column is missing at Collect time, the underlying Frame.DropColumn surfaces ErrColumnNotFound.
func (*LazyFrame) Explain ¶
Explain returns a human-readable representation of the plan tree. Deepest node first (which is how the tree evaluates: bottom-up). Handy for debugging what a chain of fluent methods actually built.
Example:
Limit(1000)
Project(col("id"), (col("value") * lit(1.08)) AS "usd")
Filter((col("value") > lit(100)))
Scan[frame](500 rows × 3 cols)
func (*LazyFrame) ExplainOptimized ¶
ExplainOptimized returns the Explain output for the plan tree after the default rule set has been applied.
func (*LazyFrame) ExplainPhysical ¶
ExplainPhysical returns a description of how the LazyFrame will be executed — which operators stream, which materialize, which scan strategy each source uses. Predicts the compilation choices Compile would make without actually building the executor tree (no goroutines started, no right-side materialization for joins, no file I/O). Cheap enough to call in tests and inspection loops.
Format: outer-most node first, one node per line, two-space indent per depth. Each label is prefixed with the strategy ("Streaming*" or "Materialize*") so the choice is visible at a glance.
Example (analytical pipeline over parquet):
StreamingAggregate(keys=[region], aggs=[value_sum])
StreamingJoin(inner, left.user_id = right.user_id)
Filter((col("value") > lit(100)))
ScanFile[stream, parquet]("events.parquet", cols=[user_id value region])
ScanFrame(100 rows × 2 cols)
func (*LazyFrame) Explode ¶ added in v0.2.1
Explode appends an Explode node — one row per component of the named geometry or list column. Semantics match Frame.Explode: multi-part geometries expand to their constituents; List<T> columns expand to one row per element, with null/empty lists producing a single output row with a null element (polars-parity); non-exploded columns are duplicated across the expansion.
The exploded column's output type is the list element type for List<T> columns, or unchanged for geometry columns (Binary/WKB with the multi-part reduced to a single part). Errors for non-exploded- able column types surface at Collect().
func (*LazyFrame) Filter ¶
Filter appends a Filter node. cond must produce a Boolean Series when evaluated; the error surfaces at Collect() time, not here.
func (*LazyFrame) GroupBy ¶
func (lf *LazyFrame) GroupBy(keys ...string) *LazyGroupBy
GroupBy returns a lazy group-by builder. Chain .Agg(aggs...) to get back a LazyFrame whose Collect() runs Frame.GroupBy(keys...).Agg(aggs...).
The two-step shape mirrors the eager API — no ambiguity about what gb, err := lf.GroupBy(...) means (there's no error return here, missing keys surface at Collect).
func (*LazyFrame) Head ¶
Head returns the first n rows. Alias for Limit — the plan node is the same. Kept as a separate method for pandas-shaped ergonomics.
func (*LazyFrame) Join ¶
Join appends a Join node combining lf and right on (leftKey, rightKey). Semantics match Frame.Join for all six JoinType values; see that method's documentation for null-key handling and key- coalescing on Right/Full joins.
func (*LazyFrame) Limit ¶
Limit appends a Limit node that keeps the first n rows. Negative or zero n produces an empty result at Collect() time.
func (*LazyFrame) Optimize ¶
func (lf *LazyFrame) Optimize() LogicalPlan
Optimize returns the optimizer-rewritten plan without executing. Inspection aid: pair with String() / Explain() to see what a chain of fluent methods reduces to.
func (*LazyFrame) PartitionMetadata ¶ added in v0.2.0
func (lf *LazyFrame) PartitionMetadata() *PartitionMetadata
PartitionMetadata returns the partition claim on this LazyFrame's output, or nil if no claim has been made. The claim is derived from the root plan node — scan sources populate it at construction time (see NewScanNode's WithPartitionMetadata option), intermediate nodes propagate it via rules landing in step 2 of the v0.3.0 plan.
Consumers of this method today are primarily test code and debugging; the alignment predicate that decides whether .Over(K) / Join(K) / GroupBy(K) can skip shuffle lands in step 3-4 of the v0.3.0 plan. Users composing hand-annotated claims go through LazyFrame.WithPartitionAssertion (step 3).
func (*LazyFrame) Plan ¶
func (lf *LazyFrame) Plan() LogicalPlan
Plan returns the underlying plan tree. Used by tree walkers and by tests exercising plan structure directly.
func (*LazyFrame) Rename ¶ added in v0.2.4
Rename appends a Rename step that changes the column named old to new, preserving column order and buffers. Missing old surfaces ErrColumnNotFound at Collect(). Same-name rename (old == new) is a no-op.
func (*LazyFrame) Schema ¶
Schema returns the plan's output schema without executing anything. For plans that involve type inference (Project, WithColumn), fields whose expressions can't be statically typed are reported with a nil Type — Collect() will surface the underlying evaluation error.
func (*LazyFrame) Select ¶
Select appends a Project node — the resulting LazyFrame contains only the columns produced by exprs, in that order. Each expression's output column name comes from Namer.OutputName if the expression has one (Col("id") → "id", something.Alias("x") → "x"); otherwise a positional default ("expr_0", "expr_1", ...) is used.
Zero expressions is a valid but empty Select — the resulting Frame has 0 columns. Add an Alias if you want a non-default output name for computed columns.
func (*LazyFrame) SelectCols ¶ added in v0.2.4
SelectCols is a name-based shorthand for Select — picks the given columns from the input plan, in the given order. Equivalent to Select(Col(names[0]), Col(names[1]), ...).
Also handles column reordering: SelectCols("b", "a") returns a LazyFrame whose output has "b" before "a". Missing columns surface at Collect() (colRefNode's Eval reports the not-found error).
func (*LazyFrame) SortBy ¶
SortBy appends a Sort node. Semantics match Frame.SortBy: multi-key stable, nulls-last, direction per-key.
func (*LazyFrame) Tail ¶
Tail returns the last n rows. Unlike Head, this cannot be implemented as a plain Limit — offset depends on the total row count, which isn't known until the input has been materialized. Dispatches to Frame.Tail at Collect time.
func (*LazyFrame) WithColumn ¶
WithColumn appends a WithColumn node. If a column named name already exists at this point in the plan, it will be replaced; otherwise the new column is appended.
func (*LazyFrame) WithPartitionAssertion ¶ added in v0.2.0
func (lf *LazyFrame) WithPartitionAssertion(assertion *PartitionMetadata) (*LazyFrame, error)
WithPartitionAssertion attaches user-provided PartitionMetadata to the LazyFrame. Enables partition-aware operators (.Over(K), future partition-wise Join / GroupBy) on sources whose partitioning can't be inferred automatically — RawUnload / RawCTAS in athenaio, hand-crafted parquet scans, custom UDFs that write partitioned output.
Only narrowing is allowed. The assertion must:
- Match the input's Columns exactly (can't change what's partitioned on).
- Match the input's HashFn exactly (can't change hash function).
- Provide a SortedBy that's a (possibly empty) prefix of the input's SortedBy. A writer that enforced [a, b, c] as a lex sort also enforced [a, b] as a prefix, so shorter prefixes are narrowings; different columns or reorderings are not.
- Downgrade SortEnforced from true to false, or leave it. It may not upgrade false → true (that would be a stronger claim than the source made).
Nil input claim → any assertion allowed (opaque source, user owns the whole claim). Nil assertion → always allowed (narrows any claim to "no claim").
User owns correctness. gobi never verifies the assertion against actual data. A wrong assertion produces wrong window results with no visible error.
type LazyGroupBy ¶
type LazyGroupBy struct {
// contains filtered or unexported fields
}
LazyGroupBy is the intermediate builder returned by LazyFrame.GroupBy. Its only method, Agg, closes the group-by out into a LazyFrame.
func (*LazyGroupBy) Agg ¶
func (lg *LazyGroupBy) Agg(aggs ...Aggregation) *LazyFrame
Agg attaches the given aggregations and returns a LazyFrame whose output schema is [group keys...] + [agg outputs...] in the order given. Naming, type mapping, and null semantics match the eager GroupBy.Agg.
type LogicalPlan ¶
type LogicalPlan interface {
// Schema returns the output schema of this node. Called during
// LazyFrame.Schema() and by nodes that need to inspect their
// input's shape (e.g. Project computing its output columns).
Schema() *arrow.Schema
// Children returns the immediate sub-plans, in evaluation order
// (empty for leaves). Used by tree walkers, optimizers, and
// Explain().
Children() []LogicalPlan
// String returns a single-line description of this node —
// no children, no formatting. Used as the label in Explain
// output; the tree walker handles indentation and recursion.
String() string
// PartitionMetadata returns the partition claim carried by this
// node's output rows. nil = no claim; alignment proofs never
// prove anything against a nil claim. Consumed by the optimizer
// to prove shuffle-free .Over(K) / Join(K) / GroupBy(K).
//
// Scan sources (parquetio's ScanFile, athenaio's UnloadAndRead,
// hand-annotated via LazyFrame.WithPartitionAssertion) attach
// metadata at construction time. Intermediate nodes derive
// their output metadata from their inputs — see the propagation
// rules in contrib/athenaio/PARTITION-METADATA.md. Every non-
// scan node returns nil today (step 1 of the v0.3.0 plan);
// propagation wiring lands in step 2.
PartitionMetadata() *PartitionMetadata
}
LogicalPlan represents a node in a query plan tree. Plans are immutable data structures — building a plan does not execute anything. LazyFrame consumes a LogicalPlan and executes it via Collect().
A future optimizer will walk plan trees, rewrite them, and translate them to a physical plan for execution. Slice 1 (this file) provides the tree shape and node types; Collect() dispatches each node to the existing eager engine.
func NewScanNode ¶
func NewScanNode(label string, schema *arrow.Schema, read func() (*Frame, error), opts ...ScanOption) LogicalPlan
NewScanNode constructs a leaf plan node representing a deferred I/O source. label is used in Explain output (e.g. "Scan[parquet](path)"), schema is the eagerly-inferred output schema (or nil if unknown at construction), and read is called by Collect() to materialize the scan's *Frame.
Optional ScanOptions declare capabilities the optimizer can exploit — WithColumnProjection enables projection pushdown from any Project/Filter above the scan.
Exposed for source packages (parquetio, csvio, ...) to build scan leaves without a per-format node type in the core package. Most callers should use the format-specific wrapper (parquetio.ScanFile and friends) instead of building nodes by hand.
func Optimize ¶
func Optimize(plan LogicalPlan, rules ...Rule) LogicalPlan
Optimize applies rules to plan until either nothing changes or the iteration cap is hit. Returns the (possibly rewritten) root. If rules is empty, DefaultRules() is used.
type Namer ¶
type Namer interface {
OutputName() string
}
Namer is implemented by expression nodes that carry a meaningful output column name. Select and WithColumn use it to derive default column names (Col("id") → "id", Col(x).Alias("y") → "y").
Nodes that don't implement Namer, or whose OutputName is empty, fall back to a positional default ("expr_0", "expr_1", ...).
type Option ¶
type Option interface {
// contains filtered or unexported methods
}
Option configures a parallel gobi operation. Values are applied to an internal options struct in the order the caller supplies them, so later options override earlier ones.
Every parallel entry point (currently SJoin; more to come) accepts a trailing `...Option`. Callers that don't care can omit them entirely.
func Workers ¶
Workers overrides the maximum number of parallel workers used by the operation it is passed to.
- Workers(n) with n > 0 caps parallelism at n workers.
- Workers(0) or Workers(-1) means "use the package default" (see SetMaxParallelism); if that too is unset, GOMAXPROCS is used.
- Workers(1) forces sequential execution.
type PartitionMetadata ¶ added in v0.2.0
type PartitionMetadata struct {
// Columns are the partition columns in the order used by the
// hash function. hash(a, b) ≠ hash(b, a) in every hash function
// gobi tags, so ordering is significant. Alignment always
// requires ordered equality on this slice.
Columns []string
// HashFn is a versioned, source-namespaced string tag naming
// the hash function used to partition. Empty string is reserved
// for value-partitioning (Hive-style directory-per-unique-value)
// where "same value → same partition" is trivial.
//
// Cross-tag comparisons always fail — the optimizer never
// assumes two sources' hash functions are compatible even when
// both name the same underlying algorithm. Type-encoding of
// hash inputs differs across sources (Trino's hash normalizes
// decimals differently than xxhash64 over UTF-8 bytes, for
// example). Alignment holds iff HashFn strings are byte-equal.
//
// Reserved tags (see PARTITION-METADATA.md for the registry):
// "" — value partitioning
// "gobi/xxhash64/v1" — gobi runtime shuffle
// "athenaio/iceberg/murmur3-32/v1" — athenaio Iceberg CTAS
// "athenaio/hive/bucket/v1" — athenaio Hive CTAS
// "pgio/hash/v1" — reserved for pgio
// "bigqueryio/hash/v1" — reserved for bigqueryio
HashFn string
// SortedBy describes within-partition ordering. Nil = unsorted.
// Each SortKey is a (column, direction) pair — direction matters
// for Diff / Shift / fill-forward correctness.
SortedBy []SortKey
// SortEnforced distinguishes "writer guaranteed the sort" (e.g.
// Iceberg's first-class sorted_by table property) from "sort
// was a hint, verify at read time or don't rely on it for
// correctness" (e.g. Hive's sorted_by, which is advisory).
//
// Operators that use sortedness only for performance (skipping
// a re-sort) may trust either value. Operators whose correctness
// depends on order (Diff, Shift with fill_forward) MUST check
// this flag and either verify at read time or fall back to a
// sorted path.
SortEnforced bool
}
PartitionMetadata describes how a LazyFrame's rows are physically grouped by partition key. Populated by scan sources that can prove partitioning (athenaio's CTAS write path, future parquetio per-file partitioning claims, hand-annotated via WithPartitionAssertion). Consumed by the optimizer to prove alignment for Over / Join / GroupBy and eliminate cross-worker shuffles.
Two nil-versus-empty distinctions matter:
- A nil *PartitionMetadata means "no claim made" — the optimizer assumes worst-case (any row can be anywhere) and inserts the shuffle it would insert today.
- A non-nil pointer with Columns == nil is an explicit "no partitioning" claim (a source that ran without bucketing) and is distinct from nil. Alignment proofs refuse to prove anything against it. Never conflate the two.
func (*PartitionMetadata) Clone ¶ added in v0.2.0
func (m *PartitionMetadata) Clone() *PartitionMetadata
Clone returns a deep copy of m. Used by plan-tree walkers that need to attach a modified metadata to a downstream node without mutating the upstream one. Returns nil for a nil receiver.
type PredicateSink ¶
type PredicateSink interface {
LogicalPlan
// ApplyPredicate returns a plan node identical to the receiver
// but with pred available for row-group / bloom-filter skipping
// at read time. The Filter node above the scan is not removed
// (row-level filtering still runs after coarse skipping), so
// callbacks may return the receiver unchanged when they decide
// the hint isn't useful.
ApplyPredicate(pred Expr) LogicalPlan
}
PredicateSink is implemented by scan nodes that can accept a filter-predicate hint from the optimizer. Rules test via type assertion; scans that don't implement it are left untouched by predicate pushdown.
type ProjectableScan ¶
type ProjectableScan interface {
LogicalPlan
// ProjectColumns returns a plan node identical to the receiver
// but restricted to the given column names. If projection is
// not beneficial (e.g. caller already set an explicit column
// list), implementations should return the receiver unchanged.
ProjectColumns(cols []string) LogicalPlan
}
ProjectableScan is implemented by scan nodes that can accept a column-projection hint from the optimizer. Rules test for this interface via type assertion; scans that don't implement it are left untouched by projection pushdown.
type Resampler ¶
type Resampler struct {
// contains filtered or unexported fields
}
Resampler bins rows of a Frame by fixed time intervals aligned to the Unix epoch. Use Frame.ResampleEvery to construct one, then call Agg to produce a downsampled Frame.
Bucket alignment: bucketStart = floor(unix_ns / interval_ns) * interval_ns. A 1-hour resample produces buckets that start on the hour in UTC — regardless of any timezone label on the input series. If you need calendar-aligned resampling (e.g. daily buckets that start at midnight New York time), truncate to a calendar boundary first and group on that.
func (*Resampler) Agg ¶
func (r *Resampler) Agg(aggs ...Aggregation) (*Frame, error)
Agg computes the requested aggregations over each non-empty bucket. The output frame has one row per bucket, ordered by bucket start, with the time column named the same as the input's time column followed by one column per aggregation. Empty buckets are omitted (this mirrors GroupBy's behavior).
type Rule ¶
type Rule interface {
Name() string
Apply(plan LogicalPlan) (rewritten LogicalPlan, changed bool)
}
Rule is a single plan-tree rewrite. A rule is a pure function from a plan to an equivalent plan, potentially cheaper to execute. The optimizer applies rules to a fixed point — no rule reports a change on the final pass.
Rules should walk the whole tree themselves; the optimizer does not traverse for them. This lets a rule choose bottom-up or top-down order depending on what it does.
func DefaultRules ¶
func DefaultRules() []Rule
DefaultRules returns the rule set applied by Optimize when no explicit list is passed. Order is a best-effort ordering that enables downstream folds — FoldConstants can turn a filter's condition into a literal, which RemoveTrivialTrueFilter then eliminates. The optimizer runs to a fixed point, so any correct interleaving eventually converges.
type ScanOption ¶
type ScanOption func(*scanFileNode)
ScanOption configures optional capabilities on a scan node. Source packages (parquetio, csvio, ...) pass these to NewScanNode to declare features the optimizer can exploit — currently just column-projection pushdown.
func WithColumnProjection ¶
func WithColumnProjection(fn func(cols []string) LogicalPlan) ScanOption
WithColumnProjection registers a callback that returns a new scan node projected to the given column names. The optimizer's projection-pushdown rule calls this when it determines a scan source is being asked for a subset of its columns.
The callback should:
- Return nil if projection doesn't apply (e.g. the caller already restricted columns explicitly). Treated as "no change" — the receiver stays in the plan.
- Otherwise return a fresh scan node with the projection applied — the optimizer replaces the old node with what this callback returns.
cols is guaranteed non-empty and sorted; entries outside the scan's schema are the callback's responsibility to filter out.
func WithParallelStreamReads ¶
func WithParallelStreamReads(fn func() []func(cb func(*Frame) error) error) ScanOption
WithParallelStreamReads registers a callback that returns N stream-read closures, each processing a disjoint portion of the source. The Layer 6 executor spawns one producer goroutine per closure and fan-ins their batches into the downstream pipeline.
The callback is responsible for deciding N (typically bounded by GOMAXPROCS and by the source's natural partition count — e.g. number of parquet row-groups). Return nil (or a slice of length 0-1) to signal "no parallel version available"; the executor falls back to WithStreamRead in that case.
Semantics: batches from different workers arrive in unspecified order. Downstream operators that require order (Sort, Tail) buffer and reorder internally, so this is safe to enable for any plan shape.
func WithPartitionMetadata ¶ added in v0.2.0
func WithPartitionMetadata(meta *PartitionMetadata) ScanOption
WithPartitionMetadata attaches a partition claim to a scan node. Sources that can prove partitioning (athenaio's UnloadAndRead after read-back verification, parquetio when per-file partition info is available, etc.) use this option to populate metadata the optimizer will consume in step 4 / step 6 of the v0.3.0 plan.
Nil meta is a no-op — same as not calling the option. Callers that want to explicitly claim "no partitioning" (distinct from "no claim made") pass a non-nil pointer with Columns == nil.
func WithPredicatePushdown ¶
func WithPredicatePushdown(fn func(pred Expr) LogicalPlan) ScanOption
WithPredicatePushdown registers a callback that returns a new scan node with a predicate baked in. The optimizer's PushPredicateToScan rule calls this when a Filter sits directly above the scan; the scan source is expected to use the predicate for row-group / bloom-filter skipping at read time.
The Filter node above the scan is NOT removed after pushdown — row-group skipping is coarse (whole groups only), so the row-level Filter still runs for correctness. Callbacks should treat the predicate as a hint, not a guarantee.
nil return = "no change" (same convention as WithColumnProjection).
func WithStreamRead ¶
func WithStreamRead(fn func(cb func(*Frame) error) error) ScanOption
WithStreamRead registers a streaming callback API for scan sources that support incremental read (parquetio.ReadFileChunksFunc, csvio.ReadFileChunksFunc). fn should call cb once per record batch and honor the batch-lifetime contract of the source package (typically: batches are Released after cb returns).
When present, the Layer 6 executor uses this callback for true bounded-memory streaming through the plan. When absent, the executor falls back to the `read` closure (whole-file materialize then batch — correct but not memory-bounded).
type Series ¶
type Series struct {
// contains filtered or unexported fields
}
Series is a single named, typed Arrow column.
A Series does not own its column: constructors that receive an *arrow.Column treat it as borrowed. Callers wanting shared lifetime should Retain the underlying column; DataFrame.Release does not release Series contents.
func NewSeries ¶
NewSeries returns a Series wrapping col. The Series takes the column's name from col.Name(); its field is derived from col.Field().
func NewTimestampSeries ¶
NewTimestampSeries builds a Timestamp[ns] Series from the given time.Time values. Passing a nil validity slice means every row is valid; otherwise validity[i]==false marks row i as null (its value is ignored).
func PointsFromXY ¶
PointsFromXY builds a geometry Series of 2D WKB Points from two coordinate columns. x and y must be numeric (Float64, Float32, Int64, or Int32) and the same length. Mixed-type inputs are promoted to Float64. Null values on either side emit a null geometry for that row.
The returned Series is a WKB Binary column tagged with geometry metadata + the given EPSG code, so it plugs directly into Frame.WithColumn, Frame.SJoin, GeoParquet write paths, and other geometry-aware operations.
Modeled on geopandas.points_from_xy — the intended flow is to build a geometry column from two attribute columns without hand-rolling the WKB encoding:
lat, _ := df.Column("lat")
lng, _ := df.Column("lng")
geom, _ := gobi.PointsFromXY(lng, lat, 4326) // x=lng, y=lat
df, _ = df.WithColumn("geometry", geom)
Note the argument order: x first, y second. In geographic coordinates that means longitude first, latitude second — matching GeoJSON / WKB / shapefile conventions (and geopandas).
func PointsFromXYZ ¶
PointsFromXYZ is the 3D variant of PointsFromXY. z must be numeric and the same length as x and y; rows with a null z produce null geometries even if x and y are valid.
The resulting Point geometries carry HasZ=true so downstream WKB encoding emits XYZ type codes (1001..) rather than 2D (1..).
func (Series) AddDuration ¶
AddDuration returns a new Timestamp[ns] Series with d added to each row. Nulls propagate.
func (Series) Bools ¶ added in v0.2.4
Bools returns the Series values as []bool. Nulls come through as false.
func (Series) Column ¶
Column returns the underlying Arrow column. Do not mutate the returned value; use Series methods for slicing.
func (Series) Concat ¶
Concat returns a new Series with s's values followed by each other's values, in order. All series must share the same arrow type; type mismatches return an error naming both sides.
The result is a multi-chunk column — each input becomes a chunk. Zero-copy: no memcpy of the underlying arrow buffers.
func (Series) Diff ¶
Diff returns a Series holding the element-wise difference between s and its n-lagged self: `out[i] = s[i] - s[i-n]`. The first n positions are null (no previous value to subtract). n must be positive; n=0 is disallowed (would trivially be all zeros); use Shift(-n) if you want a negative-lag first-difference.
Only numeric types are supported (matching the underlying Series.Sub). Non-numeric callers should compose Shift + a domain-specific comparison instead.
This is the columnar equivalent of pandas / polars `diff(n)` used for period-over-period changes, discrete derivatives, and change-point detection.
func (Series) DiffDuration ¶
DiffDuration returns an Int64 Series whose row i is (s[i] - other[i]) expressed in nanoseconds. Nulls on either side produce nulls in the output.
func (Series) Difference ¶
Difference returns the distinct non-null values in s that are absent from other, in first-occurrence order. Types must match.
func (Series) Div ¶
Div returns s / o element-wise, promoting to float64. Division by zero yields ±Inf or NaN per IEEE 754.
func (Series) Float32Values ¶ added in v0.2.9
Float32Values returns a zero-copy view of the underlying float32 slice when s is a single-chunk Float32 Series. Returns (nil, false) on multi-chunk or type mismatch.
func (Series) Float32s ¶ added in v0.2.4
Float32s returns the Series values as []float32. Nulls come through as 0.
func (Series) Float64Values ¶ added in v0.2.9
Float64Values returns a zero-copy view of the underlying float64 slice when s is a single-chunk Float64 Series. Returns (nil, false) on multi-chunk or type mismatch. Null rows still occupy positions in the slice — combine with Nulls() to filter them.
func (Series) Float64s ¶ added in v0.2.4
Float64s returns the Series values as []float64. Nulls come through as 0.
func (Series) GeomArea ¶
GeomArea returns a Float64 Series holding the planar (XY) area of each geometry in s, in u². Non-polygonal geometries contribute 0. Null geometries produce null values.
func (Series) GeomBounds ¶
GeomBounds returns a Frame with four Float64 columns — MinX, MinY, MaxX, MaxY — one row per input geometry. Null geometries produce four nulls.
func (Series) GeomCentroid ¶
GeomCentroid returns a geometry Series holding the centroid of each input geometry as a Point (encoded as WKB). Null inputs produce nulls. The output column inherits s's CRS.
func (Series) GeomLength ¶
GeomLength returns a Float64 Series holding the planar (XY) length of each geometry in u. Non-linear geometries contribute 0. Null geometries produce null values.
func (Series) Geometry ¶
Geometry decodes the WKB at row i into a Geometry. Returns ErrNotGeometry if the series is not a geometry column.
func (Series) HasNulls ¶ added in v0.2.9
HasNulls reports whether the Series has any null rows. Cheap — consults arrow's cached NullN metadata per chunk without touching the bitmap.
func (Series) Int32Values ¶ added in v0.2.9
Int32Values returns a zero-copy view of the underlying int32 slice when s is a single-chunk Int32 Series. Returns (nil, false) on multi-chunk or type mismatch.
func (Series) Int32s ¶ added in v0.2.4
Int32s returns the Series values as []int32. Nulls come through as 0.
func (Series) Int64Values ¶ added in v0.2.9
Int64Values returns a zero-copy view of the underlying int64 slice when s is a single-chunk Int64 Series. Returns (nil, false) on multi-chunk or type mismatch.
func (Series) Int64s ¶ added in v0.2.4
Int64s returns the Series values as []int64. Nulls come through as 0.
func (Series) Intersect ¶
Intersect returns the distinct non-null values present in both s and other, in first-occurrence order. Types must match.
func (Series) IsDateTime ¶
IsDateTime reports whether s is a Timestamp / Date32 / Date64 column.
func (Series) IsGeometry ¶
IsGeometry reports whether the series is tagged as a WKB geometry column.
func (Series) Max ¶
Max returns the maximum non-null numeric value, or NaN when the series has no non-null rows.
func (Series) Mean ¶
Mean returns the arithmetic mean of non-null numeric values, or NaN when the series has no non-null rows.
func (Series) Min ¶
Min returns the minimum non-null numeric value, or NaN when the series has no non-null rows.
func (Series) NUnique ¶
NUnique returns the count of distinct non-null values in s.
Equivalent to `s.Unique().Len()` but skips the arrow array construction. Uses the same byte-encoding as GroupBy so numeric bit-equal values collapse identically. O(n) time, O(distinct) memory.
func (Series) NullCount ¶ added in v0.2.9
NullCount returns the total number of null rows across all chunks. Cheap — sums each chunk's cached NullN.
func (Series) Nulls ¶ added in v0.2.4
Nulls returns a []bool where true means "row i is null". Zero-length series → empty slice, no error. Use alongside a value extractor to distinguish arrow-null from a zero-valued row.
vals, _ := s.Int64s()
nulls := s.Nulls()
for i, v := range vals {
if nulls[i] { continue } // skip nulls
// ... use v
}
Fast path: chunks with no nulls (per arrow's cached NullN) skip the bitmap walk entirely — leave those output slots at their zero value. Chunks with nulls read the raw validity bitmap once per row rather than the (offset-recomputing) IsNull call. Fully-null Series still allocate the []bool.
func (Series) RollingCount ¶
RollingCount returns an Int64 Series holding the count of non-null values in each window. Rows before the first full window are null.
func (Series) RollingMax ¶
RollingMax returns a Float64 Series holding the maximum non-null value over each window.
func (Series) RollingMean ¶
RollingMean returns a Float64 Series holding the arithmetic mean of s over each window (non-null values only).
func (Series) RollingMin ¶
RollingMin returns a Float64 Series holding the minimum non-null value over each window.
func (Series) RollingSum ¶
RollingSum returns a Float64 Series where row i is the sum of s over the closed window [i-window+1 .. i]. window must be >= 1.
func (Series) Shift ¶
Shift returns a new Series with values shifted by n positions. Positive n shifts values forward (down): the first n positions become null, and each output position i gets the source value from position i-n when that index is in bounds.
Negative n shifts backward (up): the last |n| positions become null; output position i gets the source value from position i+|n|.
n=0 is a no-op that still returns a fresh Series (new arrow array, same values). Extreme |n| >= Len() returns an all-null Series of the same type + name — same as pandas / polars.
Nulls in the source at the source index propagate to the output. The output preserves the source's arrow type, name, and field metadata (including the geometry tag, if any).
func (Series) Strings ¶ added in v0.2.4
Strings returns the Series values as []string. Nulls come through as "". Works for both String and LargeString columns.
func (Series) SubDuration ¶
SubDuration returns a new Timestamp[ns] Series with d subtracted from each row.
func (Series) TimeAt ¶
TimeAt returns the value at row i as a time.Time, plus a validity flag (false for null). The returned time.Time carries the series' timezone (UTC if the series is tz-naive). Errors for non-datetime series.
func (Series) Timestamps ¶ added in v0.2.4
Timestamps returns the Series values as []arrow.Timestamp (int64 under the hood). Nulls come through as 0. The unit and timezone are preserved in the source column's arrow type; use DataType() to recover them if you need to interpret the values.
func (Series) Timezone ¶
Timezone returns the IANA timezone label on s (e.g. "America/New_York"), or "" if the series is tz-naive or not a Timestamp column.
func (Series) TruncateTo ¶
TruncateTo returns a new Timestamp[ns] Series with each row rounded down to the nearest boundary of the given unit. UnitDay truncates to 00:00:00 UTC of the same date.
func (Series) TruncateToCalendar ¶
func (s Series) TruncateToCalendar(unit CalendarUnit) (Series, error)
TruncateToCalendar truncates each row to a calendar boundary (week, month, year). If s carries a timezone, the boundary is computed in that timezone (so "start of month" is midnight local time in the tz, not UTC). Week uses ISO semantics: previous Monday at 00:00.
func (Series) Uint32Values ¶ added in v0.2.9
Uint32Values returns a zero-copy view of the underlying uint32 slice when s is a single-chunk Uint32 Series.
func (Series) Uint32s ¶ added in v0.2.4
Uint32s returns the Series values as []uint32. Nulls come through as 0.
func (Series) Uint64Values ¶ added in v0.2.9
Uint64Values returns a zero-copy view of the underlying uint64 slice when s is a single-chunk Uint64 Series.
func (Series) Uint64s ¶ added in v0.2.4
Uint64s returns the Series values as []uint64. Nulls come through as 0.
func (Series) Union ¶
Union returns the distinct non-null values in either s or other, in first-occurrence order. Types must match. Nulls are treated as equal for set membership — matching Frame.Union — but the null value itself is not emitted in the output (parity with Series.Unique which drops nulls).
func (Series) Unique ¶
Unique returns a Series of distinct non-null values in first- occurrence order. The result's arrow type matches the input's.
Nulls are dropped (matches pandas / polars `unique` semantics). Callers that want a "did I see any null?" signal should combine with `Series.NullCount()`.
func (Series) Weekday ¶
Weekday returns each row's day-of-week as Int64 with Sunday=0..Saturday=6 (matches Go's time.Weekday int values).
func (Series) WithTimezone ¶
WithTimezone returns a copy of s that carries the given IANA timezone label. The underlying Unix-nanosecond values are NOT shifted — only the display timezone changes. This matches pandas' `tz_convert` when the input is already tz-aware, or "assume the values are absolute instants and now render them in tz" when the input is naive.
Passing tz == "" strips any existing label (result is tz-naive). Passing a name that time.LoadLocation cannot resolve returns an error.
type SortKey ¶
SortKey names a column to sort by and its direction. Compose multiple SortKeys in a single SortBy call for lexicographic (a-then-b-then-c) ordering — earlier keys have priority; later keys break ties.
Nulls sort last regardless of Descending, matching pandas / polars default behavior. NaN floats also sort last (numpy semantics).
type SpatialPredicate ¶
type SpatialPredicate uint8
SpatialPredicate names a binary spatial predicate for SJoin.
const ( // SPIntersects matches when the left and right geometries share any point. SPIntersects SpatialPredicate = iota // SPContains matches when the left geometry fully contains the right. SPContains // SPWithin matches when the left geometry lies fully within the right. SPWithin )
func (SpatialPredicate) String ¶
func (p SpatialPredicate) String() string
type Stats ¶
type Stats interface {
// MinMax returns the inclusive bounds for col over the range
// this Stats describes. ok=false when statistics are missing.
MinMax(col string) (minV, maxV any, ok bool)
// NullCount returns the number of null values in col over the
// range. ok=false when null counts weren't recorded.
NullCount(col string) (n int64, ok bool)
// TotalRows is the total row count of the range.
TotalRows() int64
}
Stats reports column-level bounds used by CanPossiblyMatch to prove predicates unsatisfiable over a data range (typically a parquet row-group). Implementations are supplied by source packages: parquetio, csvio, etc.
The values returned by MinMax must be Go-typed scalars matching the column's arrow type: int64 for INT64, float64 for FLOAT64, string for STRING, bool for BOOL, and so on. Mixed types or unknown columns should signal ok=false so the caller falls back to the conservative "possibly matches" answer.
type TimeRolling ¶
type TimeRolling struct {
// contains filtered or unexported fields
}
TimeRolling represents a right-anchored, time-based rolling window over a Frame. Use Frame.RollingBy to construct one.
Source Files
¶
- collect_set.go
- compile.go
- doc.go
- errors.go
- exec.go
- exec_aggregate.go
- exec_aggregate_parallel.go
- exec_join.go
- exec_join_merge.go
- exec_ops.go
- exec_scan_parallel.go
- explain_physical.go
- explode.go
- expr.go
- expr_cast.go
- expr_eval.go
- expr_frame.go
- expr_haversine.go
- expr_if.go
- expr_list.go
- expr_null.go
- expr_over.go
- expr_shift.go
- expr_sql.go
- expr_timestamp.go
- frame.go
- frame_ops.go
- from_structs.go
- geoparquet.go
- groupby.go
- groupby_aligned.go
- groupby_fast.go
- join.go
- lazy.go
- optimize.go
- options.go
- partition.go
- pivot.go
- plan.go
- points.go
- predicate_stats.go
- resample.go
- rolling.go
- schema.go
- series.go
- series_extract.go
- series_geom.go
- series_ops.go
- series_ops_simd_fallback.go
- series_shift.go
- series_time.go
- series_values.go
- setops.go
- sjoin.go
- sort.go
- unique.go
Directories
¶
| Path | Synopsis |
|---|---|
|
contrib
|
|
|
athenaio
module
|
|
|
Package csvio reads and writes CSV data as gobi Frames.
|
Package csvio reads and writes CSV data as gobi Frames. |
|
Package geojsonio reads and writes gobi Frames as GeoJSON per RFC 7946.
|
Package geojsonio reads and writes gobi Frames as GeoJSON per RFC 7946. |
|
Package geometry provides 2D geometry primitives (Point, LineString, Polygon, MultiPoint) with WKB and WKT encoding, a coordinate reference system model, and common spatial operations (area, distance, centroid, convex hull, intersection tests).
|
Package geometry provides 2D geometry primitives (Point, LineString, Polygon, MultiPoint) with WKB and WKT encoding, a coordinate reference system model, and common spatial operations (area, distance, centroid, convex hull, intersection tests). |
|
Package gpkgio reads and writes gobi Frames as OGC GeoPackage (SQLite) files.
|
Package gpkgio reads and writes gobi Frames as OGC GeoPackage (SQLite) files. |
|
Package kmlio reads and writes KML (Keyhole Markup Language, OGC 12-007r2) and KMZ (zipped KML) as gobi Frames.
|
Package kmlio reads and writes KML (Keyhole Markup Language, OGC 12-007r2) and KMZ (zipped KML) as gobi Frames. |
|
Package parquetio reads and writes gobi Frames as Apache Parquet.
|
Package parquetio reads and writes gobi Frames as Apache Parquet. |
|
Package pgio reads and writes gobi Frames against PostgreSQL / PostGIS databases.
|
Package pgio reads and writes gobi Frames against PostgreSQL / PostGIS databases. |
|
Package shpio reads and writes ESRI Shapefiles as gobi Frames.
|
Package shpio reads and writes ESRI Shapefiles as gobi Frames. |