Visitar URL original
SPEC: Add vector type to v4 spec by yyanyy · Pull Request #18416 · apache/iceberg · GitHub
Skip to content

SPEC: Add vector type to v4 spec - #18416

Draft
yyanyy wants to merge 1 commit into
apache:mainfrom
yyanyy:spec/vector-type
Draft

yyanyy wants to merge 1 commit into
apache:mainfrom
yyanyy:spec/vector-type

Conversation

@yyanyy

@yyanyy yyanyy commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Adds a v4 vector(E, D) primitive type for fixed-length dense numeric vectors. Non-null vectors contain exactly D non-null finite elements of the allowed type E. Avro and ORC map vectors to arrays with reader and writer enforcement, while Parquet uses VECTOR(D) following apache/parquet-format#624. Schema JSON uses vector(<E>, <D>), and Appendix D defines JSON value serialization.

Issue: #18297

Test plan:

  • git diff --check origin/main...HEAD
  • Parsed format/spec.md using Python-Markdown with the tables extension.
  • make lint could not install its Python dependencies because the package index was unreachable; docs CI is required.

AI Disclosure

  • Model: GPT-5.6
  • Platform/Tool: Codex
  • Human Oversight: partially reviewed
  • Prompt Summary: Generated the vector type spec wording and mapping/serialization table updates from the author's proposal and review feedback.

@github-actions github-actions Bot added the Specification Issues that may introduce spec changes. label Oct 7, 2026
@yyanyy
yyanyy marked this pull request as draft October 7, 2026 21:25
Comment thread format/spec.md

Every non-null `vector(E, D)` value must contain exactly D non-null elements of type E. Floating-point elements must not be `NaN`, positive infinity, or negative infinity. The vector value itself may be null when the containing field is optional.

No type promotion to or from `vector` is defined, including changes to its element type or dimension. Lower and upper bounds are not defined for vector values.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might want to add something to the effect of "a list of type E and length D is not equivalent to a vector(E,D)"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1.

I want to add two more points

  • "No type promotion is defined" reads as unspecified, not forbidden.
  • The unknown exception is the v3+ rule that unknown promotes to any type. Without it, this sentence contradicts that table.

A vector must not be promoted to another type. No type other than unknown may be promoted to vector. The element type and dimension must not change. A list of element type E is not a vector(E, D), even when every value has length D.

I would also add more details along with the upper and lower bounds

Equality of vector values is element-wise, using the equality rules of element type. A vector must not be an identifier field. No sort order is defined for a vector value. Writers must not write lower or upper bounds for a vector field.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concerning lower/upper bounds, we should also adjust the table in the "Field Statistics" section to mention vectors are excluded.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't have stats for vectors, then we need to rely on other means to identify int8/uint8 etc.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What stats would let you know the type width? I know we have some things around variable length types but with int float and friends I'm not sure they would make sense

Comment thread format/spec.md

##### Vector

Every non-null `vector(E, D)` value must contain exactly D non-null elements of type E. Floating-point elements must not be `NaN`, positive infinity, or negative infinity. The vector value itself may be null when the containing field is optional.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last sentence is doing more work than it looks like, and "containing field" makes it harder to read than it needs to be. Suggested:

A non-null vector(E, D) contains exactly D elements of type E, and every element is non-null. float and double elements must be finite: NaN, +Infinity, and -Infinity are invalid. The vector value may be null only when the vector field is optional.

