ABT · 员工检索 · 一期设计

拼音模糊搜索

一套结构,姓名只是第一个字段

✅ 结论:不动主表,新建 4 张派生表;加字段只插 1 行配置 + 回填 1 次,查询代码不改。

只设计不改代码 · 全部数字为本地实测(10 万员工 × 5 字段造数)

0.25ms全拼/首字母(整串索引)
480ms同一件事走 token(慢 1900×)
≤250ms一期接口 P95 门禁
823MB10 万人 × 5 字段容量
4 表 · 15 个索引对象加字段不增索引
01 / 为什么现在搜不准

姓名字段零索引,检索全是前导通配

⚠️ 现状每输入一个字就扫一次表,且完全没有拼音能力——中文打错一个字就搜不到。

单表 LIKE
41~43 ms
两表 JOIN
183~200 ms
4 列 OR
342~395 ms
空结果全扫
248 ms
新方案·最坏
23.9 ms

时延随"命中率"剧烈波动,无法做 SLA;给姓名加索引也救不了——前导通配用不上 B-tree(实测 possible_keys=NULL)。

02 / 数据模型

1 张全局配置表 + 3 张租户派生表

✅ 主表零变更:user_info 不加列、不加索引,避开给每个租户 ALTER 111 列热表。

sys_search_field · 字段注册表(全局 1 张)
字段码 / 生成策略位掩码 / 权重 / 敏感标记 / 是否允许模糊 → 加字段=插 1 行
sys_search_doc · 整串层(按租户分表)
一个实体一个字段一个值:精确 / 前缀 / 乱序 / 后缀;多值用 value_seq 展开
sys_search_token · 分解层(按租户分表)
位置化读音 1:zhang · 汉字 1gram / 2gram → 全拼 / 首字母 / 混排 / 多音 / 同音
sys_search_sync · 回填断点(按租户分表)
水位线 / 断点 / 重试 / 对账,最终一致 ≤5 分钟

一句话原则:能整串直接比的放 doc,必须拆开才比得了的放 token。租户表进 copyTables(178 → 181),漏加会静默串租户,已列为静态断言。

03 / 查询链路

应用层解析 → 分级短路 → 分层排序

✅ 数据库只做等值 / 前缀,零特殊功能、零自定义函数。

归一化→ 读注册表(缓存60s)→ 字面档→ 全拼/首字母→ 包含/混排/多音→ 乱序/后缀→ 去重+排序→ 取前 20 条详情
输入走哪层实测
张三丰整串等值0.25 ms
张三(前缀 1.2 万人)整串前缀1.2~1.3 ms
三丰(中段)2-gram + 校验0.37 ms
zhangsanfeng全拼等值0.25 ms
zsf / zs首字母0.25 / 0.29 ms
shanchangle(多音)位置化 token0.7 ms
张丰三(乱序)字符升序等值0.31 ms
zhangsf(混排·最贵)位置化 token20~30 ms
无命中(8 档全跑)全档23.9 ms

硬规则:按字段拆多条 SQL(一条 field_code IN (...) 大 SQL 实测计划摇摆,坏计划 2.2 s);召回阶段不 JOIN(JOIN 后 361 ms vs 29.8 ms)。

04 / 排序 · 待拍板

「字真 > 拼音」保住了,
但「姓名优先」会打架

⚠️ 搜「保安」:部门 19,234 行 + 岗位 14,286 行排在前面,员工「张保安」掉到第 33,521 位。

部门「保安*」
17,311 人
岗位「保安队长」
14,286 行
员工「张保安」
1 行
口径 A · 紧密度优先
tier 在前:匹配最紧的永远最前,但姓名被大值域字段淹没(200 条内不可见)
口径 B · 权重前移 + 配额
weight 在前 + 每字段保底 ≥3 条:「张保安」进前 5,部门仍保留 ≥3 条

建议 B:硬要求由第一位 hit_class 保证(两种口径都不变),模型与 SQL 不用改,只改 ORDER BY + 一层 Java 配额。

05 / 容量与代价

10 万人 × 5 字段 = 823 MB

✅ 索引占 67%(553 MB)——体积主要花在索引,不是数据。

60.0万doc 行数 · 173 MB
424.0万token 行数 · 650 MB
48.4行/人 · 写放大
240s10 万人全量回填
规模doctoken合计
1 万 × 5 字段6.0 万42.4 万≈82 MB
10 万 × 5 字段(实测)60.0 万424.0 万823 MB
10 万 × 仅姓名(一期)10.0 万96.5 万≈186 MB
50 万 × 5 字段300 万2,120 万≈4.03 GB

省钱的结论:工号 / 手机号不生成 gram(0 token 行)。11 位手机号若做 gram,一人 21 行,是姓名的 2 倍多,纯浪费。

06 / 选型

为什么是 MySQL 派生表

✅ 唯一同时满足「租户物理分表 + 离线可落地 + 加字段零代码 + 零新组件」的路线。

维度现状 LIKE主表加列本方案ES/Meili
拼音/首字母/多音无可可需自建
字真 > 拼音分层无5 档8 档·字段中立靠 boost
租户物理分表天然每租户 ALTER新表入清单需路由
离线可落地是是零新组件需新运维面
加字段成本—加列+DDL1 行配置+回填改 mapping
实测时延41~395 ms未测0.25~30 ms5~20 ms

