SpringBoot 整合Weka框架實戰(zhàn)操作指南
一、前言
在微服務(wù)開發(fā)中,經(jīng)常會遇到需要進行推薦的場景,比如在電商場景中,需要基于用戶的過往購買歷史,選品喜歡,軌跡等指標(biāo)信息進行選品推薦,再比如在社交應(yīng)用中,需要根據(jù)用戶的操作歷史、個人標(biāo)簽等推薦一些功能從而展示給用戶。盡管這樣的推薦操作可以結(jié)合一些大數(shù)據(jù)、機器學(xué)習(xí)等推薦算法來做,但是對一些小型的系統(tǒng)來說,考慮到對接成本、學(xué)習(xí)成本和維護成本等因素,本篇將詳細介紹下在微服務(wù)應(yīng)用中如何對接第三方的機器學(xué)習(xí)框架,從而實現(xiàn)特定場景下的業(yè)務(wù)推薦。
二、Java對接使用的機器學(xué)習(xí)技術(shù)方案
接下來介紹幾種適合Java開發(fā)語言模式下的機器學(xué)習(xí)框架技術(shù)方案。
2.1 Weka 介紹
Weka(Waikato Environment for Knowledge Analysis)是一款由新西蘭懷卡托大學(xué)開發(fā)的開源機器學(xué)習(xí)與數(shù)據(jù)挖掘軟件,以其易用性、豐富的算法庫和可視化界面聞名。它支持從數(shù)據(jù)預(yù)處理到模型評估的全流程,適合教學(xué)、研究和快速原型開發(fā)。官網(wǎng):https://ml.cms.waikato.ac.nz/weka/
Weka,是一款免費、非商業(yè)化、基于Java的開源的機器學(xué)習(xí)與數(shù)據(jù)挖掘軟件,并提供了maven依賴,擁有豐富的Java API。

Github 地址:Weka Wiki

2.1.1 Weka 主要特點
Weka 具備如下特點:
- 開源免費:基于GNU通用公共許可證,用戶可自由使用、修改和分發(fā)。
- 跨平臺支持:基于Java開發(fā),可在Windows、macOS、Linux等系統(tǒng)運行。
- 圖形用戶界面(GUI):提供直觀的可視化操作,無需編程即可完成數(shù)據(jù)挖掘任務(wù)。
- 命令行接口:支持通過腳本自動化處理大規(guī)模數(shù)據(jù)或批量任務(wù)。
- 豐富的算法庫:集成數(shù)百種機器學(xué)習(xí)算法,涵蓋分類、回歸、聚類、關(guān)聯(lián)規(guī)則挖掘等。
2.1.2 Weka 核心功能模塊
Weka通過不同界面模塊實現(xiàn)數(shù)據(jù)挖掘流程:
- Explorer:主界面,包含以下子面板:
- Preprocess:數(shù)據(jù)清洗、特征選擇、離散化、標(biāo)準(zhǔn)化等。
- Classify:分類算法(如決策樹、SVM、神經(jīng)網(wǎng)絡(luò))訓(xùn)練與評估。
- Cluster:聚類分析(如K-Means、DBSCAN)。
- Associate:關(guān)聯(lián)規(guī)則挖掘(如Apriori算法)。
- Select attributes:特征選擇與降維。
- Visualize:數(shù)據(jù)可視化(散點圖、箱線圖等)。
- Experimenter:設(shè)計對比實驗,評估不同算法性能。
- Knowledge Flow:通過拖拽組件構(gòu)建數(shù)據(jù)處理流程圖,支持復(fù)雜工作流。
- Simple CLI:命令行交互,適合快速測試或腳本調(diào)用。
2.1.3 Weka 支持的算法類型
Weka 支持如下算法類型
- 分類:決策樹(J48/C4.5)、隨機森林、樸素貝葉斯、SVM、邏輯回歸、神經(jīng)網(wǎng)絡(luò)等。
- 回歸:線性回歸、M5規(guī)則樹、支持向量回歸(SVR)。
- 聚類:K-Means、EM、DBSCAN、層次聚類。
- 關(guān)聯(lián)規(guī)則:Apriori、FP-Growth。
- 特征選擇:信息增益、卡方檢驗、ReliefF、主成分分析(PCA)。
2.1.4 Weka 應(yīng)用場景
Weka 在下面的一些場景中可以考慮選擇使用:
- 學(xué)術(shù)研究:算法驗證、教學(xué)演示(如機器學(xué)習(xí)課程實驗)。
- 快速原型開發(fā):測試不同算法對數(shù)據(jù)的適應(yīng)性。
- 小規(guī)模數(shù)據(jù)挖掘:適合處理GB級以下數(shù)據(jù)(大數(shù)據(jù)需結(jié)合Hadoop/Spark擴展)。
- 工業(yè)應(yīng)用:客戶分群、欺詐檢測、文本分類等(需結(jié)合業(yè)務(wù)邏輯優(yōu)化)。
2.2 Apache Spark MLlib 介紹
Apache Spark MLlib 是一個專為大規(guī)模數(shù)據(jù)處理設(shè)計的分布式機器學(xué)習(xí)庫,作為 Apache Spark 生態(tài)系統(tǒng)的核心組件,它通過利用 Spark 的分布式計算框架,能夠高效處理海量數(shù)據(jù),并加速模型的訓(xùn)練和預(yù)測過程。官網(wǎng):MLlib | Apache Spark

