This is an automated email from the ASF dual-hosted git repository.
laskoviymishka pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-go.git
The following commit(s) were added to refs/heads/main by this push:
new 21e85b611 docs: document variant type, field-extract filtering, and
shredding (#2045)
21e85b611 is described below
commit 21e85b611b13625a340cfe29f0344fbd1cc0d54f
Author: Neelesh Salian <[email protected]>
AuthorDate: Wed Sep 23 12:29:28 2026 -0700
docs: document variant type, field-extract filtering, and shredding (#2045)
* docs: document variant type, field-extract filtering, and shredding
* PR comment fixes and cleanup
---
website/src/SUMMARY.md | 1 +
website/src/api.md | 2 +-
website/src/expression-dsl.md | 2 +
website/src/feature-status.md | 3 +-
website/src/row-filter-syntax.md | 20 +++++++
website/src/variant.md | 110 +++++++++++++++++++++++++++++++++++++++
6 files changed, 136 insertions(+), 2 deletions(-)
diff --git a/website/src/SUMMARY.md b/website/src/SUMMARY.md
index 01d9ce92f..3506e9aa9 100644
--- a/website/src/SUMMARY.md
+++ b/website/src/SUMMARY.md
@@ -26,6 +26,7 @@
- [Configuration](./configuration.md)
- [CLI](./cli.md)
- [API](./api.md)
+ - [Variant Type](./variant.md)
- [Row Filter Syntax](./row-filter-syntax.md)
- [Expression DSL](./expression-dsl.md)
- [Concurrent Writes](./concurrent-writes.md)
diff --git a/website/src/api.md b/website/src/api.md
index 127517c9b..83747beb6 100644
--- a/website/src/api.md
+++ b/website/src/api.md
@@ -589,7 +589,7 @@ When iceberg-go converts an Iceberg schema to Arrow (e.g.
for the scanner output
| `struct<...>` | `arrow.StructOf(...)` |
| `list<E>` | `arrow.ListOf(E)` (or `LargeListOf` if `useLargeTypes`) |
| `map<K, V>` | `arrow.MapOf(K, V)` |
-| `variant` | `arrow.ExtensionType` for Variant |
+| `variant` | `arrow.ExtensionType` for Variant (see [Variant
Type](./variant.md)) |
Helpers in
[`table/arrow_utils.go`](https://github.com/apache/iceberg-go/blob/main/table/arrow_utils.go):
diff --git a/website/src/expression-dsl.md b/website/src/expression-dsl.md
index e5f50c066..f482b66d1 100644
--- a/website/src/expression-dsl.md
+++ b/website/src/expression-dsl.md
@@ -56,6 +56,7 @@ A *term* is the left-hand side of a predicate. Iceberg-go has
two flavors:
- `Reference("column_name")` - an unbound term that names a column
(`exprs.go:373`). Typing happens at bind time, when the expression is matched
against a schema. This is what you almost always want.
- `BoundReference` - the resolved form, produced by `Reference.Bind(schema,
caseSensitive)` (`exprs.go:389`). You only encounter these when writing custom
expression visitors.
+- `Extract(ref, path, typ)` - a variant sub-path term that navigates a
member-selector path (`$.a.b` or `$['a']['b']`; no array indexing or wildcards)
into a `variant` column and casts the leaf to `typ` (`variant_extract.go`). Use
it inside any predicate builder to filter on a field within a variant. See [Row
Filter Syntax](./row-filter-syntax.md#variant-extraction).
The interfaces are:
@@ -126,6 +127,7 @@ For projection, evaluation, and visitor patterns, see
`visitors.go` and the scan
| Filter a scan or row-level delete | Convenience builders +
`NewAnd`/`NewOr`/`NewNot` |
| Combine many clauses dynamically | Start from `AlwaysTrue{}` (for AND) or
`AlwaysFalse{}` (for OR), fold with `NewAnd`/`NewOr` |
| Construct a predicate whose operator is chosen at runtime |
`UnaryPredicate(op, term)`, `LiteralPredicate(op, term, lit)`,
`SetPredicate(op, term, lits)` |
+| Filter on a field inside a variant column | `Extract(ref, path, typ)` inside
a predicate builder |
| Walk an expression tree | A custom `BooleanExprVisitor` from `visitors.go` |
For the per-operator cookbook, return to [Row Filter
Syntax](./row-filter-syntax.md).
diff --git a/website/src/feature-status.md b/website/src/feature-status.md
index 87d81986f..800932cd6 100644
--- a/website/src/feature-status.md
+++ b/website/src/feature-status.md
@@ -50,7 +50,8 @@ All V1 features are supported. V1 is the format-version
baseline.
| Row lineage (`_row_id`, `_last_updated_sequence_number`) | Supported |
| Encryption keys in metadata | Supported |
| Variant type, non-shredded | Supported (PR
[#932](https://github.com/apache/iceberg-go/pull/932); umbrella
[#929](https://github.com/apache/iceberg-go/issues/929)) |
-| Variant type, shredded reader / writer | In progress
([#986](https://github.com/apache/iceberg-go/issues/986),
[#987](https://github.com/apache/iceberg-go/issues/987)) |
+| Variant type, shredded reader / writer | Supported (reader
[#1238](https://github.com/apache/iceberg-go/pull/1238), writer
[#1351](https://github.com/apache/iceberg-go/pull/1351)) |
+| Variant predicate pushdown / field extract | Supported (PR
[#1607](https://github.com/apache/iceberg-go/pull/1607)) |
| Deletion vectors, read | Supported |
| Deletion vectors, write (unpartitioned) | Supported |
| Deletion vectors, write (partitioned) | In progress
([#1135](https://github.com/apache/iceberg-go/issues/1135), PR
[#1151](https://github.com/apache/iceberg-go/pull/1151)) |
diff --git a/website/src/row-filter-syntax.md b/website/src/row-filter-syntax.md
index ccb2490f0..83857ce98 100644
--- a/website/src/row-filter-syntax.md
+++ b/website/src/row-filter-syntax.md
@@ -88,6 +88,26 @@ iceberg.NotStartsWith(iceberg.Reference("name"), "tmp_")
Operators `OpStartsWith` and `OpNotStartsWith` (`exprs.go:53-54`). The value
must be a `string`.
+## Variant extraction
+
+`iceberg.Extract(ref, path, typ)` builds a term that navigates a
member-selector path into a `variant` column and casts the leaf to `typ`. The
path uses dot (`$.user.age`) or quoted-bracket (`$['user']['age']`) notation;
array indexing (`$.items[0]`), wildcards, filters, and recursive descent are
rejected at bind time. It is an `UnboundTerm`, so it plugs into the same
predicate builders as `iceberg.Reference`:
+
+```go
+filter := iceberg.EqualTo(
+ iceberg.Extract(iceberg.Reference("payload"), "$.user.age",
iceberg.PrimitiveTypes.Int64),
+ int64(30),
+)
+```
+
+The referenced column must be a `variant`, and a target type is required.
Supported target types: `bool`, `int32`, `int64`, `float32`, `float64`, `date`,
`time`, `timestamp`, `timestamptz`, `timestamp_ns`, `timestamptz_ns`, `string`,
`fixed`, `binary`, `decimal`, `uuid`.
+
+Caveats:
+
+- Extract predicates prune whole data files by shredded-field bounds
(best-effort, and only for shredded fields), then filter row by row. Row-group
statistics and bloom filters do not apply to them.
+- Extract terms are DSL-only (no string row-filter form) and are not
REST-serializable. Under local scan planning (the default) they run as local
residuals; with remote scan planning, a filter containing an Extract term fails
to serialize rather than being silently dropped.
+
+See [Variant Type](./variant.md) for shredding.
+
## Constants
```go
diff --git a/website/src/variant.md b/website/src/variant.md
new file mode 100644
index 000000000..56cf52830
--- /dev/null
+++ b/website/src/variant.md
@@ -0,0 +1,110 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+-->
+
+# Variant Type
+
+`variant` is the Iceberg v3 semi-structured type: a single self-describing
column
+that holds arbitrary JSON-like values (objects, arrays, and scalars) without a
+fixed schema. iceberg-go supports both non-shredded and shredded variants, and
can
+push predicates down into individual variant fields.
+
+## Reading and writing
+
+A variant column is declared with `iceberg.VariantType{}` in the table schema
and
+maps to the Arrow `variant` extension type (see [API](./api.md)). Non-shredded
+variant values need no extra configuration: write an Arrow record whose variant
+column uses the extension type, and read it back the same way.
+
+Build the column with a variant builder and write it like any other Arrow
column
+(the table must be format version 3):
+
+```go
+import (
+ "fmt"
+
+ "github.com/apache/arrow-go/v18/arrow"
+ "github.com/apache/arrow-go/v18/arrow/array"
+ "github.com/apache/arrow-go/v18/arrow/extensions"
+ "github.com/apache/arrow-go/v18/arrow/memory"
+ "github.com/apache/arrow-go/v18/parquet/variant"
+ "github.com/apache/iceberg-go"
+ "github.com/apache/iceberg-go/table"
+)
+
+// tbl was created with table.PropertyFormatVersion = "3" and this schema.
+schema := iceberg.NewSchema(0,
+ iceberg.NestedField{ID: 1, Name: "payload", Type: iceberg.VariantType{}},
+)
+arrowSchema, _ := table.SchemaToArrowSchema(schema, nil, true, false)
+
+bldr := extensions.NewVariantBuilder(memory.DefaultAllocator,
extensions.NewDefaultVariantType())
+defer bldr.Release()
+
+var vb variant.Builder
+_ = vb.Append(map[string]any{"x": int64(320), "target": "button-submit"})
+val, _ := vb.Build()
+bldr.Append(val)
+
+col := bldr.NewArray()
+defer col.Release()
+rec := array.NewRecordBatch(arrowSchema, []arrow.Array{col}, 1)
+defer rec.Release()
+
+tx := tbl.NewTransaction()
+arrTable := array.NewTableFromRecords(arrowSchema, []arrow.Record{rec})
+defer arrTable.Release()
+_ = tx.AppendTable(ctx, arrTable, 1024, nil)
+tbl, _ = tx.Commit(ctx)
+```
+
+A normal scan reads it back; the variant column comes back as an
`*extensions.VariantArray`:
+
+```go
+result, _ := tbl.Scan().ToArrowTable(ctx)
+defer result.Release()
+
+variants := result.Column(0).Data().Chunk(0).(*extensions.VariantArray)
+v, _ := variants.Value(0)
+fmt.Println(v.Value()) // variant.ObjectValue for the object above
+```
+
+## Shredding
+
+Shredding stores the fields of a variant as typed Parquet sub-columns instead
of a
+single opaque blob. This lets scans read and filter a field as a native column
+rather than decoding every value. Shredding is opt-in and configured with two
write
+properties (see [Configuration](./configuration.md#parquet-writer)):
+
+- `write.parquet.shred-variants` - enable shredding of top-level variant
columns
+ (default `false`).
+- `write.parquet.variant-inference-buffer-size` - rows buffered per file to
infer
+ the shredding schema (default `100`).
+
+The reader accepts both shredded and non-shredded data; no read-side
+configuration is required.
+
+## Filtering on variant fields
+
+Filter on a field inside a variant with `iceberg.Extract`, which plugs into the
+usual predicate builders. See [Row Filter
Syntax](./row-filter-syntax.md#variant-extraction)
+for usage, supported target types, and caveats.
+
+## Constraints
+
+- A variant column cannot be a partition source or an identity-transform
source.