Elmar 排行问题 vs trajectory-calibrator
对照:
jetwave-app-server/doc/Elmar-Ranking-Issue-Analysis-Report.md
结论日期:2026-08-28
问题:双计是不是校准程序把ok留下、又写了一条updated?
结论(先看这个)
不是校准程序「一条会话写出两条」的问题。
报告 Issue 2.3 的 Root Cause B(Calibration Pair Not Deactivated)不成立。ok / updated 是同一条 source_id 上的状态标签,不是新旧两条记录。
双计更像是:设备/上传侧同一航次进了两条 history(不同 id)→ 校准各写一行 → 排行 SQL 两条都 SUM。
时区 / 月周榜差异与校准程序无关。
报告三件事分别是谁的问题
| 报告条目 | 是不是校准程序 | 真正归属 |
|---|---|---|
| 2.1 月榜高、周榜低/消失 | 否 | 产品/UX。8/1–14 猛骑,15–26 停了 12 天,周榜周一清零 |
| 2.2 周日进不了本周周榜 | 否 | App 排行接口写死 Asia/Shanghai 算本周一(AppBusinessOtherServiceImpl.resolveStartDay)。校准明确 不改 run_time |
| 2.3 近秒级成对记录、里程虚高 | 不是 B | A 更可能:重复上传 / history 未去重。排行 SUM 两条都算 |
校准程序实际怎么写库
trajectory-calibrator/calibrate_trajectory.py:
- 原表
surf_motion_trajectory_history永不改 - 校准表
surf_motion_trajectory_calibrated:UNIQUE KEY uk_source_id (source_id) - 写入是
INSERT … ON DUPLICATE KEY UPDATE,一条 history 永远对应一行校准 - 重跑只会覆盖同一行的字段和
calibration_status,不会再插一行
ok vs updated 含义(build_calibrated_row):
| status | 含义 |
|---|---|
ok |
航时/航程已与 JSON 一致,没改数字 |
updated |
航时或航程按轨迹 JSON 改过(纠错,不是新会话) |
review_needed |
异常会话,notes 里 exclude_from_ranking=true |
所以「id 48424 (ok) + id 48423 (updated)」是两张不同的 history(两个 source_id),各自校准后一个碰巧没改、一个改过。Aug 4 / Aug 9 还有 两条都是 updated,更不可能是「旧 ok 没删、新 updated 插进来」。
校准表自己的 id 是独立自增,不等于 source_id。报告里的 id 若是校准表主键,数字相邻只说明几乎同时写入,仍然是两条源记录。
排行为什么会把一对都加上
SurfMotionTrajectoryHistoryMapper.xml:
WHERE c.deleted = 0
AND c.calibration_status IN ('ok', 'updated')
GROUP BY c.play_user_id
-- SUM(c.sum_distance)
- 同时收
ok和updated是对的(否则改过数的合法航次进不了榜) - 没有按
object_key/ 时间窗去重 - 没有读
calibration_notes.exclude_from_ranking(只有review_needed会被 status 挡掉)
一对记录时间差 2–91 秒、里程接近但不等(19.13 vs 17.44),符合「同一次骑行上传两次、JSON 略有出入」而不是「同一 source 校准分身」。
校准程序有没有责任
| 有 | 没有 |
|---|---|
不做近重复会话检测(同用户、run_time 数秒内、里程接近)并标 review_needed / exclude_from_ranking |
不会为一次校准插第二行 |
排行侧也没消费 exclude_from_ranking |
不会把周日划错周(run_time 原样保留) |
若某条 updated 把航程校准得更大,那是纠错,不是双计根因 |
不会改周榜时区 |
虚高的主因是 两条源记录都被 SUM,不是校准把一条变成两条。
建议核验(P0,先定罪再改)
对报告里每一对,查校准表 + history:
SELECT c.id, c.source_id, c.calibration_status, c.run_time, c.sum_distance,
c.object_key, h.object_key AS hist_key, h.add_time
FROM surf_motion_trajectory_calibrated c
JOIN surf_motion_trajectory_history h ON h.id = c.source_id
WHERE c.id IN (48423, 48424, 48429, 48431, 48872, 48800, 48995, 48994,
49325, 49322, 52547, 52579, 52661, 52670)
OR c.source_id IN (48423, 48424, 48429, 48431, 48872, 48800, 48995, 48994,
49325, 49322, 52547, 52579, 52661, 52670)
ORDER BY c.run_time, c.id;
判定:
- 两个不同
source_id,object_key相同或几乎相同 → 重复上传,修 App/入库去重,校准不用为 B 改写库模型 - 同一个
source_id两行 → 才是校准/表约束坏了(与当前 UNIQUE 设计矛盾,需先查库) - 一对一个
ok一个updated且source_id不同 → 仍是两条航次,不是校准分身
修复落点:history 入库去重(object_key 或 user+run_time 秒级窗口);排行可临时对近重复只留一条。校准侧可选:近重复标 review_needed。时区改 resolveStartDay,不要改校准写 run_time。