2.2.1 核心模塊介紹
MLlib 的架構(gòu)由多個核心模塊組成,協(xié)同工作以簡化大規(guī)模數(shù)據(jù)處理中的機器學(xué)習(xí)任務(wù)復(fù)雜性:
- 算法庫:提供豐富的監(jiān)督學(xué)習(xí)(如邏輯回歸、決策樹、隨機森林)和無監(jiān)督學(xué)習(xí)(如 K-Means 聚類、高斯混合模型)算法,支持分類、回歸、聚類、降維等任務(wù),并涵蓋推薦系統(tǒng)(如基于交替最小二乘法的協(xié)同過濾)和特征工程功能。
- 管道機制(Pipelines):通過串聯(lián)多個
Transformer(數(shù)據(jù)轉(zhuǎn)換組件,如標(biāo)準(zhǔn)化、歸一化)和Estimator(可訓(xùn)練模型,如邏輯回歸、決策樹),構(gòu)建模塊化的機器學(xué)習(xí)工作流,簡化任務(wù)流程并支持復(fù)用。 - 數(shù)據(jù)類型:基于 Spark 的核心數(shù)據(jù)結(jié)構(gòu)
RDD(彈性分布式數(shù)據(jù)集,提供容錯和并行計算能力)和DataFrame(類似 SQL 表的高層次數(shù)據(jù)類型,支持模式化數(shù)據(jù)結(jié)構(gòu)和 SQL 查詢),其中DataFrame是當(dāng)前主要支持的數(shù)據(jù)類型,能更好地與 Spark SQL 集成。
2.2.2 核心功能介紹
MLlib 核心功能如下:
- 算法支持:
- 分類:支持二分類和多分類任務(wù),如邏輯回歸、決策樹、隨機森林、樸素貝葉斯等。
- 回歸:支持線性回歸、嶺回歸、Lasso 回歸等,用于預(yù)測連續(xù)值。
- 聚類:如 K-Means、高斯混合模型等,用于發(fā)現(xiàn)數(shù)據(jù)中的模式和相似性。
- 推薦系統(tǒng):如基于交替最小二乘法的協(xié)同過濾算法,用于為用戶推薦商品或內(nèi)容。
- 降維:如主成分分析(PCA)、奇異值分解(SVD)等,用于降低數(shù)據(jù)維度。
- 特征處理:提供多種特征提取和轉(zhuǎn)換方法,如 TF-IDF、Word2Vec、PCA 等,將原始數(shù)據(jù)轉(zhuǎn)換為機器學(xué)習(xí)算法可處理的特征表示。
- 模型評估:提供豐富的評估指標(biāo)工具,支持不同類型模型的性能評估:
- 分類模型:精度、召回率、F1 值、ROC 曲線等。
- 回歸模型:均方誤差(MSE)、均方根誤差(RMSE)、平均絕對誤差(MAE)等。
- 聚類模型:輪廓系數(shù)、簇間距離等。
2.2.3 技術(shù)優(yōu)勢
MLlib 具備如下技術(shù)優(yōu)勢:
- 分布式計算能力:基于 Spark 的分布式計算框架,充分利用集群資源進行并行計算,大幅提升計算效率,尤其適合大規(guī)模數(shù)據(jù)集。
- 簡潔易用的 API:提供簡潔的 API 接口,支持 Scala、Java、Python 和 R 等多種編程語言,降低用戶使用門檻。
- 可擴展性:用戶可根據(jù)需求自定義算法和模型,并通過 Spark 的擴展機制將其集成到 MLlib 中。
- 與 Spark 生態(tài)無縫集成:與 Spark SQL、Spark Streaming 等組件無縫協(xié)作,支持復(fù)雜的數(shù)據(jù)處理和分析流程。
2.2.4 適用場景
在下面的一些場景中可以考慮使用MLlib :
- 分類任務(wù):如垃圾郵件檢測、情感分析、圖像識別等。
- 回歸任務(wù):如房價預(yù)測、股票價格預(yù)測等。
- 聚類任務(wù):如客戶分群、市場細分、圖像分割等。
- 推薦系統(tǒng):如電商平臺的個性化商品推薦、音視頻網(wǎng)站的內(nèi)容推薦等。
- 特征工程:如特征選擇、特征提取、數(shù)據(jù)標(biāo)準(zhǔn)化等
2.3 EasyRec 介紹
EasyRec 是阿里巴巴開源的推薦系統(tǒng)框架,基于 TensorFlow 和 PyTorch 構(gòu)建,提供模塊化設(shè)計、分布式訓(xùn)練和在線預(yù)測等功能,適用于電商、音樂等領(lǐng)域,旨在簡化推薦系統(tǒng)開發(fā)并提升推薦效果。
2.3.1 技術(shù)亮點
- 模塊化設(shè)計:EasyRec 將推薦系統(tǒng)拆分為數(shù)據(jù)處理、特征工程、模型訓(xùn)練和在線預(yù)測等多個獨立模塊,用戶可根據(jù)業(yè)務(wù)需求自由組合,減少代碼復(fù)用,提升開發(fā)效率。
- 兼容主流深度學(xué)習(xí)框架:支持 TensorFlow 和 PyTorch 兩大主流深度學(xué)習(xí)框架,滿足不同開發(fā)者的技術(shù)偏好,降低技術(shù)切換成本。
- 高性能分布式訓(xùn)練:通過 horovod、TF-Replicator 等工具,EasyRec 提供高性能的分布式訓(xùn)練能力,支持大規(guī)模數(shù)據(jù)集和復(fù)雜模型訓(xùn)練,加速模型收斂,降低實驗周期。
- 在線預(yù)測服務(wù):EasyRec 內(nèi)置在線預(yù)測服務(wù),能夠無縫對接到生產(chǎn)環(huán)境,提供低延遲的實時推薦,平滑從模型研發(fā)到業(yè)務(wù)上線的流程。
2.3.2 技術(shù)核心模塊架構(gòu)
EasyRec 核心模塊架構(gòu)如下:
- 數(shù)據(jù)處理層:支持多種數(shù)據(jù)輸入方式,包括 MaxCompute、HDFS、CSV 文件等,滿足不同數(shù)據(jù)源的需求。
- 特征工程層:提供豐富的特征類型支持,包括 IdFeature、RawFeature、TagFeature、SequenceFeature 以及 ComboFeature 等,滿足不同業(yè)務(wù)場景的特征需求。
- 模型訓(xùn)練層:集成 DeepFM、DIN、MultiTower 及 DSSM 等經(jīng)典推薦排序和召回算法,支持多任務(wù)學(xué)習(xí)、圖神經(jīng)網(wǎng)絡(luò)等高級功能,滿足不同業(yè)務(wù)場景的模型需求。
- 在線預(yù)測層:提供高性能的在線預(yù)測服務(wù),支持模型增量更新、特征埋點等功能,滿足實時推薦的需求。
2.3.3 技術(shù)優(yōu)勢
EasyRec 具備如下優(yōu)勢:
- 易用性:通過簡潔的 API 設(shè)計,讓推薦系統(tǒng)的開發(fā)變得簡單,降低推薦系統(tǒng)開發(fā)的門檻。
- 靈活性:支持 TensorFlow 和 PyTorch,可按需選擇,且模塊化設(shè)計方便定制,滿足不同業(yè)務(wù)場景的需求。
- 高效性:提供分布式訓(xùn)練和在線預(yù)測服務(wù),加快模型迭代速度,提升推薦系統(tǒng)的性能。
- 全面性:覆蓋推薦系統(tǒng)的全生命周期,從數(shù)據(jù)預(yù)處理到模型部署,提供一站式的解決方案。
2.3.4 適用場景
EasyRec 可廣泛應(yīng)用于電商、音樂、視頻、新聞等各類需要個性化推薦的場景,無論是商品推薦、內(nèi)容推送還是廣告定向,都能幫助提升用戶體驗和業(yè)務(wù)轉(zhuǎn)化率。
EasyRec 已經(jīng)在阿里巴巴集團內(nèi)部多個業(yè)務(wù)場景中得到廣泛應(yīng)用,如淘寶、天貓、優(yōu)酷等,取得了顯著的業(yè)務(wù)效果。同時,EasyRec 也積極與社區(qū)合作,推動推薦系統(tǒng)技術(shù)的發(fā)展和應(yīng)用。
三、基于Weka 實現(xiàn)貨品推薦上架操作案例
接下來將通過一個實際案例,適用Weka實現(xiàn)一個貨品的推薦上架案例。
3.1 案例需求
完整的需求描述如下:
- 倉庫有大貨架,中型貨架,還有小貨架,三種貨架類型;
- 每種貨架能夠容納的貨品尺寸,體積,重量各不相同;
- 對于需要上架的貨品根據(jù)其尺寸、重量完成上架推薦;
3.2 前置準(zhǔn)備
3.2.1 數(shù)據(jù)準(zhǔn)備
使用Weka 框架最后進行推薦的使用,需要導(dǎo)入樣本數(shù)據(jù),構(gòu)建決策樹,配合上述的需求,在本地提前準(zhǔn)備一個CSV文件,里面有如下樣本數(shù)據(jù):
length,width,height,weight,fragile,shelf_type 50,40,30,5,false,small_shelf 120,80,150,120,false,floor_stack 30,20,10,1,false,small_shelf 200,60,40,80,true,high_rack 10,10,5,0.5,false,small_shelf 300,120,80,300,false,floor_stack 80,60,180,50,false,high_rack 25,20,15,2,true,small_shelf 150,100,200,150,false,floor_stack 60,40,160,40,false,high_rack
3.2.2 導(dǎo)入核心依賴
創(chuàng)建一個springboot 工程,導(dǎo)入如下核心依賴:
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<satoken.version>1.37.0</satoken.version>
<spring-ai.version>1.0.0-M6</spring-ai.version>
<spring-ai-alibaba.version>1.0.0-M6.1</spring-ai-alibaba.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.2</version>
<relativePath/>
</parent>
<dependencies>
<!-- For handling CSV files -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>nz.ac.waikato.cms.weka</groupId>
<artifactId>weka-stable</artifactId>
<version>3.8.6</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MySQL連接驅(qū)動 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter</artifactId>
<version>${spring-ai-alibaba.version}</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<name>Central Portal Snapshots</name>
<id>central-portal-snapshots</id>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>3.3 基于本地樣本數(shù)據(jù)實現(xiàn)方案
基于上述的本地樣本數(shù)據(jù),完成一個基于Weka 機器學(xué)習(xí)框架的推薦上架的案例實現(xiàn)。
3.3.1 導(dǎo)入核心依賴
pom中導(dǎo)入Weka的依賴
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>nz.ac.waikato.cms.weka</groupId>
<artifactId>weka-stable</artifactId>
<version>3.8.6</version>
</dependency>3.3.2 添加本地樣本數(shù)據(jù)
在本地的resources 目錄下增加一個csv 樣本文件,樣本的數(shù)據(jù)如下:

3.3.3 完整的實現(xiàn)代碼
完整的實現(xiàn)代碼如下:
package com.congge.command.v3;
import weka.classifiers.trees.J48;
import weka.core.Instances;
import weka.core.converters.ConverterUtils.DataSource;
/**
* 基于本地的訓(xùn)練文件樣本數(shù)據(jù)進行預(yù)測
*/
public class ShelfRecommendationSystemV3 {
private J48 decisionTree;
private Instances dataStructure;
/**
* 加載訓(xùn)練數(shù)據(jù)并構(gòu)建模型
*/
public void trainModel(String csvFilePath) throws Exception {
// 1. 加載CSV數(shù)據(jù)
DataSource source = new DataSource(csvFilePath);
Instances data = source.getDataSet();
// 2. 設(shè)置類別屬性(貨架類型)
if (data.classIndex() == -1) {
data.setClassIndex(data.numAttributes() - 1);
}
// 3. 保存數(shù)據(jù)結(jié)構(gòu)用于后續(xù)預(yù)測
this.dataStructure = new Instances(data, 0);
// 4. 構(gòu)建決策樹模型
decisionTree = new J48();
decisionTree.buildClassifier(data);
System.out.println("模型訓(xùn)練完成!");
}
/**
* 預(yù)測新貨物的推薦貨架類型
*/
public String predictShelfType(double length, double width, double height,
double weight, boolean fragile) throws Exception {
if (decisionTree == null || dataStructure == null) {
throw new IllegalStateException("模型尚未訓(xùn)練,請先調(diào)用trainModel方法");
}
// 創(chuàng)建新實例
weka.core.Instance instance = new weka.core.DenseInstance(6);
instance.setDataset(dataStructure);
// 設(shè)置屬性值
instance.setValue(0, length);
instance.setValue(1, width);
instance.setValue(2, height);
instance.setValue(3, weight);
instance.setValue(4, fragile ? "true" : "false");
// 進行預(yù)測
double prediction = decisionTree.classifyInstance(instance);
return dataStructure.classAttribute().value((int) prediction);
}
/**
* 評估模型準(zhǔn)確率(使用訓(xùn)練數(shù)據(jù)簡單評估)
*/
public void evaluateModel(String csvFilePath) throws Exception {
DataSource source = new DataSource(csvFilePath);
Instances data = source.getDataSet();
if (data.classIndex() == -1) {
data.setClassIndex(data.numAttributes() - 1);
}
// 簡單評估(實際應(yīng)用中應(yīng)該使用交叉驗證)
weka.classifiers.Evaluation eval = new weka.classifiers.Evaluation(data);
eval.evaluateModel(decisionTree, data);
System.out.println("\n模型評估結(jié)果:");
System.out.println(eval.toSummaryString());
System.out.println(eval.toClassDetailsString());
System.out.println(eval.toMatrixString());
}
public static void main(String[] args) {
ShelfRecommendationSystemV3 system = new ShelfRecommendationSystemV3();
try {
// 1. 訓(xùn)練模型
String csvPath = "data/shelf_data.csv";
system.trainModel(csvPath);
// 2. 評估模型(可選)
system.evaluateModel(csvPath);
// 3. 測試預(yù)測
System.out.println("\n測試預(yù)測:");
// 測試用例1: 小而輕的貨物
String recommendation1 = system.predictShelfType(30, 20, 10, 1, false);
System.out.printf("貨物(30x20x10cm, 1kg, 非易碎) 推薦貨架: %s%n", recommendation1);
// 測試用例2: 大而重的貨物
String recommendation2 = system.predictShelfType(200, 100, 180, 200, false);
System.out.printf("貨物(200x100x180cm, 200kg, 非易碎) 推薦貨架: %s%n", recommendation2);
// 測試用例3: 易碎的中等大小貨物
String recommendation3 = system.predictShelfType(60, 40, 30, 5, true);
System.out.printf("貨物(60x40x30cm, 5kg, 易碎) 推薦貨架: %s%n", recommendation3);
} catch (Exception e) {
e.printStackTrace();
}
}
}運行一下,效果如下:
- 在控制臺中,輸出了完整的決策樹結(jié)構(gòu);
- 同時結(jié)合樣本數(shù)據(jù),也給出了基于3組測試數(shù)據(jù)的推薦上架庫位;