Comment thread format/spec.md
| | **`uuid`** | Universally unique identifiers | Should use 16-byte fixed |
| | **`fixed(L)`** | Fixed-length byte array of length L | |
| | **`binary`** | Arbitrary-length byte array | |
| [v4](#version-4) | **`vector(E, D)`** | Fixed-length collection of finite numeric values with element type E and dimension D | E must be `int`, `long`, `float`, or `double`; D must be positive |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

identity still allows every primitive except geometry and geography. We probably should exclude vector there.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do we think about storing smaller precision int/uint/float values?
The current types are very wide, and don't match types used on real world AI workloads.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, vectors used in search are predominantly 8-bit integer types, half- and single-precision floats. Double and long are rarely used.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would have to be a subsequent proposal since we don't have such types defined in iceberg yet.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

➕1 to support 8-bit byte data type as well.

Comment thread format/spec.md
| **`binary`** | `binary` | | |
| **`struct`** | `group` | | |
| **`list`** | `3-level list` | `LIST` | See Parquet docs for 3-level representation. |
| **`vector(E, D)`** | `3-level list` | `VECTOR(D)` | The element must be required and use the Parquet mapping for E. See [apache/parquet-format#624](https://github.com/apache/parquet-format/pull/624). |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to restate the physical contract here instead of using an unmerged Parquet PR as the normative text. We can update it later as the Parquet spec finalizes.

I am putting some keywords here. VECTOR(D), repeated group list, required primitive element mapped from E, exactly D elements, elements non-null and finite.

Comment thread format/spec.md
|**`binary`**|`bytes`||
|**`struct`**|`record`||
|**`list`**|`array`||
|**`vector(E, D)`**|`array`|Array elements must use the Avro mapping for E and must not be null. Readers and writers must enforce the vector dimension and element requirements.|

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avro stores both list and vector as array. The file type alone does not say which one it is.

Iceberg marks a list by writing element-id on the Avro array. That is the list element's field id. A vector has no element field id, so its array must not have element-id. A writer that adds one makes the file look like a list.

Suggested note on the Avro row:

Array elements must use the Avro mapping for E and must not be null. The array must not have element-id. Readers and writers enforce dimension D and the element rules from the Iceberg schema. An array of length D is not a vector.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to add an Avro logical type for vector?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the community sync, we said it might make sense to ask the Avro community about this. I started a discussion thread on the Avro dev mailing list: https://lists.apache.org/thread.html/ds0gm18b8cghotv4xtsmgo2ybghht60m

Comment thread format/spec.md

Every non-null `vector(E, D)` value must contain exactly D non-null elements of type E. Floating-point elements must not be `NaN`, positive infinity, or negative infinity. The vector value itself may be null when the containing field is optional.

No type promotion to or from `vector` is defined, including changes to its element type or dimension. Lower and upper bounds are not defined for vector values.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1.

I want to add two more points

  • "No type promotion is defined" reads as unspecified, not forbidden.
  • The unknown exception is the v3+ rule that unknown promotes to any type. Without it, this sentence contradicts that table.

A vector must not be promoted to another type. No type other than unknown may be promoted to vector. The element type and dimension must not change. A list of element type E is not a vector(E, D), even when every value has length D.

I would also add more details along with the upper and lower bounds

Equality of vector values is element-wise, using the equality rules of element type. A vector must not be an identifier field. No sort order is defined for a vector value. Writers must not write lower or upper bounds for a vector field.

Comment thread format/spec.md

### Version 4

The `vector` type is added in v4. Writing `vector` into a v3 or earlier schema is invalid.

@stevenzwu stevenzwu Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems unnecessary. I don't think we say this for the new types introduced in v3.

Writing `vector` into a v3 or earlier schema is invalid.

Comment thread format/spec.md

##### Vector

Every non-null `vector(E, D)` value must contain exactly D non-null elements of type E. Floating-point elements must not be `NaN`, positive infinity, or negative infinity. The vector value itself may be null when the containing field is optional.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to allow -0, +0?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you suggesting we might only allow one representation of the number zero? If yes, do you have use-cases in mind?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some research, and found that some AI hardware has some issues with these values. That said, I agree with the things discussed on the sync, and we should support these values as most other vector storage systems support it.

@PFischbeck PFischbeck left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this!

  • We should (probably) disallow vector default values, i.e., only allow null as default
  • We should disallow vector in all partition transforms (in expressions-spec.md)

Comment thread format/spec.md

##### Vector

Every non-null `vector(E, D)` value must contain exactly D non-null elements of type E. Floating-point elements must not be `NaN`, positive infinity, or negative infinity. The vector value itself may be null when the containing field is optional.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you suggesting we might only allow one representation of the number zero? If yes, do you have use-cases in mind?

Comment thread format/spec.md

Every non-null `vector(E, D)` value must contain exactly D non-null elements of type E. Floating-point elements must not be `NaN`, positive infinity, or negative infinity. The vector value itself may be null when the containing field is optional.

No type promotion to or from `vector` is defined, including changes to its element type or dimension. Lower and upper bounds are not defined for vector values.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concerning lower/upper bounds, we should also adjust the table in the "Field Statistics" section to mention vectors are excluded.

Comment thread format/spec.md
| **`binary`** | **`JSON string`** | `"000102ff"` | Stored as a hexadecimal string |
| **`struct`** | **`JSON object by field ID`** | `{"1": 1, "2": "bar"}` | Stores struct fields using the field ID as the JSON field name; field values are stored using this JSON single-value format |
| **`list`** | **`JSON array of values`** | `[1, 2, 3]` | Stores a JSON array of values that are serialized using this JSON single-value format |
| **`vector(E, D)`** | **`JSON array of values`** | `[1.0, 2.0, 3.0]` | Stores exactly D values using E's JSON single-value format |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would this be used for?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we allowing defaults? If so that would be one use case but this would be a pretty inefficient storage since I assume folks would want to default to all 0 or something

Comment thread format/spec.md
| **`binary`** | `binary` | | |
| **`struct`** | `struct` | | |
| **`list`** | `array` | | |
| **`vector(E, D)`** | `array` | | Array elements must use the ORC mapping for E and must not be null. Readers and writers must enforce the vector dimension and element requirements. |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not too familiar with ORC, but does it make sense to also add new ORC type attributes to mark it as vector?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly orc is a zombie in our ecosystem at the moment so whatever we do that is minimally sufficient is probably fine.

Comment thread format/spec.md
|**`binary`**|`bytes`||
|**`struct`**|`record`||
|**`list`**|`array`||
|**`vector(E, D)`**|`array`|Array elements must use the Avro mapping for E and must not be null. Readers and writers must enforce the vector dimension and element requirements.|

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to add an Avro logical type for vector?

@RussellSpitzer

Copy link
Copy Markdown
Member

Thanks for working on this!

  • We should (probably) disallow vector default values, i.e., only allow null as default
  • We should disallow vector in all partition transforms (in expressions-spec.md)

I think these are reasonable. For the purposes of the spec, while this is a primitive it basically should follow the same rules as list imho

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Specification Issues that may introduce spec changes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants