應用場景:
有時我們需要從一些列數據中根據權重隨機選取指定條數記錄出來,這裏需要權重、隨機,我們根據權重越大的,出現概率越大。例如廣告系統。
實現原理:
需求確認後在網上找了很多的資料,可惜沒有比較合適的方案,還有就是在下才疏學淺沒有搞明白他們的實現原理,下面和大家分享一種,有不合理之處還請大家指正。廢話少說,其實算法很簡單,如下:
落實到代碼:
@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;
}
}