# MLflow Java Client

Java client for [MLflow](https://mlflow.org) REST API.
See also the MLflow [Python API](https://mlflow.org/docs/latest/python_api/index.html)
and [REST API](https://mlflow.org/docs/latest/rest_api.html).

## Requirements

* Java 1.8
* Maven
* Run the [MLflow Tracking Server 0.4.2](https://mlflow.org/docs/latest/tracking.html#running-a-tracking-server)

## Build

### Build with tests

The MLflow Java client tests require that MLflow is on the PATH (to start a local server),
so it is recommended to run them from within a development conda environment.

To build a deployable JAR and run tests:

```
mvn package
```

## Run

To run a simple sample.
```
java -cp target/mlflow-java-client-0.4.2.jar \
  com.databricks.mlflow.client.samples.QuickStartDriver http://localhost:5001
```

## JSON Serialization

MLflow Java client uses [Protobuf](https://developers.google.com/protocol-buffers/) 3.6.0 to serialize the JSON payload.
* [service.proto](../mlflow/protos/service.proto) - Protobuf definition of data objects.
* [com.databricks.api.proto.mlflow.Service.java](src/main/java/com/databricks/api/proto/mlflow/Service.java) - Generated Java classes of all data objects.
* [generate-protos.sh](generate-protos.sh) - One time script to generate Service.java. If service.proto changes you will need to re-run this script.
* Javadoc can be generated by running ``mvn javadoc:javadoc``. The output will be in [target/site/apidocs/index.html](target/site/apidocs/index.html). 
Here is the javadoc for [Service.java](target/site/apidocs/com/databricks/api/proto/mlflow/Service.html).

## Java Client API

See [ApiClient.java](src/main/java/org/mlflow/client/ApiClient.java) 
and [Service.java domain objects](src/main/java/org/mlflow/api/proto/mlflow/Service.java).

```
Run getRun(String runUuid)
RunInfo createRun()
RunInfo createRun(long experimentId)
RunInfo createRun(long experimentId, String appName)
RunInfo createRun(CreateRun request)
List<RunInfo> listRunInfos(long experimentId)


List<Experiment> listExperiments()
GetExperiment.Response getExperiment(long experimentId)
Optional<Experiment> getExperimentByName(String experimentName)
long createExperiment(String experimentName)

void logParam(String runUuid, String key, String value)
void logMetric(String runUuid, String key, float value)
void setTerminated(String runUuid)
void setTerminated(String runUuid, RunStatus status)
void setTerminated(String runUuid, RunStatus status, long endTime)
ListArtifacts.Response listArtifacts(String runUuid, String path)
```

## Usage

### Java Usage

For a simple example see [QuickStartDriver.java](src/main/java/org/mlflow/client/samples/QuickStartDriver.java).
For full examples of API coverage see the [tests](src/test/java/org/mlflow/client) such as [ApiClientTest.java](src/test/java/org/mlflow/client/ApiClientTest.java).

```
package org.mlflow.tracking.samples;

import java.util.List;
import java.util.Optional;

import org.apache.log4j.Level;
import org.apache.log4j.LogManager;

import org.mlflow.api.proto.Service.*;
import org.mlflow.tracking.MlflowClient;

/**
 * This is an example application which uses the MLflow Tracking API to create and manage
 * experiments and runs.
 */
public class QuickStartDriver {
  public static void main(String[] args) throws Exception {
    (new QuickStartDriver()).process(args);
  }

  void process(String[] args) throws Exception {
    MlflowClient client;
    if (args.length < 1) {
      client = new MlflowClient();
    } else {
      client = new MlflowClient(args[0]);
    }

    boolean verbose = args.length >= 2 && "true".equals(args[1]);
    if (verbose) {
      LogManager.getLogger("org.mlflow.client").setLevel(Level.DEBUG);
    }

    System.out.println("====== createExperiment");
    String expName = "Exp_" + System.currentTimeMillis();
    long expId = client.createExperiment(expName);
    System.out.println("createExperiment: expId=" + expId);

    System.out.println("====== getExperiment");
    GetExperiment.Response exp = client.getExperiment(expId);
    System.out.println("getExperiment: " + exp);

    System.out.println("====== listExperiments");
    List<Experiment> exps = client.listExperiments();
    System.out.println("#experiments: " + exps.size());
    exps.forEach(e -> System.out.println("  Exp: " + e));

    createRun(client, expId);

    System.out.println("====== getExperiment again");
    GetExperiment.Response exp2 = client.getExperiment(expId);
    System.out.println("getExperiment: " + exp2);

    System.out.println("====== getExperiment by name");
    Optional<Experiment> exp3 = client.getExperimentByName(expName);
    System.out.println("getExperimentByName: " + exp3);
  }

  void createRun(MlflowClient client, long expId) {
    System.out.println("====== createRun");

    // Create run
    String sourceFile = "MyFile.java";
    RunInfo runCreated = client.createRun(expId, sourceFile);
    System.out.println("CreateRun: " + runCreated);
    String runId = runCreated.getRunUuid();

    // Log parameters
    client.logParam(runId, "min_samples_leaf", "2");
    client.logParam(runId, "max_depth", "3");

    // Log metrics
    client.logMetric(runId, "auc", 2.12F);
    client.logMetric(runId, "accuracy_score", 3.12F);
    client.logMetric(runId, "zero_one_loss", 4.12F);

    // Update finished run
    client.setTerminated(runId, RunStatus.FINISHED);

    // Get run details
    Run run = client.getRun(runId);
    System.out.println("GetRun: " + run);
  }
}
```
