Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add Databricks ML flow api endpoints #206

Merged
merged 29 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
12723e5
DevOps Pipeline
Jul 8, 2024
43ab379
New models
Jul 8, 2024
5b2b0b7
update Unity Catalog Client
Jul 8, 2024
77446ef
Fix query parametor error which neglected the correct format with ? f…
Jul 9, 2024
49b8913
Fix run_workspace_id type to long (int64) from string
Jul 9, 2024
8dca740
Add sample program to Examples
Jul 12, 2024
0faa491
Merge branch 'unity-catalog-models' into devops-build
Jul 12, 2024
f60affc
Add Machine Learning Experiment Api endpoint and test
Jul 12, 2024
c12d40d
Add Machine Learning Experiment Api endpoint and test
Jul 12, 2024
bf119e2
Merge branch 'mlflow' of https://dev.azure.com/InsightFactory/factory…
Jul 12, 2024
34b2a25
Updated build-databricks-client.yml working directory path
Jul 14, 2024
71cb0ad
Updated build-databricks-client.yml error
Jul 15, 2024
eaa3ad4
Updated build-databricks-client.yml. Bump build version to avoid vers…
Jul 15, 2024
c8b8bcc
Updated build-databricks-client.yml fix minor version
Jul 15, 2024
442076e
Updated build-databricks-client.yml working directory path
Jul 14, 2024
2b6a77e
Updated build-databricks-client.yml error
Jul 15, 2024
c7221f1
Updated build-databricks-client.yml. Bump build version to avoid vers…
Jul 15, 2024
7db579f
Updated build-databricks-client.yml fix minor version
Jul 15, 2024
4c5bdd2
Add format whitespace and update ML endpointAdd Machine Learning Expe…
Jul 12, 2024
52a87b0
Add sample programAdd format whitespace and update ML endpointAdd Mac…
Jul 12, 2024
23764c5
Add Machine Learning Experiment Api endpoint and test
Jul 12, 2024
51c262c
Add format whitespace and update ML endpointAdd Machine Learning Expe…
Jul 12, 2024
470bc10
Add sample programAdd format whitespace and update ML endpointAdd Mac…
Jul 12, 2024
2216561
Merge branch 'mlflow' of https://dev.azure.com/InsightFactory/factory…
Jul 15, 2024
0161bfa
Remove ADO file
memoryz Sep 13, 2024
cccdfec
Apply code review comments
memoryz Sep 13, 2024
7aed71c
missing semicolon
memoryz Sep 13, 2024
6a87bd6
bug fix and cleanups
memoryz Sep 13, 2024
73ad763
apply code review comments
memoryz Sep 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Microsoft.Azure.Databricks.Client.Models.UnityCatalog;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace Microsoft.Azure.Databricks.Client.Sample;

