Skip to content

Commit 6a96cf1

Browse files
committed
Some fixes on experiments. Adding the run service and misc additions
1 parent dd904fa commit 6a96cf1

File tree

12 files changed

+154
-225
lines changed

12 files changed

+154
-225
lines changed

src/MLFlowClient.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,9 @@ export
6060
restoreexperiment,
6161
searchexperiments,
6262
getexperimentbyname
63+
64+
include("services/run.jl")
65+
export
66+
createrun
67+
6368
end

src/deprecated.jl

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/services/experiment.jl

Lines changed: 46 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
createexperiment(instance::MLFlow; name::String="",
2+
createexperiment(instance::MLFlow, name::String;
33
artifact_location::String="",
44
tags::Union{Dict{<:Any}, Array{<:Any}}=[])
55
@@ -18,13 +18,9 @@ default.
1818
# Returns
1919
The ID of the newly created experiment.
2020
"""
21-
function createexperiment(instance::MLFlow; name::String="",
22-
artifact_location::String="",
21+
function createexperiment(instance::MLFlow, name::String;
22+
artifact_location::Union{String, Missing}=missing,
2323
tags::Union{Dict{<:Any}, Array{<:Any}}=[])::String
24-
if name |> isempty
25-
name = UUIDs.uuid4() |> string
26-
end
27-
2824
tags = tags |> parsetags
2925

3026
try
@@ -100,26 +96,26 @@ function getexperimentbyname(instance::MLFlow, experiment_name::String)
10096
end
10197

10298
"""
103-
deleteexperiment(mlf::MLFlow, experiment_id::String)
104-
deleteexperiment(mlf::MLFlow, experiment_id::Integer)
105-
deleteexperiment(mlf::MLFlow, experiment::Experiment)
99+
deleteexperiment(instance::MLFlow, experiment_id::String)
100+
deleteexperiment(instance::MLFlow, experiment_id::Integer)
101+
deleteexperiment(instance::MLFlow, experiment::Experiment)
106102
107103
Mark an experiment and associated metadata, runs, metrics, params, and tags for
108104
deletion. If the experiment uses FileStore, artifacts associated with
109105
experiment are also deleted.
110106
111107
# Arguments
112-
- `mlf`: [`MLFlow`](@ref) configuration.
108+
- `instance`: [`MLFlow`](@ref) configuration.
113109
- `experiment_id`: ID of the associated experiment.
114110
115111
# Returns
116112
117113
`true` if successful. Otherwise, raises exception.
118114
"""
119-
function deleteexperiment(mlf::MLFlow, experiment_id::String)
115+
function deleteexperiment(instance::MLFlow, experiment_id::String)
120116
endpoint = "experiments/delete"
121117
try
122-
mlfpost(mlf, endpoint; experiment_id=experiment_id)
118+
mlfpost(instance, endpoint; experiment_id=experiment_id)
123119
return true
124120
catch e
125121
if isa(e, HTTP.ExceptionRequest.StatusError) && e.status == 404
@@ -129,32 +125,32 @@ function deleteexperiment(mlf::MLFlow, experiment_id::String)
129125
throw(e)
130126
end
131127
end
132-
deleteexperiment(mlf::MLFlow, experiment_id::Integer) =
133-
deleteexperiment(mlf, string(experiment_id))
134-
deleteexperiment(mlf::MLFlow, experiment::Experiment) =
135-
deleteexperiment(mlf, experiment.experiment_id)
128+
deleteexperiment(instance::MLFlow, experiment_id::Integer) =
129+
deleteexperiment(instance, string(experiment_id))
130+
deleteexperiment(instance::MLFlow, experiment::Experiment) =
131+
deleteexperiment(instance, experiment.experiment_id)
136132

137133
"""
138-
restoreexperiment(mlf::MLFlow, experiment_id::String)
139-
restoreexperiment(mlf::MLFlow, experiment_id::Integer)
140-
restoreexperiment(mlf::MLFlow, experiment::Experiment)
134+
restoreexperiment(instance::MLFlow, experiment_id::String)
135+
restoreexperiment(instance::MLFlow, experiment_id::Integer)
136+
restoreexperiment(instance::MLFlow, experiment::Experiment)
141137
142138
Restore an experiment marked for deletion. This also restores associated
143139
metadata, runs, metrics, params, and tags. If experiment uses FileStore,
144140
underlying artifacts associated with experiment are also restored.
145141
146142
# Arguments
147-
- `mlf`: [`MLFlow`](@ref) configuration.
143+
- `instance`: [`MLFlow`](@ref) configuration.
148144
- `experiment_id`: ID of the associated experiment.
149145
150146
# Returns
151147
152148
`true` if successful. Otherwise, raises exception.
153149
"""
154-
function restoreexperiment(mlf::MLFlow, experiment_id::String)
150+
function restoreexperiment(instance::MLFlow, experiment_id::String)
155151
endpoint = "experiments/restore"
156152
try
157-
mlfpost(mlf, endpoint; experiment_id=experiment_id)
153+
mlfpost(instance, endpoint; experiment_id=experiment_id)
158154
return true
159155
catch e
160156
if isa(e, HTTP.ExceptionRequest.StatusError) && e.status == 404
@@ -166,48 +162,51 @@ function restoreexperiment(mlf::MLFlow, experiment_id::String)
166162
throw(e)
167163
end
168164
end
169-
restoreexperiment(mlf::MLFlow, experiment_id::Integer) =
170-
deleteexperiment(mlf, string(experiment_id))
171-
restoreexperiment(mlf::MLFlow, experiment::Experiment) =
172-
deleteexperiment(mlf, experiment.experiment_id)
165+
restoreexperiment(instance::MLFlow, experiment_id::Integer) =
166+
deleteexperiment(instance, string(experiment_id))
167+
restoreexperiment(instance::MLFlow, experiment::Experiment) =
168+
deleteexperiment(instance, experiment.experiment_id)
173169

174170
"""
175-
updateexperiment(mlf::MLFlow, experiment_id::String, new_name::String)
176-
updateexperiment(mlf::MLFlow, experiment_id::Integer, new_name::String)
177-
updateexperiment(mlf::MLFlow, experiment::Experiment, new_name::String)
171+
updateexperiment(instance::MLFlow, experiment_id::String, new_name::String)
172+
updateexperiment(instance::MLFlow, experiment_id::Integer,
173+
new_name::String)
174+
updateexperiment(instance::MLFlow, experiment::Experiment,
175+
new_name::String)
178176
179177
Update experiment metadata.
180178
181179
# Arguments
182-
- `mlf`: [`MLFlow`](@ref) configuration.
180+
- `instance`: [`MLFlow`](@ref) configuration.
183181
- `experiment_id`: ID of the associated experiment.
184182
- `new_name`: If provided, the experiment’s name is changed to the new name.
185183
The new name must be unique.
186184
187185
# Returns
188186
`true` if successful. Otherwise, raises exception.
189187
"""
190-
function updateexperiment(mlf::MLFlow, experiment_id::String, new_name::String)
188+
function updateexperiment(instance::MLFlow, experiment_id::String,
189+
new_name::String)
191190
endpoint = "experiments/update"
192191
try
193-
mlfpost(mlf, endpoint; experiment_id=experiment_id, new_name=new_name)
192+
mlfpost(instance, endpoint; experiment_id=experiment_id, new_name=new_name)
194193
return true
195194
catch e
196195
throw(e)
197196
end
198197
end
199-
updateexperiment(mlf::MLFlow, experiment_id::Integer, new_name::String) =
200-
updateexperiment(mlf, string(experiment_id), new_name)
201-
updateexperiment(mlf::MLFlow, experiment::Experiment, new_name::String) =
202-
updateexperiment(mlf, experiment.experiment_id, new_name::String)
198+
updateexperiment(instance::MLFlow, experiment_id::Integer, new_name::String) =
199+
updateexperiment(instance, string(experiment_id), new_name)
200+
updateexperiment(instance::MLFlow, experiment::Experiment, new_name::String) =
201+
updateexperiment(instance, experiment.experiment_id, new_name::String)
203202

204203
"""
205-
searchexperiments(mlf::MLFlow; max_results::Integer=20000,
204+
searchexperiments(instance::MLFlow; max_results::Integer=20000,
206205
page_token::String="", filter::String="", order_by::Array{String}=[],
207206
view_type::ViewType=ACTIVE_ONLY)
208207
209208
# Arguments
210-
- `mlf`: [`MLFlow`](@ref) configuration.
209+
- `instance`: [`MLFlow`](@ref) configuration.
211210
- `max_results`: Maximum number of experiments desired.
212211
- `page_token`: Token indicating the page of experiments to fetch.
213212
- `filter`: A filter expression over experiment attributes and tags that allows
@@ -221,9 +220,9 @@ unspecified, return only active experiments.
221220
# Returns
222221
- vector of [`MLFlowExperiment`](@ref) experiments that were found in the MLFlow instance
223222
"""
224-
function searchexperiments(mlf::MLFlow; max_results::Integer=20000,
223+
function searchexperiments(instance::MLFlow; max_results::Integer=20000,
225224
page_token::String="", filter::String="", order_by::Array{String}=String[],
226-
view_type::ViewType=ACTIVE_ONLY)
225+
view_type::ViewType=ACTIVE_ONLY)::Tuple{Array{Experiment}, Union{String, Nothing}}
227226
endpoint = "experiments/search"
228227
parameters = (; max_results, page_token, filter,
229228
:view_type => view_type |> Integer)
@@ -233,8 +232,12 @@ function searchexperiments(mlf::MLFlow; max_results::Integer=20000,
233232
end
234233

235234
try
236-
result = mlfget(mlf, endpoint; parameters...)
237-
return result["experiments"] |> (x -> [Experiment(y) for y in x])
235+
result = mlfget(instance, endpoint; parameters...)
236+
237+
experiments = result["experiments"] |> (x -> [Experiment(y) for y in x])
238+
next_page_token = get(result, "next_page_token", nothing)
239+
240+
return experiments, next_page_token
238241
catch e
239242
throw(e)
240243
end

src/services/run.jl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""
2+
createrun(instance::MLFlow, experiment_id::String;
3+
run_name::Union{String, Missing}=missing,
4+
start_time::Union{Integer, Missing}=missing,
5+
tags::Union{Dict{<:Any}, Array{<:Any}}=[])
6+
7+
Create a new run within an experiment. A run is usually a single execution of a
8+
machine learning or data ETL pipeline.
9+
10+
# Arguments
11+
- `instance`: [`MLFlow`](@ref) configuration.
12+
- `experiment_id`: ID of the associated experiment.
13+
- `run_name`: Name of the run.
14+
- `start_time`: Unix timestamp in milliseconds of when the run started.
15+
- `tags`: Additional metadata for run.
16+
17+
# Returns
18+
An instance of type [`Run`](@ref).
19+
"""
20+
function createrun(instance::MLFlow, experiment_id::String;
21+
run_name::Union{String, Missing}=missing,
22+
start_time::Union{Integer, Missing}=missing,
23+
tags::Union{Dict{<:Any}, Array{<:Any}}=[])
24+
tags = tags |> parsetags
25+
26+
try
27+
result = mlfpost(instance, "runs/create"; experiment_id=experiment_id,
28+
run_name=run_name, start_time=start_time, tags=tags)
29+
return result["run"] |> Run
30+
catch e
31+
throw(e)
32+
end
33+
end

src/types/dataset.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@ struct Dataset
2424
schema::Union{String, Nothing}
2525
profile::Union{String, Nothing}
2626
end
27-
Dataset(name, digest, source_type, source; schema=nothing, profile=nothing) =
28-
Dataset(name, digest, source_type, source, schema, profile)
27+
Dataset(data::Dict{String, Any}) = Dataset(
28+
data["name"], data["digest"], data["source_type"], data["source"],
29+
get(data, "schema", nothing), get(data, "profile", nothing))
2930
Base.show(io::IO, t::Dataset) = show(io, ShowCase(t, new_lines=true))
3031

3132
"""
@@ -45,5 +46,7 @@ struct DatasetInput
4546
tags::Array{Tag}
4647
dataset::Dataset
4748
end
48-
DatasetInput(dataset; tags=[]) = DatasetInput(tags, dataset)
49+
DatasetInput(data::Dict{String, Any}) = DatasetInput(
50+
[Tag(tag) for tag in get(data, "tags", [])],
51+
Dataset(data["dataset"]))
4952
Base.show(io::IO, t::DatasetInput) = show(io, ShowCase(t, new_lines=true))

src/types/enums.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Status of a run.
3232
FAILED=4
3333
KILLED=5
3434
end
35+
RunStatus(status::String) = Dict(value => key for (key, value) in RunStatus |> Base.Enums.namemap)[status |> Symbol] |> RunStatus
3536

3637
"""
3738
ViewType

src/types/run.jl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,14 @@ struct RunInfo
5757
experiment_id::String
5858
status::RunStatus
5959
start_time::Int64
60-
end_time::Int64
60+
end_time::Union{Int64, Nothing}
6161
artifact_uri::String
6262
lifecycle_stage::String
6363
end
64+
RunInfo(data::Dict{String, Any}) = RunInfo(data["run_id"], data["run_name"],
65+
data["experiment_id"], RunStatus(data["status"]), data["start_time"],
66+
get(data, "end_time", nothing), data["artifact_uri"],
67+
data["lifecycle_stage"])
6468
Base.show(io::IO, t::RunInfo) = show(io, ShowCase(t, new_lines=true))
6569

6670
"""
@@ -78,6 +82,10 @@ struct RunData
7882
params::Array{Param}
7983
tags::Array{Tag}
8084
end
85+
RunData(data::Dict{String, Any}) = RunData(
86+
[Metric(metric) for metric in get(data, "metrics", [])],
87+
[Param(param) for param in get(data, "params", [])],
88+
[Tag(tag) for tag in get(data, "tags", [])])
8189
Base.show(io::IO, t::RunData) = show(io, ShowCase(t, new_lines=true))
8290

8391
"""
@@ -91,6 +99,9 @@ Run inputs.
9199
struct RunInputs
92100
dataset_inputs::Array{DatasetInput}
93101
end
102+
RunInputs(data::Dict{String, Any}) = RunInputs(
103+
[DatasetInput(dataset_input) for dataset_input in
104+
get(data, "dataset_inputs", [])])
94105
Base.show(io::IO, t::RunInputs) = show(io, ShowCase(t, new_lines=true))
95106

96107
"""
@@ -103,4 +114,6 @@ struct Run
103114
data::RunData
104115
inputs::RunInputs
105116
end
117+
Run(data::Dict{String, Any}) = Run(RunInfo(data["info"]),
118+
RunData(data["data"]), RunInputs(data["inputs"]))
106119
Base.show(io::IO, t::Run) = show(io, ShowCase(t, new_lines=true))

src/utils.jl

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,5 @@
11
IntOrString = Union{Int, String}
22

3-
"""
4-
generatefilterfromentity_type(filter_params::AbstractDict{K,V}, entity_type::String) where {K,V}
5-
6-
Generates a `filter` string from `filter_params` dictionary and `entity_type`.
7-
8-
# Arguments
9-
- `filter_params`: dictionary to use for filter generation.
10-
- `entity_type`: entity type to use for filter generation.
11-
12-
# Returns
13-
A string that can be passed as `filter` to [`searchruns`](@ref).
14-
15-
# Examples
16-
17-
```@example
18-
generatefilterfromentity_type(Dict("paramkey1" => "paramvalue1", "paramkey2" => "paramvalue2"), "param")
19-
```
20-
"""
21-
function generatefilterfromentity_type(filter_params::AbstractDict{K,V}, entity_type::String) where {K,V}
22-
length(filter_params) > 0 || return ""
23-
# NOTE: may have issues with escaping.
24-
filters = ["$(entity_type).\"$(k)\" = \"$(v)\"" for (k, v) filter_params]
25-
join(filters, " and ")
26-
end
27-
28-
"""
29-
generatefilterfromparams(filter_params::AbstractDict{K,V}) where {K,V}
30-
31-
Generates a `filter` string from `filter_params` dictionary and `param` entity type.
32-
"""
33-
generatefilterfromparams(filter_params::AbstractDict{K,V}) where {K,V} = generatefilterfromentity_type(filter_params, "param")
34-
"""
35-
generatefilterfrommattributes(filter_attributes::AbstractDict{K,V}) where {K,V}
36-
37-
Generates a `filter` string from `filter_attributes` dictionary and `attribute` entity type.
38-
"""
39-
generatefilterfromattributes(filter_attributes::AbstractDict{K,V}) where {K,V} = generatefilterfromentity_type(filter_attributes, "attribute")
40-
413
const MLFLOW_ERROR_CODES = (;
424
RESOURCE_ALREADY_EXISTS = "RESOURCE_ALREADY_EXISTS",
435
RESOURCE_DOES_NOT_EXIST = "RESOURCE_DOES_NOT_EXIST",

test/runtests.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ end
44

55
include("base.jl")
66

7-
include("services/experiments.jl")
7+
include("services/experiment.jl")
8+
include("services/run.jl")
89
# include("test_functional.jl")
9-
# include("test_experiments.jl")
1010
# include("test_runs.jl")
1111
# include("test_loggers.jl")

0 commit comments

Comments
 (0)