zxl
2025-11-10 cb415813de667096290d6bd0f924f5b523104117
ycl-server/src/main/java/com/ycl/platform/service/impl/DataCenterServiceImpl.java
@@ -1723,6 +1723,7 @@
     */
    @Override
    public Result videoOneMachineDocumentQualified(DataCenterQuery params) {
        long startTime = System.currentTimeMillis();
        List<String> likeFileds = Arrays.asList("ip.showValue", "name.showValue", "serialNumber.showValue");
        SysDept sysDept = getSysDeptByLoginUser();
        List<Criteria> andCriteria;
@@ -1781,99 +1782,131 @@
        long total = mongoTemplate.count(query, MonitorQualifyResult.class);
        MongoUtil.setPage(query, params, TIME_FIELD);
        List<MonitorQualifyResult> resultList = mongoTemplate.find(query, MonitorQualifyResult.class);
        List<MonitorQualifyResultVO> resultVOS = new ArrayList<>();
        for (MonitorQualifyResult result : resultList) {
            MonitorQualifyResultVO vo = MonitorQualifyResult.getVO(result);
            resultVOS.add(vo);
        }
        // 统计数量
        long endTime =  System.currentTimeMillis();
        // 统计数量(改造后:一次聚合返回所有结果)
        long startTime2 = System.currentTimeMillis();
        MongoDatabase database = mongoTemplate.getDb();
        MongoCollection<Document> collection = database.getCollection("uy_monitor_qualify");
        Document areDocument = null;
// 1. 构建公共过滤条件(deviceNo前缀 + tag过滤)
        List<Document> commonFilters = new ArrayList<>(2);
        if (areaDeptEnum != null) {
            String areaCodePrefix = areaDeptEnum.getCode();
            areDocument = new Document("deviceNo", new Document("$regex", "^" + areaCodePrefix));
            commonFilters.add(new Document("deviceNo", new Document("$regex", "^" + areaCodePrefix)));
        }
        //总数
        List<Document> dList1 = new ArrayList<>(2);
        if (areDocument != null){
            dList1.add(areDocument);
        }
        setTag(params, dList1);
        Document totalFilter = new Document("$and", dList1);
        //list1
        setTag(params, commonFilters); // 添加tag过滤条件
        Document commonFilter = commonFilters.isEmpty() ? new Document() : new Document("$and", commonFilters);
        //合格数
        List<Document> dList2 = new ArrayList<>(2);
        if (areDocument != null){
            dList2.add(areDocument);
        }
        dList2.add(new Document("serialNumber.error", Boolean.FALSE));
        dList2.add(new Document("name.error", Boolean.FALSE));
        dList2.add(new Document("civilCode.error", Boolean.FALSE));
        dList2.add(new Document("integrated_device.error", Boolean.FALSE));
        dList2.add(new Document("jkdwlx.error", Boolean.FALSE));
        dList2.add(new Document("latitude.error", Boolean.FALSE));
        dList2.add(new Document("longitude.error", Boolean.FALSE));
        dList2.add(new Document("macdz.error", Boolean.FALSE));
        dList2.add(new Document("name.error", Boolean.FALSE));
        dList2.add(new Document("sbzt.error", Boolean.FALSE));
        dList2.add(new Document("sxjcjqy.error", Boolean.FALSE));
        dList2.add(new Document("sxjgnlx.error", Boolean.FALSE));
        setTag(params, dList2);
        Document qualifyFilter = new Document("$and", dList2);
        //不合格数
        List<Document> dList3 = new ArrayList<>(2);
        if (areDocument != null){
            dList3.add(areDocument);
        }
        setTag(params, dList3);
        List<Document> errorConditions = new ArrayList<>();
        errorConditions.add(new Document("serialNumber.error", new Document("$eq", Boolean.TRUE)));
        errorConditions.add(new Document("name.error", new Document("$eq", Boolean.TRUE)));
        errorConditions.add(new Document("civilCode.error", new Document("$eq", Boolean.TRUE)));
        errorConditions.add(new Document("integrated_device.error", new Document("$eq", Boolean.TRUE)));
        errorConditions.add(new Document("jkdwlx.error", new Document("$eq", Boolean.TRUE)));
        errorConditions.add(new Document("latitude.error", new Document("$eq", Boolean.TRUE)));
        errorConditions.add(new Document("longitude.error", new Document("$eq", Boolean.TRUE)));
        errorConditions.add(new Document("macdz.error", new Document("$eq", Boolean.TRUE)));
        errorConditions.add(new Document("name.error", new Document("$eq", Boolean.TRUE)));
        errorConditions.add(new Document("sbzt.error", new Document("$eq", Boolean.TRUE)));
        errorConditions.add(new Document("sxjcjqy.error", new Document("$eq", Boolean.TRUE)));
        errorConditions.add(new Document("sxjgnlx.error", new Document("$eq", Boolean.TRUE)));
        Document errorFilter = new Document("$or", errorConditions);
        dList3.add(errorFilter);
        Document unQualifyFilter = new Document("$and", dList3);
// 2. 构建合格/不合格的error条件(复用原逻辑,去重name.error)
// 合格条件:所有error为false
        List<Document> qualifyErrorConditions = new ArrayList<>();
        qualifyErrorConditions.add(new Document("serialNumber.error", Boolean.FALSE));
        qualifyErrorConditions.add(new Document("name.error", Boolean.FALSE));
        qualifyErrorConditions.add(new Document("civilCode.error", Boolean.FALSE));
        qualifyErrorConditions.add(new Document("integrated_device.error", Boolean.FALSE));
        qualifyErrorConditions.add(new Document("jkdwlx.error", Boolean.FALSE));
        qualifyErrorConditions.add(new Document("latitude.error", Boolean.FALSE));
        qualifyErrorConditions.add(new Document("longitude.error", Boolean.FALSE));
        qualifyErrorConditions.add(new Document("macdz.error", Boolean.FALSE));
        qualifyErrorConditions.add(new Document("sbzt.error", Boolean.FALSE));
        qualifyErrorConditions.add(new Document("sxjcjqy.error", Boolean.FALSE));
        qualifyErrorConditions.add(new Document("sxjgnlx.error", Boolean.FALSE));
        Document qualifyFilter = new Document("$and", qualifyErrorConditions);
        List<Document> lists = Arrays.asList(totalFilter, qualifyFilter, unQualifyFilter);
        List<String> rList = lists.stream().map(filter -> {
            // 构建聚合管道
            List<Document> pipeline = Arrays.asList(
                    new Document("$match", filter),
                    // $group 去重
                    new Document("$group", new Document("_id", "$serialNumber.showValue")),
                    new Document("$count", "uniqueDeviceIds")
            );
            // 执行聚合查询并获取结果
            AggregateIterable<Document> result = collection.aggregate(pipeline);
            Integer uniqueDeviceIdCount = 0;
            for (Document doc : result) {
                uniqueDeviceIdCount = doc.getInteger("uniqueDeviceIds");
                break; // 不需要继续遍历,因为 $count 只会产生一个结果
            }
            return uniqueDeviceIdCount + "";
        }).collect(Collectors.toList());
// 不合格条件:至少一个error为true
        List<Document> unQualifyErrorConditions = new ArrayList<>();
        unQualifyErrorConditions.add(new Document("serialNumber.error", Boolean.TRUE));
        unQualifyErrorConditions.add(new Document("name.error", Boolean.TRUE));
        unQualifyErrorConditions.add(new Document("civilCode.error", Boolean.TRUE));
        unQualifyErrorConditions.add(new Document("integrated_device.error", Boolean.TRUE));
        unQualifyErrorConditions.add(new Document("jkdwlx.error", Boolean.TRUE));
        unQualifyErrorConditions.add(new Document("latitude.error", Boolean.TRUE));
        unQualifyErrorConditions.add(new Document("longitude.error", Boolean.TRUE));
        unQualifyErrorConditions.add(new Document("macdz.error", Boolean.TRUE));
        unQualifyErrorConditions.add(new Document("sbzt.error", Boolean.TRUE));
        unQualifyErrorConditions.add(new Document("sxjcjqy.error", Boolean.TRUE));
        unQualifyErrorConditions.add(new Document("sxjgnlx.error", Boolean.TRUE));
        Document unQualifyFilter = new Document("$or", unQualifyErrorConditions);
// 3. 构建一次聚合管道(用$facet合并三个统计维度)
        List<Document> pipeline = new ArrayList<>();
// 步骤1:先应用公共过滤条件(deviceNo + tag),减少后续处理数据量
        if (!commonFilters.isEmpty()) {
            pipeline.add(new Document("$match", commonFilter));
        }
// 步骤2:用$facet分面查询,同时计算总数、合格数、不合格数
        pipeline.add(new Document("$facet", new Document()
                // 总数:按serialNumber.showValue去重后计数
                .append("total", Arrays.asList(
                        new Document("$group", new Document("_id", "$serialNumber.showValue")),
                        new Document("$count", "uniqueDeviceIds")
                ))
                // 合格数:先过滤合格条件,再去重计数
                .append("qualify", Arrays.asList(
                        new Document("$match", qualifyFilter),
                        new Document("$group", new Document("_id", "$serialNumber.showValue")),
                        new Document("$count", "uniqueDeviceIds")
                ))
                // 不合格数:先过滤不合格条件,再去重计数
                .append("unQualify", Arrays.asList(
                        new Document("$match", unQualifyFilter),
                        new Document("$group", new Document("_id", "$serialNumber.showValue")),
                        new Document("$count", "uniqueDeviceIds")
                ))
        ));
//        Document explainResult = collection.aggregate(pipeline).explain();
//
//// 打印执行计划(日志或控制台输出)
//        log.info("聚合查询执行计划:{}", explainResult.toJson());
// 4. 执行聚合查询(仅一次数据库交互)
        AggregateIterable<Document> facetResult = collection.aggregate(pipeline).allowDiskUse(true);
        Document resultDoc = facetResult.iterator().next(); // $facet仅返回一个文档
// 5. 解析结果(处理空结果场景,默认计数为0)
        int totalCount = parseFacetCount(resultDoc, "total");
        int qualifyCount = parseFacetCount(resultDoc, "qualify");
        int unQualifyCount = parseFacetCount(resultDoc, "unQualify");
// 6. 组装rList(保持原格式不变,后续逻辑无需修改)
        List<String> rList = new ArrayList<>(Arrays.asList(
                String.valueOf(totalCount),
                String.valueOf(qualifyCount),
                String.valueOf(unQualifyCount)
        ));
// 原合格率计算逻辑不变
        BigDecimal onlineRate = BigDecimal.ZERO;
        if (!StringUtils.isEmpty(rList.get(0)) && !"0".equals(rList.get(0))) {
            onlineRate = new BigDecimal(rList.get(1)).divide(new BigDecimal(rList.get(0)), 3,RoundingMode.DOWN).multiply(new BigDecimal("100"));
        if (totalCount != 0) {
            onlineRate = new BigDecimal(qualifyCount)
                    .divide(new BigDecimal(totalCount), 3, RoundingMode.DOWN)
                    .multiply(new BigDecimal("100"));
        }
        rList.add(this.remove0(onlineRate));
        long endTime2 = System.currentTimeMillis();
        log.info("统计耗时:{} ms", (endTime2 - startTime2));
        rList.add(this.remove0(onlineRate));
        HashMap<String, Object> map = new HashMap<>();
        map.put("count", rList);
        map.put("list", resultVOS);
        return Result.ok().data(map).total(total);
    }
    private int parseFacetCount(Document resultDoc, String facetName) {
        List<Document> facetList = (List<Document>) resultDoc.get(facetName);
        if (facetList == null || facetList.isEmpty()) {
            return 0;
        }
        Document countDoc = facetList.get(0);
        return countDoc.getInteger("uniqueDeviceIds", 0);
    }
    /**
     * 视频:档案考核比
     * 档案留存总量:mongo存的所有去重后的档案