This is an automated email from the ASF dual-hosted git repository.

jshao 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 0bd4e54aad [#7382] feat(model): Implement operations for model version 
with multiple URIs (#7622)
0bd4e54aad is described below

commit 0bd4e54aaddba059807b3591bd0841469591336d
Author: XiaoZ <[email protected]>
AuthorDate: Tue Jul 22 14:52:04 2025 +0800

    [#7382] feat(model): Implement operations for model version with multiple 
URIs (#7622)
    
    ### What changes were proposed in this pull request?
    
    This PR implements operations for model version with multiple URIs.
    
    ### Why are the changes needed?
    
    Fix: #7382
    
    ### Does this PR introduce _any_ user-facing change?
    
    No.
    
    ### How was this patch tested?
    
    UT.
    
    ---------
    
    Co-authored-by: zhanghan <[email protected]>
---
 .../org/apache/gravitino/model/ModelCatalog.java   |  10 +-
 .../catalog/model/ModelCatalogOperations.java      |  69 +++-
 .../gravitino/catalog/model/ModelVersionImpl.java  |   2 +-
 .../catalog/model/TestModelCatalogOperations.java  | 368 +++++++++++++++------
 .../catalog/EntityCombinedModelVersion.java        |   4 +-
 .../catalog/ModelNormalizeDispatcher.java          |   4 +-
 .../catalog/ModelOperationDispatcher.java          |   4 +-
 .../gravitino/connector/BaseModelVersion.java      |  21 +-
 .../apache/gravitino/hook/ModelHookDispatcher.java |   8 +-
 .../gravitino/listener/ModelEventDispatcher.java   |  15 +-
 .../listener/api/info/ModelVersionInfo.java        |   2 +-
 .../org/apache/gravitino/TestModelVersion.java     |   2 +-
 .../catalog/TestModelOperationDispatcher.java      | 262 ++++++++++++---
 .../gravitino/connector/TestCatalogOperations.java |  74 ++++-
 .../listener/api/event/TestModelEvent.java         |  67 ++--
 .../gravitino/meta/TestEntityCombinedObject.java   |  29 ++
 16 files changed, 718 insertions(+), 223 deletions(-)

diff --git a/api/src/main/java/org/apache/gravitino/model/ModelCatalog.java 
b/api/src/main/java/org/apache/gravitino/model/ModelCatalog.java
index 9ef85ea42b..9f0f8caf1d 100644
--- a/api/src/main/java/org/apache/gravitino/model/ModelCatalog.java
+++ b/api/src/main/java/org/apache/gravitino/model/ModelCatalog.java
@@ -75,8 +75,8 @@ public interface ModelCatalog {
   /**
    * Register a model in the catalog if the model is not existed, otherwise 
the {@link
    * ModelAlreadyExistsException} will be thrown. The {@link Model} object 
will be created when the
-   * model is registered, users can call {@link 
ModelCatalog#linkModelVersion(NameIdentifier,
-   * String, String[], String, Map)} to link the model version to the 
registered {@link Model}.
+   * model is registered, users can call {@link 
ModelCatalog#linkModelVersion(NameIdentifier, Map,
+   * String[], String, Map)} to link the model version to the registered 
{@link Model}.
    *
    * @param ident The name identifier of the model.
    * @param comment The comment of the model. The comment is optional and can 
be null.
@@ -96,7 +96,7 @@ public interface ModelCatalog {
    * linked to the registered model.
    *
    * @param ident The name identifier of the model.
-   * @param uri The model artifact URI.
+   * @param uris The names and URIs of the model version artifact.
    * @param aliases The aliases of the model version. The aliases should be 
unique in this model,
    *     otherwise the {@link ModelVersionAliasesAlreadyExistException} will 
be thrown. The aliases
    *     are optional and can be empty. Also, be aware that the alias cannot 
be a number or a number
@@ -111,14 +111,14 @@ public interface ModelCatalog {
    */
   default Model registerModel(
       NameIdentifier ident,
-      String uri,
+      Map<String, String> uris,
       String[] aliases,
       String comment,
       Map<String, String> properties)
       throws NoSuchSchemaException, ModelAlreadyExistsException,
           ModelVersionAliasesAlreadyExistException {
     Model model = registerModel(ident, comment, properties);
-    linkModelVersion(ident, uri, aliases, comment, properties);
+    linkModelVersion(ident, uris, aliases, comment, properties);
     return model;
   }
 
diff --git 
a/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogOperations.java
 
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogOperations.java
index 9fda7c72b3..52172136f6 100644
--- 
a/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogOperations.java
+++ 
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogOperations.java
@@ -28,6 +28,7 @@ import java.time.Instant;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import org.apache.gravitino.Catalog;
 import org.apache.gravitino.Entity;
@@ -45,6 +46,7 @@ import 
org.apache.gravitino.exceptions.ModelVersionAliasesAlreadyExistException;
 import org.apache.gravitino.exceptions.NoSuchEntityException;
 import org.apache.gravitino.exceptions.NoSuchModelException;
 import org.apache.gravitino.exceptions.NoSuchModelVersionException;
+import org.apache.gravitino.exceptions.NoSuchModelVersionURINameException;
 import org.apache.gravitino.exceptions.NoSuchSchemaException;
 import org.apache.gravitino.meta.AuditInfo;
 import org.apache.gravitino.meta.ModelEntity;
@@ -226,7 +228,7 @@ public class ModelCatalogOperations extends 
ManagedSchemaOperations
   @Override
   public void linkModelVersion(
       NameIdentifier ident,
-      String uri,
+      Map<String, String> uris,
       String[] aliases,
       String comment,
       Map<String, String> properties)
@@ -245,7 +247,7 @@ public class ModelCatalogOperations extends 
ManagedSchemaOperations
             // executing the insert operation.
             .withVersion(INIT_VERSION)
             .withAliases(aliasList)
-            .withUris(ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, uri))
+            .withUris(uris)
             .withComment(comment)
             .withProperties(properties)
             .withAuditInfo(
@@ -267,6 +269,24 @@ public class ModelCatalogOperations extends 
ManagedSchemaOperations
     }
   }
 
+  @Override
+  public String getModelVersionUri(NameIdentifier ident, int version, String 
uriName)
+      throws NoSuchModelVersionException, NoSuchModelVersionURINameException {
+    NameIdentifierUtil.checkModel(ident);
+    NameIdentifier modelVersionIdent = 
NameIdentifierUtil.toModelVersionIdentifier(ident, version);
+
+    return internalGetModelVersionUri(ident, modelVersionIdent, 
Optional.ofNullable(uriName));
+  }
+
+  @Override
+  public String getModelVersionUri(NameIdentifier ident, String alias, String 
uriName)
+      throws NoSuchModelVersionException, NoSuchModelVersionURINameException {
+    NameIdentifierUtil.checkModel(ident);
+    NameIdentifier modelVersionIdent = 
NameIdentifierUtil.toModelVersionIdentifier(ident, alias);
+
+    return internalGetModelVersionUri(ident, modelVersionIdent, 
Optional.ofNullable(uriName));
+  }
+
   @Override
   public boolean deleteModelVersion(NameIdentifier ident, int version) {
     NameIdentifierUtil.checkModel(ident);
@@ -504,7 +524,7 @@ public class ModelCatalogOperations extends 
ManagedSchemaOperations
     return ModelVersionImpl.builder()
         .withVersion(modelVersion.version())
         .withAliases(modelVersion.aliases().toArray(new String[0]))
-        .withUri(modelVersion.uris().get(ModelVersion.URI_NAME_UNKNOWN))
+        .withUris(modelVersion.uris())
         .withComment(modelVersion.comment())
         .withProperties(modelVersion.properties())
         .withAuditInfo(modelVersion.auditInfo())
@@ -524,6 +544,49 @@ public class ModelCatalogOperations extends 
ManagedSchemaOperations
     }
   }
 
+  private String internalGetModelVersionUri(
+      NameIdentifier modelIdent, NameIdentifier modelVersionIdent, 
Optional<String> uriName) {
+    ModelVersion modelVersion = internalGetModelVersion(modelVersionIdent);
+
+    Map<String, String> uris = modelVersion.uris();
+    // If the uriName is present, get from the uris directly
+    if (uriName.isPresent()) {
+      return getUriByName(uris, uriName.get(), modelVersionIdent);
+    }
+
+    // If there is only one uri of the model version, use it
+    if (uris.size() == 1) {
+      return uris.values().iterator().next();
+    }
+
+    // If the uri name is null, try to get the default uri name from the model 
version properties
+    Map<String, String> modelVersionProperties = modelVersion.properties();
+    if 
(modelVersionProperties.containsKey(ModelVersion.PROPERTY_DEFAULT_URI_NAME)) {
+      String defaultUriName = 
modelVersionProperties.get(ModelVersion.PROPERTY_DEFAULT_URI_NAME);
+      return getUriByName(uris, defaultUriName, modelVersionIdent);
+    }
+
+    // If the default uri name is not set for the model version, try to get 
the default uri name
+    // from the model properties
+    Map<String, String> modelProperties = getModel(modelIdent).properties();
+    if (modelProperties.containsKey(ModelVersion.PROPERTY_DEFAULT_URI_NAME)) {
+      String defaultUriName = 
modelProperties.get(ModelVersion.PROPERTY_DEFAULT_URI_NAME);
+      return getUriByName(uris, defaultUriName, modelVersionIdent);
+    }
+
+    throw new IllegalArgumentException(
+        "The default uri name needs to be set when the uri name is not 
specified");
+  }
+
+  private String getUriByName(
+      Map<String, String> uris, String uriName, NameIdentifier 
modelVersionIdent) {
+    if (!uris.containsKey(uriName)) {
+      throw new NoSuchModelVersionURINameException(
+          "URI name %s does not exist in model version %s", uriName, 
modelVersionIdent);
+    }
+    return uris.get(uriName);
+  }
+
   private boolean internalDeleteModelVersion(NameIdentifier ident) {
     try {
       return store.delete(ident, Entity.EntityType.MODEL_VERSION);
diff --git 
a/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelVersionImpl.java
 
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelVersionImpl.java
index cff72c06ec..67d3104e0a 100644
--- 
a/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelVersionImpl.java
+++ 
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelVersionImpl.java
@@ -32,7 +32,7 @@ public class ModelVersionImpl extends BaseModelVersion {
       modelVersion.version = version;
       modelVersion.comment = comment;
       modelVersion.aliases = aliases;
-      modelVersion.uri = uri;
+      modelVersion.uris = uris;
       modelVersion.properties = properties;
       modelVersion.auditInfo = auditInfo;
       return modelVersion;
diff --git 
a/catalogs/catalog-model/src/test/java/org/apache/gravtitino/catalog/model/TestModelCatalogOperations.java
 
b/catalogs/catalog-model/src/test/java/org/apache/gravtitino/catalog/model/TestModelCatalogOperations.java
index 930e29f8ad..dd3fcb830d 100644
--- 
a/catalogs/catalog-model/src/test/java/org/apache/gravtitino/catalog/model/TestModelCatalogOperations.java
+++ 
b/catalogs/catalog-model/src/test/java/org/apache/gravtitino/catalog/model/TestModelCatalogOperations.java
@@ -64,6 +64,7 @@ import 
org.apache.gravitino.exceptions.ModelVersionAliasesAlreadyExistException;
 import org.apache.gravitino.exceptions.NoSuchCatalogException;
 import org.apache.gravitino.exceptions.NoSuchModelException;
 import org.apache.gravitino.exceptions.NoSuchModelVersionException;
+import org.apache.gravitino.exceptions.NoSuchModelVersionURINameException;
 import org.apache.gravitino.exceptions.NoSuchSchemaException;
 import org.apache.gravitino.exceptions.SchemaAlreadyExistsException;
 import org.apache.gravitino.meta.AuditInfo;
@@ -404,8 +405,8 @@ public class TestModelCatalogOperations {
     Map<String, String> versionProperties = 
StringIdentifier.newPropertiesWithId(versionId, null);
 
     String[] aliases = new String[] {"alias1", "alias2"};
-    ops.linkModelVersion(
-        modelIdent, "model_version_path", aliases, "version1 comment", 
versionProperties);
+    Map<String, String> uris = ImmutableMap.of("n1", "u1", "n2", "u2");
+    ops.linkModelVersion(modelIdent, uris, aliases, "version1 comment", 
versionProperties);
 
     Model loadedModel = ops.getModel(modelIdent);
     Assertions.assertEquals(1, loadedModel.latestVersion());
@@ -413,7 +414,7 @@ public class TestModelCatalogOperations {
     ModelVersion loadedVersion = ops.getModelVersion(modelIdent, 0);
     Assertions.assertEquals(0, loadedVersion.version());
     Assertions.assertEquals("version1 comment", loadedVersion.comment());
-    Assertions.assertEquals("model_version_path", loadedVersion.uri());
+    Assertions.assertEquals(uris, loadedVersion.uris());
     Assertions.assertEquals(versionProperties, loadedVersion.properties());
 
     // Test get a model version using alias
@@ -430,7 +431,7 @@ public class TestModelCatalogOperations {
             ops.linkModelVersion(
                 NameIdentifierUtil.ofModel(
                     METALAKE_NAME, CATALOG_NAME, schemaName, 
"non-existent-model"),
-                "model_version_path",
+                uris,
                 aliases,
                 "version1 comment",
                 versionProperties));
@@ -442,7 +443,7 @@ public class TestModelCatalogOperations {
             ops.linkModelVersion(
                 NameIdentifierUtil.ofModel(
                     METALAKE_NAME, CATALOG_NAME, "non-existent-schema", 
modelName),
-                "model_version_path",
+                uris,
                 aliases,
                 "version1 comment",
                 versionProperties));
@@ -452,21 +453,13 @@ public class TestModelCatalogOperations {
         ModelVersionAliasesAlreadyExistException.class,
         () ->
             ops.linkModelVersion(
-                modelIdent,
-                "model_version_path",
-                new String[] {"alias1"},
-                "version1 comment",
-                versionProperties));
+                modelIdent, uris, new String[] {"alias1"}, "version1 comment", 
versionProperties));
 
     Assertions.assertThrows(
         ModelVersionAliasesAlreadyExistException.class,
         () ->
             ops.linkModelVersion(
-                modelIdent,
-                "model_version_path",
-                new String[] {"alias2"},
-                "version1 comment",
-                versionProperties));
+                modelIdent, uris, new String[] {"alias2"}, "version1 comment", 
versionProperties));
 
     // Test get a model version from non-existent model
     Assertions.assertThrows(
@@ -490,7 +483,7 @@ public class TestModelCatalogOperations {
     StringIdentifier versionId2 = 
StringIdentifier.fromId(idGenerator.nextId());
     Map<String, String> versionProperties2 = 
StringIdentifier.newPropertiesWithId(versionId2, null);
 
-    ops.linkModelVersion(modelIdent, "model_version_path2", null, null, 
versionProperties2);
+    ops.linkModelVersion(modelIdent, uris, null, null, versionProperties2);
 
     // Test get a model version with null alias, comment and properties
     ModelVersion loadedVersion2 = ops.getModelVersion(modelIdent, 1);
@@ -498,6 +491,7 @@ public class TestModelCatalogOperations {
     Assertions.assertNull(loadedVersion2.comment());
     Assertions.assertEquals(versionProperties2, loadedVersion2.properties());
     Assertions.assertEquals(0, loadedVersion2.aliases().length);
+    Assertions.assertEquals(uris, loadedVersion2.uris());
 
     // Test get a model version with alias
     Assertions.assertThrows(
@@ -521,10 +515,10 @@ public class TestModelCatalogOperations {
     // Create a model version
     StringIdentifier versionId = StringIdentifier.fromId(idGenerator.nextId());
     Map<String, String> versionProperties = 
StringIdentifier.newPropertiesWithId(versionId, null);
+    Map<String, String> uris = ImmutableMap.of("n1", "u1", "n2", "u2");
 
     String[] aliases = new String[] {"alias1", "alias2"};
-    ops.linkModelVersion(
-        modelIdent, "model_version_path", aliases, "version1 comment", 
versionProperties);
+    ops.linkModelVersion(modelIdent, uris, aliases, "version1 comment", 
versionProperties);
 
     // List linked model versions
     int[] versions = ops.listModelVersions(modelIdent);
@@ -534,7 +528,7 @@ public class TestModelCatalogOperations {
     ModelVersion loadedVersion = ops.getModelVersion(modelIdent, versions[0]);
     Assertions.assertEquals(0, loadedVersion.version());
     Assertions.assertEquals("version1 comment", loadedVersion.comment());
-    Assertions.assertEquals("model_version_path", loadedVersion.uri());
+    Assertions.assertEquals(uris, loadedVersion.uris());
     Assertions.assertEquals(versionProperties, loadedVersion.properties());
 
     // Create another model version
@@ -542,8 +536,7 @@ public class TestModelCatalogOperations {
     Map<String, String> versionProperties2 = 
StringIdentifier.newPropertiesWithId(versionId2, null);
 
     String[] aliases2 = new String[] {"alias3", "alias4"};
-    ops.linkModelVersion(
-        modelIdent, "model_version_path2", aliases2, "version2 comment", 
versionProperties2);
+    ops.linkModelVersion(modelIdent, uris, aliases2, "version2 comment", 
versionProperties2);
 
     // List linked model versions
     int[] versions2 = ops.listModelVersions(modelIdent);
@@ -587,37 +580,37 @@ public class TestModelCatalogOperations {
     // Create a model version
     StringIdentifier versionId = StringIdentifier.fromId(idGenerator.nextId());
     Map<String, String> versionProperties = 
StringIdentifier.newPropertiesWithId(versionId, null);
+    Map<String, String> uris = ImmutableMap.of("n1", "u1", "n2", "u2");
 
     String[] aliases = new String[] {"alias1", "alias2"};
-    ops.linkModelVersion(
-        modelIdent, "model_version_path", aliases, "version1 comment", 
versionProperties);
+    ops.linkModelVersion(modelIdent, uris, aliases, "version1 comment", 
versionProperties);
 
     // List linked model versions info
     ModelVersion[] versions = ops.listModelVersionInfos(modelIdent);
     Assertions.assertEquals(1, versions.length);
     Assertions.assertEquals(0, versions[0].version());
     Assertions.assertEquals("version1 comment", versions[0].comment());
-    Assertions.assertEquals("model_version_path", versions[0].uri());
+    Assertions.assertEquals(uris, versions[0].uris());
     Assertions.assertEquals(versionProperties, versions[0].properties());
 
     // Create another model version
     StringIdentifier versionId2 = 
StringIdentifier.fromId(idGenerator.nextId());
     Map<String, String> versionProperties2 = 
StringIdentifier.newPropertiesWithId(versionId2, null);
+    Map<String, String> uris2 = ImmutableMap.of("n3", "u3");
 
     String[] aliases2 = new String[] {"alias3", "alias4"};
-    ops.linkModelVersion(
-        modelIdent, "model_version_path2", aliases2, "version2 comment", 
versionProperties2);
+    ops.linkModelVersion(modelIdent, uris2, aliases2, "version2 comment", 
versionProperties2);
 
     // List linked model versions
     ModelVersion[] versions2 = ops.listModelVersionInfos(modelIdent);
     Assertions.assertEquals(2, versions2.length);
     Assertions.assertEquals(0, versions2[0].version());
     Assertions.assertEquals("version1 comment", versions2[0].comment());
-    Assertions.assertEquals("model_version_path", versions2[0].uri());
+    Assertions.assertEquals(uris, versions2[0].uris());
     Assertions.assertEquals(versionProperties, versions2[0].properties());
     Assertions.assertEquals(1, versions2[1].version());
     Assertions.assertEquals("version2 comment", versions2[1].comment());
-    Assertions.assertEquals("model_version_path2", versions2[1].uri());
+    Assertions.assertEquals(uris2, versions2[1].uris());
     Assertions.assertEquals(versionProperties2, versions2[1].properties());
 
     // Test list model versions in a non-existent model
@@ -637,6 +630,171 @@ public class TestModelCatalogOperations {
                     METALAKE_NAME, CATALOG_NAME, "non-existent-schema", 
modelName)));
   }
 
+  @Test
+  public void testLinkAndGetModelVersionUriWithoutDefaultUriName() {
+    // Create schema and model
+    String schemaName = randomSchemaName();
+    createSchema(schemaName);
+
+    NameIdentifier modelIdent =
+        NameIdentifierUtil.ofModel(METALAKE_NAME, CATALOG_NAME, schemaName, 
"model");
+    StringIdentifier stringId = StringIdentifier.fromId(idGenerator.nextId());
+    Map<String, String> properties = 
StringIdentifier.newPropertiesWithId(stringId, null);
+
+    ops.registerModel(modelIdent, "model comment", properties);
+
+    // Link a model version to the registered model
+    StringIdentifier versionId = StringIdentifier.fromId(idGenerator.nextId());
+    Map<String, String> versionProperties = 
StringIdentifier.newPropertiesWithId(versionId, null);
+
+    String[] aliases = new String[] {"alias1", "alias2"};
+    Map<String, String> uris = ImmutableMap.of("n1", "u1", "n2", "u2");
+    ops.linkModelVersion(modelIdent, uris, aliases, "version comment", 
versionProperties);
+
+    Model loadedModel = ops.getModel(modelIdent);
+    Assertions.assertEquals(1, loadedModel.latestVersion());
+    ModelVersion loadedVersion = ops.getModelVersion(modelIdent, 0);
+    Assertions.assertEquals(0, loadedVersion.version());
+    Assertions.assertEquals("version comment", loadedVersion.comment());
+    Assertions.assertEquals(uris, loadedVersion.uris());
+    Assertions.assertEquals(versionProperties, loadedVersion.properties());
+
+    // Test get uri with uri name
+    Assertions.assertEquals("u1", ops.getModelVersionUri(modelIdent, 0, "n1"));
+    Assertions.assertEquals("u2", ops.getModelVersionUri(modelIdent, 0, "n2"));
+    Assertions.assertEquals("u1", ops.getModelVersionUri(modelIdent, "alias1", 
"n1"));
+    Assertions.assertEquals("u2", ops.getModelVersionUri(modelIdent, "alias1", 
"n2"));
+    Assertions.assertEquals("u1", ops.getModelVersionUri(modelIdent, "alias2", 
"n1"));
+    Assertions.assertEquals("u2", ops.getModelVersionUri(modelIdent, "alias2", 
"n2"));
+
+    // Test get uri without uri name
+    Assertions.assertThrows(
+        IllegalArgumentException.class, () -> 
ops.getModelVersionUri(modelIdent, 0, null));
+    Assertions.assertThrows(
+        IllegalArgumentException.class, () -> 
ops.getModelVersionUri(modelIdent, "alias1", null));
+    Assertions.assertThrows(
+        IllegalArgumentException.class, () -> 
ops.getModelVersionUri(modelIdent, "alias2", null));
+
+    // Test get uri from non-existing version
+    Assertions.assertThrows(
+        NoSuchModelVersionException.class, () -> 
ops.getModelVersionUri(modelIdent, 1, "n1"));
+    Assertions.assertThrows(
+        NoSuchModelVersionException.class,
+        () -> ops.getModelVersionUri(modelIdent, "alias3", "n1"));
+
+    // Test get uri with no-existing uri name
+    Assertions.assertThrows(
+        NoSuchModelVersionURINameException.class,
+        () -> ops.getModelVersionUri(modelIdent, 0, "n3"));
+    Assertions.assertThrows(
+        NoSuchModelVersionURINameException.class,
+        () -> ops.getModelVersionUri(modelIdent, "alias1", "n3"));
+    Assertions.assertThrows(
+        NoSuchModelVersionURINameException.class,
+        () -> ops.getModelVersionUri(modelIdent, "alias2", "n3"));
+  }
+
+  @Test
+  public void testLinkAndGetModelVersionUriWithDefaultUriName() {
+    // Create schema and model
+    String schemaName = randomSchemaName();
+    createSchema(schemaName);
+
+    NameIdentifier modelIdent =
+        NameIdentifierUtil.ofModel(METALAKE_NAME, CATALOG_NAME, schemaName, 
"model");
+    StringIdentifier stringId = StringIdentifier.fromId(idGenerator.nextId());
+    Map<String, String> properties =
+        StringIdentifier.newPropertiesWithId(
+            stringId, ImmutableMap.of(ModelVersion.PROPERTY_DEFAULT_URI_NAME, 
"n1"));
+
+    ops.registerModel(modelIdent, "model comment", properties);
+
+    // Link a model version without default uri name
+    StringIdentifier versionId1 = 
StringIdentifier.fromId(idGenerator.nextId());
+    Map<String, String> versionPropsWithoutDefaultUriName =
+        StringIdentifier.newPropertiesWithId(versionId1, null);
+
+    String[] aliases = new String[] {"alias1", "alias2"};
+    Map<String, String> uris = ImmutableMap.of("n1", "u1", "n2", "u2");
+    ops.linkModelVersion(
+        modelIdent, uris, aliases, "version1 comment", 
versionPropsWithoutDefaultUriName);
+
+    Model loadedModel = ops.getModel(modelIdent);
+    Assertions.assertEquals(1, loadedModel.latestVersion());
+    ModelVersion version1 = ops.getModelVersion(modelIdent, 0);
+    Assertions.assertEquals(0, version1.version());
+    Assertions.assertEquals("version1 comment", version1.comment());
+    Assertions.assertEquals(uris, version1.uris());
+    Assertions.assertEquals(versionPropsWithoutDefaultUriName, 
version1.properties());
+
+    // Test get uri with uri name
+    Assertions.assertEquals("u1", ops.getModelVersionUri(modelIdent, 0, "n1"));
+    Assertions.assertEquals("u2", ops.getModelVersionUri(modelIdent, 0, "n2"));
+    Assertions.assertEquals("u1", ops.getModelVersionUri(modelIdent, "alias1", 
"n1"));
+    Assertions.assertEquals("u2", ops.getModelVersionUri(modelIdent, "alias1", 
"n2"));
+    Assertions.assertEquals("u1", ops.getModelVersionUri(modelIdent, "alias2", 
"n1"));
+    Assertions.assertEquals("u2", ops.getModelVersionUri(modelIdent, "alias2", 
"n2"));
+
+    // Test get uri without uri name
+    Assertions.assertEquals("u1", ops.getModelVersionUri(modelIdent, 0, null));
+    Assertions.assertEquals("u1", ops.getModelVersionUri(modelIdent, "alias1", 
null));
+    Assertions.assertEquals("u1", ops.getModelVersionUri(modelIdent, "alias2", 
null));
+
+    // Test get uri from non-existing version
+    Assertions.assertThrows(
+        NoSuchModelVersionException.class, () -> 
ops.getModelVersionUri(modelIdent, 1, "n1"));
+    Assertions.assertThrows(
+        NoSuchModelVersionException.class,
+        () -> ops.getModelVersionUri(modelIdent, "alias3", "n1"));
+
+    // Test get uri with no-existing uri name
+    Assertions.assertThrows(
+        NoSuchModelVersionURINameException.class,
+        () -> ops.getModelVersionUri(modelIdent, 0, "n3"));
+    Assertions.assertThrows(
+        NoSuchModelVersionURINameException.class,
+        () -> ops.getModelVersionUri(modelIdent, "alias1", "n3"));
+    Assertions.assertThrows(
+        NoSuchModelVersionURINameException.class,
+        () -> ops.getModelVersionUri(modelIdent, "alias2", "n3"));
+
+    // Link a model version without default uri name
+    StringIdentifier versionId2 = 
StringIdentifier.fromId(idGenerator.nextId());
+    Map<String, String> versionPropsWithDefaultUriName =
+        StringIdentifier.newPropertiesWithId(
+            versionId2, 
ImmutableMap.of(ModelVersion.PROPERTY_DEFAULT_URI_NAME, "n2"));
+    ops.linkModelVersion(
+        modelIdent,
+        uris,
+        new String[] {"alias3"},
+        "version2 comment",
+        versionPropsWithDefaultUriName);
+
+    ModelVersion version2 = ops.getModelVersion(modelIdent, 1);
+    Assertions.assertEquals(1, version2.version());
+    Assertions.assertEquals("version2 comment", version2.comment());
+    Assertions.assertEquals(uris, version2.uris());
+    Assertions.assertEquals(versionPropsWithDefaultUriName, 
version2.properties());
+
+    // Test get uri with uri name
+    Assertions.assertEquals("u1", ops.getModelVersionUri(modelIdent, 1, "n1"));
+    Assertions.assertEquals("u2", ops.getModelVersionUri(modelIdent, 1, "n2"));
+    Assertions.assertEquals("u1", ops.getModelVersionUri(modelIdent, "alias3", 
"n1"));
+    Assertions.assertEquals("u2", ops.getModelVersionUri(modelIdent, "alias3", 
"n2"));
+
+    // Test get uri without uri name
+    Assertions.assertEquals("u2", ops.getModelVersionUri(modelIdent, 1, null));
+    Assertions.assertEquals("u2", ops.getModelVersionUri(modelIdent, "alias3", 
null));
+
+    // Test get uri with no-existing uri name
+    Assertions.assertThrows(
+        NoSuchModelVersionURINameException.class,
+        () -> ops.getModelVersionUri(modelIdent, 1, "n3"));
+    Assertions.assertThrows(
+        NoSuchModelVersionURINameException.class,
+        () -> ops.getModelVersionUri(modelIdent, "alias3", "n3"));
+  }
+
   @Test
   public void testDeleteModelVersion() {
     // Create schema and model
@@ -654,10 +812,10 @@ public class TestModelCatalogOperations {
     // Create a model version
     StringIdentifier versionId = StringIdentifier.fromId(idGenerator.nextId());
     Map<String, String> versionProperties = 
StringIdentifier.newPropertiesWithId(versionId, null);
+    Map<String, String> uris = ImmutableMap.of("n1", "u1", "n2", "u2");
 
     String[] aliases = new String[] {"alias1", "alias2"};
-    ops.linkModelVersion(
-        modelIdent, "model_version_path", aliases, "version1 comment", 
versionProperties);
+    ops.linkModelVersion(modelIdent, uris, aliases, "version1 comment", 
versionProperties);
 
     // Delete the model version
     Assertions.assertTrue(ops.deleteModelVersion(modelIdent, 0));
@@ -682,8 +840,7 @@ public class TestModelCatalogOperations {
             0));
 
     // Test delete model version using alias
-    ops.linkModelVersion(
-        modelIdent, "model_version_path", aliases, "version1 comment", 
versionProperties);
+    ops.linkModelVersion(modelIdent, uris, aliases, "version1 comment", 
versionProperties);
 
     Assertions.assertTrue(ops.deleteModelVersion(modelIdent, "alias1"));
     Assertions.assertFalse(ops.deleteModelVersion(modelIdent, "alias1"));
@@ -696,8 +853,7 @@ public class TestModelCatalogOperations {
     Model loadedModel = ops.getModel(modelIdent);
     Assertions.assertEquals(2, loadedModel.latestVersion());
 
-    ops.linkModelVersion(
-        modelIdent, "model_version_path", aliases, "version1 comment", 
versionProperties);
+    ops.linkModelVersion(modelIdent, uris, aliases, "version1 comment", 
versionProperties);
     int[] versions = ops.listModelVersions(modelIdent);
     Assertions.assertEquals(1, versions.length);
     Assertions.assertEquals(2, versions[0]);
@@ -720,10 +876,10 @@ public class TestModelCatalogOperations {
     // Create a model version
     StringIdentifier versionId = StringIdentifier.fromId(idGenerator.nextId());
     Map<String, String> versionProperties = 
StringIdentifier.newPropertiesWithId(versionId, null);
+    Map<String, String> uris = ImmutableMap.of("n1", "u1", "n2", "u2");
 
     String[] aliases = new String[] {"alias1", "alias2"};
-    ops.linkModelVersion(
-        modelIdent, "model_version_path", aliases, "version1 comment", 
versionProperties);
+    ops.linkModelVersion(modelIdent, uris, aliases, "version1 comment", 
versionProperties);
 
     // Delete the model
     Assertions.assertTrue(ops.deleteModel(modelIdent));
@@ -922,7 +1078,7 @@ public class TestModelCatalogOperations {
 
     String versionComment = "version1 comment";
     String versionNewComment = "new version1 comment";
-    String versionUri = "model_version_path";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = new String[] {"alias1", "alias2"};
 
     NameIdentifier modelIdent =
@@ -934,7 +1090,8 @@ public class TestModelCatalogOperations {
     StringIdentifier versionId = StringIdentifier.fromId(idGenerator.nextId());
     Map<String, String> versionProperties = 
StringIdentifier.newPropertiesWithId(versionId, null);
 
-    ops.linkModelVersion(modelIdent, versionUri, versionAliases, 
versionComment, versionProperties);
+    ops.linkModelVersion(
+        modelIdent, versionUris, versionAliases, versionComment, 
versionProperties);
 
     // validate loaded model
     Model loadedModel = ops.getModel(modelIdent);
@@ -945,7 +1102,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(0, loadedVersion.version());
     Assertions.assertArrayEquals(versionAliases, loadedVersion.aliases());
     Assertions.assertEquals(versionComment, loadedVersion.comment());
-    Assertions.assertEquals(versionUri, loadedVersion.uri());
+    Assertions.assertEquals(versionUris, loadedVersion.uris());
     Assertions.assertEquals(versionProperties, loadedVersion.properties());
 
     // update comment via version and validate
@@ -954,7 +1111,7 @@ public class TestModelCatalogOperations {
 
     Assertions.assertEquals(0, updatedModelVersion.version());
     Assertions.assertEquals(versionNewComment, updatedModelVersion.comment());
-    Assertions.assertEquals(versionUri, updatedModelVersion.uri());
+    Assertions.assertEquals(versionUris, updatedModelVersion.uris());
     Assertions.assertEquals(versionProperties, 
updatedModelVersion.properties());
   }
 
@@ -968,7 +1125,7 @@ public class TestModelCatalogOperations {
 
     String versionComment = "version1 comment";
     String versionNewComment = "new version1 comment";
-    String versionUri = "model_version_path";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = new String[] {"alias1", "alias2"};
     String versionAlias = versionAliases[0];
 
@@ -981,7 +1138,8 @@ public class TestModelCatalogOperations {
     StringIdentifier versionId = StringIdentifier.fromId(idGenerator.nextId());
     Map<String, String> versionProperties = 
StringIdentifier.newPropertiesWithId(versionId, null);
 
-    ops.linkModelVersion(modelIdent, versionUri, versionAliases, 
versionComment, versionProperties);
+    ops.linkModelVersion(
+        modelIdent, versionUris, versionAliases, versionComment, 
versionProperties);
 
     Model loadedModel = ops.getModel(modelIdent);
 
@@ -993,7 +1151,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(0, loadedVersion.version());
     Assertions.assertArrayEquals(versionAliases, loadedVersion.aliases());
     Assertions.assertEquals(versionComment, loadedVersion.comment());
-    Assertions.assertEquals(versionUri, loadedVersion.uri());
+    Assertions.assertEquals(versionUris, loadedVersion.uris());
     Assertions.assertEquals(versionProperties, loadedVersion.properties());
 
     // update comment via alias and validate
@@ -1004,7 +1162,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(0, updatedModelVersion.version());
     Assertions.assertArrayEquals(versionAliases, 
updatedModelVersion.aliases());
     Assertions.assertEquals(versionNewComment, updatedModelVersion.comment());
-    Assertions.assertEquals(versionUri, updatedModelVersion.uri());
+    Assertions.assertEquals(versionUris, updatedModelVersion.uris());
     Assertions.assertEquals(versionProperties, 
updatedModelVersion.properties());
   }
 
@@ -1017,7 +1175,7 @@ public class TestModelCatalogOperations {
     String modelComment = "model1 comment";
 
     String versionComment = "version1 comment";
-    String versionUri = "model_version_path";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = new String[] {"alias1", "alias2"};
 
     NameIdentifier modelIdent =
@@ -1035,7 +1193,8 @@ public class TestModelCatalogOperations {
     tmpMap.put("key1", "new value");
     Map<String, String> newProperties = ImmutableMap.copyOf(tmpMap);
 
-    ops.linkModelVersion(modelIdent, versionUri, versionAliases, 
versionComment, versionProperties);
+    ops.linkModelVersion(
+        modelIdent, versionUris, versionAliases, versionComment, 
versionProperties);
 
     // validate loaded model
     Model loadedModel = ops.getModel(modelIdent);
@@ -1046,7 +1205,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(0, loadedVersion.version());
     Assertions.assertArrayEquals(versionAliases, loadedVersion.aliases());
     Assertions.assertEquals(versionComment, loadedVersion.comment());
-    Assertions.assertEquals(versionUri, loadedVersion.uri());
+    Assertions.assertEquals(versionUris, loadedVersion.uris());
     Assertions.assertEquals(versionProperties, loadedVersion.properties());
 
     // set property via version and validate
@@ -1057,7 +1216,7 @@ public class TestModelCatalogOperations {
         ops.alterModelVersion(modelIdent, 0, updatePropertyChange, 
addPropertyChange);
 
     Assertions.assertEquals(0, updatedModelVersion.version());
-    Assertions.assertEquals(versionUri, updatedModelVersion.uri());
+    Assertions.assertEquals(versionUris, updatedModelVersion.uris());
     Assertions.assertEquals(versionComment, updatedModelVersion.comment());
     Assertions.assertArrayEquals(versionAliases, 
updatedModelVersion.aliases());
     Assertions.assertEquals(newProperties, updatedModelVersion.properties());
@@ -1072,7 +1231,7 @@ public class TestModelCatalogOperations {
     String modelComment = "model1 comment";
 
     String versionComment = "version1 comment";
-    String versionUri = "model_version_path";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = new String[] {"alias1", "alias2"};
 
     NameIdentifier modelIdent =
@@ -1090,7 +1249,8 @@ public class TestModelCatalogOperations {
     tmpMap.put("key1", "new value");
     Map<String, String> newProperties = ImmutableMap.copyOf(tmpMap);
 
-    ops.linkModelVersion(modelIdent, versionUri, versionAliases, 
versionComment, versionProperties);
+    ops.linkModelVersion(
+        modelIdent, versionUris, versionAliases, versionComment, 
versionProperties);
 
     // validate loaded model
     Model loadedModel = ops.getModel(modelIdent);
@@ -1101,7 +1261,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(0, loadedVersion.version());
     Assertions.assertArrayEquals(versionAliases, loadedVersion.aliases());
     Assertions.assertEquals(versionComment, loadedVersion.comment());
-    Assertions.assertEquals(versionUri, loadedVersion.uri());
+    Assertions.assertEquals(versionUris, loadedVersion.uris());
     Assertions.assertEquals(versionProperties, loadedVersion.properties());
 
     // set property via version and validate
@@ -1113,7 +1273,7 @@ public class TestModelCatalogOperations {
             modelIdent, versionAliases[0], updatePropertyChange, 
addPropertyChange);
 
     Assertions.assertEquals(0, updatedModelVersion.version());
-    Assertions.assertEquals(versionUri, updatedModelVersion.uri());
+    Assertions.assertEquals(versionUris, updatedModelVersion.uris());
     Assertions.assertEquals(versionComment, updatedModelVersion.comment());
     Assertions.assertArrayEquals(versionAliases, 
updatedModelVersion.aliases());
     Assertions.assertEquals(newProperties, updatedModelVersion.properties());
@@ -1128,7 +1288,7 @@ public class TestModelCatalogOperations {
     String modelComment = "model1 comment";
 
     String versionComment = "version1 comment";
-    String versionUri = "model_version_path";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = new String[] {"alias1", "alias2"};
 
     NameIdentifier modelIdent =
@@ -1144,7 +1304,8 @@ public class TestModelCatalogOperations {
     Map<String, String> newVersionProperties =
         StringIdentifier.newPropertiesWithId(versionId, 
ImmutableMap.of("key1", "value1"));
 
-    ops.linkModelVersion(modelIdent, versionUri, versionAliases, 
versionComment, versionProperties);
+    ops.linkModelVersion(
+        modelIdent, versionUris, versionAliases, versionComment, 
versionProperties);
 
     // validate loaded model
     Model loadedModel = ops.getModel(modelIdent);
@@ -1155,7 +1316,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(0, loadedVersion.version());
     Assertions.assertArrayEquals(versionAliases, loadedVersion.aliases());
     Assertions.assertEquals(versionComment, loadedVersion.comment());
-    Assertions.assertEquals(versionUri, loadedVersion.uri());
+    Assertions.assertEquals(versionUris, loadedVersion.uris());
     Assertions.assertEquals(versionProperties, loadedVersion.properties());
 
     // set property via version and validate
@@ -1164,7 +1325,7 @@ public class TestModelCatalogOperations {
     ModelVersion updatedModelVersion = ops.alterModelVersion(modelIdent, 0, 
removeProperty);
 
     Assertions.assertEquals(0, updatedModelVersion.version());
-    Assertions.assertEquals(versionUri, updatedModelVersion.uri());
+    Assertions.assertEquals(versionUris, updatedModelVersion.uris());
     Assertions.assertEquals(versionComment, updatedModelVersion.comment());
     Assertions.assertArrayEquals(versionAliases, 
updatedModelVersion.aliases());
     Assertions.assertEquals(newVersionProperties, 
updatedModelVersion.properties());
@@ -1179,7 +1340,7 @@ public class TestModelCatalogOperations {
     String modelComment = "model1 comment";
 
     String versionComment = "version1 comment";
-    String versionUri = "model_version_path";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = new String[] {"alias1", "alias2"};
 
     NameIdentifier modelIdent =
@@ -1195,7 +1356,8 @@ public class TestModelCatalogOperations {
     Map<String, String> newVersionProperties =
         StringIdentifier.newPropertiesWithId(versionId, 
ImmutableMap.of("key1", "value1"));
 
-    ops.linkModelVersion(modelIdent, versionUri, versionAliases, 
versionComment, versionProperties);
+    ops.linkModelVersion(
+        modelIdent, versionUris, versionAliases, versionComment, 
versionProperties);
 
     // validate loaded model
     Model loadedModel = ops.getModel(modelIdent);
@@ -1206,7 +1368,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(0, loadedVersion.version());
     Assertions.assertArrayEquals(versionAliases, loadedVersion.aliases());
     Assertions.assertEquals(versionComment, loadedVersion.comment());
-    Assertions.assertEquals(versionUri, loadedVersion.uri());
+    Assertions.assertEquals(versionUris, loadedVersion.uris());
     Assertions.assertEquals(versionProperties, loadedVersion.properties());
 
     // set property via version and validate
@@ -1216,7 +1378,7 @@ public class TestModelCatalogOperations {
         ops.alterModelVersion(modelIdent, versionAliases[0], removeProperty);
 
     Assertions.assertEquals(0, updatedModelVersion.version());
-    Assertions.assertEquals(versionUri, updatedModelVersion.uri());
+    Assertions.assertEquals(versionUris, updatedModelVersion.uris());
     Assertions.assertEquals(versionComment, updatedModelVersion.comment());
     Assertions.assertArrayEquals(versionAliases, 
updatedModelVersion.aliases());
     Assertions.assertEquals(newVersionProperties, 
updatedModelVersion.properties());
@@ -1231,7 +1393,7 @@ public class TestModelCatalogOperations {
     String modelComment = "model1 comment";
 
     String versionComment = "version1 comment";
-    String versionUri = "model_version_path";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = new String[] {"alias1", "alias2"};
     String newVersionUri = "s3://bucket/path/to/new/version";
 
@@ -1246,7 +1408,8 @@ public class TestModelCatalogOperations {
         StringIdentifier.newPropertiesWithId(
             versionId, ImmutableMap.of("key1", "value1", "key2", "value2"));
 
-    ops.linkModelVersion(modelIdent, versionUri, versionAliases, 
versionComment, versionProperties);
+    ops.linkModelVersion(
+        modelIdent, versionUris, versionAliases, versionComment, 
versionProperties);
 
     // validate loaded model
     Model loadedModel = ops.getModel(modelIdent);
@@ -1257,7 +1420,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(0, loadedVersion.version());
     Assertions.assertArrayEquals(versionAliases, loadedVersion.aliases());
     Assertions.assertEquals(versionComment, loadedVersion.comment());
-    Assertions.assertEquals(versionUri, loadedVersion.uri());
+    Assertions.assertEquals(versionUris, loadedVersion.uris());
     Assertions.assertEquals(versionProperties, loadedVersion.properties());
 
     // validate update version uri
@@ -1265,7 +1428,8 @@ public class TestModelCatalogOperations {
     ModelVersion updatedModelVersion = ops.alterModelVersion(modelIdent, 0, 
updateUriChange);
 
     Assertions.assertEquals(0, updatedModelVersion.version());
-    Assertions.assertEquals(newVersionUri, updatedModelVersion.uri());
+    Assertions.assertEquals(
+        ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, newVersionUri), 
updatedModelVersion.uris());
     Assertions.assertEquals(versionComment, updatedModelVersion.comment());
     Assertions.assertArrayEquals(versionAliases, 
updatedModelVersion.aliases());
     Assertions.assertEquals(versionProperties, 
updatedModelVersion.properties());
@@ -1280,7 +1444,7 @@ public class TestModelCatalogOperations {
     String modelComment = "model1 comment";
 
     String versionComment = "version1 comment";
-    String versionUri = "model_version_path";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = new String[] {"alias1", "alias2"};
     String newVersionUri = "s3://bucket/path/to/new/version";
 
@@ -1295,7 +1459,8 @@ public class TestModelCatalogOperations {
         StringIdentifier.newPropertiesWithId(
             versionId, ImmutableMap.of("key1", "value1", "key2", "value2"));
 
-    ops.linkModelVersion(modelIdent, versionUri, versionAliases, 
versionComment, versionProperties);
+    ops.linkModelVersion(
+        modelIdent, versionUris, versionAliases, versionComment, 
versionProperties);
 
     // validate loaded model
     Model loadedModel = ops.getModel(modelIdent);
@@ -1306,7 +1471,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(0, loadedVersion.version());
     Assertions.assertArrayEquals(versionAliases, loadedVersion.aliases());
     Assertions.assertEquals(versionComment, loadedVersion.comment());
-    Assertions.assertEquals(versionUri, loadedVersion.uri());
+    Assertions.assertEquals(versionUris, loadedVersion.uris());
     Assertions.assertEquals(versionProperties, loadedVersion.properties());
 
     // validate update version uri
@@ -1315,7 +1480,8 @@ public class TestModelCatalogOperations {
         ops.alterModelVersion(modelIdent, versionAliases[0], updateUriChange);
 
     Assertions.assertEquals(0, updatedModelVersion.version());
-    Assertions.assertEquals(newVersionUri, updatedModelVersion.uri());
+    Assertions.assertEquals(
+        ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, newVersionUri), 
updatedModelVersion.uris());
     Assertions.assertEquals(versionComment, updatedModelVersion.comment());
     Assertions.assertArrayEquals(versionAliases, 
updatedModelVersion.aliases());
     Assertions.assertEquals(versionProperties, 
updatedModelVersion.properties());
@@ -1330,7 +1496,7 @@ public class TestModelCatalogOperations {
     String modelComment = "model1 comment";
 
     String versionComment = "version1 comment";
-    String versionUri = "model_version_path";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = new String[] {"alias1", "alias2"};
     String[] newVersionAliases = new String[] {"new_alias1", "new_alias2"};
 
@@ -1345,7 +1511,8 @@ public class TestModelCatalogOperations {
         StringIdentifier.newPropertiesWithId(
             versionId, ImmutableMap.of("key1", "value1", "key2", "value2"));
 
-    ops.linkModelVersion(modelIdent, versionUri, versionAliases, 
versionComment, versionProperties);
+    ops.linkModelVersion(
+        modelIdent, versionUris, versionAliases, versionComment, 
versionProperties);
 
     // validate loaded model
     Model loadedModel = ops.getModel(modelIdent);
@@ -1356,7 +1523,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(0, loadedVersion.version());
     Assertions.assertArrayEquals(versionAliases, loadedVersion.aliases());
     Assertions.assertEquals(versionComment, loadedVersion.comment());
-    Assertions.assertEquals(versionUri, loadedVersion.uri());
+    Assertions.assertEquals(versionUris, loadedVersion.uris());
     Assertions.assertEquals(versionProperties, loadedVersion.properties());
 
     // validate update version aliases
@@ -1364,7 +1531,7 @@ public class TestModelCatalogOperations {
     ModelVersion updatedModelVersion = ops.alterModelVersion(modelIdent, 0, 
change);
 
     Assertions.assertEquals(0, updatedModelVersion.version());
-    Assertions.assertEquals(versionUri, updatedModelVersion.uri());
+    Assertions.assertEquals(versionUris, updatedModelVersion.uris());
     Assertions.assertEquals(versionComment, updatedModelVersion.comment());
     Assertions.assertArrayEquals(newVersionAliases, 
updatedModelVersion.aliases());
     Assertions.assertEquals(versionProperties, 
updatedModelVersion.properties());
@@ -1373,7 +1540,7 @@ public class TestModelCatalogOperations {
     ModelVersion reloadVersion = ops.getModelVersion(modelIdent, 0);
     Assertions.assertEquals(0, reloadVersion.version());
     Assertions.assertArrayEquals(newVersionAliases, reloadVersion.aliases());
-    Assertions.assertEquals(versionUri, reloadVersion.uri());
+    Assertions.assertEquals(versionUris, reloadVersion.uris());
     Assertions.assertEquals(versionComment, reloadVersion.comment());
     Assertions.assertEquals(versionProperties, reloadVersion.properties());
   }
@@ -1387,7 +1554,7 @@ public class TestModelCatalogOperations {
     String modelComment = "model1 comment";
 
     String versionComment = "version1 comment";
-    String versionUri = "model_version_path";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = new String[] {"alias1", "alias2"};
     String[] newVersionAliases = new String[] {"new_alias1", "new_alias2"};
 
@@ -1402,7 +1569,8 @@ public class TestModelCatalogOperations {
         StringIdentifier.newPropertiesWithId(
             versionId, ImmutableMap.of("key1", "value1", "key2", "value2"));
 
-    ops.linkModelVersion(modelIdent, versionUri, versionAliases, 
versionComment, versionProperties);
+    ops.linkModelVersion(
+        modelIdent, versionUris, versionAliases, versionComment, 
versionProperties);
 
     // validate loaded model
     Model loadedModel = ops.getModel(modelIdent);
@@ -1413,7 +1581,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(0, loadedVersion.version());
     Assertions.assertArrayEquals(versionAliases, loadedVersion.aliases());
     Assertions.assertEquals(versionComment, loadedVersion.comment());
-    Assertions.assertEquals(versionUri, loadedVersion.uri());
+    Assertions.assertEquals(versionUris, loadedVersion.uris());
     Assertions.assertEquals(versionProperties, loadedVersion.properties());
 
     // validate update version aliases
@@ -1421,7 +1589,7 @@ public class TestModelCatalogOperations {
     ModelVersion updatedModelVersion = ops.alterModelVersion(modelIdent, 
"alias1", change);
 
     Assertions.assertEquals(0, updatedModelVersion.version());
-    Assertions.assertEquals(versionUri, updatedModelVersion.uri());
+    Assertions.assertEquals(versionUris, updatedModelVersion.uris());
     Assertions.assertEquals(versionComment, updatedModelVersion.comment());
     Assertions.assertArrayEquals(newVersionAliases, 
updatedModelVersion.aliases());
     Assertions.assertEquals(versionProperties, 
updatedModelVersion.properties());
@@ -1430,7 +1598,7 @@ public class TestModelCatalogOperations {
     ModelVersion reloadVersion = ops.getModelVersion(modelIdent, "new_alias2");
     Assertions.assertEquals(0, reloadVersion.version());
     Assertions.assertArrayEquals(newVersionAliases, reloadVersion.aliases());
-    Assertions.assertEquals(versionUri, reloadVersion.uri());
+    Assertions.assertEquals(versionUris, reloadVersion.uris());
     Assertions.assertEquals(versionComment, reloadVersion.comment());
     Assertions.assertEquals(versionProperties, reloadVersion.properties());
   }
@@ -1444,7 +1612,7 @@ public class TestModelCatalogOperations {
     String modelComment = "model2 comment";
 
     String versionComment = "version1 comment";
-    String versionUri = "model_version_path";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = new String[] {"alias1", "alias2"};
     String[] newVersionAliases = new String[] {"new_alias1", "new_alias2"};
 
@@ -1459,7 +1627,8 @@ public class TestModelCatalogOperations {
         StringIdentifier.newPropertiesWithId(
             versionId, ImmutableMap.of("key1", "value1", "key2", "value2"));
 
-    ops.linkModelVersion(modelIdent, versionUri, versionAliases, 
versionComment, versionProperties);
+    ops.linkModelVersion(
+        modelIdent, versionUris, versionAliases, versionComment, 
versionProperties);
 
     // validate loaded model
     Model loadedModel = ops.getModel(modelIdent);
@@ -1470,7 +1639,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(0, loadedVersion.version());
     Assertions.assertArrayEquals(versionAliases, loadedVersion.aliases());
     Assertions.assertEquals(versionComment, loadedVersion.comment());
-    Assertions.assertEquals(versionUri, loadedVersion.uri());
+    Assertions.assertEquals(versionUris, loadedVersion.uris());
     Assertions.assertEquals(versionProperties, loadedVersion.properties());
 
     // validate update version aliases
@@ -1479,7 +1648,7 @@ public class TestModelCatalogOperations {
     ModelVersion updatedModelVersion = ops.alterModelVersion(modelIdent, 0, 
change);
 
     Assertions.assertEquals(0, updatedModelVersion.version());
-    Assertions.assertEquals(versionUri, updatedModelVersion.uri());
+    Assertions.assertEquals(versionUris, updatedModelVersion.uris());
     Assertions.assertEquals(versionComment, updatedModelVersion.comment());
     Assertions.assertArrayEquals(
         new String[] {"alias2", "new_alias1", "new_alias2"}, 
updatedModelVersion.aliases());
@@ -1490,7 +1659,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(0, reloadVersion.version());
     Assertions.assertArrayEquals(
         new String[] {"alias2", "new_alias1", "new_alias2"}, 
reloadVersion.aliases());
-    Assertions.assertEquals(versionUri, reloadVersion.uri());
+    Assertions.assertEquals(versionUris, reloadVersion.uris());
     Assertions.assertEquals(versionComment, reloadVersion.comment());
     Assertions.assertEquals(versionProperties, reloadVersion.properties());
   }
@@ -1504,7 +1673,7 @@ public class TestModelCatalogOperations {
     String modelComment = "model3 comment";
 
     String versionComment = "version1 comment";
-    String versionUri = "model_version_path";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = new String[] {"alias1", "alias2"};
     String[] newVersionAliases = new String[] {"new_alias1", "new_alias2"};
 
@@ -1519,7 +1688,8 @@ public class TestModelCatalogOperations {
         StringIdentifier.newPropertiesWithId(
             versionId, ImmutableMap.of("key1", "value1", "key2", "value2"));
 
-    ops.linkModelVersion(modelIdent, versionUri, versionAliases, 
versionComment, versionProperties);
+    ops.linkModelVersion(
+        modelIdent, versionUris, versionAliases, versionComment, 
versionProperties);
 
     // validate loaded model
     Model loadedModel = ops.getModel(modelIdent);
@@ -1530,7 +1700,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(0, loadedVersion.version());
     Assertions.assertArrayEquals(versionAliases, loadedVersion.aliases());
     Assertions.assertEquals(versionComment, loadedVersion.comment());
-    Assertions.assertEquals(versionUri, loadedVersion.uri());
+    Assertions.assertEquals(versionUris, loadedVersion.uris());
     Assertions.assertEquals(versionProperties, loadedVersion.properties());
 
     // validate update version aliases
@@ -1539,7 +1709,7 @@ public class TestModelCatalogOperations {
     ModelVersion updatedModelVersion = ops.alterModelVersion(modelIdent, 
"alias1", change);
 
     Assertions.assertEquals(0, updatedModelVersion.version());
-    Assertions.assertEquals(versionUri, updatedModelVersion.uri());
+    Assertions.assertEquals(versionUris, updatedModelVersion.uris());
     Assertions.assertEquals(versionComment, updatedModelVersion.comment());
     Assertions.assertArrayEquals(
         new String[] {"alias2", "new_alias1", "new_alias2"}, 
updatedModelVersion.aliases());
@@ -1550,7 +1720,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(0, reloadVersion.version());
     Assertions.assertArrayEquals(
         new String[] {"alias2", "new_alias1", "new_alias2"}, 
reloadVersion.aliases());
-    Assertions.assertEquals(versionUri, reloadVersion.uri());
+    Assertions.assertEquals(versionUris, reloadVersion.uris());
     Assertions.assertEquals(versionComment, reloadVersion.comment());
     Assertions.assertEquals(versionProperties, reloadVersion.properties());
   }
@@ -1564,7 +1734,7 @@ public class TestModelCatalogOperations {
     String modelComment = "model1 comment";
 
     String versionComment = "version1 comment";
-    String versionUri = "model_version_path";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = new String[] {"alias2", "alias3"};
 
     NameIdentifier modelIdent =
@@ -1578,7 +1748,8 @@ public class TestModelCatalogOperations {
         StringIdentifier.newPropertiesWithId(
             versionId, ImmutableMap.of("key1", "value1", "key2", "value2"));
 
-    ops.linkModelVersion(modelIdent, versionUri, versionAliases, 
versionComment, versionProperties);
+    ops.linkModelVersion(
+        modelIdent, versionUris, versionAliases, versionComment, 
versionProperties);
 
     // validate loaded model
     Model loadedModel = ops.getModel(modelIdent);
@@ -1589,7 +1760,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(0, loadedVersion.version());
     Assertions.assertArrayEquals(versionAliases, loadedVersion.aliases());
     Assertions.assertEquals(versionComment, loadedVersion.comment());
-    Assertions.assertEquals(versionUri, loadedVersion.uri());
+    Assertions.assertEquals(versionUris, loadedVersion.uris());
     Assertions.assertEquals(versionProperties, loadedVersion.properties());
 
     // validate update version aliases
@@ -1599,7 +1770,7 @@ public class TestModelCatalogOperations {
     ModelVersion updatedModelVersion = ops.alterModelVersion(modelIdent, 0, 
change);
 
     Assertions.assertEquals(0, updatedModelVersion.version());
-    Assertions.assertEquals(versionUri, updatedModelVersion.uri());
+    Assertions.assertEquals(versionUris, updatedModelVersion.uris());
     Assertions.assertEquals(versionComment, updatedModelVersion.comment());
     Assertions.assertEquals(
         ImmutableSet.of("alias1", "alias2"),
@@ -1612,7 +1783,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(
         ImmutableSet.of("alias1", "alias2"),
         Arrays.stream(reloadVersion.aliases()).collect(Collectors.toSet()));
-    Assertions.assertEquals(versionUri, reloadVersion.uri());
+    Assertions.assertEquals(versionUris, reloadVersion.uris());
     Assertions.assertEquals(versionComment, reloadVersion.comment());
     Assertions.assertEquals(versionProperties, reloadVersion.properties());
   }
@@ -1626,7 +1797,7 @@ public class TestModelCatalogOperations {
     String modelComment = "model1 comment";
 
     String versionComment = "version1 comment";
-    String versionUri = "model_version_path";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = new String[] {"alias2", "alias3"};
 
     NameIdentifier modelIdent =
@@ -1640,7 +1811,8 @@ public class TestModelCatalogOperations {
         StringIdentifier.newPropertiesWithId(
             versionId, ImmutableMap.of("key1", "value1", "key2", "value2"));
 
-    ops.linkModelVersion(modelIdent, versionUri, versionAliases, 
versionComment, versionProperties);
+    ops.linkModelVersion(
+        modelIdent, versionUris, versionAliases, versionComment, 
versionProperties);
 
     // validate loaded model
     Model loadedModel = ops.getModel(modelIdent);
@@ -1651,7 +1823,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(0, loadedVersion.version());
     Assertions.assertArrayEquals(versionAliases, loadedVersion.aliases());
     Assertions.assertEquals(versionComment, loadedVersion.comment());
-    Assertions.assertEquals(versionUri, loadedVersion.uri());
+    Assertions.assertEquals(versionUris, loadedVersion.uris());
     Assertions.assertEquals(versionProperties, loadedVersion.properties());
 
     // validate update version aliases
@@ -1661,7 +1833,7 @@ public class TestModelCatalogOperations {
     ModelVersion updatedModelVersion = ops.alterModelVersion(modelIdent, 
"alias3", change);
 
     Assertions.assertEquals(0, updatedModelVersion.version());
-    Assertions.assertEquals(versionUri, updatedModelVersion.uri());
+    Assertions.assertEquals(versionUris, updatedModelVersion.uris());
     Assertions.assertEquals(versionComment, updatedModelVersion.comment());
     Assertions.assertEquals(
         ImmutableSet.of("alias1", "alias2"),
@@ -1674,7 +1846,7 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(
         ImmutableSet.of("alias1", "alias2"),
         Arrays.stream(reloadVersion.aliases()).collect(Collectors.toSet()));
-    Assertions.assertEquals(versionUri, reloadVersion.uri());
+    Assertions.assertEquals(versionUris, reloadVersion.uris());
     Assertions.assertEquals(versionComment, reloadVersion.comment());
     Assertions.assertEquals(versionProperties, reloadVersion.properties());
   }
diff --git 
a/core/src/main/java/org/apache/gravitino/catalog/EntityCombinedModelVersion.java
 
b/core/src/main/java/org/apache/gravitino/catalog/EntityCombinedModelVersion.java
index 748a5c1238..6207450988 100644
--- 
a/core/src/main/java/org/apache/gravitino/catalog/EntityCombinedModelVersion.java
+++ 
b/core/src/main/java/org/apache/gravitino/catalog/EntityCombinedModelVersion.java
@@ -76,8 +76,8 @@ public final class EntityCombinedModelVersion implements 
ModelVersion {
   }
 
   @Override
-  public String uri() {
-    return modelVersion.uri();
+  public Map<String, String> uris() {
+    return modelVersion.uris();
   }
 
   @Override
diff --git 
a/core/src/main/java/org/apache/gravitino/catalog/ModelNormalizeDispatcher.java 
b/core/src/main/java/org/apache/gravitino/catalog/ModelNormalizeDispatcher.java
index 73c4935a03..5bf32f892b 100644
--- 
a/core/src/main/java/org/apache/gravitino/catalog/ModelNormalizeDispatcher.java
+++ 
b/core/src/main/java/org/apache/gravitino/catalog/ModelNormalizeDispatcher.java
@@ -118,12 +118,12 @@ public class ModelNormalizeDispatcher implements 
ModelDispatcher {
   @Override
   public void linkModelVersion(
       NameIdentifier ident,
-      String uri,
+      Map<String, String> uris,
       String[] aliases,
       String comment,
       Map<String, String> properties)
       throws NoSuchModelException, ModelVersionAliasesAlreadyExistException {
-    dispatcher.linkModelVersion(normalizeCaseSensitive(ident), uri, aliases, 
comment, properties);
+    dispatcher.linkModelVersion(normalizeCaseSensitive(ident), uris, aliases, 
comment, properties);
   }
 
   @Override
diff --git 
a/core/src/main/java/org/apache/gravitino/catalog/ModelOperationDispatcher.java 
b/core/src/main/java/org/apache/gravitino/catalog/ModelOperationDispatcher.java
index b44a25b75a..f3d3389098 100644
--- 
a/core/src/main/java/org/apache/gravitino/catalog/ModelOperationDispatcher.java
+++ 
b/core/src/main/java/org/apache/gravitino/catalog/ModelOperationDispatcher.java
@@ -186,7 +186,7 @@ public class ModelOperationDispatcher extends 
OperationDispatcher implements Mod
   @Override
   public void linkModelVersion(
       NameIdentifier ident,
-      String uri,
+      Map<String, String> uris,
       String[] aliases,
       String comment,
       Map<String, String> properties)
@@ -205,7 +205,7 @@ public class ModelOperationDispatcher extends 
OperationDispatcher implements Mod
                 c ->
                     c.doWithModelOps(
                         m -> {
-                          m.linkModelVersion(ident, uri, aliases, comment, 
updatedProperties);
+                          m.linkModelVersion(ident, uris, aliases, comment, 
updatedProperties);
                           return null;
                         }),
                 NoSuchModelException.class,
diff --git 
a/core/src/main/java/org/apache/gravitino/connector/BaseModelVersion.java 
b/core/src/main/java/org/apache/gravitino/connector/BaseModelVersion.java
index e58a90d1f7..049baadf1a 100644
--- a/core/src/main/java/org/apache/gravitino/connector/BaseModelVersion.java
+++ b/core/src/main/java/org/apache/gravitino/connector/BaseModelVersion.java
@@ -34,7 +34,7 @@ public abstract class BaseModelVersion implements 
ModelVersion {
 
   @Nullable protected String comment;
 
-  protected String uri;
+  protected Map<String, String> uris;
 
   protected Map<String, String> properties;
 
@@ -58,10 +58,10 @@ public abstract class BaseModelVersion implements 
ModelVersion {
     return comment;
   }
 
-  /** @return the URI of the model artifact. */
+  /** @return the URIs of the model artifact. */
   @Override
-  public String uri() {
-    return uri;
+  public Map<String, String> uris() {
+    return uris;
   }
 
   /** @return the properties of the model version. */
@@ -84,7 +84,7 @@ public abstract class BaseModelVersion implements 
ModelVersion {
 
     SELF withComment(String comment);
 
-    SELF withUri(String uri);
+    SELF withUris(Map<String, String> uris);
 
     SELF withProperties(Map<String, String> properties);
 
@@ -103,7 +103,7 @@ public abstract class BaseModelVersion implements 
ModelVersion {
 
     protected String comment;
 
-    protected String uri;
+    protected Map<String, String> uris;
 
     protected Map<String, String> properties;
 
@@ -146,14 +146,13 @@ public abstract class BaseModelVersion implements 
ModelVersion {
     }
 
     /**
-     * Sets the URI of the model artifact.
+     * Sets the URIs of the model artifact.
      *
-     * @param uri The URI of the model artifact.
+     * @param uris The URIs of the model artifact.
      * @return The builder instance.
      */
-    @Override
-    public SELF withUri(String uri) {
-      this.uri = uri;
+    public SELF withUris(Map<String, String> uris) {
+      this.uris = uris;
       return self();
     }
 
diff --git 
a/core/src/main/java/org/apache/gravitino/hook/ModelHookDispatcher.java 
b/core/src/main/java/org/apache/gravitino/hook/ModelHookDispatcher.java
index eb18f704ee..50651e9b00 100644
--- a/core/src/main/java/org/apache/gravitino/hook/ModelHookDispatcher.java
+++ b/core/src/main/java/org/apache/gravitino/hook/ModelHookDispatcher.java
@@ -115,12 +115,12 @@ public class ModelHookDispatcher implements 
ModelDispatcher {
   @Override
   public void linkModelVersion(
       NameIdentifier ident,
-      String uri,
+      Map<String, String> uris,
       String[] aliases,
       String comment,
       Map<String, String> properties)
       throws NoSuchModelException, ModelVersionAliasesAlreadyExistException {
-    dispatcher.linkModelVersion(ident, uri, aliases, comment, properties);
+    dispatcher.linkModelVersion(ident, uris, aliases, comment, properties);
   }
 
   @Override
@@ -153,7 +153,7 @@ public class ModelHookDispatcher implements ModelDispatcher 
{
   @Override
   public Model registerModel(
       NameIdentifier ident,
-      String uri,
+      Map<String, String> uris,
       String[] aliases,
       String comment,
       Map<String, String> properties)
@@ -163,7 +163,7 @@ public class ModelHookDispatcher implements ModelDispatcher 
{
     AuthorizationUtils.checkCurrentUser(
         ident.namespace().level(0), PrincipalUtils.getCurrentUserName());
 
-    Model model = dispatcher.registerModel(ident, uri, aliases, comment, 
properties);
+    Model model = dispatcher.registerModel(ident, uris, aliases, comment, 
properties);
 
     // Set the creator as owner of the model.
     OwnerDispatcher ownerManager = 
GravitinoEnv.getInstance().ownerDispatcher();
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java 
b/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java
index bd51d4680d..68c3da14e3 100644
--- a/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java
+++ b/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java
@@ -122,7 +122,7 @@ public class ModelEventDispatcher implements 
ModelDispatcher {
   @Override
   public Model registerModel(
       NameIdentifier ident,
-      String uri,
+      Map<String, String> uris,
       String[] aliases,
       String comment,
       Map<String, String> properties)
@@ -130,7 +130,7 @@ public class ModelEventDispatcher implements 
ModelDispatcher {
           ModelVersionAliasesAlreadyExistException {
     ModelInfo registerModelRequest = new ModelInfo(ident.name(), properties, 
comment);
     ModelVersionInfo linkModelVersionRequest =
-        new ModelVersionInfo(uri, comment, properties, aliases);
+        new ModelVersionInfo(uris, comment, properties, aliases, null);
     String user = PrincipalUtils.getCurrentUserName();
     RegisterAndLinkModelPreEvent registerAndLinkModelPreEvent =
         new RegisterAndLinkModelPreEvent(
@@ -138,9 +138,9 @@ public class ModelEventDispatcher implements 
ModelDispatcher {
 
     eventBus.dispatchEvent(registerAndLinkModelPreEvent);
     try {
-      Model registeredModel = dispatcher.registerModel(ident, uri, aliases, 
comment, properties);
+      Model registeredModel = dispatcher.registerModel(ident, uris, aliases, 
comment, properties);
       ModelInfo registeredModelInfo = new ModelInfo(registeredModel);
-      eventBus.dispatchEvent(new RegisterAndLinkModelEvent(user, ident, 
registeredModelInfo, uri));
+      eventBus.dispatchEvent(new RegisterAndLinkModelEvent(user, ident, 
registeredModelInfo, uris));
       return registeredModel;
     } catch (Exception e) {
       eventBus.dispatchEvent(
@@ -203,17 +203,18 @@ public class ModelEventDispatcher implements 
ModelDispatcher {
   @Override
   public void linkModelVersion(
       NameIdentifier ident,
-      String uri,
+      Map<String, String> uris,
       String[] aliases,
       String comment,
       Map<String, String> properties)
       throws NoSuchModelException, ModelVersionAliasesAlreadyExistException {
-    ModelVersionInfo linkModelRequest = new ModelVersionInfo(uri, comment, 
properties, aliases);
+    ModelVersionInfo linkModelRequest =
+        new ModelVersionInfo(uris, comment, properties, aliases, null);
     String user = PrincipalUtils.getCurrentUserName();
 
     eventBus.dispatchEvent(new LinkModelVersionPreEvent(user, ident, 
linkModelRequest));
     try {
-      dispatcher.linkModelVersion(ident, uri, aliases, comment, properties);
+      dispatcher.linkModelVersion(ident, uris, aliases, comment, properties);
       eventBus.dispatchEvent(new LinkModelVersionEvent(user, ident, 
linkModelRequest));
     } catch (Exception e) {
       eventBus.dispatchEvent(new LinkModelVersionFailureEvent(user, ident, e, 
linkModelRequest));
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/info/ModelVersionInfo.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/info/ModelVersionInfo.java
index bfcccb9caa..c11b8414c4 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/info/ModelVersionInfo.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/info/ModelVersionInfo.java
@@ -47,7 +47,7 @@ public class ModelVersionInfo {
    */
   public ModelVersionInfo(ModelVersion modelVersion) {
     this(
-        ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, modelVersion.uri()),
+        modelVersion.uris(),
         modelVersion.comment(),
         modelVersion.properties(),
         modelVersion.aliases(),
diff --git a/core/src/test/java/org/apache/gravitino/TestModelVersion.java 
b/core/src/test/java/org/apache/gravitino/TestModelVersion.java
index 487496c5fb..df1b622239 100644
--- a/core/src/test/java/org/apache/gravitino/TestModelVersion.java
+++ b/core/src/test/java/org/apache/gravitino/TestModelVersion.java
@@ -32,7 +32,7 @@ public class TestModelVersion extends BaseModelVersion {
       modelVersion.version = version;
       modelVersion.comment = comment;
       modelVersion.aliases = aliases;
-      modelVersion.uri = uri;
+      modelVersion.uris = uris;
       modelVersion.properties = properties;
       modelVersion.auditInfo = auditInfo;
       return modelVersion;
diff --git 
a/core/src/test/java/org/apache/gravitino/catalog/TestModelOperationDispatcher.java
 
b/core/src/test/java/org/apache/gravitino/catalog/TestModelOperationDispatcher.java
index ac03b5c3da..bbfd791096 100644
--- 
a/core/src/test/java/org/apache/gravitino/catalog/TestModelOperationDispatcher.java
+++ 
b/core/src/test/java/org/apache/gravitino/catalog/TestModelOperationDispatcher.java
@@ -38,6 +38,7 @@ import org.apache.gravitino.GravitinoEnv;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.exceptions.NoSuchModelException;
 import org.apache.gravitino.exceptions.NoSuchModelVersionException;
+import org.apache.gravitino.exceptions.NoSuchModelVersionURINameException;
 import org.apache.gravitino.lock.LockManager;
 import org.apache.gravitino.model.Model;
 import org.apache.gravitino.model.ModelChange;
@@ -161,11 +162,12 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     Assertions.assertEquals(0, model.latestVersion());
 
     String[] aliases = new String[] {"alias1", "alias2"};
-    modelOperationDispatcher.linkModelVersion(modelIdent, "path", aliases, 
"comment", props);
+    Map<String, String> uris = ImmutableMap.of("n1", "u1", "n2", "u2");
+    modelOperationDispatcher.linkModelVersion(modelIdent, uris, aliases, 
"comment", props);
 
     ModelVersion linkedModelVersion = 
modelOperationDispatcher.getModelVersion(modelIdent, 0);
     Assertions.assertEquals(0, linkedModelVersion.version());
-    Assertions.assertEquals("path", linkedModelVersion.uri());
+    Assertions.assertEquals(uris, linkedModelVersion.uris());
     Assertions.assertArrayEquals(aliases, linkedModelVersion.aliases());
     Assertions.assertEquals("comment", linkedModelVersion.comment());
     Assertions.assertEquals(props, linkedModelVersion.properties());
@@ -175,14 +177,14 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     ModelVersion linkedModelVersionWithAlias =
         modelOperationDispatcher.getModelVersion(modelIdent, "alias1");
     Assertions.assertEquals(0, linkedModelVersionWithAlias.version());
-    Assertions.assertEquals("path", linkedModelVersionWithAlias.uri());
+    Assertions.assertEquals(uris, linkedModelVersion.uris());
     Assertions.assertArrayEquals(aliases, 
linkedModelVersionWithAlias.aliases());
     
Assertions.assertFalse(linkedModelVersionWithAlias.properties().containsKey(ID_KEY));
 
     ModelVersion linkedModelVersionWithAlias2 =
         modelOperationDispatcher.getModelVersion(modelIdent, "alias2");
     Assertions.assertEquals(0, linkedModelVersionWithAlias2.version());
-    Assertions.assertEquals("path", linkedModelVersionWithAlias2.uri());
+    Assertions.assertEquals(uris, linkedModelVersion.uris());
     Assertions.assertArrayEquals(aliases, 
linkedModelVersionWithAlias2.aliases());
     
Assertions.assertFalse(linkedModelVersionWithAlias2.properties().containsKey(ID_KEY));
 
@@ -191,7 +193,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     testPropertyException(
         () ->
             modelOperationDispatcher.linkModelVersion(
-                modelIdent, "path", aliases, "comment", illegalProps),
+                modelIdent, uris, aliases, "comment", illegalProps),
         "Properties or property prefixes are reserved and cannot be set",
         ID_KEY);
   }
@@ -212,8 +214,10 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
 
     String[] aliases1 = new String[] {"alias1"};
     String[] aliases2 = new String[] {"alias2"};
-    modelOperationDispatcher.linkModelVersion(modelIdent, "path1", aliases1, 
"comment", props);
-    modelOperationDispatcher.linkModelVersion(modelIdent, "path2", aliases2, 
"comment", props);
+    Map<String, String> uris1 = ImmutableMap.of("n1", "u1", "n2", "u2");
+    Map<String, String> uris2 = ImmutableMap.of("n3", "u3");
+    modelOperationDispatcher.linkModelVersion(modelIdent, uris1, aliases1, 
"comment", props);
+    modelOperationDispatcher.linkModelVersion(modelIdent, uris2, aliases2, 
"comment", props);
 
     int[] versions = modelOperationDispatcher.listModelVersions(modelIdent);
     Assertions.assertEquals(2, versions.length);
@@ -237,12 +241,13 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     Assertions.assertEquals(0, model.latestVersion());
 
     String[] aliases = new String[] {"alias1", "alias2"};
-    modelOperationDispatcher.linkModelVersion(modelIdent, "path", aliases, 
"comment", props);
+    Map<String, String> uris = ImmutableMap.of("n1", "u1", "n2", "u2");
+    modelOperationDispatcher.linkModelVersion(modelIdent, uris, aliases, 
"comment", props);
 
     ModelVersion[] versions = 
modelOperationDispatcher.listModelVersionInfos(modelIdent);
     Assertions.assertEquals(1, versions.length);
     Assertions.assertEquals(0, versions[0].version());
-    Assertions.assertEquals("path", versions[0].uri());
+    Assertions.assertEquals(uris, versions[0].uris());
     Assertions.assertArrayEquals(aliases, versions[0].aliases());
     Assertions.assertEquals("comment", versions[0].comment());
     Assertions.assertEquals(props, versions[0].properties());
@@ -263,7 +268,8 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     Assertions.assertEquals(0, model.latestVersion());
 
     String[] aliases = new String[] {"alias1"};
-    modelOperationDispatcher.linkModelVersion(modelIdent, "path", aliases, 
"comment", props);
+    Map<String, String> uris1 = ImmutableMap.of("n1", "u1", "n2", "u2");
+    modelOperationDispatcher.linkModelVersion(modelIdent, uris1, aliases, 
"comment", props);
     
Assertions.assertTrue(modelOperationDispatcher.deleteModelVersion(modelIdent, 
0));
     
Assertions.assertFalse(modelOperationDispatcher.deleteModelVersion(modelIdent, 
0));
     Assertions.assertThrows(
@@ -275,7 +281,8 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
 
     // Tet delete model version with alias
     String[] aliases2 = new String[] {"alias2"};
-    modelOperationDispatcher.linkModelVersion(modelIdent, "path2", aliases2, 
"comment", props);
+    Map<String, String> uris2 = ImmutableMap.of("n3", "u3");
+    modelOperationDispatcher.linkModelVersion(modelIdent, uris2, aliases2, 
"comment", props);
     
Assertions.assertTrue(modelOperationDispatcher.deleteModelVersion(modelIdent, 
"alias2"));
     
Assertions.assertFalse(modelOperationDispatcher.deleteModelVersion(modelIdent, 
"alias2"));
     Assertions.assertThrows(
@@ -283,6 +290,153 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
         () -> modelOperationDispatcher.getModelVersion(modelIdent, "alias2"));
   }
 
+  @Test
+  public void testLinkAndGetModelVersionUriWithoutDefaultUriName() {
+    String schemaName = randomSchemaName();
+    NameIdentifier schemaIdent = NameIdentifier.of(metalake, catalog, 
schemaName);
+    schemaOperationDispatcher.createSchema(schemaIdent, "comment", null);
+
+    Map<String, String> props = ImmutableMap.of("k1", "v1", "k2", "v2");
+    String modelName = randomModelName();
+    NameIdentifier modelIdent =
+        NameIdentifierUtil.ofModel(metalake, catalog, schemaName, modelName);
+
+    Model model = modelOperationDispatcher.registerModel(modelIdent, 
"comment", props);
+    Assertions.assertEquals(0, model.latestVersion());
+
+    String[] aliases = new String[] {"alias1", "alias2"};
+    Map<String, String> uris = ImmutableMap.of("n1", "u1", "n2", "u2");
+    modelOperationDispatcher.linkModelVersion(modelIdent, uris, aliases, 
"comment", props);
+
+    ModelVersion linkedModelVersion = 
modelOperationDispatcher.getModelVersion(modelIdent, 0);
+    Assertions.assertEquals(0, linkedModelVersion.version());
+    Assertions.assertEquals(uris, linkedModelVersion.uris());
+    Assertions.assertArrayEquals(aliases, linkedModelVersion.aliases());
+    Assertions.assertEquals("comment", linkedModelVersion.comment());
+    Assertions.assertEquals(props, linkedModelVersion.properties());
+    
Assertions.assertFalse(linkedModelVersion.properties().containsKey(ID_KEY));
+
+    // get uri with uri name
+    Assertions.assertEquals("u1", 
modelOperationDispatcher.getModelVersionUri(modelIdent, 0, "n1"));
+    Assertions.assertEquals("u2", 
modelOperationDispatcher.getModelVersionUri(modelIdent, 0, "n2"));
+    Assertions.assertEquals(
+        "u1", modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias1", "n1"));
+    Assertions.assertEquals(
+        "u1", modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias2", "n1"));
+    Assertions.assertEquals(
+        "u2", modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias1", "n2"));
+    Assertions.assertEquals(
+        "u2", modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias2", "n2"));
+
+    // get uri without uri name
+    Assertions.assertThrows(
+        IllegalArgumentException.class,
+        () -> modelOperationDispatcher.getModelVersionUri(modelIdent, 0, 
null));
+    Assertions.assertThrows(
+        IllegalArgumentException.class,
+        () -> modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias1", null));
+    Assertions.assertThrows(
+        IllegalArgumentException.class,
+        () -> modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias2", null));
+
+    // non-existing version
+    Assertions.assertThrows(
+        NoSuchModelVersionException.class,
+        () -> modelOperationDispatcher.getModelVersionUri(modelIdent, 1, 
"n1"));
+    Assertions.assertThrows(
+        NoSuchModelVersionException.class,
+        () -> modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias3", "n1"));
+
+    // no-existing uri name
+    Assertions.assertThrows(
+        NoSuchModelVersionURINameException.class,
+        () -> modelOperationDispatcher.getModelVersionUri(modelIdent, 0, 
"n3"));
+    Assertions.assertThrows(
+        NoSuchModelVersionURINameException.class,
+        () -> modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias1", "n3"));
+    Assertions.assertThrows(
+        NoSuchModelVersionURINameException.class,
+        () -> modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias2", "n3"));
+  }
+
+  @Test
+  public void testLinkAndGetModelVersionUriWithDefaultUriName() {
+    String schemaName = randomSchemaName();
+    NameIdentifier schemaIdent = NameIdentifier.of(metalake, catalog, 
schemaName);
+    schemaOperationDispatcher.createSchema(schemaIdent, "comment", null);
+
+    // set default uri name to "n1" at model level
+    Map<String, String> modelProps =
+        ImmutableMap.of(ModelVersion.PROPERTY_DEFAULT_URI_NAME, "n1", "k1", 
"v1");
+    String modelName = randomModelName();
+    NameIdentifier modelIdent =
+        NameIdentifierUtil.ofModel(metalake, catalog, schemaName, modelName);
+
+    Model model = modelOperationDispatcher.registerModel(modelIdent, 
"comment", modelProps);
+    Assertions.assertEquals(0, model.latestVersion());
+
+    String[] aliases = new String[] {"alias1", "alias2"};
+    Map<String, String> uris = ImmutableMap.of("n1", "u1", "n2", "u2");
+    // link a model version without default uri name
+    Map<String, String> versionPropsWithoutDefaultUriName = 
ImmutableMap.of("k1", "v1", "k2", "v2");
+    modelOperationDispatcher.linkModelVersion(
+        modelIdent, uris, aliases, "comment", 
versionPropsWithoutDefaultUriName);
+
+    ModelVersion version1 = 
modelOperationDispatcher.getModelVersion(modelIdent, 0);
+    Assertions.assertEquals(0, version1.version());
+    Assertions.assertEquals(uris, version1.uris());
+    Assertions.assertArrayEquals(aliases, version1.aliases());
+    Assertions.assertEquals("comment", version1.comment());
+    Assertions.assertEquals(versionPropsWithoutDefaultUriName, 
version1.properties());
+    Assertions.assertFalse(version1.properties().containsKey(ID_KEY));
+
+    // get uri with uri name
+    Assertions.assertEquals("u1", 
modelOperationDispatcher.getModelVersionUri(modelIdent, 0, "n1"));
+    Assertions.assertEquals("u2", 
modelOperationDispatcher.getModelVersionUri(modelIdent, 0, "n2"));
+    Assertions.assertEquals(
+        "u1", modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias1", "n1"));
+    Assertions.assertEquals(
+        "u1", modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias2", "n1"));
+    Assertions.assertEquals(
+        "u2", modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias1", "n2"));
+    Assertions.assertEquals(
+        "u2", modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias2", "n2"));
+
+    // get uri without uri name
+    Assertions.assertEquals("u1", 
modelOperationDispatcher.getModelVersionUri(modelIdent, 0, null));
+    Assertions.assertEquals(
+        "u1", modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias1", null));
+    Assertions.assertEquals(
+        "u1", modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias2", null));
+
+    // link a model version with default uri name
+    Map<String, String> versionPropsWithDefaultUriName =
+        ImmutableMap.of(ModelVersion.PROPERTY_DEFAULT_URI_NAME, "n2", "k1", 
"v1");
+    modelOperationDispatcher.linkModelVersion(
+        modelIdent, uris, new String[] {"alias3"}, "comment", 
versionPropsWithDefaultUriName);
+
+    ModelVersion version2 = 
modelOperationDispatcher.getModelVersion(modelIdent, 1);
+    Assertions.assertEquals(1, version2.version());
+    Assertions.assertEquals(uris, version2.uris());
+    Assertions.assertArrayEquals(new String[] {"alias3"}, version2.aliases());
+    Assertions.assertEquals("comment", version2.comment());
+    Assertions.assertEquals(versionPropsWithDefaultUriName, 
version2.properties());
+    Assertions.assertFalse(version2.properties().containsKey(ID_KEY));
+
+    // get uri with uri name
+    Assertions.assertEquals("u1", 
modelOperationDispatcher.getModelVersionUri(modelIdent, 1, "n1"));
+    Assertions.assertEquals("u2", 
modelOperationDispatcher.getModelVersionUri(modelIdent, 1, "n2"));
+    Assertions.assertEquals(
+        "u1", modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias3", "n1"));
+    Assertions.assertEquals(
+        "u2", modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias3", "n2"));
+
+    // get uri without uri name
+    Assertions.assertEquals("u2", 
modelOperationDispatcher.getModelVersionUri(modelIdent, 1, null));
+    Assertions.assertEquals(
+        "u2", modelOperationDispatcher.getModelVersionUri(modelIdent, 
"alias3", null));
+  }
+
   @Test
   public void testRenameModel() {
     String schemaName = "test_rename_model_schema";
@@ -431,7 +585,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     String modelComment = "model which tests update";
     Map<String, String> props = ImmutableMap.of("k1", "v1", "k2", "v2");
 
-    String versionUri = "s3://test-bucket/test-path/model.json";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = {"alias1", "alias2"};
     String versionComment = "version which tests update";
     String versionNewComment = "new version comment";
@@ -444,13 +598,13 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     modelOperationDispatcher.registerModel(modelIdent, modelComment, props);
 
     modelOperationDispatcher.linkModelVersion(
-        modelIdent, versionUri, versionAliases, versionComment, props);
+        modelIdent, versionUris, versionAliases, versionComment, props);
     ModelVersionChange changeComment = 
ModelVersionChange.updateComment(versionNewComment);
     ModelVersion modelVersion = 
modelOperationDispatcher.getModelVersion(modelIdent, "alias1");
     ModelVersion alteredModelVersion =
         modelOperationDispatcher.alterModelVersion(modelIdent, "alias1", 
changeComment);
 
-    Assertions.assertEquals(modelVersion.uri(), alteredModelVersion.uri());
+    Assertions.assertEquals(modelVersion.uris(), alteredModelVersion.uris());
     Assertions.assertEquals(modelVersion.aliases(), 
alteredModelVersion.aliases());
     Assertions.assertEquals(versionNewComment, alteredModelVersion.comment());
     Assertions.assertEquals(modelVersion.properties(), 
alteredModelVersion.properties());
@@ -466,7 +620,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     Map<String, String> props = ImmutableMap.of("k1", "v1", "k2", "v2");
     Map<String, String> newProps = ImmutableMap.of("k1", "new value", "k2", 
"v2", "k3", "v3");
 
-    String versionUri = "s3://test-bucket/test-path/model.json";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = {"alias1", "alias2"};
     String versionComment = "version which tests update";
 
@@ -478,7 +632,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     modelOperationDispatcher.registerModel(modelIdent, modelComment, props);
 
     modelOperationDispatcher.linkModelVersion(
-        modelIdent, versionUri, versionAliases, versionComment, props);
+        modelIdent, versionUris, versionAliases, versionComment, props);
 
     ModelVersionChange[] changes =
         new ModelVersionChange[] {
@@ -489,7 +643,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     ModelVersion alteredModelVersion =
         modelOperationDispatcher.alterModelVersion(modelIdent, 0, changes);
 
-    Assertions.assertEquals(modelVersion.uri(), alteredModelVersion.uri());
+    Assertions.assertEquals(modelVersion.uris(), alteredModelVersion.uris());
     Assertions.assertEquals(modelVersion.version(), 
alteredModelVersion.version());
     Assertions.assertEquals(modelVersion.aliases(), 
alteredModelVersion.aliases());
     Assertions.assertEquals(modelVersion.comment(), 
alteredModelVersion.comment());
@@ -506,7 +660,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     Map<String, String> props = ImmutableMap.of("k1", "v1", "k2", "v2");
     Map<String, String> newProps = ImmutableMap.of("k1", "new value", "k2", 
"v2", "k3", "v3");
 
-    String versionUri = "s3://test-bucket/test-path/model.json";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = {"alias1", "alias2"};
     String versionComment = "version which tests update";
 
@@ -518,7 +672,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     modelOperationDispatcher.registerModel(modelIdent, modelComment, props);
 
     modelOperationDispatcher.linkModelVersion(
-        modelIdent, versionUri, versionAliases, versionComment, props);
+        modelIdent, versionUris, versionAliases, versionComment, props);
 
     ModelVersionChange[] changes =
         new ModelVersionChange[] {
@@ -530,7 +684,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     ModelVersion alteredModelVersion =
         modelOperationDispatcher.alterModelVersion(modelIdent, 
versionAliases[0], changes);
 
-    Assertions.assertEquals(modelVersion.uri(), alteredModelVersion.uri());
+    Assertions.assertEquals(modelVersion.uris(), alteredModelVersion.uris());
     Assertions.assertEquals(modelVersion.version(), 
alteredModelVersion.version());
     Assertions.assertEquals(modelVersion.aliases(), 
alteredModelVersion.aliases());
     Assertions.assertEquals(modelVersion.comment(), 
alteredModelVersion.comment());
@@ -547,7 +701,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     Map<String, String> props = ImmutableMap.of("k1", "v1", "k2", "v2");
     Map<String, String> newProps = ImmutableMap.of("k2", "v2");
 
-    String versionUri = "s3://test-bucket/test-path/model.json";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = {"alias1", "alias2"};
     String versionComment = "version which tests update";
 
@@ -559,7 +713,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     modelOperationDispatcher.registerModel(modelIdent, modelComment, props);
 
     modelOperationDispatcher.linkModelVersion(
-        modelIdent, versionUri, versionAliases, versionComment, props);
+        modelIdent, versionUris, versionAliases, versionComment, props);
 
     ModelVersionChange change = ModelVersionChange.removeProperty("k1");
 
@@ -567,7 +721,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     ModelVersion alteredModelVersion =
         modelOperationDispatcher.alterModelVersion(modelIdent, 0, change);
 
-    Assertions.assertEquals(modelVersion.uri(), alteredModelVersion.uri());
+    Assertions.assertEquals(modelVersion.uris(), alteredModelVersion.uris());
     Assertions.assertEquals(modelVersion.version(), 
alteredModelVersion.version());
     Assertions.assertEquals(modelVersion.aliases(), 
alteredModelVersion.aliases());
     Assertions.assertEquals(modelVersion.comment(), 
alteredModelVersion.comment());
@@ -584,7 +738,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     Map<String, String> props = ImmutableMap.of("k1", "v1", "k2", "v2");
     Map<String, String> newProps = ImmutableMap.of("k2", "v2");
 
-    String versionUri = "s3://test-bucket/test-path/model.json";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = {"alias1", "alias2"};
     String versionComment = "version which tests update";
 
@@ -596,7 +750,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     modelOperationDispatcher.registerModel(modelIdent, modelComment, props);
 
     modelOperationDispatcher.linkModelVersion(
-        modelIdent, versionUri, versionAliases, versionComment, props);
+        modelIdent, versionUris, versionAliases, versionComment, props);
 
     ModelVersionChange change = ModelVersionChange.removeProperty("k1");
 
@@ -605,7 +759,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     ModelVersion alteredModelVersion =
         modelOperationDispatcher.alterModelVersion(modelIdent, 
versionAliases[0], change);
 
-    Assertions.assertEquals(modelVersion.uri(), alteredModelVersion.uri());
+    Assertions.assertEquals(modelVersion.uris(), alteredModelVersion.uris());
     Assertions.assertEquals(modelVersion.version(), 
alteredModelVersion.version());
     Assertions.assertEquals(modelVersion.aliases(), 
alteredModelVersion.aliases());
     Assertions.assertEquals(modelVersion.comment(), 
alteredModelVersion.comment());
@@ -622,7 +776,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     Map<String, String> props = ImmutableMap.of("k1", "v1", "k2", "v2");
     String newUri = "s3://new-bucket/new-path/new-model.json";
 
-    String versionUri = "s3://test-bucket/test-path/model.json";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = {"alias1", "alias2"};
     String versionComment = "version which tests update";
 
@@ -634,7 +788,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     modelOperationDispatcher.registerModel(modelIdent, modelComment, props);
 
     modelOperationDispatcher.linkModelVersion(
-        modelIdent, versionUri, versionAliases, versionComment, props);
+        modelIdent, versionUris, versionAliases, versionComment, props);
 
     ModelVersionChange change = ModelVersionChange.updateUri(newUri);
     ModelVersion modelVersion = 
modelOperationDispatcher.getModelVersion(modelIdent, 0);
@@ -658,7 +812,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     Map<String, String> props = ImmutableMap.of("k1", "v1", "k2", "v2");
     String newUri = "s3://new-bucket/new-path/new-model.json";
 
-    String versionUri = "s3://test-bucket/test-path/model.json";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = {"alias1", "alias2"};
     String versionComment = "version which tests update";
 
@@ -670,7 +824,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     modelOperationDispatcher.registerModel(modelIdent, modelComment, props);
 
     modelOperationDispatcher.linkModelVersion(
-        modelIdent, versionUri, versionAliases, versionComment, props);
+        modelIdent, versionUris, versionAliases, versionComment, props);
 
     ModelVersionChange change = ModelVersionChange.updateUri(newUri);
     ModelVersion modelVersion =
@@ -694,7 +848,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     String modelComment = "model which tests update";
     Map<String, String> props = ImmutableMap.of("k1", "v1", "k2", "v2");
 
-    String versionUri = "s3://test-bucket/test-path/model.json";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = {"alias1", "alias2"};
     String versionComment = "version which tests update";
 
@@ -706,7 +860,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     modelOperationDispatcher.registerModel(modelIdent, modelComment, props);
 
     modelOperationDispatcher.linkModelVersion(
-        modelIdent, versionUri, versionAliases, versionComment, props);
+        modelIdent, versionUris, versionAliases, versionComment, props);
 
     ModelVersionChange change =
         ModelVersionChange.updateAliases(new String[] {"new_alias1", 
"new_alias2"}, versionAliases);
@@ -714,7 +868,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     ModelVersion alteredModelVersion =
         modelOperationDispatcher.alterModelVersion(modelIdent, 0, change);
 
-    Assertions.assertEquals(modelVersion.uri(), alteredModelVersion.uri());
+    Assertions.assertEquals(modelVersion.uris(), alteredModelVersion.uris());
     Assertions.assertEquals(modelVersion.version(), 
alteredModelVersion.version());
     Assertions.assertArrayEquals(
         new String[] {"new_alias1", "new_alias2"}, 
alteredModelVersion.aliases());
@@ -723,7 +877,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
 
     // Reload model version
     ModelVersion reloadedModelVersion = 
modelOperationDispatcher.getModelVersion(modelIdent, 0);
-    Assertions.assertEquals(modelVersion.uri(), reloadedModelVersion.uri());
+    Assertions.assertEquals(modelVersion.uris(), reloadedModelVersion.uris());
     Assertions.assertEquals(modelVersion.version(), 
reloadedModelVersion.version());
     Assertions.assertArrayEquals(
         new String[] {"new_alias1", "new_alias2"}, 
reloadedModelVersion.aliases());
@@ -740,7 +894,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     String modelComment = "model which tests update";
     Map<String, String> props = ImmutableMap.of("k1", "v1", "k2", "v2");
 
-    String versionUri = "s3://test-bucket/test-path/model.json";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = {"alias1", "alias2"};
     String versionComment = "version which tests update";
 
@@ -752,7 +906,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     modelOperationDispatcher.registerModel(modelIdent, modelComment, props);
 
     modelOperationDispatcher.linkModelVersion(
-        modelIdent, versionUri, versionAliases, versionComment, props);
+        modelIdent, versionUris, versionAliases, versionComment, props);
 
     ModelVersionChange change =
         ModelVersionChange.updateAliases(new String[] {"new_alias1", 
"new_alias2"}, versionAliases);
@@ -761,7 +915,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     ModelVersion alteredModelVersion =
         modelOperationDispatcher.alterModelVersion(modelIdent, 
versionAliases[0], change);
 
-    Assertions.assertEquals(modelVersion.uri(), alteredModelVersion.uri());
+    Assertions.assertEquals(modelVersion.uris(), alteredModelVersion.uris());
     Assertions.assertEquals(modelVersion.version(), 
alteredModelVersion.version());
     Assertions.assertArrayEquals(
         new String[] {"new_alias1", "new_alias2"}, 
alteredModelVersion.aliases());
@@ -771,7 +925,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     // Reload model version
     ModelVersion reloadedModelVersion =
         modelOperationDispatcher.getModelVersion(modelIdent, "new_alias1");
-    Assertions.assertEquals(modelVersion.uri(), reloadedModelVersion.uri());
+    Assertions.assertEquals(modelVersion.uris(), reloadedModelVersion.uris());
     Assertions.assertEquals(modelVersion.version(), 
reloadedModelVersion.version());
     Assertions.assertArrayEquals(
         new String[] {"new_alias1", "new_alias2"}, 
reloadedModelVersion.aliases());
@@ -788,7 +942,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     String modelComment = "model which tests update";
     Map<String, String> props = ImmutableMap.of("k1", "v1", "k2", "v2");
 
-    String versionUri = "s3://test-bucket/test-path/model.json";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = {"alias1", "alias2"};
     String versionComment = "version which tests update";
 
@@ -800,7 +954,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     modelOperationDispatcher.registerModel(modelIdent, modelComment, props);
 
     modelOperationDispatcher.linkModelVersion(
-        modelIdent, versionUri, versionAliases, versionComment, props);
+        modelIdent, versionUris, versionAliases, versionComment, props);
 
     ModelVersionChange change =
         ModelVersionChange.updateAliases(
@@ -809,7 +963,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     ModelVersion alteredModelVersion =
         modelOperationDispatcher.alterModelVersion(modelIdent, 0, change);
 
-    Assertions.assertEquals(modelVersion.uri(), alteredModelVersion.uri());
+    Assertions.assertEquals(modelVersion.uris(), alteredModelVersion.uris());
     Assertions.assertEquals(modelVersion.version(), 
alteredModelVersion.version());
     Assertions.assertArrayEquals(
         new String[] {"alias2", "new_alias1", "new_alias2"}, 
alteredModelVersion.aliases());
@@ -818,7 +972,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
 
     // Reload model version
     ModelVersion reloadedModelVersion = 
modelOperationDispatcher.getModelVersion(modelIdent, 0);
-    Assertions.assertEquals(modelVersion.uri(), reloadedModelVersion.uri());
+    Assertions.assertEquals(modelVersion.uris(), reloadedModelVersion.uris());
     Assertions.assertEquals(modelVersion.version(), 
reloadedModelVersion.version());
     Assertions.assertArrayEquals(
         new String[] {"alias2", "new_alias1", "new_alias2"}, 
reloadedModelVersion.aliases());
@@ -835,7 +989,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     String modelComment = "model which tests update";
     Map<String, String> props = ImmutableMap.of("k1", "v1", "k2", "v2");
 
-    String versionUri = "s3://test-bucket/test-path/model.json";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = {"alias1", "alias2"};
     String versionComment = "version which tests update";
 
@@ -847,7 +1001,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     modelOperationDispatcher.registerModel(modelIdent, modelComment, props);
 
     modelOperationDispatcher.linkModelVersion(
-        modelIdent, versionUri, versionAliases, versionComment, props);
+        modelIdent, versionUris, versionAliases, versionComment, props);
 
     ModelVersionChange change =
         ModelVersionChange.updateAliases(
@@ -857,7 +1011,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     ModelVersion alteredModelVersion =
         modelOperationDispatcher.alterModelVersion(modelIdent, 
versionAliases[0], change);
 
-    Assertions.assertEquals(modelVersion.uri(), alteredModelVersion.uri());
+    Assertions.assertEquals(modelVersion.uris(), alteredModelVersion.uris());
     Assertions.assertEquals(modelVersion.version(), 
alteredModelVersion.version());
     Assertions.assertArrayEquals(
         new String[] {"alias2", "new_alias1", "new_alias2"}, 
alteredModelVersion.aliases());
@@ -867,7 +1021,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     // Reload model version
     ModelVersion reloadedModelVersion =
         modelOperationDispatcher.getModelVersion(modelIdent, "new_alias1");
-    Assertions.assertEquals(modelVersion.uri(), reloadedModelVersion.uri());
+    Assertions.assertEquals(modelVersion.uris(), reloadedModelVersion.uris());
     Assertions.assertEquals(modelVersion.version(), 
reloadedModelVersion.version());
     Assertions.assertArrayEquals(
         new String[] {"alias2", "new_alias1", "new_alias2"}, 
reloadedModelVersion.aliases());
@@ -884,7 +1038,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     String modelComment = "model which tests update";
     Map<String, String> props = ImmutableMap.of("k1", "v1", "k2", "v2");
 
-    String versionUri = "s3://test-bucket/test-path/model.json";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = {"alias2", "alias3"};
     String versionComment = "version which tests update";
 
@@ -896,7 +1050,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     modelOperationDispatcher.registerModel(modelIdent, modelComment, props);
 
     modelOperationDispatcher.linkModelVersion(
-        modelIdent, versionUri, versionAliases, versionComment, props);
+        modelIdent, versionUris, versionAliases, versionComment, props);
 
     ModelVersionChange change =
         ModelVersionChange.updateAliases(
@@ -905,7 +1059,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     ModelVersion alteredModelVersion =
         modelOperationDispatcher.alterModelVersion(modelIdent, 0, change);
 
-    Assertions.assertEquals(modelVersion.uri(), alteredModelVersion.uri());
+    Assertions.assertEquals(modelVersion.uris(), alteredModelVersion.uris());
     Assertions.assertEquals(modelVersion.version(), 
alteredModelVersion.version());
     Assertions.assertEquals(
         ImmutableSet.of("alias1", "alias2"),
@@ -915,7 +1069,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
 
     // Reload model version
     ModelVersion reloadedModelVersion = 
modelOperationDispatcher.getModelVersion(modelIdent, 0);
-    Assertions.assertEquals(modelVersion.uri(), reloadedModelVersion.uri());
+    Assertions.assertEquals(modelVersion.uris(), reloadedModelVersion.uris());
     Assertions.assertEquals(modelVersion.version(), 
reloadedModelVersion.version());
     Assertions.assertEquals(
         ImmutableSet.of("alias1", "alias2"),
@@ -933,7 +1087,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     String modelComment = "model which tests update";
     Map<String, String> props = ImmutableMap.of("k1", "v1", "k2", "v2");
 
-    String versionUri = "s3://test-bucket/test-path/model.json";
+    Map<String, String> versionUris = 
ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uri");
     String[] versionAliases = {"alias2", "alias3"};
     String versionComment = "version which tests update";
 
@@ -945,7 +1099,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     modelOperationDispatcher.registerModel(modelIdent, modelComment, props);
 
     modelOperationDispatcher.linkModelVersion(
-        modelIdent, versionUri, versionAliases, versionComment, props);
+        modelIdent, versionUris, versionAliases, versionComment, props);
 
     ModelVersionChange change =
         ModelVersionChange.updateAliases(
@@ -954,7 +1108,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     ModelVersion alteredModelVersion =
         modelOperationDispatcher.alterModelVersion(modelIdent, "alias2", 
change);
 
-    Assertions.assertEquals(modelVersion.uri(), alteredModelVersion.uri());
+    Assertions.assertEquals(modelVersion.uris(), alteredModelVersion.uris());
     Assertions.assertEquals(modelVersion.version(), 
alteredModelVersion.version());
     Assertions.assertEquals(
         ImmutableSet.of("alias1", "alias2"),
@@ -965,7 +1119,7 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     // Reload model version
     ModelVersion reloadedModelVersion =
         modelOperationDispatcher.getModelVersion(modelIdent, "alias1");
-    Assertions.assertEquals(modelVersion.uri(), reloadedModelVersion.uri());
+    Assertions.assertEquals(modelVersion.uris(), reloadedModelVersion.uris());
     Assertions.assertEquals(modelVersion.version(), 
reloadedModelVersion.version());
     Assertions.assertEquals(
         ImmutableSet.of("alias1", "alias2"),
diff --git 
a/core/src/test/java/org/apache/gravitino/connector/TestCatalogOperations.java 
b/core/src/test/java/org/apache/gravitino/connector/TestCatalogOperations.java
index ee28f522e5..61cdef1f1d 100644
--- 
a/core/src/test/java/org/apache/gravitino/connector/TestCatalogOperations.java
+++ 
b/core/src/test/java/org/apache/gravitino/connector/TestCatalogOperations.java
@@ -66,6 +66,7 @@ import org.apache.gravitino.exceptions.NoSuchFilesetException;
 import org.apache.gravitino.exceptions.NoSuchLocationNameException;
 import org.apache.gravitino.exceptions.NoSuchModelException;
 import org.apache.gravitino.exceptions.NoSuchModelVersionException;
+import org.apache.gravitino.exceptions.NoSuchModelVersionURINameException;
 import org.apache.gravitino.exceptions.NoSuchSchemaException;
 import org.apache.gravitino.exceptions.NoSuchTableException;
 import org.apache.gravitino.exceptions.NoSuchTopicException;
@@ -847,7 +848,7 @@ public class TestCatalogOperations
   @Override
   public void linkModelVersion(
       NameIdentifier ident,
-      String uri,
+      Map<String, String> uris,
       String[] aliases,
       String comment,
       Map<String, String> properties)
@@ -856,6 +857,19 @@ public class TestCatalogOperations
       throw new NoSuchModelException("Model %s does not exist", ident);
     }
 
+    if (uris == null || uris.isEmpty()) {
+      throw new IllegalArgumentException("Uri must be set for model version");
+    }
+    uris.forEach(
+        (name, uri) -> {
+          if (StringUtils.isBlank(name)) {
+            throw new IllegalArgumentException("URI name must not be blank");
+          }
+          if (StringUtils.isBlank(uri)) {
+            throw new IllegalArgumentException("URI must not be blank for 
name: " + name);
+          }
+        });
+
     String[] aliasArray = aliases != null ? aliases : new String[0];
     for (String alias : aliasArray) {
       Pair<NameIdentifier, String> aliasPair = Pair.of(ident, alias);
@@ -871,7 +885,7 @@ public class TestCatalogOperations
             .withVersion(version)
             .withAliases(aliases)
             .withComment(comment)
-            .withUri(uri)
+            .withUris(uris)
             .withProperties(properties)
             .withAuditInfo(
                 
AuditInfo.builder().withCreator("test").withCreateTime(Instant.now()).build())
@@ -895,6 +909,22 @@ public class TestCatalogOperations
     models.put(ident, updatedModel);
   }
 
+  @Override
+  public String getModelVersionUri(NameIdentifier ident, String alias, String 
uriName)
+      throws NoSuchModelVersionException, NoSuchModelVersionURINameException {
+    Model model = getModel(ident);
+    ModelVersion modelVersion = getModelVersion(ident, alias);
+    return internalGetModelVersionUri(model, modelVersion, uriName);
+  }
+
+  @Override
+  public String getModelVersionUri(NameIdentifier ident, int version, String 
uriName)
+      throws NoSuchModelVersionException, NoSuchModelVersionURINameException {
+    Model model = getModel(ident);
+    ModelVersion modelVersion = getModelVersion(ident, version);
+    return internalGetModelVersionUri(model, modelVersion, uriName);
+  }
+
   @Override
   public boolean deleteModelVersion(NameIdentifier ident, int version) {
     if (!models.containsKey(ident)) {
@@ -1044,6 +1074,44 @@ public class TestCatalogOperations
     return internalUpdateModelVersion(ident, version, changes);
   }
 
+  private String internalGetModelVersionUri(
+      Model model, ModelVersion modelVersion, String uriName) {
+    Map<String, String> uris = modelVersion.uris();
+    // If the uriName is not null, get from the uris directly
+    if (uriName != null) {
+      return getUriByName(uris, uriName);
+    }
+
+    // If there is only one uri of the model version, use it
+    if (uris.size() == 1) {
+      return uris.values().iterator().next();
+    }
+
+    // If the uri name is null, try to get the default uri name from the model 
version properties
+    Map<String, String> modelVersionProperties = modelVersion.properties();
+    if 
(modelVersionProperties.containsKey(ModelVersion.PROPERTY_DEFAULT_URI_NAME)) {
+      String defaultUriName = 
modelVersionProperties.get(ModelVersion.PROPERTY_DEFAULT_URI_NAME);
+      return getUriByName(uris, defaultUriName);
+    }
+
+    // If the default uri name is not set for the model version, try to get 
the default uri name
+    // from the model properties
+    Map<String, String> modelProperties = model.properties();
+    if (modelProperties.containsKey(ModelVersion.PROPERTY_DEFAULT_URI_NAME)) {
+      String defaultUriName = 
modelProperties.get(ModelVersion.PROPERTY_DEFAULT_URI_NAME);
+      return getUriByName(uris, defaultUriName);
+    }
+
+    throw new IllegalArgumentException("Either uri name of default uri name 
should be provided");
+  }
+
+  private String getUriByName(Map<String, String> uris, String uriName) {
+    if (!uris.containsKey(uriName)) {
+      throw new NoSuchModelVersionURINameException("URI name %s does not 
exist", uriName);
+    }
+    return uris.get(uriName);
+  }
+
   private ModelVersion internalUpdateModelVersion(
       NameIdentifier ident, int version, ModelVersionChange... changes)
       throws NoSuchModelException, NoSuchModelVersionException, 
IllegalArgumentException {
@@ -1107,7 +1175,7 @@ public class TestCatalogOperations
             .withComment(newComment)
             .withProperties(newProps)
             .withAuditInfo(updatedAuditInfo)
-            .withUri(newUri)
+            .withUris(ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, newUri))
             .withAliases(newAliases)
             .build();
 
diff --git 
a/core/src/test/java/org/apache/gravitino/listener/api/event/TestModelEvent.java
 
b/core/src/test/java/org/apache/gravitino/listener/api/event/TestModelEvent.java
index 3b4f7b4766..ac31f7e7d1 100644
--- 
a/core/src/test/java/org/apache/gravitino/listener/api/event/TestModelEvent.java
+++ 
b/core/src/test/java/org/apache/gravitino/listener/api/event/TestModelEvent.java
@@ -79,14 +79,14 @@ public class TestModelEvent {
     this.alterNameModel = getMockModel("modelA_rename", "commentA");
     this.alterCommentModelVersion =
         getMockModelVersion(
-            "uriA",
+            ImmutableMap.of("name1", "uri1", "name2", "uri2"),
             1,
             new String[] {"aliasProduction"},
             newModelVersionComment,
             ImmutableMap.of("color", "#FFFFFF"));
     this.otherAlterCommentModelVersion =
         getMockModelVersion(
-            "uriB",
+            ImmutableMap.of("name3", "uri3"),
             2,
             new String[] {"aliasTest"},
             newModelVersionComment,
@@ -95,8 +95,13 @@ public class TestModelEvent {
     this.modelUpdateCommentChange = getMockModelVersionChange("new comment");
 
     this.firstModelVersion =
-        mockModelVersion("uriA", new String[] {"aliasProduction"}, 
"versionInfoA");
-    this.secondModelVersion = mockModelVersion("uriB", new String[] 
{"aliasTest"}, "versionInfoB");
+        mockModelVersion(
+            ImmutableMap.of("name1", "uri1", "name2", "uri2"),
+            new String[] {"aliasProduction"},
+            "versionInfoA");
+    this.secondModelVersion =
+        mockModelVersion(
+            ImmutableMap.of("name3", "uri3"), new String[] {"aliasTest"}, 
"versionInfoB");
 
     this.notExistingIdent =
         NameIdentifierUtil.ofModel("metalake", "catalog", "schema", 
"not_exist");
@@ -135,7 +140,8 @@ public class TestModelEvent {
   @Test
   void testModelVersionInfo() {
     ModelVersion modelVersion =
-        mockModelVersion("uriA", new String[] {"aliasProduction"}, 
"versionInfoA");
+        mockModelVersion(
+            ImmutableMap.of("nameA", "uriA"), new String[] 
{"aliasProduction"}, "versionInfoA");
     ModelVersionInfo modelVersionInfo = new ModelVersionInfo(modelVersion);
 
     checkModelVersionInfo(modelVersionInfo, modelVersion);
@@ -143,7 +149,8 @@ public class TestModelEvent {
 
   @Test
   void testModelVersionInfoWithoutComment() {
-    ModelVersion modelVersion = mockModelVersion("uriA", new String[] 
{"aliasProduction"}, null);
+    ModelVersion modelVersion =
+        mockModelVersion(ImmutableMap.of("nameA", "uriA"), new String[] 
{"aliasProduction"}, null);
     ModelVersionInfo modelVersionInfo = new ModelVersionInfo(modelVersion);
 
     checkModelVersionInfo(modelVersionInfo, modelVersion);
@@ -152,7 +159,8 @@ public class TestModelEvent {
   @Test
   void testModelVersionInfoWithAudit() {
     ModelVersion modelVersion =
-        getMockModelWithAudit("uriA", new String[] {"aliasProduction"}, 
"versionInfoA");
+        getMockModelWithAudit(
+            ImmutableMap.of("nameA", "uriA"), new String[] 
{"aliasProduction"}, "versionInfoA");
     ModelVersionInfo modelVersionInfo = new ModelVersionInfo(modelVersion);
 
     checkModelVersionInfo(modelVersionInfo, modelVersion);
@@ -216,7 +224,7 @@ public class TestModelEvent {
   void testRegisterAndLinkModelEvent() {
     dispatcher.registerModel(
         existingIdentA,
-        "uriA",
+        ImmutableMap.of("name1", "uri1", "name2", "uri2"),
         new String[] {"aliasProduction"},
         "commentA",
         ImmutableMap.of("color", "#FFFFFF"));
@@ -238,8 +246,7 @@ public class TestModelEvent {
     ModelVersionInfo linkModelVersionRequest =
         registerAndLinkModelPreEvent.linkModelVersionRequest();
 
-    Assertions.assertEquals(
-        firstModelVersion.uri(), 
linkModelVersionRequest.uris().get(ModelVersion.URI_NAME_UNKNOWN));
+    Assertions.assertEquals(firstModelVersion.uris(), 
linkModelVersionRequest.uris());
     Assertions.assertEquals("commentA", 
linkModelVersionRequest.comment().orElse(null));
     checkArray(firstModelVersion.aliases(), 
linkModelVersionRequest.aliases().orElse(null));
     checkProperties(firstModelVersion.properties(), 
linkModelVersionRequest.properties());
@@ -260,8 +267,7 @@ public class TestModelEvent {
 
     // validate post-event model uri info
     Map<String, String> versionUris = registerAndLinkModelEvent.uris();
-    Assertions.assertEquals(
-        firstModelVersion.uri(), 
versionUris.get(ModelVersion.URI_NAME_UNKNOWN));
+    Assertions.assertEquals(firstModelVersion.uris(), versionUris);
   }
 
   @Test
@@ -271,7 +277,7 @@ public class TestModelEvent {
         () ->
             failureDispatcher.registerModel(
                 existingIdentA,
-                "uriA",
+                ImmutableMap.of("name1", "uri1", "name2", "uri2"),
                 new String[] {"aliasProduction"},
                 "commentA",
                 ImmutableMap.of("color", "#FFFFFF")));
@@ -294,8 +300,7 @@ public class TestModelEvent {
         registerAndLinkModelFailureEvent.linkModelVersionRequest();
 
     checkModelInfo(registerModelRequest, modelA);
-    Assertions.assertEquals(
-        firstModelVersion.uri(), 
linkModelVersionRequest.uris().get(ModelVersion.URI_NAME_UNKNOWN));
+    Assertions.assertEquals(firstModelVersion.uris(), 
linkModelVersionRequest.uris());
     Assertions.assertEquals("commentA", 
linkModelVersionRequest.comment().orElse(null));
     checkArray(firstModelVersion.aliases(), 
linkModelVersionRequest.aliases().orElse(null));
     checkProperties(firstModelVersion.properties(), 
linkModelVersionRequest.properties());
@@ -430,7 +435,7 @@ public class TestModelEvent {
   void testLinkModelVersionEvent() {
     dispatcher.linkModelVersion(
         existingIdentA,
-        "uriA",
+        ImmutableMap.of("name1", "uri1", "name2", "uri2"),
         new String[] {"aliasProduction"},
         "versionInfoA",
         ImmutableMap.of("color", "#FFFFFF"));
@@ -467,7 +472,7 @@ public class TestModelEvent {
         () ->
             failureDispatcher.linkModelVersion(
                 existingIdentA,
-                "uriA",
+                ImmutableMap.of("name1", "uri1", "name2", "uri2"),
                 new String[] {"aliasProduction"},
                 "versionInfoA",
                 ImmutableMap.of("color", "#FFFFFF")));
@@ -1067,7 +1072,7 @@ public class TestModelEvent {
 
     // validate ModelVersionInfo
     Assertions.assertEquals(
-        ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uriA"), 
modelVersionInfo.uris());
+        ImmutableMap.of("name1", "uri1", "name2", "uri2"), 
modelVersionInfo.uris());
     Assertions.assertTrue(modelVersionInfo.aliases().isPresent());
     Assertions.assertArrayEquals(
         new String[] {"aliasProduction"}, modelVersionInfo.aliases().get());
@@ -1093,8 +1098,7 @@ public class TestModelEvent {
     ModelVersionInfo modelVersionInfo = 
alterModelVersionEvent.alteredModelVersionInfo();
 
     // validate ModelVersionInfo
-    Assertions.assertEquals(
-        ImmutableMap.of(ModelVersion.URI_NAME_UNKNOWN, "uriB"), 
modelVersionInfo.uris());
+    Assertions.assertEquals(ImmutableMap.of("name3", "uri3"), 
modelVersionInfo.uris());
     Assertions.assertTrue(modelVersionInfo.aliases().isPresent());
     Assertions.assertArrayEquals(new String[] {"aliasTest"}, 
modelVersionInfo.aliases().get());
     Assertions.assertTrue(modelVersionInfo.comment().isPresent());
@@ -1163,7 +1167,7 @@ public class TestModelEvent {
         .thenReturn(modelB);
     when(dispatcher.registerModel(
             existingIdentA,
-            "uriA",
+            ImmutableMap.of("name1", "uri1", "name2", "uri2"),
             new String[] {"aliasProduction"},
             "commentA",
             ImmutableMap.of("color", "#FFFFFF")))
@@ -1220,10 +1224,14 @@ public class TestModelEvent {
   }
 
   private ModelVersion getMockModelVersion(
-      String uri, int version, String[] aliases, String comment, Map<String, 
String> properties) {
+      Map<String, String> uris,
+      int version,
+      String[] aliases,
+      String comment,
+      Map<String, String> properties) {
     ModelVersion mockModelVersion = mock(ModelVersion.class);
     when(mockModelVersion.version()).thenReturn(version);
-    when(mockModelVersion.uri()).thenReturn(uri);
+    when(mockModelVersion.uris()).thenReturn(uris);
     when(mockModelVersion.aliases()).thenReturn(aliases);
     when(mockModelVersion.comment()).thenReturn(comment);
     when(mockModelVersion.properties()).thenReturn(properties);
@@ -1244,10 +1252,11 @@ public class TestModelEvent {
     return model;
   }
 
-  private ModelVersion mockModelVersion(String uri, String[] aliases, String 
comment) {
+  private ModelVersion mockModelVersion(
+      Map<String, String> uris, String[] aliases, String comment) {
     ModelVersion modelVersion = mock(ModelVersion.class);
     when(modelVersion.version()).thenReturn(1);
-    when(modelVersion.uri()).thenReturn(uri);
+    when(modelVersion.uris()).thenReturn(uris);
     when(modelVersion.aliases()).thenReturn(aliases);
     when(modelVersion.comment()).thenReturn(comment);
     when(modelVersion.properties()).thenReturn(ImmutableMap.of("color", 
"#FFFFFF"));
@@ -1255,8 +1264,9 @@ public class TestModelEvent {
     return modelVersion;
   }
 
-  private ModelVersion getMockModelWithAudit(String uri, String[] aliases, 
String comment) {
-    ModelVersion modelVersion = mockModelVersion(uri, aliases, comment);
+  private ModelVersion getMockModelWithAudit(
+      Map<String, String> uris, String[] aliases, String comment) {
+    ModelVersion modelVersion = mockModelVersion(uris, aliases, comment);
     Audit mockAudit = mock(Audit.class);
 
     when(mockAudit.creator()).thenReturn("demo_user");
@@ -1282,8 +1292,7 @@ public class TestModelEvent {
 
   private void checkModelVersionInfo(ModelVersionInfo modelVersionInfo, 
ModelVersion modelVersion) {
     // check normal fields
-    Assertions.assertEquals(
-        modelVersion.uri(), 
modelVersionInfo.uris().get(ModelVersion.URI_NAME_UNKNOWN));
+    Assertions.assertEquals(modelVersion.uris(), modelVersionInfo.uris());
     Assertions.assertEquals(modelVersion.comment(), 
modelVersionInfo.comment().orElse(null));
 
     // check aliases
diff --git 
a/core/src/test/java/org/apache/gravitino/meta/TestEntityCombinedObject.java 
b/core/src/test/java/org/apache/gravitino/meta/TestEntityCombinedObject.java
index 4c8f1f2325..3f363073e7 100644
--- a/core/src/test/java/org/apache/gravitino/meta/TestEntityCombinedObject.java
+++ b/core/src/test/java/org/apache/gravitino/meta/TestEntityCombinedObject.java
@@ -20,6 +20,7 @@ package org.apache.gravitino.meta;
 
 import static org.mockito.Mockito.mock;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import java.time.Instant;
 import java.util.HashMap;
@@ -28,12 +29,14 @@ import java.util.Set;
 import org.apache.gravitino.Schema;
 import org.apache.gravitino.catalog.EntityCombinedFileset;
 import org.apache.gravitino.catalog.EntityCombinedModel;
+import org.apache.gravitino.catalog.EntityCombinedModelVersion;
 import org.apache.gravitino.catalog.EntityCombinedSchema;
 import org.apache.gravitino.catalog.EntityCombinedTable;
 import org.apache.gravitino.catalog.EntityCombinedTopic;
 import org.apache.gravitino.file.Fileset;
 import org.apache.gravitino.messaging.Topic;
 import org.apache.gravitino.model.Model;
+import org.apache.gravitino.model.ModelVersion;
 import org.apache.gravitino.rel.Table;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
@@ -65,6 +68,7 @@ public class TestEntityCombinedObject {
   private final Table originTable = mockTable();
   private final Fileset originFileset = mockFileset();
   private final Model originModel = mockModel();
+  private final ModelVersion originModelVersion = mockModelVersion();
 
   @Test
   public void testSchema() {
@@ -136,6 +140,21 @@ public class TestEntityCombinedObject {
     Assertions.assertEquals(originModel.auditInfo(), 
entityCombinedModel.auditInfo());
   }
 
+  @Test
+  public void testModelVersion() {
+    EntityCombinedModelVersion entityCombinedModelVersion =
+        
EntityCombinedModelVersion.of(originModelVersion).withHiddenProperties(hiddenProperties);
+    Assertions.assertEquals(originModelVersion.comment(), 
entityCombinedModelVersion.comment());
+    Map<String, String> filterProp = new 
HashMap<>(originModelVersion.properties());
+    filterProp.remove("k3");
+    filterProp.remove(null);
+    filterProp.remove("k5");
+    Assertions.assertEquals(filterProp, 
entityCombinedModelVersion.properties());
+    Assertions.assertEquals(originModelVersion.auditInfo(), 
entityCombinedModelVersion.auditInfo());
+    Assertions.assertEquals(originModelVersion.version(), 
entityCombinedModelVersion.version());
+    Assertions.assertEquals(originModelVersion.uris(), 
entityCombinedModelVersion.uris());
+  }
+
   private Schema mockSchema() {
     Schema mockSchema = mock(Schema.class);
     Mockito.when(mockSchema.name()).thenReturn("testSchema");
@@ -180,4 +199,14 @@ public class TestEntityCombinedObject {
     Mockito.when(mockModel.properties()).thenReturn(entityProperties);
     return mockModel;
   }
+
+  private ModelVersion mockModelVersion() {
+    ModelVersion mockModelVersion = mock(ModelVersion.class);
+    Mockito.when(mockModelVersion.version()).thenReturn(1);
+    Mockito.when(mockModelVersion.comment()).thenReturn("test model version 
comment");
+    Mockito.when(mockModelVersion.auditInfo()).thenReturn(auditInfo);
+    Mockito.when(mockModelVersion.properties()).thenReturn(entityProperties);
+    Mockito.when(mockModelVersion.uris()).thenReturn(ImmutableMap.of("n1", 
"u1", "n2", "u2"));
+    return mockModelVersion;
+  }
 }

Reply via email to