甲方原稿的分层思想被完整继承(应用层生成派生值、库只做等值/前缀、CASE 分层),落地形态按 abt 的租户分表改造;它的「3 表 7 索引」在此变成「4 表 15 个索引对象」,差异来自注册表、断点表、幂等唯一键与 2 个整串读音索引。

07 / 冗余量 · 甲方硬要求

加一个字段,到底要改什么

✅ 已接入的源表:注册表插 1 行 + 回填 1 次,代码 0 行;索引对象 15 → 15 不变。

字段策略token/人改动
姓名(一期)精确+前缀+包含+全拼+首字母+乱序9.65—
工号 / 手机号精确+前缀(手机再加后缀)0插 1 行 + 回填
部门(多值)精确+前缀+包含+全拼+首字母28.04插 1 行 + 1 个适配器
岗位精确+前缀+包含4.71插 1 行 + 回填
标签(多值)精确+包含—插 1 行 + 1 个适配器

必须明示的边界:「零代码」只对已接入的源表成立;第一次接一张新表,必然要写 1 个约 20 行的取值适配器。部门这类值域小的字段,二期建议改「实体维」(280 万行 → 2.8 万行,51~85 ms → 0.3 ms)。

08 / 一致性

异步水位线扫描,≤5 分钟最终一致

✅ 零侵入业务写路径:触发器方案不可行(MySQL 没有汉字→拼音能力),双写会拖慢人员保存。

每分钟扫 update_time→ 窗口回退 60s→ 按 entity 整条重算→ 幂等 upsert→ 断点续跑 / 失败退避
09 / 验收门禁

60 条可判定条目,门禁 4 条硬线

✅ 判定五档:PASS / FAIL / EXPECTED-FAIL / BLOCKED / KNOWN,退出码只看真 FAIL。

P95 ≤250ms接口 · P50 ≤80 ms
10/10同一 SQL 计划必须一致
0除派生表外的 ALL 扫描
15→15加字段索引数不变

计划稳定性比时延更重要:时延会骗人(现状单字只要 0.25 ms,因为扫到 20 行就停)。「加字段不改代码」用动作证明:真加一个字段 → 代码 diff 为空、索引数不变、召回 SQL 指纹不变。

10 / 风险与排期

排期第一风险不是代码,是拼音依赖

⚠️ 仓库、离线仓库、现有工具库都没有拼音能力;自建小字典已被实测证伪(缺字导致全拼搜不到)。

G0 · 开工准入
pinyin4j 2.5.1(63 KB、零传递依赖)需能拉取 + mvn -o 离线可复现;不过 → 一期整体 BLOCKED,排期 +1~3 天
静默故障两类
①租户清单漏加 → 跨租户串数据(不报错)②补建表后没回填 → 搜出 0 结果(不报错)。都靠静态断言 + 对账兜住
容量前提
buffer pool 需 ≥ 索引体积 ×1.5(10 万×5 字段 → ≥1.5 GB),否则性能门禁记 BLOCKED 而非 FAIL
分期
G0 → 一期(姓名全形态)→ 二期(工号/手机/部门岗位)→ 三期(标签/新源表)
11 / 待决策 · 5 条

需要拍板的只有 5 件

未拍板前按「建议」推进,验收侧记 KNOWN 不记 FAIL;拍板后只切一处开关,不返工。

D1排序键:紧密度优先还是权重优先

A:tier 在前 → 「张保安」第 33,521 位,200 条内不可见。B:weight 前移 + 每字段保底 ≥3 条 → 进前 5。

建议 B(模型与 SQL 不用改,只改 ORDER BY + 配额)|甲方 + 产品

D2总数要不要精确

精确 COUNT 实测 0.8 ms ~ 2.2 s(看优化器),不可承诺;探测 0.8~1.2 ms。

建议 ≤200 精确 / >200 显示「200+」|产品 + 甲方

D3手机号:能否模糊 + 派生表怎么存

开放模糊:一人 +21 行 token、10 万人 +338 MB,且开「猜号」通道。存明文需访问控制与审计,存摘要则排障变难。

建议不开放模糊 + 存明码 + 访问控制/审计|安全 + 甲方(不拍板二期不能开工)

D4拼音依赖准入(G0)

构建机能否取到 jar / 私服能否上传?自建字典已证伪。

建议开工前由运维确认,G0 不过即 BLOCKED|运维 + 甲方

D5离职是否可搜 + 新鲜度怎么判

仅在职可搜;一致性 5 分钟为门禁,组织改名 fan-out 10 分钟、时间戳兜底 24 小时作为 KNOWN 宽限。

建议如上,需业务签字|业务(HR)+ 甲方

12 / 下一步

拍完 5 条,一期即可开工

✅ 设计已闭合:模型、SQL、容量、验收、风险都有实测数字支撑;唯一外部依赖是 G0。

本报告只做设计,未改任何代码、未建分支、未提交。数字均为本地实测(10 万员工 × 5 字段造数),非估算。

员工拼音模糊搜索 · 一期设计设计稿 · 待拍板