Java点餐小程序实现个性化推荐菜品

2021-05-29 00:00:00 程序 个性化 菜品

1、业务数据表说明

顾客与订单是一对多的关系;订单与菜品是多对多的关系,所以还有一张关系表menu_order_;

《Java点餐小程序实现个性化推荐菜品》

2、从数据库查询并构建训练集

现在需要从这四张表联合查询查出 每一个顾客的下单菜品的数量。

1)存着每个顾客的下单菜品的菜品id和此菜品的下单次数。

《Java点餐小程序实现个性化推荐菜品》

2)先查出所有顾客customers,再查出每一个顾客的下单菜品的菜品id和此菜品的下单次数,写出到文件中(filename1是不带评分的数据,即userId-dishId;而filename2是userId-dishId-value)。

@PostConstruct
public void getUserItems() {
    try (Writer w1 = new BufferedWriter(new FileWriter(filename1));
         Writer w2 = new BufferedWriter(new FileWriter(filename2))) {
        // 查询所有用户
        List<Customer> customers = customerMapper.selectList(null);
        // 查询所有用户的下单菜品记录
        for (Customer customer : customers) {
            List<DishNumber> dishNumbers = orderMapper.getUserOrderDishes(customer.getCId());
            if (dishNumbers.size() == 0)
                continue;

            for (DishNumber d : dishNumbers) {
                w1.write(customer.getId() + "," + d.getDId() + "\n");
                w2.write(customer.getId() + "," + d.getDId() + "," + d.getValue() + "\n");
            }
        }
        w1.flush();
        w2.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

getUserDishes的sql语句:根据cId查询结果。

<select id="getUserOrderDishes" resultType="com.firstGroup.restaurant.model.vo.DishNumber">
        select d.id dId, count(*) value
        from menu_order_ mo, order_ o, customer c, dish d
        where o.c_id=c.c_id and mo.o_id=o.o_id and d.d_id=mo.d_id and o.c_id = #{cId}
        group by d.d_id
</select>

3)生成的训练集(数据时随意测试的,没有参考性)

数据说明:顾客id=1:下单菜品id=1,61次;菜品id=2,1次;菜品id=3,1次

 filename1;               filename2

《Java点餐小程序实现个性化推荐菜品》            《Java点餐小程序实现个性化推荐菜品》 

3、使用Mahout实现基于用户的协调过滤推荐算法

 1)有用户评分的:

/*
 * @Author Haojie
 * @Description 有评分的基于用户的协同过滤推荐算法
 * @Param
 * @return
 **/
private List<Dish> userCFWithoutRecommend(String cId, Integer number) throws Exception {

    // 建立数据模型,包含用户评分
    DataModel dm = new GenericDataModel(
            GenericDataModel
                    .toDataMap(new FileDataModel(new File(filename2))));

    // 使用曼哈顿距离计算类似度
    UserSimilarity us = new EuclideanDistanceSimilarity(dm);

    //指定NearestNUserNeighborhood做为近邻算法
    UserNeighborhood unb = new NearestNUserNeighborhood(10, us, dm);

    // 构建包含用户评分的UserCF推荐器
    Recommender re = new GenericUserBasedRecommender(dm, unb, us);

    // 返回推荐结果,为cId用户推荐number个商品
    Integer id = customerMapper.selectById(cId).getId();
    List<RecommendedItem> list = re.recommend(id, number);
    List<Dish> dishes = new ArrayList<>();
    System.out.println("根据用户cId=" + cId + ", userId=" + id + "的点餐习惯,推荐的前" + number + "个菜品的id和推荐度如下:");

    for (RecommendedItem recommendedItem : list) {
        System.out.println(recommendedItem.getItemID() + " : " + recommendedItem.getValue());
        dishes.add(dishMapper.selectOne(new LambdaQueryWrapper<Dish>().eq(Dish::getId,
                recommendedItem.getItemID())));
    }
    return dishes;
}

 2)无用户评分的:

/*
 * @Author Haojie
 * @Description 无评分的基于用户的协同过滤推荐算法
 * @Param
 * @return
 **/
private List<Dish> userCFWithoutScoreRecommend(String cId, Integer number) throws Exception {

    // 建立数据模型,不包含用户评分
    DataModel dm = new GenericDataModel(
            GenericDataModel
                    .toDataMap(new FileDataModel(new File(filename1))));

    // 使用曼哈顿距离计算类似度
    UserSimilarity us = new CityBlockSimilarity(dm);

    //指定NearestNUserNeighborhood做为近邻算法
    UserNeighborhood unb = new NearestNUserNeighborhood(5, us, dm);

    // 构建不包含用户评分的UserCF推荐器
    Recommender re = new GenericBooleanPrefUserBasedRecommender(dm, unb, us);

    // 返回推荐结果,为cId用户推荐number个商品
    Integer id = customerMapper.selectById(cId).getId();
    List<RecommendedItem> list = re.recommend(id, number);
    List<Dish> dishes = new ArrayList<>();
    System.out.println("根据用户cId=" + cId + ", userId=" + id + "的点餐习惯,推荐的前" + number + "个菜品的id和推荐度如下:");

    for (RecommendedItem recommendedItem : list) {
        System.out.println(recommendedItem.getItemID() + " : " + recommendedItem.getValue());
        dishes.add(dishMapper.selectOne(new LambdaQueryWrapper<Dish>().eq(Dish::getId,
                recommendedItem.getItemID())));
    }
    return dishes;
}

最终都可以返回推荐的菜品数据。

问题

实现起来非常简单,但是有非常大的问题,那就是训练的数据只有id和评分,数据太少了;应该是整个菜品的属性,菜品分类,用户属性等等都拿去训练才比较合理。

参考:

1、Mahout实践,协同过滤算法介绍:

Java实现算法推荐:Mahout实践 – JavaShuo

2、具体实战:

Mahout推荐算法编程实践-demo说明 – JavaShuo

3、其他参考

012_流式计算系统(Mahout协同过滤) (bbsmax.com)

    原文作者:WHJwhj552200
    原文地址: https://blog.csdn.net/WHJwhj552200/article/details/125038175
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。

相关文章