Awesome
JPMML-Transpiler
Java Transpiler (Translator + Compiler) API for Predictive Model Markup Language (PMML).
Table of Contents
Features
JPMML-Transpiler is a value add-on library to the JPMML-Evaluator library platform.
JPMML-Transpiler traverses an org.dmg.pmml.PMML
class model object, and "transpiles" dummy XML-backed objects into smart and optimized Java-backed objects for speedier execution:
- Expressions become
org.jpmml.evaluator.JavaExpression
subclasses. - Models become
org.jpmml.evaluator.java.JavaModel
subclasses. - Predicates become
org.jpmml.evaluator.JavaPredicate
subclasses.
Prerequisites
- JPMML-Evaluator 1.6.4 or newer.
Installation
Release versions
The current release version is 1.3.7 (13 October, 2024):
JPMML-Transpiler library JAR files (together with accompanying Java source and Javadocs JAR files) are released via Maven Central Repository.
<dependency>
<groupId>org.jpmml</groupId>
<artifactId>pmml-transpiler</artifactId>
<version>1.3.7</version>
</dependency>
JPMML-Transpiler executable uber-JAR files are released via GitHub.
Snapshot versions
Clone the project. Enter the project root directory and build using Apache Maven:
$ git clone https://github.com/jpmml/jpmml-transpiler.git
$ cd jpmml-transpiler
$ mvn clean install
The build produces two files:
pmml-transpiler/target/pmml-transpiler-1.3-SNAPSHOT.jar
- the library JAR file.pmml-transpiler-example/target/pmml-transpiler-example-executable-1.3-SNAPSHOT.jar
- the executable uber-JAR file (the library JAR file plus all its transitive dependencies).
Usage
TL;DR
Building a model evaluator from a PMML file using the org.jpmml.evaluator.LoadingModelEvaluatorBuilder
builder class.
The transpilation is attempted by invoking the LoadingModelEvaluatorBuilder#transform(PMMLTransformer)
method (between the load and build stages) with a properly configured org.jpmml.transpiler.TranspilerTransformer
argument:
import org.jpmml.evaluator.Evaluator;
import org.jpmml.evaluator.LoadingModelEvaluatorBuilder;
import org.jpmml.transpiler.FileTranspiler
//import org.jpmml.transpiler.InMemoryTranspiler
import org.jpmml.transpiler.Transpiler
import org.jpmml.transpiler.TranspilerTransformer
File pmmlFile = ...;
LoadingModelEvaluatorBuilder evaluatorBuilder = new LoadingModelEvaluatorBuilder()
.load(pmmlFile);
try {
Transpiler transpiler = new FileTranspiler("com.mycompany.MyModel", new File(pmmlFile.getAbsolutePath() + ".jar"));
//Transpiler transpiler = new InMemoryTranspiler("com.mycompany.MyModel");
evaluatorBuilder = evaluatorBuilder.transform(new TranspilerTransformer(transpiler));
} catch(IOException ioe){
ioe.printStackTrace(System.err);
//throw ioe;
}
Evaluator evaluator = evaluatorBuilder.build();
The internal state of the model evaluator builder is only updated if the transpilation succeeds.
Deep dive
Transpiling an XML-backed org.dmg.pmml.PMML
object to an com.sun.codemodel.JCodeModel
object:
import com.sun.codemodel.JCodeModel;
import org.jpmml.model.PMMLUtil;
import org.jpmml.transpiler.TranspilerUtil;
PMML xmlPmml;
try(InputStream is = ...){
xmlPmml = PMMLUtil.unmarshal(is);
}
// Generate Java source
// Set the fully-qualified name of the generated PMML subclass to `com.mycompany.MyModel`
JCodeModel codeModel = TranspilerUtil.translate(xmlPmml, "com.mycompany.MyModel");
// Compile Java source to Java bytecode
TranspilerUtil.compile(codeModel);
Storing the JCodeModel
object to a PMML service provider Java archive:
File jarFile = new File(...);
try(OutputStream os = new FileOutputStream(jarFile)){
TranspilerUtil.archive(codeModel, os);
}
A PMML service provider Java archive is a Java ARchive (JAR) file that contains all transpilation results (Java source and bytecode files), plus a /META-INF/services/org.dmg.pmml.PMML
service provider configuration file.
Such Java archives can be regarded as "model plug-ins" to a Java application.
Creating a java.net.URLClassLoader
object to interact with the contents of a PMML service provider Java archive in a local filesystem:
import java.net.URL;
import java.net.URLClassLoader;
File jarFile = ...;
URL[] classpath = {
(jarFile.toURI()).toURL()
};
try(URLClassLoader clazzLoader = new URLClassLoader(classpath)){
// Load and instantiate generated PMML subclass(es)
}
The generated PMML
subclass can always be loaded and instantiated using Java's service-provider loading facility.
If the classpath contains exactly one PMML service provider Java archive, then it's possible to use the org.jpmml.model.PMMLUtil#load(ClassLoader)
utility method:
import org.dmg.pmml.PMML;
import org.jpmml.model.PMMLUtil;
PMML javaPmml = PMMLUtil.load(clazzLoader);
If the classpath contains more than one PMML service provider Java archives, then it becomes necessary to fall back to Java's standard APIs:
import java.util.ServiceLoader;
import org.dmg.pmml.PMML;
ServiceLoader<PMML> pmmlServiceLoader = ServiceLoader.load(PMML.class, clazzLoader);
for(Iterator<PMML> pmmlIt = pmmlServiceLoader.iterator(); pmmlIt.hasNext(); ){
PMML javaPmml = pmmlIt.next();
}
Alternatively, if the fully qualified name of the generated PMML
subclass is known, then it's possible to load and instantiate it manually:
Class<?> clazz = clazzLoader.loadClass("com.mycompany.MyModel");
Class<? extends PMML> pmmlClazz = clazz.asSubclass(PMML.class);
PMML javaPmml = pmmlClazz.newInstance();
The Java-backed PMML
object is at its peak performance right from the start. There is no need to apply any optimizers or interners to it. The only noteworthy downside of the Java-backed object compared to the XML-backed object is the lack of SAX Locator information, which makes pinpointing evaluation exceptions to exact model source code location more difficult.
Building a model evaluator from a Java-backed PMML
object:
import org.jpmml.evaluator.ModelEvaluatorBuilder;
Evaluator evaluator = new ModelEvaluatorBuilder(javaPmml)
.build();
Building a model evaluator from a PMML service provider Java archive:
import org.jpmml.evaluator.ServiceLoadingModelEvaluatorBuilder;
File jarFile = ...;
Evaluator evaluator = new ServiceLoadingModelEvaluatorBuilder()
.loadService((jarFile.toURI()).toURL())
.build();
Java-backed model evaluators are functionally equivalent to XML-backed model evaluators.
Benchmarking
See benchmarking.md
Support
Limited public support is available via the JPMML mailing list.
License
JPMML-Transpiler is licensed under the terms and conditions of the GNU Affero General Public License, Version 3.0. For a quick summary of your rights ("Can") and obligations ("Cannot" and "Must") under AGPLv3, please refer to TLDRLegal.
If you would like to use JPMML-Transpiler in a proprietary software project, then it is possible to enter into a licensing agreement which makes JPMML-Transpiler available under the terms and conditions of the BSD 3-Clause License instead.
Additional information
JPMML-Transpiler is developed and maintained by Openscoring Ltd, Estonia.
Interested in using Java PMML API software in your company? Please contact info@openscoring.io