应用场景:
有时我们需要从一些列数据中根据权重随机选取指定条数记录出来,这里需要权重、随机,我们根据权重越大的,出现概率越大。例如广告系统。
实现原理:
需求确认后在网上找了很多的资料,可惜没有比较合适的方案,下面和大家分享一种,有不合理之处还请大家指正。废话少说,其实算法很简单,如下:
落实到代码:
@Service
public class AdvertiseService extends BaseService{
private static final Logger log = LoggerFactory.getLogger(AdvertiseService.class);
static List<WeightCategory> categorys = new ArrayList<WeightCategory>();
private static Random random = new Random();
@Autowired
private RedisService redisService;
@Value("${redis.cache.time}")
private int redisCacheTime;
/**
* 通过权重获取Id
*/
private String weightRandomId() {
// 获取权重集合
getAdvertiseWeightList();
Integer weightSum = 0;
String advertiseId = null;
for (WeightCategory wc : categorys) {
weightSum += wc.getWeight();
}
if (weightSum <= 0) {
log.info("Error: weightSum=" + weightSum.toString());
return null;
}
Integer n = random.nextInt(weightSum); // n in [0, weightSum)
Integer m = 0;
for (WeightCategory wc : categorys) {
if (m <= n && n < m + wc.getWeight()) {
advertiseId = wc.getAdvertiseId();
log.info("This Random advertiseId is " + advertiseId);
break;
}
m += wc.getWeight();
}
return advertiseId;
}
/**
* 获取广告权重list
*/
private void getAdvertiseWeightList() {
// 从缓存中获取
String key = getKey("getAdvertiseList");
if (redisService.exists(key)) {
String value = redisService.get(key);
if (StringUtils.isNotBlank(value)) {
categorys = JSON.parseObject(value, advertiseListType);
}
} else {
// 从数据库中获取
List<Advertise> list = shopAdvertiseService.list();
if (list != null && list.size() > 0) {
// 清空数据
categorys.clear();
// 获取权重
for (Advertise advertise : list) {
// 添加数据
categorys.add(new WeightCategory(advertise.getId(), advertise.getWeight()));
}
// 存入redis缓存
redisService.setex(key, JSON.toJSONString(categorys), redisCacheTime);
}
}
}
}
class WeightCategory {
private String advertiseId;
private Integer weight;
public String getAdvertiseId() {
return advertiseId;
}
public void setAdvertiseId(String advertiseId) {
this.advertiseId = advertiseId;
}
public Integer getWeight() {
return weight;
}
public void setWeight(Integer weight) {
this.weight = weight;
}
public WeightCategory() {
super();
}
public WeightCategory(String advertiseId, Integer weight) {
super();
this.advertiseId = advertiseId;
this.weight = weight;
}
}