第五部分:在线推荐服务
5.1 推荐服务实现
// smart-rec-api/src/main/java/com/smartrec/api/service/RecommendService.java
package com.smartrec.api.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.cache.annotation.Cacheable;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* 推荐服务
*
* 这是推荐系统的核心服务,协调召回、排序、重排等模块,
* 为用户生成个性化推荐结果。
*
* 性能优化:
* 1. 多级缓存:本地缓存(Caffeine) + 分布式缓存(Redis)
* 2. 异步处理:使用CompletableFuture并行执行
* 3. 预计算:热门推荐等可提前计算
*/
@Slf4j
@Service
public class RecommendService {
// 本地缓存(Caffeine)
private final Cache<Long, List<RecommendItem>> localCache = Caffeine.newBuilder()
.maximumSize(10000)
.expireAfterWrite(1, TimeUnit.MINUTES)
.recordStats()
.build();
private final MultiChannelRecallMerger recallMerger;
private final RankingService rankingService;
private final ReRankService reRankService;
private final FeatureExtractor featureExtractor;
public RecommendService(
MultiChannelRecallMerger recallMerger,
RankingService rankingService,
ReRankService reRankService,
FeatureExtractor featureExtractor) {
this.recallMerger = recallMerger;
this.rankingService = rankingService;
this.reRankService = reRankService;
this.featureExtractor = featureExtractor;
}
/**
* 获取个性化推荐
*
* 这是推荐系统的核心流程:
* 1. 获取用户行为特征
* 2. 多路召回候选物品
* 3. 特征提取
* 4. 排序模型打分
* 5. 重排(多样性、去重、业务规则)
*
* @param userId 用户ID
* @param size 推荐数量
* @param context 上下文信息
* @return 推荐结果列表
*/
public List<RecommendItem> recommend(Long userId, int size, ContextInfo context) {
long startTime = System.currentTimeMillis();
// 1. 检查本地缓存
List<RecommendItem> cached = localCache.getIfPresent(userId);
if (cached != null && !cached.isEmpty()) {
log.debug("Cache hit for user: {}", userId);
return cached.subList(0, Math.min(size, cached.size()));
}
// 2. 获取用户行为
List<UserAction> userActions = getUserActions(userId, 100);
// 如果用户行为为空,返回热门推荐
if (userActions.isEmpty()) {
log.info("New user: {}, returning hot recommendations", userId);
return getHotRecommendations(size);
}
// 3. 多路召回
List<RecallItem> recallItems = recallMerger.merge(userId, userActions, size * 3);
if (recallItems.isEmpty()) {
log.warn("No recall items for user: {}", userId);
return getHotRecommendations(size);
}
// 4. 特征提取与排序
List<RankingItem> rankingItems = new ArrayList<>();
for (RecallItem recallItem : recallItems) {
// 提取特征向量
FeatureVector features = featureExtractor.buildFeatureVector(
userId, recallItem.getItemId(), context);
// 模型预测
float score = rankingService.predict(features);
rankingItems.add(new RankingItem(recallItem.getItemId(), score));
}
// 5. 按分数排序
rankingItems.sort((a, b) -> Float.compare(b.getScore(), a.getScore()));
// 6. 重排(多样性调整)
List<RecommendItem> recommendations = reRankService.rerank(rankingItems, size);
// 7. 缓存结果
localCache.put(userId, recommendations);
long duration = System.currentTimeMillis() - startTime;
log.info("Recommend for user {} completed in {}ms, {} items returned",
userId, duration, recommendations.size());
return recommendations;
}
/**
* 获取热门推荐(兜底策略)
*/
private List<RecommendItem> getHotRecommendations(int size) {
// 从Redis获取全局热门商品
List<Long> hotItems = getGlobalHotItems(size);
List<RecommendItem> results = new ArrayList<>();
for (Long itemId : hotItems) {
results.add(new RecommendItem(itemId, 0.5f, "hot"));
}
return results;
}
private List<UserAction> getUserActions(Long userId, int limit) {
// 从Redis获取用户最近的行为
return new ArrayList<>();
}
private List<Long> getGlobalHotItems(int limit) {
// 从Redis获取热门商品列表
return new ArrayList<>();
}
}
第六部分:A/B测试框架
6.1 A/B测试实现
// smart-rec-api/src/main/java/com/smartrec/api/abtest/ABTestManager.java
package com.smartrec.api.abtest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* A/B测试管理器
*
* A/B测试是推荐系统迭代的核心工具,通过对比不同算法、不同模型的效果,
* 用数据驱动决策,避免"拍脑袋"式优化。
*
* A/B测试的关键要素:
* 1. 实验分组:实验组和对照组
* 2. 流量分配:均匀分配或按比例分配
* 3. 指标评估:CTR、转化率、停留时长等
* 4. 统计显著性:确保结果不是随机波动
*/
@Slf4j
@Component
public class ABTestManager {
// 实验配置
private final Map<String, Experiment> experiments = new ConcurrentHashMap<>();
public ABTestManager() {
// 注册实验
registerExperiment(Experiment.builder()
.name("ranking_model_v2")
.description("新版排序模型A/B测试")
.variants(Map.of(
"control", 0.5, // 50%流量使用旧模型
"treatment", 0.5 // 50%流量使用新模型
))
.defaultVariant("control")
.build());
registerExperiment(Experiment.builder()
.name("recall_strategy")
.description("召回策略对比")
.variants(Map.of(
"itemcf", 0.33,
"vector", 0.33,
"hybrid", 0.34
))
.defaultVariant("hybrid")
.build());
}
/**
* 获取用户所属的实验变体
*
* 使用一致性哈希保证同一用户始终看到同一版本
*/
public String getVariant(Long userId, String experimentName) {
Experiment experiment = experiments.get(experimentName);
if (experiment == null) {
return null;
}
// 使用用户ID哈希分配
int hash = Math.abs(userId.hashCode() % 100);
int cumulative = 0;
for (Map.Entry<String, Double> entry : experiment.getVariants().entrySet()) {
cumulative += entry.getValue() * 100;
if (hash < cumulative) {
return entry.getKey();
}
}
return experiment.getDefaultVariant();
}
/**
* 记录实验指标
*/
public void trackMetric(Long userId, String experimentName, String metricName, double value) {
String variant = getVariant(userId, experimentName);
if (variant == null) return;
// 将指标发送到监控系统
String metricKey = String.format("abtest.%s.%s.%s", experimentName, variant, metricName);
// 记录到Prometheus
// metricsCollector.record(metricKey, value);
log.debug("Track metric: {} = {}", metricKey, value);
}
private void registerExperiment(Experiment experiment) {
experiments.put(experiment.getName(), experiment);
log.info("Registered experiment: {}", experiment.getName());
}
}
本文通过构建一个完整的智能推荐系统,全面展示了Java+AI项目开发的各个环节:
数据采集:用户行为日志的实时采集和存储
特征工程:用户特征、物品特征、交叉特征的提取和处理
召回算法:协同过滤、向量召回、多路召回合并
排序模型:DeepFM深度学习模型的训练和部署
在线服务:高性能推荐服务的实现和优化
A/B测试:实验框架和效果评估
这个实战项目涵盖了Java+AI的核心技术栈,其设计思想和实现技巧可以复用到搜索系统、广告系统、内容推荐等多种场景。希望本文能帮助你建立起AI工程化的完整知识体系,在实际工作中游刃有余!
来源:
https://tmywi.cn/category/shishang.html