Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spec: Variant lower/upper bounds #12658

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

aihuaxu
Copy link
Contributor

@aihuaxu aihuaxu commented Mar 26, 2025

This is to update the bound spec for Variant type columns. We are collecting all the shredded bounds for a column in a file into a Variant object. E.g.

For a Variant schema like,

{
  "event_type": "login",
  "user.name": "Alex", 
  "tags": ["action", "drama"]
}

when the fields are shredded, the bound object looks like:

{
  "$['event_type']": "login",
  "$['user.name']": "Alex",
  "$['tags'][0]":"action"
}

and then it's serialized into binary. In order to support dot in the key name, we will use JSON normalized path as the subcolumn path.

@github-actions github-actions bot added the Specification Issues that may introduce spec changes. label Mar 26, 2025
@aihuaxu
Copy link
Contributor Author

aihuaxu commented Mar 26, 2025

format/spec.md Outdated
@@ -648,6 +648,9 @@ Notes:
5. The `content_offset` and `content_size_in_bytes` fields are used to reference a specific blob for direct access to a deletion vector. For deletion vectors, these values are required and must exactly match the `offset` and `length` stored in the Puffin footer for the deletion vector blob.
6. The following field ids are reserved on `data_file`: 141.

For `variant` type, the `lower_bounds` and `upper_bounds` store the minimum and maximum values for all shredded subcolumns within a file. These bounds are represented as a Variant object, where each subcolumn path serves as a key and the corresponding bound value as the value. The object is then serialized into binary format (see [Variant encoding](https://github.com/apache/parquet-format/blob/master/VariantEncoding.md)).
Subcolumn paths follow the JSON path format, such as `$.event.event_type` for standard keys or `$.event.["user.name"]` for keys containing dots.
Copy link
Contributor

@rdblue rdblue Mar 26, 2025

Choose a reason for hiding this comment

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

I think that $.event.["user.name"] should not have a . after event in the format. I would also say that if we are asking for JSON path notation, then we should use the canonical "Normalized Path" form (Section 2.7), which is to always use ['name'] syntax (with single quotes, not double). I think that's probably a good idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Make sense. That would reduce the variation. I also update to add the array representation to use always index 0 like $['tags'][0]. Let me know your thoughts.

format/spec.md Outdated
@@ -648,6 +648,9 @@ Notes:
5. The `content_offset` and `content_size_in_bytes` fields are used to reference a specific blob for direct access to a deletion vector. For deletion vectors, these values are required and must exactly match the `offset` and `length` stored in the Puffin footer for the deletion vector blob.
6. The following field ids are reserved on `data_file`: 141.

For `variant` type, the `lower_bounds` and `upper_bounds` store the minimum and maximum values for all shredded subcolumns within a file. These bounds are represented as a Variant object, where each subcolumn path serves as a key and the corresponding bound value as the value. The object is then serialized into binary format (see [Variant encoding](https://github.com/apache/parquet-format/blob/master/VariantEncoding.md)).
Copy link
Contributor

Choose a reason for hiding this comment

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

For variant type, the lower_bounds and upper_bounds store the minimum and maximum values for all shredded subcolumns within a file.

I'm not quite sure if we need to add the collection behavior of lower_bound and upper_bound under different conditions as mentioned in the proposal. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@XBaith What kind of collection behavior you are referring to? Can you clarify?

Copy link
Contributor

Choose a reason for hiding this comment

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

Lower and upper bound statistics for subcolumns are collected for each data file based on the following conditions:
Uniform Value Types:
If all subcolumn values match the shredded type, lower/upper bounds are collected.
Example: For event.location.longitude, if all values are of the double type, the lower/upper bounds are written to the manifest file.
Mixed Value Types:
If the subcolumn contains multiple types (e.g., double and string), lower/upper bound statistics are not collected.
Example: For event.location.longitude, if the values include both double and string, lower/upper bounds are excluded.
Some subcolumn values are nulls or missing:
If some subcolumn values are null or missing in a file, but the available values match the shredded type, lower/upper bounds are still collected.
If all the subcolumn values are nulls, then lower/upper bounds are not collected. null_value_counts stat can be collected in later implementation to be used with value_counts to know they are all nulls.

@@ -648,6 +648,9 @@ Notes:
5. The `content_offset` and `content_size_in_bytes` fields are used to reference a specific blob for direct access to a deletion vector. For deletion vectors, these values are required and must exactly match the `offset` and `length` stored in the Puffin footer for the deletion vector blob.
6. The following field ids are reserved on `data_file`: 141.

For `variant` type, the `lower_bounds` and `upper_bounds` store the lower and upper bounds for all shredded subcolumns within a file. These bounds are represented as a Variant object, where each subcolumn path serves as a key and the corresponding bound value as the value. The object is then serialized into binary format (see [Variant encoding](https://github.com/apache/parquet-format/blob/master/VariantEncoding.md)).
Subcolumn paths follow the JSON path format to use normalized path, such as `$['location']['latitude']` or `$['user.name']`. If the shredded subcolumn is an array, represent it using the index 0 to indicate the array structure, such as `$['tags'][0]`.
Copy link
Contributor

Choose a reason for hiding this comment

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

There shouldn't be a need to include array paths. Bounds for array data are not tracked.

@@ -1558,6 +1561,7 @@ The binary single-value serialization can be used to store the lower and upper b
|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`geometry`** | A single point, encoded as a x:y:z:m concatenation of its 8-byte little-endian IEEE 754 coordinate values. x and y are mandatory. This becomes x:y if z and m are both unset, x:y:z if only m is unset, and x:y:NaN:m if only z is unset. |
| **`geography`** | A single point, encoded as a x:y:z:m concatenation of its 8-byte little-endian IEEE 754 coordinate values. x and y are mandatory. This becomes x:y if z and m are both unset, x:y:z if only m is unset, and x:y:NaN:m if only z is unset. |
| **`variant`** | A `Variant` object, where each subcolumn path serves as a key and the corresponding bound value as the value. Subcolumn paths follow the JSON path format. |
Copy link
Contributor

Choose a reason for hiding this comment

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

Variant is not something that we can reference here because that is a class in the implementation. I think what you want to say is that the serialized value is a variant metadata (v1) concatenated with a variant object. The object's fields are field paths in the normalized JSON path format and the values are the upper or lower bound corresponding to the shredded type in the data file.

@@ -648,6 +648,9 @@ Notes:
5. The `content_offset` and `content_size_in_bytes` fields are used to reference a specific blob for direct access to a deletion vector. For deletion vectors, these values are required and must exactly match the `offset` and `length` stored in the Puffin footer for the deletion vector blob.
6. The following field ids are reserved on `data_file`: 141.

For `variant` type, the `lower_bounds` and `upper_bounds` store the lower and upper bounds for all shredded subcolumns within a file. These bounds are represented as a Variant object, where each subcolumn path serves as a key and the corresponding bound value as the value. The object is then serialized into binary format (see [Variant encoding](https://github.com/apache/parquet-format/blob/master/VariantEncoding.md)).
Copy link
Contributor

Choose a reason for hiding this comment

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

This should not state "all shredded subcolumns". First, "all" is not a requirement and is actually misleading because the fields are only those for which we can guarantee the lower and upper bounds are accurate. I would also not use the somewhat confusing term "subcolumn". In the variant spec we refer to fields. You may also want to call out a special case where the root is not an object. In that case the lower or upper bound is tracked by the field name "$" indicating the root.

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.

4 participants