修正用纸统计 useCount 口径:仅厕位模式(runl_mode=0)厕位行累计,对齐老代码意图并消除其分支不一致 bug
This commit is contained in:
@@ -755,7 +755,7 @@
|
||||
- 入参:`districtId`(必填正整数)、`startDate`/`endDate`(必填 yyyy-MM-dd,startDate≤endDate≤今天)、
|
||||
`positionMode`(position=仅厕位/wall=仅厕墙,只作用于 ES 换纸卷数口径)、`deviceType`(0/1)、`buildingId`、`floor`、`toiletId`。
|
||||
- 聚合维度 gender(0男1女2母婴3残卫4第三5其他99未知):
|
||||
`paperLengthM`=Σpaper_length/100(米,3 位小数)、`useCount`=Σuse_count(厕墙行恒 0 直接求和)、
|
||||
`paperLengthM`=Σpaper_length/100(米,3 位小数)、`useCount`=Σuse_count(仅厕位模式 runl_mode=0 的厕位行累计,厕墙行恒 0)、
|
||||
`deviceDayCount`=按日 distinct 厕位/厕数之和(老系统 perPositionsCount,输出改名)、
|
||||
`perUseLengthM`=paperLengthM/useCount(useCount=0 为 null);另输出按日明细(date/gender/paperLengthM/useCount/deviceDayCount)。
|
||||
- 换纸卷数 `rfidCount`(ES):读 `district_strategy.rfid_use_flag`(行 id=站点 id)——
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
(实现为左闭右开 `[start, end+1)` 避免秒精度丢行);可选 `building_id/floor/toilet_id/device_type` 精确匹配。
|
||||
- 聚合维度 `gender`(gender 为 null 的行跳过,老 :178-180):
|
||||
- `paperLengthM` = Σpaper_length / 100(paper_length 单位厘米,输出米,3 位小数);
|
||||
- `useCount` = Σuse_count(老代码对厕位/厕墙、runl_mode 有多个分支,但厕墙行 use_count 恒 0,
|
||||
等价于直接求和——老 :188-203 分支差异不影响结果);
|
||||
- `useCount` = Σuse_count(**仅 position_id>0 且 runl_mode=0 的厕位模式行累计**,厕墙行恒 0;
|
||||
这是老 :200-203、:220-222 分支的意图——老 :188 的日分组已存在分支漏判 runlMode,按意图统一);
|
||||
- `deviceDayCount` = 按日 distinct 厕位/厕数之和(老 :190-192、:249:positionSet 存
|
||||
`p_{positionId}`(厕位行)与 `t_{toiletId}`(厕墙行),每天取 set size 再累加)。
|
||||
老出参字段名 perPositionsCount 注释有误,本工具改名 deviceDayCount);
|
||||
@@ -91,7 +91,7 @@
|
||||
| rfid 去重实现 | count+分页拉全量文档,内存 Set 去重 | terms 聚合 size 10000 数 bucket | 不拉全量、低内存低耗时;上限 10000 对正常站点足够,超限部分不计(见 §2.2) |
|
||||
| district_strategy 不存在 / rfid_use_flag=null | NPE(:324-325) | 按"未使用 rfid"口径走 state=2 count | 该表与站点 1:1,缺失视为未启用 rfid;避免 500 |
|
||||
| Dictionary 字典缺失 | NPE 被外层 catch 吞掉,继续执行 | 抛 IllegalStateException | fail fast,避免权限/口径配置异常导致错误数据范围 |
|
||||
| use_count 聚合 | 厕位/厕墙/runl_mode 多分支 | 直接求和 | 厕墙行恒 0,分支差异不影响结果,简化口径 |
|
||||
| use_count 聚合 | 厕位/厕墙/runl_mode 多分支,:188 已存在日分组分支漏判 runlMode | 仅 position_id>0 且 runl_mode=0 行累计 | 统一为老代码新分组分支的意图口径(厕位模式使用人次),消除老代码分支不一致的 bug |
|
||||
| DB 时间过滤 | between 含两端(秒精度) | 左闭右开 [start, end+1) | 等价且避免 23:59:59 之后毫秒级数据丢行 |
|
||||
|
||||
## 6. 行级权限说明
|
||||
|
||||
+11
-3
@@ -233,13 +233,21 @@ public class DistrictPaperStatisticsTools implements ToolObject {
|
||||
int paperLength = row.getPaperLength() == null ? 0 : row.getPaperLength();
|
||||
int useCount = row.getUseCount() == null ? 0 : row.getUseCount();
|
||||
agg.paperCm += paperLength;
|
||||
agg.useCount += useCount;
|
||||
boolean positionRow = row.getPositionId() != null && row.getPositionId() > 0;
|
||||
// useCount 仅厕位模式(runl_mode=0)的厕位行累计,厕墙恒 0(老 :200-203/220-222 意图;
|
||||
// 老代码日分组已存在分支漏判 runlMode,此处按意图统一,见设计文档差异点)
|
||||
boolean countUse = positionRow && row.getRunlMode() != null && row.getRunlMode() == 0;
|
||||
if (countUse) {
|
||||
agg.useCount += useCount;
|
||||
}
|
||||
String day = DAY_FORMAT.format(row.getStatisticsTime().toInstant().atZone(SHANGHAI));
|
||||
DailyAgg dailyAgg = agg.daily.computeIfAbsent(day, key -> new DailyAgg());
|
||||
dailyAgg.paperCm += paperLength;
|
||||
dailyAgg.useCount += useCount;
|
||||
if (countUse) {
|
||||
dailyAgg.useCount += useCount;
|
||||
}
|
||||
// 厕位行按 positionId、厕墙行按 toiletId 计台(老 "p_"/"t_" positionSet)
|
||||
if (row.getPositionId() != null && row.getPositionId() > 0) {
|
||||
if (positionRow) {
|
||||
dailyAgg.positionKeys.add("p_" + row.getPositionId());
|
||||
} else {
|
||||
dailyAgg.positionKeys.add("t_" + row.getToiletId());
|
||||
|
||||
+22
@@ -116,6 +116,7 @@ class DistrictPaperStatisticsToolsTest {
|
||||
row.setToiletId(toiletId);
|
||||
row.setPaperLength(paperLengthCm);
|
||||
row.setUseCount(useCount);
|
||||
row.setRunlMode(0);
|
||||
return row;
|
||||
}
|
||||
|
||||
@@ -285,6 +286,27 @@ class DistrictPaperStatisticsToolsTest {
|
||||
anyLong(), anyLong(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void useCountOnlyAccumulatesForPositionModeRows() {
|
||||
mockDistrictAndDictionary();
|
||||
MonthlyStatistics wallModeRow = row(today.minusDays(1), 11L, 3L, 0, 100, 5);
|
||||
wallModeRow.setRunlMode(1);
|
||||
when(monthlyStatisticsMapper.selectList(any())).thenReturn(List.of(
|
||||
wallModeRow,
|
||||
row(today.minusDays(1), 11L, 3L, 0, 100, 2)));
|
||||
when(districtStrategyMapper.selectOne(any())).thenReturn(null);
|
||||
when(esGateway.countState2(anyString(), anyBoolean(), anyLong(), anyInt(), anyLong(), anyLong(),
|
||||
any(), any())).thenReturn(0L);
|
||||
|
||||
Map<String, Object> result = tools.districtPaperStatisticsQuery(9L, start, end, null, null, null, null, null);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> summary = (List<Map<String, Object>>) result.get("summaryByGender");
|
||||
// runl_mode=1 的厕位行 useCount 不计入,仅厕位模式(runl_mode=0)累计
|
||||
assertEquals(2L, summary.get(0).get("useCount"));
|
||||
assertEquals(2.0, summary.get(0).get("paperLengthM"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void useCountZeroYieldsNullPerUseLength() {
|
||||
mockDistrictAndDictionary();
|
||||
|
||||
Reference in New Issue
Block a user