3.4 基于數(shù)據(jù)庫的樣本數(shù)據(jù)實現(xiàn)方案
仍然是基于Weka 機器學(xué)習(xí)框架,假如我們的樣本數(shù)據(jù)存儲在數(shù)據(jù)庫的表中,下面看具體的實現(xiàn)
3.4.1 添加一張測試樣本表
增加如下的樣本數(shù)據(jù)測試表,并添加一些初始化數(shù)據(jù)
CREATE TABLE product_shelf_mapping (
id INT AUTO_INCREMENT PRIMARY KEY,
product_name VARCHAR(100),
length DOUBLE NOT NULL COMMENT '長度(cm)',
width DOUBLE NOT NULL COMMENT '寬度(cm)',
height DOUBLE NOT NULL COMMENT '高度(cm)',
weight DOUBLE NOT NULL COMMENT '重量(kg)',
shelf_type ENUM('small_shelf', 'high_shelf', 'floor_stack') NOT NULL COMMENT '貨架類型',
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
-- 清空表(測試時使用,生產(chǎn)環(huán)境請移除)
TRUNCATE TABLE product_shelf_mapping;
-- 插入測試數(shù)據(jù)
INSERT INTO product_shelf_mapping (product_name, length, width, height, weight, shelf_type) VALUES
-- 小貨架(體積小、重量輕)
('小型電子元件', 15, 10, 5, 0.2, 'small_shelf'),
('辦公文具套裝', 30, 20, 8, 0.5, 'small_shelf'),
('手機配件盒', 25, 15, 5, 0.3, 'small_shelf'),
('化妝品樣品', 12, 8, 6, 0.1, 'small_shelf'),
('LED燈泡', 10, 10, 15, 0.15, 'small_shelf'),
-- 高位貨架(中等體積、中等重量,可堆疊)
('書籍禮盒', 40, 30, 20, 2.5, 'high_shelf'),
('廚房調(diào)料套裝', 35, 25, 15, 1.8, 'high_shelf'),
('玩具模型箱', 50, 40, 30, 3.0, 'high_shelf'),
('家庭清潔用品', 45, 35, 25, 2.2, 'high_shelf'),
('寵物食品袋', 55, 40, 20, 4.0, 'high_shelf'),
-- 地堆貨架(超長、超重或異形貨物)
('大型家具部件', 200, 80, 30, 25.0, 'floor_stack'),
('健身器材包裝', 180, 60, 40, 30.0, 'floor_stack'),
('工業(yè)設(shè)備箱', 150, 100, 50, 50.0, 'floor_stack'),
('自行車包裝箱', 160, 70, 20, 18.0, 'floor_stack'),
('長條形管材', 300, 10, 10, 12.0, 'floor_stack'),
-- 邊界值測試(接近分類閾值的貨物)
('中型電器箱', 60, 50, 40, 8.0, 'high_shelf'), -- 接近地堆但重量稍輕
('超重小物件', 20, 20, 10, 15.0, 'floor_stack'), -- 重量大但體積小
('細長物品', 150, 5, 5, 3.0, 'floor_stack'), -- 超長但重量輕
('扁平大件', 120, 90, 2, 5.0, 'floor_stack'); -- 面積大但高度低3.4.2 導(dǎo)入依賴
除了上面的Weka 框架庫,還需要引入mysql依賴
<!-- MySQL連接驅(qū)動 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>3.4.3 完整的實現(xiàn)代碼
下面是基于mysql表作為樣本數(shù)據(jù)的完整代碼
package com.congge.command.v2;
import lombok.Data;
import weka.classifiers.trees.J48;
import weka.core.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* 基于數(shù)據(jù)庫的樣本數(shù)據(jù)進行預(yù)測
*/
public class ShelfRecommendationSystem {
// MySQL數(shù)據(jù)庫配置
private static final String DB_URL = "jdbc:mysql://rm-bp15bb46ti34x4glgdo.mysql.rds.aliyuncs.com:3306/gh_log";
private static final String DB_USER = "root";
private static final String DB_PASSWORD = "Dkf5381200";
public static void main(String[] args) {
try {
// 1. 從MySQL加載訓(xùn)練數(shù)據(jù)
List<Product> trainingData = loadTrainingDataFromMySQL();
// 2. 轉(zhuǎn)換為Weka Instances格式
Instances instances = createInstances(trainingData);
// 3. 訓(xùn)練決策樹模型
J48 tree = trainDecisionTree(instances);
// 4. 測試模型
testModel(tree, instances);
// 5. 示例:對新產(chǎn)品進行貨架推薦
Product newProduct = new Product();
newProduct.setLength(120);
newProduct.setWidth(80);
newProduct.setHeight(30);
newProduct.setWeight(25);
String recommendedShelf = recommendShelf(tree, newProduct);
System.out.println("\n推薦貨架類型: " + recommendedShelf);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 從MySQL數(shù)據(jù)庫加載訓(xùn)練數(shù)據(jù)
*/
private static List<Product> loadTrainingDataFromMySQL() throws SQLException {
List<Product> products = new ArrayList<>();
try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD)) {
String query = "SELECT length, width, height, weight, shelf_type FROM product_shelf_mapping";
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query)) {
while (rs.next()) {
Product product = new Product();
product.setLength(rs.getDouble("length"));
product.setWidth(rs.getDouble("width"));
product.setHeight(rs.getDouble("height"));
product.setWeight(rs.getDouble("weight"));
product.setShelfType(rs.getString("shelf_type"));
products.add(product);
}
}
}
System.out.println("從MySQL加載了 " + products.size() + " 條訓(xùn)練數(shù)據(jù)");
return products;
}
/**
* 創(chuàng)建Weka Instances對象
*/
private static Instances createInstances(List<Product> products) {
// 定義屬性
ArrayList<Attribute> attributes = new ArrayList<>();
// 數(shù)值型屬性:長、寬、高、重
attributes.add(new Attribute("length"));
attributes.add(new Attribute("width"));
attributes.add(new Attribute("height"));
attributes.add(new Attribute("weight"));
// nominal屬性:貨架類型
ArrayList<String> shelfTypes = new ArrayList<>();
shelfTypes.add("small_shelf");
shelfTypes.add("high_shelf");
shelfTypes.add("floor_stack");
attributes.add(new Attribute("shelf_type", shelfTypes));
// 創(chuàng)建Instances對象
Instances instances = new Instances("ProductShelfRelation", attributes, 0);
instances.setClassIndex(instances.numAttributes() - 1); // 設(shè)置分類屬性
// 添加數(shù)據(jù)
for (Product product : products) {
double[] values = new double[instances.numAttributes()];
values[0] = product.getLength();
values[1] = product.getWidth();
values[2] = product.getHeight();
values[3] = product.getWeight();
// 設(shè)置分類屬性值
switch (product.getShelfType()) {
case "small_shelf": values[4] = 0; break;
case "high_shelf": values[4] = 1; break;
case "floor_stack": values[4] = 2; break;
//default: values[4] = Instance.missingValue();
default: values[4] = Utils.missingValue();
}
instances.add(new DenseInstance(1.0, values));
}
return instances;
}
/**
* 訓(xùn)練決策樹模型
*/
private static J48 trainDecisionTree(Instances instances) throws Exception {
// 設(shè)置分類器選項
String[] options = new String[1];
options[0] = "-U"; // 使用未修剪的樹
J48 tree = new J48();
tree.setOptions(options);
// 訓(xùn)練模型
tree.buildClassifier(instances);
// 輸出模型
System.out.println("\n訓(xùn)練好的決策樹模型:");
System.out.println(tree);
return tree;
}
/**
* 測試模型準(zhǔn)確率
*/
private static void testModel(J48 tree, Instances instances) throws Exception {
// 隨機劃分訓(xùn)練集和測試集 (70%訓(xùn)練, 30%測試)
instances.randomize(new Random(0));
int trainSize = (int) Math.round(instances.numInstances() * 0.7);
int testSize = instances.numInstances() - trainSize;
Instances train = new Instances(instances, 0, trainSize);
Instances test = new Instances(instances, trainSize, testSize);
// 重新訓(xùn)練模型
tree.buildClassifier(train);
// 測試模型
int correct = 0;
for (int i = 0; i < test.numInstances(); i++) {
Instance inst = test.instance(i);
double predicted = tree.classifyInstance(inst);
double actual = inst.classValue();
if (predicted == actual) {
correct++;
}
}
double accuracy = (double) correct / test.numInstances() * 100;
System.out.printf("\n模型準(zhǔn)確率: %.2f%% (%d/%d)\n", accuracy, correct, test.numInstances());
}
/**
* 為新產(chǎn)品推薦貨架類型
*/
public static String recommendShelf(J48 tree, Product product) throws Exception {
// 創(chuàng)建屬性列表 (必須與訓(xùn)練數(shù)據(jù)相同)
ArrayList<Attribute> attributes = new ArrayList<>();
attributes.add(new Attribute("length"));
attributes.add(new Attribute("width"));
attributes.add(new Attribute("height"));
attributes.add(new Attribute("weight"));
ArrayList<String> shelfTypes = new ArrayList<>();
shelfTypes.add("small_shelf");
shelfTypes.add("high_shelf");
shelfTypes.add("floor_stack");
attributes.add(new Attribute("shelf_type", shelfTypes));
// 創(chuàng)建Instances對象
Instances instances = new Instances("Temp", attributes, 0);
instances.setClassIndex(instances.numAttributes() - 1);
// 創(chuàng)建新產(chǎn)品實例
double[] values = new double[instances.numAttributes()];
values[0] = product.getLength();
values[1] = product.getWidth();
values[2] = product.getHeight();
values[3] = product.getWeight();
//values[4] = Instance.missingValue(); // 分類屬性設(shè)為缺失值
values[4] = Utils.missingValue();
instances.add(new DenseInstance(1.0, values));
// 進行預(yù)測
double prediction = tree.classifyInstance(instances.instance(0));
// 返回預(yù)測結(jié)果
return shelfTypes.get((int) prediction);
}
}
@Data
class Product {
private double length;
private double width;
private double height;
private double weight;
private String shelfType;
}運行上面的代碼做一下測試


