# recommend-server 项目须知

## 提交规则（最重要）

以下文件/目录是**本地调试/同步用**，**不要 git add 进任何业务 PR**：

- `recommend-server-service/src/main/resources/application-dev.yml`
  - 用户本地会把 eureka / redis hostName / apollo meta 改成自己的调试地址
  - 看到这个文件有 diff 时，**默认跳过它**（用户会自己处理）
- `apollo/` 目录（如 `apollo/rank.score.merge.weightv564.json` 等）
  - Git untracked，是 Apollo 后台配置的本地参考副本
  - 改这个文件**不会**自动同步到 Apollo 后台，运维要单独操作
  - **修改 Apollo JSON 永远不要 commit**
- `docs/` 目录、`实验配置/` 目录 — 本地资料，同上

`git add` 时手动列文件名，**不要用 `git add -A` 或 `git add .`**，避免把这些误带进去。

## 召回 / 排序架构

- **召回是公共池**：`RecallService.getStrategies()` 给所有用户挂载一组召回策略，并发跑 Redis 拿候选视频写入候选池
- **Rank 实验各挑各的**：每个 `RankStrategy4RegionMergeModelVxxx` 在 `mergeAndRankRovRecall()` 里通过 `RecallUtils.extractRecall(weight, param, PUSH_FROM/FORM, ...)` 按 `PUSH_FROM` 字符串挑想要的召回路
- **推论**：往 `RecallService` 加新召回**不会自动**进任何 rank 实验，必须同时改对应 rank 类的 `extractRecall` 调用才能生效
- **实验门控的两种模式**：
  - 加法门（主流）：`if (isHitXxxExp) strategies.add(...)` — 命中实验才挂载（842/568 用此模式）
  - 减法门（V564 新增）：`if (isHit564Exp) { strategies.add(...); strategies.removeIf(...) }` — 命中实验时挂新召回 + 剔除该实验不要的召回，省 Redis 调用
- **`judgeHitExp` 用 `rootSessionId` 分桶**：同一用户同一会话里要么始终命中要么始终不命中，召回/排序天然对齐

## 命名陷阱

- `PUSH_FORM`（拼错的，6+ 处）vs `PUSH_FROM`（正确，3 处）在 recall strategy 里并存
  - 加新策略时**用 `PUSH_FROM`**，别复制旧的拼错版本
  - 写过滤逻辑时**别用 `pushFrom()` 字符串过滤**，改用 `getClass().getSimpleName()`，绕开这个不一致
- 新建 RecallStrategy 时只要 `@Component implements RecallStrategy`，Spring 会自动按 `getClass().getSimpleName()` 注册到 `RecallService` 的 `strategyMap`，然后再去 `getStrategies()` 里 `add` 一行就生效

## Apollo 配置

- 文件名约定：`apollo/rank.score.merge.weightv{NNN}.json` 对应 rank 类的 `@ApolloJsonValue("${rank.score.merge.weightv{NNN}:}")`
- Key 命名约定：`xxxRov` / `xxxRos` / `xxxStr` 等，与 `mergeWeight.getOrDefault("xxx", 默认值)` 一致
- **改了 rank 类的 `extractRecall` 列表后，Apollo JSON 要同步清理废弃 key**（不会报错，但是死配置）
- 代码里 `getOrDefault(key, 默认值)` 提供兜底，所以 Apollo 没配也能跑

## V564 实验当前状态（2026-05-20 改动后）

- **Base 是 V563**（DNN 打分 `feeds_score_config_dnn_20260407.conf` + cn/dn 特征 + `userNetworkSeqFeature`），不是 V569
- 相比 V563：
  - **召回侧**：剔除 9 路（5 路特殊旧召回 via `extractOldSpecialRecall` + v1 + priori_province 系列 3 路），新增 `province_rovn`
  - **排序侧**：`provinceRov:5` 权重默认值（可在 Apollo JSON 覆盖）
- 召回侧的剔除通过 `RecallService.java` 里 `if (isHit564Exp)` 块的 `removeIf` 实现，要回滚整块删除即可
- 注意：V564 历史上曾经是 V569（XGB 系）的拷贝，2026-05-20 改为 V563 (DNN 系) 拷贝。如果以后看到 V564 用 XGB 配置出问题，多半是同步问题
