4.5 KiB
4.5 KiB
search-engine-app(技术计划)
1. 计划目标
在 APP 场景实现确定性的“断点组合搜索器”,使用 DP + TopK 生成候选 layout 并选出最优解:
- 输入:
tokens[]、breakpoints[]、availableWidth、maxLines、lineMode - 过程:DP 状态转移 + TopK 维护(去重、排序、确定性 tie-break)
- 评分:调用
scoring-tiebreak(scoreLayout+buildTieKey) - 输出:
bestLayout(breaks/lines/wrappedText/meta)或返回 “无解/超长/宽度不可用” 的可解释原因(overflow-fallback 模块将统一处理最终语义)
2. 约束与确定性口径
2.1 确定性(必须)
同输入(含 configVersion/权重/词表/断点列表)必须同输出:
- DP 遍历顺序固定(pos 升序、linesUsed 升序)
- nextPos 枚举顺序固定(按
pos升序;最后补一个N结束边界) - TopK 的排序固定:
score降序;再按tieKey逐项比较(11 节);再按breaks字典序(11.0A) - 去重固定:同
breaks序列只保留最优(score 更大;若相同用 tieKey)
2.2 复杂度(必须可控)
遵循文档 9.3 建议:
- 默认
TopK=10 - 默认
maxLines<=3(或 4) - 超长输入触发
TOO_LONG:TC>60 grapheme 或 EN>30 words(首版写死,后续 configVersion 管理)
3. DP + TopK 设计(对应文档 9.1)
3.1 状态定义
令 N=tokens.length,token 边界为 pos in [0..N]:
dp[pos][linesUsed] = TopK partial layouts ending at token boundary pos- partial layout 至少包含:
pos:当前结束位置breaks: number[]:已选择的断点序列(升序)lines: LineInfo[]:已生成的行信息(start/end/text/width/tokenCount/charCount)score: number+tieKey: number[](由 scoring-tiebreak 构造)
3.2 转移(生成下一行)
从状态 (pos, linesUsed) 选择 nextPos 生成新行区间 [pos..nextPos):
- nextPos 取值来自
breakpoints中b.pos且b.pos > pos,并按pos升序枚举 - 必须额外允许
nextPos = N(结束边界) - 每次转移需:
- 构造 lineText:使用
core-contract/joinTokens - 测量 lineWidth:优先使用
width-measurement/measureSliceWidthCached(切片缓存),若不可用返回WIDTH_UNKNOWN - 应用硬约束过滤(见 3.3)
- 计算新 layout 的评分与 tieKey(调用 scoring-tiebreak)
- 插入
dp[nextPos][linesUsed+1]并维护 TopK(去重、排序)
- 构造 lineText:使用
3.3 硬约束(本模块先落地最小集)
为了让 DP 行为稳定且可解释,首版在搜索层执行以下硬约束(其余放到评分):
- H1 不超宽:若 lineWidth 可用且
lineWidth > availableWidth,该转移无效 - H5 最大行数:
linesUsed+1 <= maxLines - 禁止空行:
nextPos > pos(区间非空) - TC 禁止行首标点(H6):
- 若
lang=TC且pos>0且tokens[pos]属于tcPunctuations,则该断点不可用(跳过)
- 若
说明:protectedPhrases 的“span 内断点剔除”属于候选断点优化(可选),首版不在搜索层做剔除,依赖 scoring 的强惩罚淘汰(文档 6.2A / 10.2A)。
3.4 结束条件与 lineMode
- 正常结束:到达
pos=N lineMode=AUTO:- 从
dp[N][1..maxLines]里选最优
- 从
lineMode=FIXED:- 优先从
dp[N][==maxLines]里选最优 - 若无解:返回 “无解” 的原因与必要 meta(由 overflow-fallback 统一降级链路与打点)
- 优先从
4. 代码落位(客户端)
建议目录:
client/src/features/textWrap/searchApp/types.tsdpTopK.ts(DP 主流程 + TopK 维护)topK.ts(去重、插入、排序、截断)constraints.ts(H1/H6/TOO_LONG 判定)index.ts__tests__/searchApp.test.ts
5. 测试计划(Vitest)
- 确定性:同输入运行 3 次输出完全一致(breaks/lines/wrappedText)
- TopK 去重:构造两条路径得到相同 breaks,断言只保留一个且为最优
- lineMode=FIXED:有解时必须返回刚好
maxLines;无解时返回 reason(例如NO_CANDIDATE) - TC 行首标点:构造 tokens 在断点后行首为
,,断言该转移被禁止 - TOO_LONG:TC>60 或 EN>30 时直接返回
TOO_LONG
6. 完成定义(DoD)
- DP+TopK 可运行,且确定性通过单测
- 使用
scoring-tiebreak进行评分与 tieKey 裁决 - 搜索层硬约束最小集落地(H1/H6/空行/maxLines)
- 无解/超长/宽度不可用时返回明确 reason(不直接在本模块做最终 overflow)