fix(server): SYB 结构过滤合并为一条,要求同时包含 "-" 和 "#" #286

Open
opened 2026-09-15 17:07:04 +08:00 by ila · 0 comments
Owner

原始需求

  • 来源:用户于 2026-09-15 提出。
  • 原话:「线上服务的 syb 商品过滤的结构过滤要改成一条:同时包含 "-" 和 "#"」。

当前行为

syb_product_filter 的 kind='char' 有两行(- 和 #),RuleSet.Match 逐条 strings.Contains,命中即返回——是或关系:

for i, x := range r.Chars {
    if strings.Contains(n, x.NormalizedKeyword) { return &r.Chars[i] }
}

线上最近一次完整同步(syb_sync_run id=541,2026-09-15 16:06):

规则 命中
- 384
# 148
char_filter_skipped 532 = 384 + 148

因为 - 先判且命中即返回,那 148 条是含 # 但不含 - 的。

目标行为

结构过滤合并为一条,语义为「variationSku 同时包含 - 和 # 才过滤」。

variationSku 现在 改后
含 - 不含 # 过滤 放行
含 # 不含 - 过滤(148 条/次) 放行
两者都含 过滤 过滤
两者都不含 放行 放行

[必须] 已向用户说明影响:每次同步至少多放行 148 条(含 # 不含 - 那批),再加上 384 条里只含 - 的部分——后者无法从现有计数推出,因为被过滤的明细不入库。按每小时一次同步计,是每天数千条的量级变化。用户于 2026-09-15 确认按此实施。

方案

保留 kind='char',改为一行,keyword 存需要同时具备的字符集合(-#),匹配改为「集合中每个字符都必须出现」。

  • RuleSet.Match 对 char 规则由 strings.Contains(n, keyword) 改为「keyword 的每个 rune 都 strings.ContainsRune(n, r)」。
  • keyword 对 char 类型的含义由「子串」变为「必需字符集合」,需在代码注释与界面文案中写清。keyword 类型不变,仍是子串匹配。
  • 新增 version-local 迁移:删除既有两行 char,写入一行 -#;沿用 #269 的 FirstOrCreate/幂等写法,重复执行不产生重复行。
  • 结构过滤仍然不可新增、不可删除,仅可停用(#269 既有约束不变)。
  • Web「结构过滤」区块文案改为说明「同时包含这些字符才过滤」。

非目标

  • 不改关键词过滤(kind='keyword')的匹配方式。
  • 不改命中计数与回写机制。
  • 不回补历史数据:过滤只影响后续同步,已入库明细不受影响,被过滤过的明细也不会追溯补入。

设计证据

后端规则变更 + 现有界面的文案调整。文案改动属于显示文案,执行最小界面检查。

验收

  • 同时含 - 和 # 的 variationSku 被过滤。
  • 只含 - 的放行。
  • 只含 # 的放行。
  • 两者都不含的放行。
  • 空 variationSku 不过滤(#269 既有规则不变)。
  • 关键词过滤行为不变。
  • 迁移在已有数据库上执行后,kind='char' 恰好一行且为 -#;重复执行不产生重复行。
  • 该行仍不可新增、不可删除,可停用。

验证

go build ./... 与 go test ./app/goauto/sybproductfilter/... ./app/goauto/sybimport/...;Web 构建。

风险

  • 过滤量显著下降,档口商品会大量重新入库。若与预期不符需尽快回退。
  • 迁移删除既有两行 char:这两行的 last_hit_count 历史计数会丢失。回退方式为再写一条迁移恢复两行。

文档影响

结构过滤的判据属于业务规则,需更新对应 Wiki 页面中 #269 的描述。

## 原始需求 - 来源:用户于 2026-09-15 提出。 - 原话:「线上服务的 syb 商品过滤的结构过滤要改成一条:同时包含 "-" 和 "#"」。 ## 当前行为 `syb_product_filter` 的 `kind='char'` 有两行(`-` 和 `#`),`RuleSet.Match` 逐条 `strings.Contains`,命中即返回——是**或**关系: ```go for i, x := range r.Chars { if strings.Contains(n, x.NormalizedKeyword) { return &r.Chars[i] } } ``` 线上最近一次完整同步(`syb_sync_run` id=541,2026-09-15 16:06): | 规则 | 命中 | |---|---| | `-` | 384 | | `#` | 148 | | `char_filter_skipped` | 532 = 384 + 148 | 因为 `-` 先判且命中即返回,那 148 条是**含 `#` 但不含 `-`** 的。 ## 目标行为 结构过滤合并为**一条**,语义为「variationSku 同时包含 `-` 和 `#` 才过滤」。 | variationSku | 现在 | 改后 | |---|---|---| | 含 `-` 不含 `#` | 过滤 | **放行** | | 含 `#` 不含 `-` | 过滤(148 条/次) | **放行** | | 两者都含 | 过滤 | 过滤 | | 两者都不含 | 放行 | 放行 | `[必须]` 已向用户说明影响:每次同步**至少多放行 148 条**(含 `#` 不含 `-` 那批),再加上 384 条里只含 `-` 的部分——后者无法从现有计数推出,因为被过滤的明细不入库。按每小时一次同步计,是每天数千条的量级变化。用户于 2026-09-15 确认按此实施。 ## 方案 保留 `kind='char'`,改为**一行**,`keyword` 存需要同时具备的字符集合(`-#`),匹配改为「集合中每个字符都必须出现」。 - `RuleSet.Match` 对 `char` 规则由 `strings.Contains(n, keyword)` 改为「keyword 的每个 rune 都 `strings.ContainsRune(n, r)`」。 - `keyword` 对 `char` 类型的含义由「子串」变为「必需字符集合」,需在代码注释与界面文案中写清。`keyword` 类型不变,仍是子串匹配。 - 新增 version-local 迁移:删除既有两行 `char`,写入一行 `-#`;沿用 #269 的 `FirstOrCreate`/幂等写法,重复执行不产生重复行。 - 结构过滤仍然不可新增、不可删除,仅可停用(#269 既有约束不变)。 - Web「结构过滤」区块文案改为说明「同时包含这些字符才过滤」。 ## 非目标 - 不改关键词过滤(`kind='keyword'`)的匹配方式。 - 不改命中计数与回写机制。 - 不回补历史数据:过滤只影响后续同步,已入库明细不受影响,被过滤过的明细也不会追溯补入。 ## 设计证据 后端规则变更 + 现有界面的文案调整。文案改动属于显示文案,执行最小界面检查。 ## 验收 - [ ] 同时含 `-` 和 `#` 的 variationSku 被过滤。 - [ ] 只含 `-` 的放行。 - [ ] 只含 `#` 的放行。 - [ ] 两者都不含的放行。 - [ ] 空 variationSku 不过滤(#269 既有规则不变)。 - [ ] 关键词过滤行为不变。 - [ ] 迁移在已有数据库上执行后,`kind='char'` 恰好一行且为 `-#`;重复执行不产生重复行。 - [ ] 该行仍不可新增、不可删除,可停用。 ## 验证 `go build ./...` 与 `go test ./app/goauto/sybproductfilter/... ./app/goauto/sybimport/...`;Web 构建。 ## 风险 - 过滤量显著下降,档口商品会大量重新入库。若与预期不符需尽快回退。 - 迁移删除既有两行 `char`:这两行的 `last_hit_count` 历史计数会丢失。回退方式为再写一条迁移恢复两行。 ## 文档影响 结构过滤的判据属于业务规则,需更新对应 Wiki 页面中 #269 的描述。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/goauto#286