internal static partial class SampleProgram
{
private static async Task TestExperimentApiClient(DatabricksClient client)
{
string run_id = "sample_run_id";
PrintDelimiter();
Console.WriteLine("Listing metastores");
var data = await client.MachineLearning.Experiments.GetRun(run_id);
Console.WriteLine($"\t{data.Info.RunId}");
PrintDelimiter();

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,22 @@ private static async Task TestUnityCatalogApi(DatabricksClient client)
Console.WriteLine($"Deleting created catalog {catalog.Name}...");
await client.UnityCatalog.Catalogs.Delete(catalog.Name);
Console.WriteLine("Catalog deleted");

Console.WriteLine("Listing Regsitered Models");
var registeredModels = await client.UnityCatalog.RegisteredModels.ListRegisteredModels();
foreach (var model in registeredModels)
{
Console.WriteLine($"\t{model.MetastoreId}, {model.Name}");
}
PrintDelimiter();

var fullName = "main.default.revenue_forecasting";
Console.WriteLine("Listing Regsitered Models");
var modelVersionsList = await client.UnityCatalog.ModelVersion.ListModelVersions(fullName);
foreach (var model in modelVersionsList)
{
Console.WriteLine($"\t{model.MetastoreId}, {model.CatalogName}");
}
PrintDelimiter();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@


using Microsoft.Azure.Databricks.Client.MachineLearning;
using Moq.Contrib.HttpClient;
using System.Net;
using System.Text.Json;
using System.Text.Json.Nodes;
using Microsoft.Azure.Databricks.Client.Models.MachineLearning.Experiment;

namespace Microsoft.Azure.Databricks.Client.Test.MachineLearning;

[TestClass]
public class ExperimentApiClientTests : MachineLearningApiClientTest
{
[TestMethod]
public async Task GetRunTest()
{
var run_id = "19d13cbfa8134b699f8b41fdab0cdd4c";
var requestUri = $"{MlflowBaseUri}/runs/get?run_id={run_id}";
var expectedResponse = @"
{
""run"": {
""info"": {
""run_id"": ""string"",
""run_uuid"": ""string"",
""experiment_id"": ""string"",
""user_id"": ""string"",
""status"": ""RUNNING"",
""start_time"": 0,
""end_time"": 0,
""artifact_uri"": ""string"",
""lifecycle_stage"": ""string""
},
""data"": {
""metrics"": [
{
""key"": ""string"",
""value"": 0.1,
""timestamp"": 0,
""step"": ""0""
}
],
""params"": [
{
""key"": ""string"",
""value"": ""string""
}
],
""tags"": [
{
""key"": ""string"",
""value"": ""string""
}
]
},
""inputs"": {
""dataset_inputs"": [
{
""tags"": [
{
""key"": ""string"",
""value"": ""string""
}
],
""dataset"": {
""name"": ""string"",
""digest"": ""string"",
""source_type"": ""string"",
""source"": ""string"",
""schema"": ""string"",
""profile"": ""string""
}
}
]
}
}
}";

var handler = CreateMockHandler();
handler
.SetupRequest(HttpMethod.Get, requestUri)
.ReturnsResponse(HttpStatusCode.OK, expectedResponse, "application/json");

var mockClient = handler.CreateClient();
mockClient.BaseAddress = BaseApiUri;

using var client = new ExperimentApiClient(mockClient);
var response = await client.GetRun(run_id);

var expected = JsonNode.Parse(expectedResponse)?["run"].Deserialize<Run>(Options);

Assert.IsNotNull(expected, "Expected object is null.");
Assert.IsNotNull(response, "Response object is null.");

if (response != null && expected != null)
{
Assert.AreEqual(expected.ToString(), response.ToString());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Microsoft.Azure.Databricks.Client.Test.MachineLearning;

[TestClass]
public class MachineLearningApiClientTest : ApiClientTest
{
protected static readonly Uri MlflowBaseUri = new(BaseApiUri, "2.0/mlflow");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
using Microsoft.Azure.Databricks.Client.Models.UnityCatalog;
using Microsoft.Azure.Databricks.Client.UnityCatalog;
using Moq.Contrib.HttpClient;
using System.Net;
using System.Text.Json;
using System.Text.Json.Nodes;

namespace Microsoft.Azure.Databricks.Client.Test.UnityCatalog;

[TestClass]
public class ModelVersionApiClientTests : UnityCatalogApiClientTest
{
[TestMethod]
public async Task ListModelVersionsTest()
{
var full_name = "main.default.revenue_forecasting";
var requestUri = $"{BaseApiUri}models/{full_name}/versions";

var expectedResponse = @"
{
""model_versions"": [
{
""model_name"": ""revenue_forecasting_model"",
""catalog_name"": ""main"",
""schema_name"": ""default"",
""comment"": ""This model version forecasts future revenue given historical data, using classic ML techniques"",
""source"": ""dbfs:/databricks/mlflow-tracking/1234567890/abcdef/artifacts/model"",
""run_id"": ""abcdef"",
""run_workspace_id"": 6051234418418567,
""version"": 1,
""status"": ""READY"",
""id"": ""9876543-21zy-abcd-3210-abcdef456789"",
""metastore_id"": ""11111111-1111-1111-1111-111111111111"",
""created_at"": 1666369196203,
""created_by"": ""[email protected]"",
""updated_at"": 1666369196203,
""updated_by"": ""[email protected]"",
""storage_location"": ""s3://my-bucket/hello/world/models/2222-2222/versions/9876543-21zy-abcd-3210-abcdef456789""
},
{
""model_name"": ""revenue_forecasting_model"",
""catalog_name"": ""main"",
""schema_name"": ""default"",
""comment"": ""This model version forecasts future revenue given historical data, using deep learning"",
""source"": ""dbfs:/databricks/mlflow-tracking/1234567890/abcdef/artifacts/model"",
""run_id"": ""abcdef"",
""run_workspace_id"": 6051234418418567,
""version"": 2,
""status"": ""READY"",
""id"": ""01234567-89ab-cdef-0123-456789abcdef"",
""metastore_id"": ""11111111-1111-1111-1111-111111111111"",
""created_at"": 1666369196907,
""created_by"": ""[email protected]"",
""updated_at"": 1666369196907,
""updated_by"": ""[email protected]"",
""storage_location"": ""s3://my-bucket/hello/world/models/2222-2222/versions/01234567-89ab-cdef-0123-456789abcdef""
}
],
""next_page_token"": ""some-page-token""
}";
var expected = JsonNode.Parse(expectedResponse)?["model_versions"].Deserialize<IEnumerable<ModelVersion>>(Options);

var handler = CreateMockHandler();
handler
.SetupRequest(HttpMethod.Get, requestUri)
.ReturnsResponse(HttpStatusCode.OK, expectedResponse, "application/json");

var mockClient = handler.CreateClient();
mockClient.BaseAddress = ApiClientTest.BaseApiUri;

using var client = new ModelVersionApiClient(mockClient);
var response = await client.ListModelVersions(full_name);

var responseJson = JsonSerializer.Serialize(response, Options);
CollectionAssert.AreEqual(expected?.ToList(), response?.ToList());
}


[TestMethod]
public async Task GetModelVersionTest()
{
var expectedResponse = @"
{
""model_name"": ""revenue_forecasting_model"",
""catalog_name"": ""main"",
""schema_name"": ""default"",
""comment"": ""This model version forecasts future revenue given historical data, using classic ML techniques"",
""source"": ""dbfs:/databricks/mlflow-tracking/1234567890/abcdef/artifacts/model"",
""run_id"": ""abcdef"",
""run_workspace_id"": 6051234418418567,
""version"": 1,
""status"": ""READY"",
""id"": ""01234567-89ab-cdef-0123-456789abcdef"",
""metastore_id"": ""11111111-1111-1111-1111-111111111111"",
""created_at"": 1666369196203,
""created_by"": ""[email protected]"",
""updated_at"": 1666369196203,
""updated_by"": ""[email protected]"",
""storage_location"": ""s3://my-bucket/hello/world/models/2222-2222/versions/01234567-89ab-cdef-0123-456789abcdef""
}
";

var full_name = "main.default.revenue_forecasting_model";
var version = 2;
var requestUri = $"{BaseApiUri}models/{full_name}/versions/{version}";

var handler = CreateMockHandler();
handler
.SetupRequest(HttpMethod.Get, requestUri)
.ReturnsResponse(HttpStatusCode.OK, expectedResponse, "application/json");

var mockClient = handler.CreateClient();
mockClient.BaseAddress = ApiClientTest.BaseApiUri;

using var client = new ModelVersionApiClient(mockClient);
var response = await client.GetModelVersion(full_name, version);

var responseJson = JsonSerializer.Serialize(response, Options);
AssertJsonDeepEquals(expectedResponse, responseJson);
}

[TestMethod]
public async Task GetModelVersionByAliasTest()
{
var full_name = "main.default.revenue_forecasting_model";
var alias = "champion";
var requestUri = $"{BaseApiUri}models/{full_name}/aliases/{alias}";


var expectedResponse = @"
{
""model_name"": ""revenue_forecasting_model"",
""catalog_name"": ""main"",
""schema_name"": ""default"",
""comment"": ""This model version forecasts future revenue, given historical data"",
""source"": ""dbfs:/databricks/mlflow-tracking/1234567890/abcdef/artifacts/model"",
""run_id"": ""abcdef"",
""run_workspace_id"": 6051234418418567,
""version"": 1,
""status"": ""PENDING_REGISTRATION"",
""id"": ""01234567-89ab-cdef-0123-456789abcdef"",
""metastore_id"": ""11111111-1111-1111-1111-111111111111"",
""created_at"": 1666369196203,
""created_by"": ""[email protected]"",
""updated_at"": 1666369196203,
""updated_by"": ""[email protected]"",
""storage_location"": ""s3://my-bucket/hello/world/models/2222-2222/versions/01234567-89ab-cdef-0123-456789abcdef"",
""aliases"": [
{
""alias_name"": ""champion"",
""version_num"": 1
}
]
}
";

var handler = CreateMockHandler();
handler
.SetupRequest(HttpMethod.Get, requestUri)
.ReturnsResponse(HttpStatusCode.OK, expectedResponse, "application/json");


var mockClient = handler.CreateClient();
mockClient.BaseAddress = ApiClientTest.BaseApiUri;

using var client = new ModelVersionApiClient(mockClient);

var response = await client.GetModelVersionByAlias(full_name, alias);
var responseJson = JsonSerializer.Serialize(response, Options);
AssertJsonDeepEquals(expectedResponse, responseJson);
}
}
Loading