Redis中的bitMap生产运用

redis中的bitMap生产运用

场景:系统可以在设备管理中对每个设备的每个预置位配置算法,在8.00到10.00这个时间段(一天可以有多个时间段:早上8-10,晚上5-6)中,每时每刻摄像头都要去检测图片,如果这时间段内没有出现交接班仪式(需要检查出两个人),在检测时间段结束后就发送报警,每天最多在检测时间段结束后报警一次。一共有四种识别场景:区别就在于图片检测的核心逻辑(交接班仪式这个地方)

思路:四种算法,大体逻辑流程一致,采用模板方法抽取公共内容,然后通过redisbitMap标记 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);
        }


    }
}
0%