This is an automated email from the ASF dual-hosted git repository.
roryqi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new 15dffd5673 [#12505] docs: Add user documentation for tag assignment
values (#12510)
15dffd5673 is described below
commit 15dffd567320454643228efcf8c52b284a52a15d
Author: roryqi <[email protected]>
AuthorDate: Thu Aug 20 14:46:55 2026 +0800
[#12505] docs: Add user documentation for tag assignment values (#12510)
### What changes were proposed in this pull request?
Add user documentation for tag assignment values, including:
- Value constraints and assignment semantics
- Assignment value inheritance
- REST, Java, and Python examples
- Exact-value metadata object lookup
### Why are the changes needed?
Tag assignment values are supported by Gravitino, but users currently
need to consult the design
document or implementation to understand and use them.
Fix: #12505
### Does this PR introduce _any_ user-facing change?
Yes. It documents the existing tag assignment value APIs and behavior.
It does not change any API
or property.
### How was this patch tested?
- Ran `git diff --check`.
- Reviewed all examples against the current REST, Java, and Python APIs.
---
docs/manage-tags-in-gravitino.md | 148 ++++++++++++++++++++++++++++++++++++++-
docs/tags.md | 26 ++++++-
2 files changed, 171 insertions(+), 3 deletions(-)
diff --git a/docs/manage-tags-in-gravitino.md b/docs/manage-tags-in-gravitino.md
index 016709b7ac..f5308db080 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">
@@ -256,6 +363,24 @@ curl -X GET -H "Accept: application/vnd.gravitino.v1+json"
\
"http://localhost:8090/api/metalakes/test/objects/table/catalog1.schema1.customers/tags?details=true"
```
+The response includes each tag's definition and assignment details:
+
+```json
+{
+ "code": 0,
+ "tags": [
+ {
+ "name": "data_domain",
+ "comment": "Business data domain",
+ "properties": {},
+ "allowedValues": ["finance", "risk", "ml"],
+ "assignmentValues": ["finance", "risk"],
+ "inherited": false
+ }
+ ]
+}
+```
+
</TabItem>
<TabItem value="java" label="Java">
@@ -263,6 +388,8 @@ 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().map(assignment -> assignment.values()).orElse(new
String[0]);
```
</TabItem>
@@ -272,6 +399,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 +435,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 +444,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 +456,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..f978c2dc9e 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.