Redis应用实战---商品购买相关性分析

前言

无论是在线上电商,或是线下超市,用户购买商品的相关性分析对商家来说都非常重要,电商平台可以根据商品相关性在商品的详情页进行推送,超市也可以根据商品之间的相关性来参考商品摆放的位置。

基于上述的业务场景,我们可以利用Redis的sorted set来实现。

sorted set(有序集合)

Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

有序集合的成员是唯一的,但分数(score)却可以重复。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 2^32 - 1。

常用命令

在这里插入图片描述

适用场景

常用于各种排行榜、新闻热榜等等。

代码示例

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.*;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class RedisShopping {
    
    

    @Autowired
    private RedisTemplate redisTemplate;

    private List<String> productList = new ArrayList<>();

    private List<String> consumerList = new ArrayList<>();

    /**
     * 1、清空历史数据
     * 2、初始化准备数据
     */
    @Before
    public void clearRedis() {
    
    
        redisTemplate.opsForZSet().removeRange("牛奶", 0, -1);
        redisTemplate.opsForZSet().removeRange("巧克力", 0, -1);
        redisTemplate.opsForZSet().removeRange("薯片", 0, -1);
        redisTemplate.opsForZSet().removeRange("可乐", 0, -1);
        redisTemplate.opsForZSet().removeRange("苹果", 0, -1);
        redisTemplate.opsForZSet().removeRange("鸡蛋", 0, -1);
        redisTemplate.opsForZSet().removeRange("啤酒", 0, -1);
        redisTemplate.opsForZSet().removeRange("牛排", 0, -1);
        redisTemplate.opsForZSet().removeRange("口香糖", 0, -1);
        redisTemplate.opsForZSet().removeRange("方便面", 0, -1);
        productList = createProduceList();
        consumerList = createConsumerList();
    }

    @Test
    public void test() {
    
    
        Map<String, Set<String>> buyProductMap = buyProduct(productList, consumerList);
        for (Map.Entry<String, Set<String>> entry : buyProductMap.entrySet()) {
    
    
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        }
        buyStatistics(buyProductMap);
    }

    /**
     * 根据购买数据,分析购买的商品之间的关联关系
     */
    @After
    public void behaviorAnalysis() {
    
    
        //遍历所有商品
        for (int i = 0; i < productList.size(); i++) {
    
    
            String prod = productList.get(i);
            //依次从redis中获取每个商品的关联数据
            Set<ZSetOperations.TypedTuple> relateSet = redisTemplate.opsForZSet().rangeWithScores(prod, 0, -1);
            if (relateSet.size() == 0) {
    
    
                System.out.println("《" + prod + "》商品没有与其他商品同时购买过!");
                System.out.println();
                continue;
            }
            System.out.println("购买《" + prod + "》商品,同时购买了");
            for (ZSetOperations.TypedTuple s : relateSet) {
    
    
                System.out.print(s.getScore().intValue() + "次 《" + s.getValue() + "》    ");
            }
            System.out.println();
            System.out.println();
        }
    }

    /**
     * 根据每个用户购买的商品,统计
     * key为购买的商品,value为同时购买的其他商品,score,购买的次数
     *
     * @param buyProductMap
     */
    private void buyStatistics(Map<String, Set<String>> buyProductMap) {
    
    
        for (Map.Entry<String, Set<String>> entry : buyProductMap.entrySet()) {
    
    
            Set<String> buyProducts = entry.getValue();
            String[] strs = buyProducts.toArray(new String[buyProducts.size()]);
            //挨个遍历每一个用户购买的所有商品
            for (int i = 0; i < strs.length; i++) {
    
    
                String s1 = strs[i];
                //通过一个指针指向的点为分界,以此向前,向后遍历统计
                /*
                假设用户购买的商品如下:
                牛奶、啤酒、苹果、泡面
                -------------------
                最终分析结果:
                牛奶:啤酒、苹果、泡面
                啤酒:牛奶、苹果、泡面
                苹果:牛奶、啤酒、泡面
                泡面:牛奶、啤酒、苹果
                 */
                for (int j = i + 1; j < strs.length; j++) {
    
    
                    redisTemplate.opsForZSet().incrementScore(s1, strs[j], 1);
                }
                for (int k = 0; k < i; k++) {
    
    
                    redisTemplate.opsForZSet().incrementScore(s1, strs[k], 1);
                }
            }
        }
    }

    /**
     * 模拟用户购物行为,每个用户购物5次,每次随机购买一件商品,如果重复则忽略
     *
     * @param productList
     * @param consumerList
     * @return
     */
    private Map<String, Set<String>> buyProduct(List<String> productList, List<String> consumerList) {
    
    
        Random r = new Random();
        Map<String, Set<String>> buyProductMap = new HashMap<>();
        for (String consumer : consumerList) {
    
    
            Set<String> set = new HashSet<>();
            for (int i = 1; i <= 5; i++) {
    
    
                int p = r.nextInt(productList.size());
                set.add(productList.get(p));
            }
            buyProductMap.put(consumer, set);
        }
        return buyProductMap;
    }

    /**
     * 模拟一批用户
     *
     * @return
     */
    private List<String> createConsumerList() {
    
    
        List<String> consumerList = new ArrayList<>();
        consumerList.add("用户A");
        consumerList.add("用户B");
        consumerList.add("用户C");
        consumerList.add("用户D");
        consumerList.add("用户E");
        consumerList.add("用户F");
        return consumerList;
    }

    /**
     * 模拟一批商品
     *
     * @return
     */
    private List<String> createProduceList() {
    
    
        List<String> productList = new ArrayList<>();
        productList.add("牛奶");
        productList.add("巧克力");
        productList.add("薯片");
        productList.add("可乐");
        productList.add("苹果");
        productList.add("鸡蛋");
        productList.add("啤酒");
        productList.add("牛排");
        productList.add("口香糖");
        productList.add("方便面");
        return productList;
    }
}

