This is an automated email from the ASF dual-hosted git repository.
jshao pushed a commit to branch branch-0.8
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/branch-0.8 by this push:
new d565a304b0 [#6222]feat(tag): Add tag support for model (#6500)
d565a304b0 is described below
commit d565a304b0a55c9d61d455535c7fcc853d93ea21
Author: mchades <[email protected]>
AuthorDate: Mon Feb 24 13:29:12 2025 +0800
[#6222]feat(tag): Add tag support for model (#6500)
### What changes were proposed in this pull request?
This PR adds the tag support for model metadata.
### Why are the changes needed?
This is to complement the tag support for model metadata.
Fix: #6222
### Does this PR introduce _any_ user-facing change?
No.
### How was this patch tested?
Add ITs in test.
(cherry picked from commit 4c5e9db46c83a105ff886e3e49e6ce04b323a5e6)
Co-authored-by: Jerry Shao <[email protected]>
---
.../java/org/apache/gravitino/MetadataObjects.java | 1 +
.../org/apache/gravitino/client/GenericModel.java | 42 +++++++-
.../gravitino/client/GenericModelCatalog.java | 4 +-
.../gravitino/client/integration/test/TagIT.java | 113 +++++++++++++++++++++
docs/manage-tags-in-gravitino.md | 8 +-
docs/open-api/tags.yaml | 4 +-
6 files changed, 161 insertions(+), 11 deletions(-)
diff --git a/api/src/main/java/org/apache/gravitino/MetadataObjects.java
b/api/src/main/java/org/apache/gravitino/MetadataObjects.java
index 557ccdefc4..e96b6e7e4a 100644
--- a/api/src/main/java/org/apache/gravitino/MetadataObjects.java
+++ b/api/src/main/java/org/apache/gravitino/MetadataObjects.java
@@ -126,6 +126,7 @@ public class MetadataObjects {
case TABLE:
case FILESET:
case TOPIC:
+ case MODEL:
parentType = MetadataObject.Type.SCHEMA;
break;
case SCHEMA:
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModel.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModel.java
index 2d356b712f..d4c0c24f1a 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModel.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModel.java
@@ -18,20 +18,35 @@
*/
package org.apache.gravitino.client;
+import com.google.common.collect.Lists;
+import java.util.List;
import java.util.Map;
import org.apache.gravitino.Audit;
+import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.MetadataObjects;
+import org.apache.gravitino.Namespace;
import org.apache.gravitino.authorization.SupportsRoles;
import org.apache.gravitino.dto.model.ModelDTO;
+import org.apache.gravitino.exceptions.NoSuchTagException;
+import org.apache.gravitino.exceptions.TagAlreadyAssociatedException;
import org.apache.gravitino.model.Model;
import org.apache.gravitino.tag.SupportsTags;
+import org.apache.gravitino.tag.Tag;
/** Represents a generic model. */
-class GenericModel implements Model {
+class GenericModel implements Model, SupportsTags {
private final ModelDTO modelDTO;
- GenericModel(ModelDTO modelDTO) {
+ private final MetadataObjectTagOperations objectTagOperations;
+
+ GenericModel(ModelDTO modelDTO, RESTClient restClient, Namespace modelNs) {
this.modelDTO = modelDTO;
+ List<String> modelFullName =
+ Lists.newArrayList(modelNs.level(1), modelNs.level(2),
modelDTO.name());
+ MetadataObject modelObject = MetadataObjects.of(modelFullName,
MetadataObject.Type.MODEL);
+ this.objectTagOperations =
+ new MetadataObjectTagOperations(modelNs.level(0), modelObject,
restClient);
}
@Override
@@ -61,7 +76,7 @@ class GenericModel implements Model {
@Override
public SupportsTags supportsTags() {
- throw new UnsupportedOperationException("Not supported yet.");
+ return this;
}
@Override
@@ -86,4 +101,25 @@ class GenericModel implements Model {
public int hashCode() {
return modelDTO.hashCode();
}
+
+ @Override
+ public String[] listTags() {
+ return objectTagOperations.listTags();
+ }
+
+ @Override
+ public Tag[] listTagsInfo() {
+ return objectTagOperations.listTagsInfo();
+ }
+
+ @Override
+ public Tag getTag(String name) throws NoSuchTagException {
+ return objectTagOperations.getTag(name);
+ }
+
+ @Override
+ public String[] associateTags(String[] tagsToAdd, String[] tagsToRemove)
+ throws TagAlreadyAssociatedException {
+ return objectTagOperations.associateTags(tagsToAdd, tagsToRemove);
+ }
}
diff --git
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModelCatalog.java
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModelCatalog.java
index 50e9eb246a..8658a97259 100644
---
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModelCatalog.java
+++
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModelCatalog.java
@@ -97,7 +97,7 @@ class GenericModelCatalog extends BaseSchemaCatalog
implements ModelCatalog {
ErrorHandlers.modelErrorHandler());
resp.validate();
- return new GenericModel(resp.getModel());
+ return new GenericModel(resp.getModel(), restClient, modelFullNs);
}
@Override
@@ -118,7 +118,7 @@ class GenericModelCatalog extends BaseSchemaCatalog
implements ModelCatalog {
ErrorHandlers.modelErrorHandler());
resp.validate();
- return new GenericModel(resp.getModel());
+ return new GenericModel(resp.getModel(), restClient, modelFullNs);
}
@Override
diff --git
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/TagIT.java
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/TagIT.java
index 4278d3f886..c532bc93f3 100644
---
a/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/TagIT.java
+++
b/clients/client-java/src/test/java/org/apache/gravitino/client/integration/test/TagIT.java
@@ -37,6 +37,7 @@ import
org.apache.gravitino.integration.test.container.ContainerSuite;
import org.apache.gravitino.integration.test.container.HiveContainer;
import org.apache.gravitino.integration.test.util.BaseIT;
import org.apache.gravitino.integration.test.util.GravitinoITUtils;
+import org.apache.gravitino.model.Model;
import org.apache.gravitino.rel.Column;
import org.apache.gravitino.rel.Table;
import org.apache.gravitino.rel.types.Types;
@@ -60,6 +61,10 @@ public class TagIT extends BaseIT {
private static Schema schema;
private static Table table;
+ private static Catalog modelCatalog;
+ private static Schema modelSchema;
+ private static Model model;
+
private static Column column;
@BeforeAll
@@ -108,6 +113,29 @@ public class TagIT extends BaseIT {
"comment",
Collections.emptyMap());
column = Arrays.stream(table.columns()).filter(c ->
c.name().equals("col1")).findFirst().get();
+
+ // Create model catalog
+ String modelCatalogName =
GravitinoITUtils.genRandomName("tag_it_model_catalog");
+ Assertions.assertFalse(metalake.catalogExists(modelCatalogName));
+ modelCatalog =
+ metalake.createCatalog(
+ modelCatalogName, Catalog.Type.MODEL, "comment",
Collections.emptyMap());
+
+ // Create model schema
+ String modelSchemaName =
GravitinoITUtils.genRandomName("tag_it_model_schema");
+
Assertions.assertFalse(modelCatalog.asSchemas().schemaExists(modelSchemaName));
+ modelSchema =
+ modelCatalog.asSchemas().createSchema(modelSchemaName, "comment",
Collections.emptyMap());
+
+ // Create model
+ String modelName = GravitinoITUtils.genRandomName("tag_it_model");
+ Assertions.assertFalse(
+
modelCatalog.asModelCatalog().modelExists(NameIdentifier.of(modelSchemaName,
modelName)));
+ model =
+ modelCatalog
+ .asModelCatalog()
+ .registerModel(
+ NameIdentifier.of(modelSchemaName, modelName), "comment",
Collections.emptyMap());
}
@AfterAll
@@ -115,6 +143,11 @@ public class TagIT extends BaseIT {
relationalCatalog.asTableCatalog().dropTable(NameIdentifier.of(schema.name(),
table.name()));
relationalCatalog.asSchemas().dropSchema(schema.name(), true);
metalake.dropCatalog(relationalCatalog.name(), true);
+
+
modelCatalog.asModelCatalog().deleteModel(NameIdentifier.of(modelSchema.name(),
model.name()));
+ modelCatalog.asSchemas().dropSchema(modelSchema.name(), true);
+ metalake.dropCatalog(modelCatalog.name(), true);
+
client.dropMetalake(metalakeName, true);
if (client != null) {
@@ -653,4 +686,84 @@ public class TagIT extends BaseIT {
String[] associatedTags1 = relationalCatalog.supportsTags().listTags();
Assertions.assertArrayEquals(new String[] {tag2.name()}, associatedTags1);
}
+
+ @Test
+ public void testAssociateTagsToModel() {
+ Tag tag1 =
+ metalake.createTag(
+ GravitinoITUtils.genRandomName("tag_it_model_tag1"),
+ "comment1",
+ Collections.emptyMap());
+ Tag tag2 =
+ metalake.createTag(
+ GravitinoITUtils.genRandomName("tag_it_model_tag2"),
+ "comment2",
+ Collections.emptyMap());
+ Tag tag3 =
+ metalake.createTag(
+ GravitinoITUtils.genRandomName("tag_it_model_tag3"),
+ "comment3",
+ Collections.emptyMap());
+
+ // Associate tags to catalog
+ modelCatalog.supportsTags().associateTags(new String[] {tag1.name()},
null);
+
+ // Associate tags to schema
+ modelSchema.supportsTags().associateTags(new String[] {tag2.name()}, null);
+
+ // Associate tags to model
+ model.supportsTags().associateTags(new String[] {tag3.name()}, null);
+
+ // Test list associated tags for model
+ String[] tags1 = model.supportsTags().listTags();
+ Assertions.assertEquals(3, tags1.length);
+ Set<String> tagNames = Sets.newHashSet(tags1);
+ Assertions.assertTrue(tagNames.contains(tag1.name()));
+ Assertions.assertTrue(tagNames.contains(tag2.name()));
+ Assertions.assertTrue(tagNames.contains(tag3.name()));
+
+ // Test list associated tags with details for model
+ Tag[] tags2 = model.supportsTags().listTagsInfo();
+ Assertions.assertEquals(3, tags2.length);
+
+ Set<Tag> nonInheritedTags =
+ Arrays.stream(tags2).filter(tag ->
!tag.inherited().get()).collect(Collectors.toSet());
+ Set<Tag> inheritedTags =
+ Arrays.stream(tags2).filter(tag ->
tag.inherited().get()).collect(Collectors.toSet());
+
+ Assertions.assertEquals(1, nonInheritedTags.size());
+ Assertions.assertEquals(2, inheritedTags.size());
+ Assertions.assertTrue(nonInheritedTags.contains(tag3));
+ Assertions.assertTrue(inheritedTags.contains(tag1));
+ Assertions.assertTrue(inheritedTags.contains(tag2));
+
+ // Test get associated tag for model
+ Tag resultTag1 = model.supportsTags().getTag(tag1.name());
+ Assertions.assertEquals(tag1, resultTag1);
+ Assertions.assertTrue(resultTag1.inherited().get());
+
+ Tag resultTag2 = model.supportsTags().getTag(tag2.name());
+ Assertions.assertEquals(tag2, resultTag2);
+ Assertions.assertTrue(resultTag2.inherited().get());
+
+ Tag resultTag3 = model.supportsTags().getTag(tag3.name());
+ Assertions.assertEquals(tag3, resultTag3);
+ Assertions.assertFalse(resultTag3.inherited().get());
+
+ // Test get objects associated with tag
+ Assertions.assertEquals(1, tag1.associatedObjects().count());
+ Assertions.assertEquals(modelCatalog.name(),
tag1.associatedObjects().objects()[0].name());
+ Assertions.assertEquals(
+ MetadataObject.Type.CATALOG,
tag1.associatedObjects().objects()[0].type());
+
+ Assertions.assertEquals(1, tag2.associatedObjects().count());
+ Assertions.assertEquals(modelSchema.name(),
tag2.associatedObjects().objects()[0].name());
+ Assertions.assertEquals(
+ MetadataObject.Type.SCHEMA,
tag2.associatedObjects().objects()[0].type());
+
+ Assertions.assertEquals(1, tag3.associatedObjects().count());
+ Assertions.assertEquals(model.name(),
tag3.associatedObjects().objects()[0].name());
+ Assertions.assertEquals(
+ MetadataObject.Type.MODEL,
tag3.associatedObjects().objects()[0].type());
+ }
}
diff --git a/docs/manage-tags-in-gravitino.md b/docs/manage-tags-in-gravitino.md
index 4163ca89d2..04e5b79ec8 100644
--- a/docs/manage-tags-in-gravitino.md
+++ b/docs/manage-tags-in-gravitino.md
@@ -23,12 +23,12 @@ the future versions.
:::info
1. Metadata objects are objects that are managed in Gravitino, such as
`CATALOG`, `SCHEMA`, `TABLE`,
- `COLUMN`, `FILESET`, `TOPIC`, `COLUMN`, etc. A metadata object is combined
by a `type` and a
+ `COLUMN`, `FILESET`, `TOPIC`, `COLUMN`, `MODEL`, etc. A metadata object is
combined by a `type` and a
comma-separated `name`. For example, a `CATAGLOG` object has a name
"catalog1" with type
"CATALOG", a `SCHEMA` object has a name "catalog1.schema1" with type
"SCHEMA", a `TABLE`
object has a name "catalog1.schema1.table1" with type "TABLE", a `COLUMN`
object has a name
"catalog1.schema1.table1.column1" with type "COLUMN".
-2. Currently, `CATALOG`, `SCHEMA`, `TABLE`, `FILESET`, `TOPIC`, and `COLUMN`
objects can be tagged.
+2. Currently, `CATALOG`, `SCHEMA`, `TABLE`, `FILESET`, `TOPIC`, `MODEL`, and
`COLUMN` objects can be tagged.
3. Tags in Gravitino is inheritable, so listing tags of a metadata object will
also list the
tags of its parent metadata objects. For example, listing tags of a `Table`
will also list
the tags of its parent `Schema` and `Catalog`.
@@ -204,8 +204,8 @@ client.deleteTag("tag2");
## Tag associations
-Gravitino allows you to associate and disassociate tags with metadata objects.
Currently, only
-`CATALOG`, `SCHEMA`, `TABLE`, `FILESET`, `TOPIC` objects can be tagged.
+Gravitino allows you to associate and disassociate tags with metadata objects.
Currently,
+`CATALOG`, `SCHEMA`, `TABLE`, `FILESET`, `TOPIC`, `MODEL`, and `COLUMN`
objects can be tagged.
### Associate and disassociate tags with a metadata object
diff --git a/docs/open-api/tags.yaml b/docs/open-api/tags.yaml
index a3be5230b9..a8b3ac053c 100644
--- a/docs/open-api/tags.yaml
+++ b/docs/open-api/tags.yaml
@@ -394,8 +394,8 @@ components:
- "TABLE"
- "FILESET"
- "TOPIC"
- - "ROLE"
- - "METALAKE"
+ - "MODEL"
+ - "COLUMN"
requests: