Java调用Python模型案例

wen java案例 2

本文目录导读:

Java调用Python模型案例

  1. 使用ProcessBuilder调用Python脚本(最简单方式)
  2. 使用Jython(适合简单场景)
  3. 使用Socket通信(推荐用于生产环境)
  4. 使用PMML(预测模型标记语言)
  5. 完整项目示例(使用REST API)
  6. 依赖配置(Maven pom.xml)
  7. 最佳实践建议

我来为您提供一个完整的Java调用Python模型的案例,这里我展示几种常见的调用方式:

使用ProcessBuilder调用Python脚本(最简单方式)

Python端(model.py)

import json
import sys
import pickle
import numpy as np
# 简单示例模型
class SimpleModel:
    def __init__(self):
        # 模拟训练好的模型
        self.weights = np.array([0.5, -0.3, 0.8])
        self.bias = 0.1
    def predict(self, features):
        return np.dot(features, self.weights) + self.bias
# 加载模型
model = SimpleModel()
def predict_from_json(json_str):
    """从JSON字符串预测"""
    data = json.loads(json_str)
    features = np.array(data['features'])
    # 进行预测
    result = model.predict(features)
    # 返回结果
    output = {
        'prediction': float(result),
        'status': 'success'
    }
    return json.dumps(output)
if __name__ == '__main__':
    # 读取stdin输入
    input_data = sys.stdin.read()
    result = predict_from_json(input_data)
    print(result)
    sys.stdout.flush()

Java端(ModelCaller.java)

import java.io.*;
import java.nio.charset.StandardCharsets;
public class ModelCaller {
    public static String callPythonModel(double[] features, String pythonPath, String scriptPath) {
        try {
            // 构建JSON输入
            StringBuilder jsonInput = new StringBuilder();
            jsonInput.append("{\"features\":[");
            for (int i = 0; i < features.length; i++) {
                jsonInput.append(features[i]);
                if (i < features.length - 1) {
                    jsonInput.append(",");
                }
            }
            jsonInput.append("]}");
            // 构建命令
            ProcessBuilder pb = new ProcessBuilder(
                pythonPath,      // Python解释器路径 ("python" 或 "python3")
                scriptPath,      // Python脚本路径
                jsonInput.toString()  // 参数
            );
            // 设置工作目录(可选)
            pb.directory(new File("/path/to/script/directory"));
            // 启动进程
            Process process = pb.start();
            // 读取输出
            BufferedReader reader = new BufferedReader(
                new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8)
            );
            StringBuilder output = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                output.append(line);
            }
            // 读取错误输出
            BufferedReader errorReader = new BufferedReader(
                new InputStreamReader(process.getErrorStream(), StandardCharsets.UTF_8)
            );
            StringBuilder errorOutput = new StringBuilder();
            while ((line = errorReader.readLine()) != null) {
                errorOutput.append(line);
            }
            // 等待进程结束
            int exitCode = process.waitFor();
            if (exitCode != 0) {
                throw new RuntimeException("Python脚本执行失败: " + errorOutput.toString());
            }
            return output.toString();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("调用Python模型失败: " + e.getMessage());
        }
    }
    public static void main(String[] args) {
        // 测试预测
        double[] features = {1.5, 2.5, 3.5};
        String pythonPath = "python3";
        String scriptPath = "/path/to/model.py";
        try {
            String result = callPythonModel(features, pythonPath, scriptPath);
            System.out.println("预测结果: " + result);
        } catch (Exception e) {
            System.err.println("错误: " + e.getMessage());
        }
    }
}

使用Jython(适合简单场景)