用户B
[啤酒, 可乐, 巧克力]
用户A
[啤酒, 方便面, 牛排, 巧克力]
用户F
[苹果, 方便面, 牛排, 巧克力]
用户E
[苹果, 方便面, 可乐]
用户D
[牛奶, 鸡蛋, 牛排, 巧克力]
用户C
[牛奶, 薯片, 牛排, 可乐]
购买《牛奶》商品,同时购买了
1次 《可乐》    1次 《巧克力》    1次 《薯片》    1次 《鸡蛋》    2次 《牛排》    

购买《巧克力》商品,同时购买了
1次 《可乐》    1次 《牛奶》    1次 《苹果》    1次 《鸡蛋》    2次 《啤酒》    2次 《方便面》    3次 《牛排》    

购买《薯片》商品,同时购买了
1次 《可乐》    1次 《牛奶》    1次 《牛排》    

购买《可乐》商品,同时购买了
1次 《啤酒》    1次 《巧克力》    1次 《方便面》    1次 《牛奶》    1次 《牛排》    1次 《苹果》    1次 《薯片》    

购买《苹果》商品,同时购买了
1次 《可乐》    1次 《巧克力》    1次 《牛排》    2次 《方便面》    

购买《鸡蛋》商品,同时购买了
1次 《巧克力》    1次 《牛奶》    1次 《牛排》    

购买《啤酒》商品,同时购买了
1次 《可乐》    1次 《方便面》    1次 《牛排》    2次 《巧克力》    

购买《牛排》商品,同时购买了
1次 《可乐》    1次 《啤酒》    1次 《苹果》    1次 《薯片》    1次 《鸡蛋》    2次 《方便面》    2次 《牛奶》    3次 《巧克力》    

《口香糖》商品没有与其他商品同时购买过!

购买《方便面》商品,同时购买了
1次 《可乐》    1次 《啤酒》    2次 《巧克力》    2次 《牛排》    2次 《苹果》    


猜你喜欢

转载自blog.csdn.net/CSDN_WYL2016/article/details/113544738