SpringBoot结合Elasticsearch实现个性化搜索推荐模型-05【接入ALS模型和LR模型实现推荐 完结篇】

此文章衔接【SpringBoot结合Elasticsearch实现个性化搜索推荐模型-04【推荐模型训练】文章

我们在第四章的时候, 完成了ALS模型和LR模型的构建,并且ALS模型我们将推荐的召回结果存储到了MYSQL当中,接下来我们将正式结合我们的ALS召回模型和LR逻辑回归模型完成推荐,在此之前首先要区分一下我们所做的搜索和推荐是独立的,搜索仍然是之前的queryByElasticSearch接口, 而推荐是一个全新的接口,也就是说用户没有指明我要搜索时,就是推荐接口返回数据,一旦用户有搜索意图了,就是搜索接口返回数据

代码实现

ALS模型接入
  1. 创建一个推荐的服务
/**
 * 推荐服务
 *
 * @author 随风
 */
public interface RecommendService {


    /**
     * 获取ALS的召回结果
     *
     * @param userId 用户id
     * @return 应推荐的商家id列表
     */
    List<String> recall(String userId);

我们的推荐就不需要像之前做搜索的时候那么多参数了,什么经纬度,名称都不要了,只需要知道当前用户是谁就行了

  1. 实现接口
/**
 * 推荐服务实现
 *
 * @author 随风
 */
@Service
public class RecommendServiceImpl implements RecommendService {

    @Resource
    private RecommendDOMapper recommendDOMapper;

    @Override
    public List<String> recall(String userId) {
        // 用户对应的召回结果 是 1对多
        RecommendDO recommendDO = recommendDOMapper.selectByUserId(userId);
        // 我们在将推荐的信息查出来的时候 要思考一个问题 如果说我没有查到当前用户所应该推荐的内容怎么办 也就是没有userId所对应的记录
        // 那我们就应该给与一个默认策略 查不到的时候 取数据库当中的默认推荐数据返回
        if (null == recommendDO) {
            recommendDO = recommendDOMapper.selectByDefaultData();
        }
        return Arrays.asList(recommendDO.getRecommend().split(","));
    }
}

  1. 引入推荐服务
    @Resource
    private RecommendService recommendService;
  1. 创建推荐接口通过查到的门店id集合反查数据库构建门店信息
    List<ShopModel> recommend(String userId);
  1. 反查数据
    @Override
    public List<ShopModel> recommend(String userId) {
        // 实际我们在真实开发环境中 一般用户的信息 我们从token里获取 这里就直接传递了
        List<String> shopIdList = recommendService.recall(userId);

        // 将查到的商家信息返回给前端
        return shopSerive.queryByIds(shopIdList);
    }
  1. 控制层调用recommend方法返回给前端,至此,第一步的召回粗排就完成了,接下来进行LR模型的接入
LR模型接入
  1. LR模型我们没有进行任何的解析直接存储到了磁盘上,怎么使用它呢?

  2. 创建一个含有排序的映射类

@Data
public class ShopSortMddel {

    private String shopId;

    private Double score;

}

  1. 创建LR模型服务
/**
 * LR模型服务
 * @author 随风
 */
public interface LrService {

    List<String> sort(List<String> shopIdList, String userId);

}
  1. 服务实现
/**
 * LR模型服务实现
 * @author 随风
 */
@Service
public class LrServiceImpl implements LrService {

    SparkSession sparkSession;

    LogisticRegressionModel logisticRegressionModel;

    @PostConstruct
    public void init() {

        // 创建Spark环境
        sparkSession = SparkSession.builder().master("local").appName("business_info").getOrCreate();

        // 读取我们训练好的LR模型
        logisticRegressionModel = LogisticRegressionModel.load("D:/lrModel");

    }


    @Override
    public List<String> sort(List<String> shopIdList, String userId) {
        // shopIdList 就是我们第一次根据ALS模型的粗排召回结果
        // 接下来我们需要构建特征
        // 特征怎么构建呢 还记得 我们在上一个章节中 构建的用于描述特性的CSV文件吗 (11维的数组)
        // 同样的我们需要将特征进行处理 转化为我们的数组
        // 举个例子 当前用户的性别 转化为 one - hot 编码放到对应的列上 第五列 男 第六列 女 如果是男 就在第五列标记为 1 反之 放到第六列
        // 这里就直接写死了

        List<ShopSortMddel> resultList = new ArrayList<>();

        for (String shopId : shopIdList) {
            // 造的假数据
            Vector dense = Vectors.dense(1, 0, 0, 0, 0, 1, 0.6, 0, 0, 1, 0);
            Vector result = logisticRegressionModel.predictProbability(dense);
            double[] array = result.toArray();
            double score = array[1];

            ShopSortMddel shopSortMddel = new ShopSortMddel();
            shopSortMddel.setShopId(shopId);
            shopSortMddel.setScore(score);
            resultList.add(shopSortMddel);
        }

        // 根据评分对结果列表进行降序排序,并返回排序后的商家ID列表
        resultList.sort((o1, o2) -> {
            if (o1.getScore() < o2.getScore()) {
                return 1;
            } else if (o1.getScore() > o2.getScore()) {
                return -1;
            }
            return 0;
        });

        return resultList.stream().map(ShopSortMddel::getShopId).collect(Collectors.toList());
    }
}
  1. 改造recall方法 加入精排
    @Override
    public List<String> recall(String userId) {
        // 第一步 ALS粗排
        // 用户对应的召回结果 是 1对多
        RecommendDO recommendDO = recommendDOMapper.selectByUserId(userId);
        // 我们在将推荐的信息查出来的时候 要思考一个问题 如果说我没有查到当前用户所应该推荐的内容怎么办 也就是没有userId所对应的记录
        // 那我们就应该给与一个默认策略 查不到的时候 取数据库当中的默认推荐数据返回
        if (null == recommendDO) {
            recommendDO = recommendDOMapper.selectByDefaultData();
        }

        // 第二步 LR精排
        List<String> shopIdList = Arrays.asList(recommendDO.getRecommend().split(","));

        return lrService.sort(shopIdList, userId);
    }
疑问解释
  1. 为什么使用了predictProbability方法 而不用predict方法呢?

如果你只需要得到一个确定的类别标签,而不关心具体概率是多少,那么可以使用 predict 方法。predict 方法通常用于那些只需明确分类结果的场景。很明显我们的场景是需要知道概率的,因为我们需要猜测用户点击哪个商家的可能性大

predictProbability方法返回的是一个概率分布数组,包含了输入特征向属于不同类别的概率,对于二分类问题,它会返回一个包含两个元素的数组,分别表示属于负类和正类的概率。负类放在数组的0号下标位置,正类放在数组的1号下标位置,自然我们要的是1号下标的正类概率,值越高代表用户对这个商家的感兴趣的程度越高,点击它的概率也越大

完结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值