import org.python.util.PythonInterpreter;
import org.python.core.*;
public class JythonExample {
    public static void main(String[] args) {
        try (PythonInterpreter pyInterp = new PythonInterpreter()) {
            // 设置Python路径
            pyInterp.exec("import sys");
            pyInterp.exec("sys.path.append('/path/to/python/scripts')");
            // 执行Python代码
            pyInterp.exec("import pickle");
            pyInterp.exec("import numpy as np");
            // 加载模型
            pyInterp.exec(
                "with open('/path/to/model.pkl', 'rb') as f:\n" +
                "    model = pickle.load(f)\n"
            );
            // 进行预测
            pyInterp.set("features", new PyList(new PyObject[]{
                new PyFloat(1.5),
                new PyFloat(2.5),
                new PyFloat(3.5)
            }));
            pyInterp.exec("prediction = model.predict(features)");
            // 获取结果
            double result = pyInterp.get("prediction", Double.class);
            System.out.println("预测结果: " + result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

使用Socket通信(推荐用于生产环境)

Python服务端(server.py)

import socket
import json
import numpy as np
class ModelServer:
    def __init__(self, host='localhost', port=5000):
        self.host = host
        self.port = port
        self.model = None
    def load_model(self):
        # 加载你的模型
        self.model = np.random.rand(3, 3)  # 示例模型
    def predict(self, features):
        # 进行预测
        return float(np.mean(features))
    def start(self):
        self.load_model()
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.bind((self.host, self.port))
            s.listen()
            print(f"模型服务启动于 {self.host}:{self.port}")
            while True:
                conn, addr = s.accept()
                with conn:
                    data = conn.recv(1024)
                    if data:
                        # 解析请求
                        request = json.loads(data.decode())
                        # 进行预测
                        features = np.array(request['features'])
                        result = self.predict(features)
                        # 发送响应
                        response = json.dumps({'prediction': result})
                        conn.sendall(response.encode())
if __name__ == '__main__':
    server = ModelServer()
    server.start()

Java客户端(SocketClient.java)

import java.io.*;
import java.net.Socket;
public class SocketClient {
    public static double predict(double[] features) {
        try (Socket socket = new Socket("localhost", 5000)) {
            // 构建请求
            StringBuilder jsonRequest = new StringBuilder();
            jsonRequest.append("{\"features\":[");
            for (int i = 0; i < features.length; i++) {
                jsonRequest.append(features[i]);
                if (i < features.length - 1) {
                    jsonRequest.append(",");
                }
            }
            jsonRequest.append("]}");
            // 发送请求
            OutputStream output = socket.getOutputStream();
            output.write(jsonRequest.toString().getBytes("UTF-8"));
            output.flush();
            // 接收响应
            InputStream input = socket.getInputStream();
            BufferedReader reader = new BufferedReader(
                new InputStreamReader(input, "UTF-8")
            );
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            // 解析响应(简单解析,实际可以使用JSON库)
            String responseStr = response.toString();
            int start = responseStr.indexOf("\"prediction\":") + 13;
            int end = responseStr.indexOf("}", start);
            String predStr = responseStr.substring(start, end).trim();
            return Double.parseDouble(predStr);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("通信失败: " + e.getMessage());
        }
    }
    public static void main(String[] args) {
        double[] features = {1.5, 2.5, 3.5};
        double result = predict(features);
        System.out.println("预测结果: " + result);
    }
}

使用PMML(预测模型标记语言)

<!-- 模型文件 model.pmml -->
<?xml version="1.0" encoding="UTF-8"?>
<PMML version="4.3" xmlns="http://www.dmg.org/PMML-4_3">
    <Header description="Simple Linear Regression"/>
    <DataDictionary numberOfFields="4">
        <DataField name="x1" optype="continuous" dataType="double"/>
        <DataField name="x2" optype="continuous" dataType="double"/>
        <DataField name="x3" optype="continuous" dataType="double"/>
        <DataField name="y" optype="continuous" dataType="double"/>
    </DataDictionary>
    <RegressionModel functionName="regression">
        <MiningSchema>
            <MiningField name="x1"/>
            <MiningField name="x2"/>
            <MiningField name="x3"/>
            <MiningField name="y" usageType="target"/>
        </MiningSchema>
        <RegressionTable intercept="0.1">
            <NumericPredictor name="x1" coefficient="0.5"/>
            <NumericPredictor name="x2" coefficient="-0.3"/>
            <NumericPredictor name="x3" coefficient="0.8"/>
        </RegressionTable>
    </RegressionModel>
</PMML>
// 使用JPMML库
import org.jpmml.evaluator.*;
import org.jpmml.model.*;
import java.io.*;
import java.util.*;
public class PMMLExample {
    public static void main(String[] args) throws Exception {
        // 加载PMML模型
        File pmmlFile = new File("/path/to/model.pmml");
        org.dmg.pmml.PMML pmml = org.jpmml.model.PMMLUtil.unmarshal(
            new FileInputStream(pmmlFile)
        );
        ModelEvaluator<?> evaluator = new RegressionModelEvaluator(pmml);
        evaluator.verify();
        // 准备输入数据
        Map<String, Object> input = new HashMap<>();
        input.put("x1", 1.5);
        input.put("x2", 2.5);
        input.put("x3", 3.5);
        // 预测
        Map<String, ?> results = evaluator.evaluate(input);
        // 获取结果
        Double prediction = (Double) results.get("y");
        System.out.println("预测结果: " + prediction);
    }
}

完整项目示例(使用REST API)

Python Flask服务(app.py)

from flask import Flask, request, jsonify
import numpy as np
import pickle
app = Flask(__name__)
# 加载模型
with open('/path/to/model.pkl', 'rb') as f:
    model = pickle.load(f)
@app.route('/predict', methods=['POST'])
def predict():
    try:
        data = request.get_json()
        features = np.array(data['features'])
        # 数据预处理
        features = features.reshape(1, -1)
        # 预测
        prediction = model.predict(features)[0]
        return jsonify({
            'success': True,
            'prediction': float(prediction),
            'timestamp': datetime.now().isoformat()
        })
    except Exception as e:
        return jsonify({
            'success': False,
            'error': str(e)
        }), 400
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Java调用代码

import java.net.http.*;
import java.net.URI;
import com.fasterxml.jackson.databind.*;
public class RESTClient {
    public static double predict(double[] features) {
        try {
            // 构建JSON请求体
            ObjectMapper mapper = new ObjectMapper();
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("features", features);
            // 创建请求
            HttpClient client = HttpClient.newHttpClient();
            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("http://localhost:5000/predict"))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(
                    mapper.writeValueAsString(requestBody)
                ))
                .build();
            // 发送请求并获取响应
            HttpResponse<String> response = client.send(
                request, HttpResponse.BodyHandlers.ofString()
            );
            // 解析响应
            JsonNode jsonNode = mapper.readTree(response.body());
            if (jsonNode.get("success").asBoolean()) {
                return jsonNode.get("prediction").asDouble();
            } else {
                throw new RuntimeException("预测失败: " + jsonNode.get("error"));
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("调用失败: " + e.getMessage());
        }
    }
    public static void main(String[] args) {
        double[] features = {1.5, 2.5, 3.5};
        double result = predict(features);
        System.out.println("预测结果: " + result);
    }
}

依赖配置(Maven pom.xml)

<dependencies>
    <!-- JSON解析 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.15.2</version>
    </dependency>
    <!-- Thymeleaf模板(可选) -->
    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf</artifactId>
        <version>3.1.1.RELEASE</version>
    </dependency>
    <!-- HTTP客户端支持(Java 11+) -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.14</version>
    </dependency>
    <!-- Jython集成(可选) -->
    <dependency>
        <groupId>org.python</groupId>
        <artifactId>jython-standalone</artifactId>
        <version>2.7.3</version>
    </dependency>
</dependencies>

最佳实践建议

  1. 性能优化

    • 使用连接池复用HTTP连接
    • 批量预测以减少调用次数
    • 缓存模型预测结果
  2. 错误处理

    • 实现重试机制
    • 设置超时时间
    • 优雅降级策略
  3. 安全性

    • 验证输入数据
    • 对敏感数据进行加密
    • 实施访问控制
  4. 监控

    • 记录调用日志
    • 监控预测延迟
    • 统计成功/失败率

选择哪种方案取决于你的具体需求:

  • 简单场景:ProcessBuilder
  • 生产环境:REST API/Docker
  • 高性能:Socket通信
  • 跨语言兼容:PMML标准

如有特殊需求或需要更多细节,请告诉我!

抱歉,评论功能暂时关闭!