营销项目--3. 策略概率装配处理
2024.07.07 day8
情景
对于大营销项目,目前已经处理好开发环境和持久化数据的问题,接下来要根据梳理出的业务流程一步步的实现,首先要实现的是抽奖策略的装配
![[Pasted image 20240707211309.png]]
任务
实现抽奖策略的装配,这个过程会需要用到数据库查询,策略值计算,redis map数据存储。
通过策略ID检索数据库策略配置,根据策略配置的概率计算出占比值,初始化到redis服务中,完成简单的随机抽奖
策略概率装配处理
Target: 将抽奖的概率初始化到应用中
原始思路:
两种抽奖算法
空间换时间
将所有可能的数据(0-10000)都存放在redis
里作为key
,对应的value
为awardId
,直接在redis
中通过key就可以获得对应的奖品id
提前计算好抽奖概率分布,用本地内存guava
或者redis
存储,抽奖的时候通过生成的随机值在空间内定位,时间复杂度为O(1)
本地内存比redis
快,但是redis
可以直接解决分布式存储问题,本地内存需要让多台分布式机器都保持数据的同步更新,需要引入配置中心和定时检测的功能。来处理应用启动前/运行中,对活动新增/变更做本地内存做数据加载处理
时间换空间
抽奖的时候生成一个随机值,用随机值和概率范围for循环对比
行动
了解两种不同的抽奖算法知识
[[抽奖算法]]安装portainer. 密码:fcjvUR2RfcjvUR2R
使用docker-compose安装redis。一个很傻逼的问题是,redis默认用户名是没有的,也没有默认密码,我一直登陆不上redis-admin,是因为设置了redis-admin的用户名和密码而不是redis的
在工程中新加上redission包,数据持久层中加上IRedisService接口和RedissionService实现类。
在application层的config重新配置了RedisClientConfig和RedisClientConfigProperties。
测试了一下redis连接是否正常:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37package com.priska.test;
import com.priska.infrastructure.persistent.redis.IRedisService;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.redisson.api.RMap;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
public class ApiTest {
private IRedisService redisService;
public void test() {
RMap<Object, Object> map = redisService.getMap("strategy_id_100001");
map.put(1,101);
map.put(2,101);
map.put(3,101);
map.put(4,102);
map.put(5,102);
map.put(6,102);
map.put(7,103);
map.put(8,103);
map.put(9,104);
map.put(10,105);
log.info("测试结果: {}", redisService.getFromMap("strategy_id_100001",10),toString());
}
}这一节实现策略概率装配的主要业务逻辑是在domain层新建strategy业务,在service.armory中实现,一个IStrategyArmory接口,一个实现类。
在实现业务逻辑之前,发现需要实现策略奖品实体(放在domain.strategy.model.entity中),和一个queryStrategyAwardList(策略服务仓储功能),这个步骤主要是能够从仓库中获取到策略奖品实体/数据(仓库可以是redis,也可以是mysql)
所以为了实现queryStrategyAwardList函数在基础仓库中实现(infrastructure.repository)
开始实现业务逻辑
测试
实现1:策略装配
- 根据
strategyId
查找StrategyAwardList
- 仓储层实现对数据库的增删查改操作,领域层定义数据库增删查改接口
- 定义接口:
domain--strategy-repository--IStrategyRepository
- 实现操作:
infrastructure--persistent--repository
Redis
查缓存后查mysql
- 根据
strategyAwadList
中的award_rate
,计算最小概率值和总概率的商,用这个结果作为查找表的度量值(千分位或者万分位)。度量值✖概率就是对应奖品在查找表中的元素个数 - 生成策略奖品概率查找表
- 在list中,存放对应奖品的数量,占位越多代表概率越高
- 乱序查找表并转化为
Map
- 将Map存放到
redis
中storeStrategyAwardSearchRateTable
也是在domain
中定义接口,在infrasturcture
实现
实现2: 简单抽奖
根据策略id进行抽奖
- 先从redis中获取
rateRange
- 根据
rateRange
生成一个随机值 - 根据该随机值在查找表中查找对应的奖品
知识
根据策略id查值。在DDD架构中,需要用什么值,不用自己实现,在基础层中调dao
若要在Redis可视化界面中只管看到数据,而非乱码,可以打开Redisson配置中注释掉的config.setCodec(new RedisCodec()); ,但是这样会有一个问题,用Redis的String类型存储的Java实例对象无法正确被反序列化,查了网上资料,直把上述代码改成config.setCodec(new JsonJacksonCodec());也就是用Jackson做序列化和反序列化,原生代码有点问题的,这样就可以同时实现解决可视化和Redis中的String值被成功反序列化成实体类这俩问题