3.5 基于AI大模型實現(xiàn)方案
核心實現(xiàn)思路:
- 定義系統(tǒng)提示詞
- 提示詞中,參考的貨架類型,需要提前根據(jù)實際業(yè)務(wù)需求+經(jīng)驗判斷擬定;
- 體積+重量一起判斷;
- 體積 = 長*寬*高
- 將用戶的問題,代入到提示詞中,讓大模型給出推薦
3.5.1 添加配置信息
在配置文件中增加如下AI相關(guān)的配置信息
spring:
# 增加ai的配置
ai:
dashscope:
api-key: 個人apikey
chat:
options:
model: qwen-max3.5.2 添加測試接口
增加一個測試接口,便于查看效果
package com.congge.command.v5;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/client/ai")
public class ChatController {
private final ChatClient chatClient;
public ChatController(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder
.build();
}
//localhost:8082/client/ai/chat?message=今天北京的天氣如何
//localhost:8082/client/ai/chat?message=你是誰
//localhost:8082/client/ai/chat?message=當(dāng)前時間是多少
@PostMapping("/chat")
public String chat(@RequestBody Product product){
Prompt prompt = new Prompt(new UserMessage(buildPrompt(product)));
String content = chatClient.prompt(prompt).call().content();
return content;
}
private static String buildPrompt(Product product) {
return String.format("""
你是一名倉庫管理專家,需要根據(jù)商品尺寸和重量推薦合適的貨架類型。
貨架類型定義:
1. small_shelf: 體積小于5000cm3且重量小于1kg的商品
2. high_shelf: 體積5000-60000cm3且重量1-10kg的商品
3. floor_stack: 體積大于60000cm3或重量大于10kg或形狀特殊的商品(如超長、超寬)
商品信息:
名稱: %s
尺寸: %.1fcm x %.1fcm x %.1fcm
重量: %.2fkg
體積: %.1fcm3
密度: %.2fg/cm3
請根據(jù)以上信息,只返回推薦貨架類型,格式為:推薦貨架類型: [類型]
""",
product.getProductName(),
product.getLength(),
product.getWidth(),
product.getHeight(),
product.getWeight(),
product.getVolume(),
product.getDensity());
}
}Product 實體類
package com.congge.command.v5;
import lombok.Data;
@Data
public class Product {
private Long id;
private String productName;
private double length;
private double width;
private double height;
private double weight;
private String shelfType;
// 計算體積
public double getVolume() {
return length * width * height;
}
// 計算密度
public double getDensity() {
return weight / getVolume();
}
}3.5.3 效果測試
啟動工程后,調(diào)用下接口,這里隨機給一組產(chǎn)品的長寬高進行測試,結(jié)果如下:

