Redis中的bitMap生产运用
目录
redis中的bitMap生产运用
场景:系统可以在设备管理中对每个设备的每个预置位配置算法,在8.00到10.00这个时间段(一天可以有多个时间段:早上8-10,晚上5-6)中,每时每刻摄像头都要去检测图片,如果这时间段内没有出现交接班仪式(需要检查出两个人),在检测时间段结束后就发送报警,每天最多在检测时间段结束后报警一次。一共有四种识别场景:区别就在于图片检测的核心逻辑(交接班仪式这个地方)
思路:四种算法,大体逻辑流程一致,采用模板方法抽取公共内容,然后通过redis的bitMap标记 key(该设备+预置位+当前时间年月日+检测类型_检测开始时间_检测结束时间)是否需要报警,在检测时间结束后对这个key判断。
流程图
伪代码逻辑
定义抽象类AbstractCarryOutHandoverIAlarmDetectHandle
/**
* 未开展交接班抽象类:
* 1. 判断当前时间是否在巡检时间段里面 HashMap<HashMap<Integer,List<String>>, String> timeRangeList
* 2. 如果在时间段内,调用人员检测接口,获取人员数量,判断是否有人,如果有人,调用未带安全帽接口判断人数
* 3. 在巡检结束后
*/
@Slf4j
public abstract class AbstractCarryOutHandoverIAlarmDetectHandle {
private static BloomFilterFactory<String> bloomFilterFactory;
static {
bloomFilterFactory = new BloomFilterFactory<>((form, info)-> info.putString(form, Charsets.UTF_8), 1000000000, 0.000000001);
}
@Override
public void detect(AlarmDetectContentBO alarmDetectContentBO) {
String filePath = alarmDetectContentBO.getFilePath();
// 1. 存储redis key
this.saveRedisKey(alarmDetectContentBO);
String noPushKey = this.getNoPushKeyRedisKey(alarmDetectContentBO);
// 先检测图片中是否有人
JSONArray jsonArray = this.detectPeopleNum(filePath);
if(!jsonArray.isEmpty()){
// 图片中的人个数
int size = jsonArray.size();
// 2. 检测区域内有人员聚集(大于等于2人),则为开展了交接班。不产生报警。
if(size >= 2){
// 3.将key存入bitMap中,表示有交接班,不报警
this.coreBusiness(alarmDetectContentBO, jsonArray);
}
}
}
/**
* 各自实现类需要做不同的业务处理
* @param alarmDetectContentBO
* @param jsonArray
*/
protected void coreBusiness(AlarmDetectContentBO alarmDetectContentBO, JSONArray jsonArray){
// 默认的实现
this.saveBitMap(this.getNoPushKeyRedisKey(alarmDetectContentBO));
}
/**
* 通过算法减少hash碰撞
* @param noPushRedisKey
*/
private void saveBitMap(String noPushRedisKey){
Jedis jedis = RedisUtils.getJedis();
// 这里采用guava的布隆过来器来计算素组的下标,规避hash冲突问题
int[] offsetList = bloomFilterFactory.murmurHashOffset(noPushRedisKey);
for(int offset : offsetList){
jedis.setbit(noPushRedisKey, offset, true);
}
}
/**
* 判断key是否存在(是否需要报警:存在就不需要报警)
* @param noPushRedisKey
* @return
*/
public boolean keyIsTrue(String noPushRedisKey){
Jedis jedis = RedisUtils.getJedis();
int[] offsetList = bloomFilterFactory.murmurHashOffset(noPushRedisKey);
for(int offset : offsetList){
if(!jedis.getbit(noPushRedisKey, offset)){
return false;
}
}
return true;
}
/**
* 存储不推送的redis key,在后面的方法中需要使用
* @param alarmDetectContentBO
*/
private void saveRedisKey(AlarmDetectContentBO alarmDetectContentBO){
}
/**
* 存储该时间段是否需要推送消息的redis key
* 计算规则:设备id:预置位:算法类型
* @param alarmDetectContentBO
* @return
*/
protected String getRedisKey(AlarmDetectContentBO alarmDetectContentBO){
return null;
}
/**
* 返回人员检测对象信息
* @param filePath
* @return
*/
protected JSONArray detectPeopleNum(String filePath){
// 调用识别人的算法
return null;
}
/**
* 检测未带安全帽集合
* @param filePath
* @param rects
*/
protected List<xxxVo> detectHelmet(String filePath, JSONArray rects){
// 调用识别安全帽 算法
return null;
}
/**
* 根据检测时间获取redisKey
* key规则:设备id:预置位:当前时间年月日:检测类型_检测开始时间_检测结束时间
* @param alarmDetectContentBO
* @return
*/
private String getNoPushKeyRedisKey(AlarmDetectContentBO alarmDetectContentBO){
return null;
}
/**
* 交接结束操作:
*/
public void handoverEndTodo(AlarmDetectContentBO alarmDetectContentBO){
// 从redis中获取检测的key
String noPushRedisKey = RedisUtils.get(this.getRedisKey(alarmDetectContentBO));
// 1. 判断noPushRedisKey是否存在并且值为true
if (!this.keyIsTrue(noPushRedisKey)){
// 2. 需要报警:调用摄像头抓图并推送事件报警
// 3. 推送事件后将key存入bitMap中,因为同一天,同一时间段推送一次
this.saveBitMap(noPushRedisKey);
}
}
}