This is an automated email from the ASF dual-hosted git repository. roryqi pushed a commit to branch tag-value-user-docs in repository https://gitbox.apache.org/repos/asf/gravitino.git
commit bd7e91f241bffdd41cbf748061a17247a05bef95 Author: roryqi <[email protected]> AuthorDate: Wed Aug 19 07:58:34 2026 +0000 [#12505] docs: Add user documentation for tag assignment values --- docs/manage-tags-in-gravitino.md | 129 ++++++++++++++++++++++++++++++++++++++- docs/tags.md | 26 +++++++- 2 files changed, 152 insertions(+), 3 deletions(-) diff --git a/docs/manage-tags-in-gravitino.md b/docs/manage-tags-in-gravitino.md index 016709b7ac..3f4138dc19 100644 --- a/docs/manage-tags-in-gravitino.md +++ b/docs/manage-tags-in-gravitino.md @@ -55,6 +55,52 @@ tag = client.create_tag( </TabItem> </Tabs> +### Create a Tag With a Value Constraint + +A tag can accept any value, no value, or only a fixed set of values. The constraint is set at +creation time and cannot be altered later. Omitting `allowedValues` over REST or Python creates an +unrestricted tag; an empty list creates a tag that can only be assigned without a value. + +<Tabs groupId='language' queryString> +<TabItem value="shell" label="REST"> + +```shell +curl -X POST -H "Accept: application/vnd.gravitino.v1+json" \ + -H "Content-Type: application/json" -d '{ + "name": "data_domain", + "comment": "Business data domain", + "allowedValues": ["finance", "risk", "ml"] +}' http://localhost:8090/api/metalakes/test/tags +``` + +</TabItem> +<TabItem value="java" label="Java"> + +```java +Tag tag = client.createTag( + "data_domain", + "Business data domain", + ImmutableMap.of(), + TagValueConstraint.ofAllowedValues("finance", "risk", "ml")); +``` + +Use `TagValueConstraint.anyValue()` for an unrestricted tag and +`TagValueConstraint.noValue()` for a tag that cannot carry assignment values. + +</TabItem> +<TabItem value="python" label="Python"> + +```python +tag = client.create_tag( + tag_name="data_domain", + comment="Business data domain", + properties={}, + allowed_values=["finance", "risk", "ml"]) +``` + +</TabItem> +</Tabs> + ### List Tags Listing returns names, or full tag objects when `details=true` is set. @@ -243,10 +289,71 @@ raw_events.supports_tags().associate_tags(["pii"], None) </TabItem> </Tabs> +### Assign and Remove Tag Values + +Tag values are updated as pairs of tag name and value. Adding a pair preserves the tag's other +values; removing a pair removes only that value. Omit `value` to represent an assignment without a +value. The REST operation uses the v2 media type for the request body. + +<Tabs groupId='language' queryString> +<TabItem value="shell" label="REST"> + +```shell +curl -X POST -H "Accept: application/vnd.gravitino.v2+json" \ + -H "Content-Type: application/vnd.gravitino.v2+json" -d '{ + "tagsToAdd": [ + {"name": "data_domain", "value": "finance"}, + {"name": "data_domain", "value": "risk"}, + {"name": "pii"} + ], + "tagsToRemove": [ + {"name": "data_domain", "value": "old"} + ] +}' http://localhost:8090/api/metalakes/test/objects/table/catalog1.schema1.customers/tags +``` + +</TabItem> +<TabItem value="java" label="Java"> + +```java +Table customers = ... +customers.supportsTags().associateTags( + new TagValue[] { + TagValue.of("data_domain", "finance"), + TagValue.of("data_domain", "risk"), + TagValue.noValue("pii") + }, + new TagValue[] {TagValue.of("data_domain", "old")}); +``` + +</TabItem> +<TabItem value="python" label="Python"> + +```python +customers = ... +customers.supports_tags().assign_tags( + tags_to_add=[ + {"name": "data_domain", "value": "finance"}, + {"name": "data_domain", "value": "risk"}, + {"name": "pii"}, + ], + tags_to_remove=[{"name": "data_domain", "value": "old"}]) +``` + +</TabItem> +</Tabs> + +The same pair can be added or removed repeatedly without changing the result. A request cannot add +the same tag both with and without values, or include the same pair in both lists. To convert a +valued assignment to a valueless one, remove every active value and add the valueless pair in the +same request. Removing the last value without adding a valueless pair detaches the tag. + ### List Tags on an Object The response includes tags inherited from ancestors. With `details=true` each tag carries an -`inherited` field, which a plain name listing does not. +`inherited` field and its `assignmentValues`, which a plain name listing does not. An empty +`assignmentValues` array means the tag is assigned without a value. `allowedValues` is null for an +unrestricted tag, empty for a valueless-only tag, and otherwise contains the tag's allowed values. <Tabs groupId='language' queryString> <TabItem value="shell" label="REST"> @@ -263,6 +370,7 @@ curl -X GET -H "Accept: application/vnd.gravitino.v1+json" \ Table customers = ... String[] tagNames = customers.supportsTags().listTags(); Tag[] tags = customers.supportsTags().listTagsInfo(); +String[] values = tags[0].assignment().get().values(); ``` </TabItem> @@ -272,6 +380,7 @@ Tag[] tags = customers.supportsTags().listTagsInfo(); customers = ... tag_names = customers.supports_tags().list_tags() tags = customers.supports_tags().list_tags_info() +values = tags[0].assignment_values() ``` </TabItem> @@ -307,7 +416,8 @@ tag = customers.supports_tags().get_tag("pii") ### List Objects Carrying a Tag The response lists direct attachments only, so a tag attached to a catalog returns that catalog -rather than the objects beneath it. +rather than the objects beneath it. Pass `value` to return only direct assignments containing that +exact, case-sensitive value. Valueless assignments do not match a value filter. <Tabs groupId='language' queryString> <TabItem value="shell" label="REST"> @@ -315,6 +425,9 @@ rather than the objects beneath it. ```shell curl -X GET -H "Accept: application/vnd.gravitino.v1+json" \ http://localhost:8090/api/metalakes/test/tags/pii/objects + +curl -X GET -H "Accept: application/vnd.gravitino.v1+json" \ + "http://localhost:8090/api/metalakes/test/tags/data_domain/objects?value=finance" ``` </TabItem> @@ -324,6 +437,18 @@ curl -X GET -H "Accept: application/vnd.gravitino.v1+json" \ Tag tag = client.getTag("pii"); MetadataObject[] objects = tag.associatedObjects().objects(); int count = tag.associatedObjects().count(); + +Tag domain = client.getTag("data_domain"); +MetadataObject[] financeObjects = domain.associatedObjects().objects("finance"); +``` + +</TabItem> +<TabItem value="python" label="Python"> + +```python +tag = client.get_tag("data_domain") +objects = tag.associated_objects().objects() +finance_objects = tag.associated_objects().objects(value="finance") ``` </TabItem> diff --git a/docs/tags.md b/docs/tags.md index ce4a334e63..135fc965d0 100644 --- a/docs/tags.md +++ b/docs/tags.md @@ -69,7 +69,7 @@ once. To reach every object in a catalog, attach the tag to the catalog. The UI attaches tags on catalogs, schemas, tables, and columns. For the other types, use the REST API described at the end of this page. -### Names and Properties +### Names, Properties, and Assignment Values A tag name is unique within its metalake and is the identifier used everywhere else, so renaming a tag changes what every stored request has to ask for. @@ -82,6 +82,24 @@ every object carrying the tag sees the same values. Properties suit facts about which team owns it or which external system it came from. Properties do not suit facts about one tagged object. +Assignment values describe one tag on one object. For example, the same `data_domain` tag can have +the value `finance` on one table and `risk` on another. An assignment can have no value, one value, +or several values. Adding a value is incremental, so adding `risk` to an assignment that already has +`finance` leaves both values in place. + +When you create a tag, you can choose one of three value constraints: + +| Constraint | Meaning | +|------------|---------| +| Any value | The tag accepts any non-blank string, and can also be assigned without a value | +| No value | The tag can only be assigned without a value | +| Allowed values | The tag accepts only values from the configured list | + +Values are case-sensitive strings of up to 256 characters. The constraint cannot be changed after +the tag is created. Tag properties and assignment values are separate: changing a property affects +the tag everywhere, while changing an assignment value affects only that object. Assignment values +are currently managed through the REST API or the Java and Python clients. + ### Inheritance An object shows the tags attached to it plus the tags attached to each of its ancestors, so a tag @@ -92,6 +110,12 @@ inherits from both of the schemas above it. Each tag appears once, whether it reaches the object through one ancestor or several. A tag attached directly to the object counts as direct even when an ancestor carries it too. +Assignment values follow the same inheritance path. If a child has no direct assignment for a tag, +it receives the values from the nearest effective ancestor. A direct assignment on the child +overrides the inherited assignment for that tag; its values are not merged with ancestor values. +For example, a table assigned `data_domain = risk` shows only `risk` even when its catalog is +assigned `data_domain = finance`. + The two are distinguishable. In the UI an inherited tag is marked with a lock icon. Over REST, a tag listing requested with `details=true` carries an `inherited` field on each tag, which a plain listing of names does not.