四、寫在文末
本文通過較大的篇幅詳細介紹了基于Java技術(shù)棧,整合機器學(xué)習(xí)算法框架Weka結(jié)合一個實際案例實現(xiàn)一個貨品上架的功能,希望對看到的同學(xué)有用哦,本篇到此結(jié)束,感謝觀看。
到此這篇關(guān)于SpringBoot 整合機器學(xué)習(xí)框架 Weka 實戰(zhàn)操作詳解的文章就介紹到這了,更多相關(guān)SpringBoot 整合 Weka內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決若依pageHelper在動態(tài)切換數(shù)據(jù)源問題
這篇文章主要介紹了解決pageHelper在動態(tài)切換數(shù)據(jù)源問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01
淺談springboot內(nèi)置tomcat和外部獨立部署tomcat的區(qū)別
這篇文章主要介紹了淺談springboot內(nèi)置tomcat和外部獨立部署tomcat的區(qū)別,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10
詳解Spring Cloud Zuul 服務(wù)網(wǎng)關(guān)
本篇文章主要介紹了詳解Spring Cloud Zuul 服務(wù)網(wǎng)關(guān),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-12-12
Spring?Data?Elasticsearch?5.0.x修改數(shù)據(jù)后無法立即刷新解決方法示例
這篇文章主要為大家介紹了Spring?Data?Elasticsearch?5.0.x修改數(shù)據(jù)后無法立即刷新解決方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08

