phase 5 part 5: cs algorithms, network-os, web-security topics with tested examples; all 43 stacks pass --strict
This commit is contained in:
1 parent
f695bbd7cc
commit
691f738f5f
22 files changed
+1955
-37
No files matched your search
@@ -0,0 +1,73 @@
|
||||
---
|
||||
id: cs.algorithms.scenario.business-algorithms
|
||||
title: 业务中的算法:热门问题 Top K、任务依赖排序、相似问题去重和缓存淘汰
|
||||
type: scenario
|
||||
domain: cs
|
||||
stack: [algorithms, redis, langgraph]
|
||||
tags: [Top K, 拓扑排序, 编辑距离, LRU, 去重, 复杂度]
|
||||
level: intermediate
|
||||
prerequisites: [cs.algorithms.complexity-patterns]
|
||||
est_hours: 1.5
|
||||
related: [cs.algorithms.interview]
|
||||
week: [16]
|
||||
---
|
||||
|
||||
# 业务中的算法:热门问题 Top K、任务依赖排序、相似问题去重和缓存淘汰
|
||||
|
||||
## 业务背景与问题
|
||||
|
||||
AI 客服运营后台需要:
|
||||
|
||||
1. 每小时展示用户最常问的 20 个问题(每小时几十万条消息);
|
||||
2. 知识库导入任务有依赖(先解析、再分块、再嵌入、再建索引),要按正确顺序执行,并发现配置中的循环依赖;
|
||||
3. 标注 Bad Case 时,大量问题只是错别字或说法略有不同,需要聚合去重;
|
||||
4. 进程内缓存最近查询的文档,内存有限。
|
||||
|
||||
## 约束
|
||||
|
||||
- 统计要在秒级完成。
|
||||
- 去重不能误合并意思不同的问题。
|
||||
|
||||
## 方案设计
|
||||
|
||||
1. **Top K**:先对问题文本做规范化(去空白、统一全半角),用哈希表计数,再用大小为 K 的堆取前 K,O(n log K);多实例时用 Redis 有序集合 `ZINCRBY` + `ZREVRANGE` 汇总。
|
||||
2. **任务依赖**:用拓扑排序得到执行顺序,检测到环时拒绝保存配置;同层没有依赖关系的任务可以并行。
|
||||
3. **相似去重**:先按规范化文本精确去重;再对候选对计算编辑距离(短文本)或向量相似度(语义),超过阈值的合并为一组,人工确认后生效。编辑距离是 O(mn),只对长度相近的候选对计算,避免 O(n²) 两两比较全部。
|
||||
4. **缓存**:LRU 淘汰;Python 中可直接用 `functools.lru_cache` 或 `OrderedDict` 实现。
|
||||
|
||||
## 关键代码
|
||||
|
||||
```python
|
||||
from patterns import edit_distance, top_k_frequent, topo_order
|
||||
|
||||
hot = top_k_frequent((normalize(m.text) for m in messages), 20)
|
||||
|
||||
order = topo_order({"index": ["embed"], "embed": ["chunk"], "chunk": ["parse"]})
|
||||
if order is None:
|
||||
raise ValueError("任务配置存在循环依赖")
|
||||
|
||||
def similar(a: str, b: str) -> bool:
|
||||
if abs(len(a) - len(b)) > 2: # 先用长度剪枝
|
||||
return False
|
||||
return edit_distance(a, b) <= max(1, len(a) // 10)
|
||||
```
|
||||
|
||||
完整实现和测试:[examples/patterns](../examples/patterns/)。
|
||||
|
||||
## 取舍
|
||||
|
||||
| 选择 | 优点 | 缺点 |
|
||||
| --- | --- | --- |
|
||||
| **精确计数 + 堆(本方案)** | 结果准确 | 内存随不同问题数增长 |
|
||||
| 近似算法(Count-Min Sketch 等) | 内存固定 | 有误差 |
|
||||
| 编辑距离去重 | 适合错别字 | 识别不了同义改写,需要配合向量相似度 |
|
||||
|
||||
## 易错点
|
||||
|
||||
- 没有规范化就计数,同一问题被拆成多个。
|
||||
- 对全部问题两两计算相似度,O(n²) 跑不完。
|
||||
- 去重阈值过松,把“退货”和“退款”合并(它们的编辑距离只有 1,但业务含义不同)——相似度只是候选,需要人工确认或结合业务规则。
|
||||
|
||||
## 面试怎么讲
|
||||
|
||||
> “运营后台的热门问题,我先做文本规范化,用哈希表计数加大小为 K 的堆取 Top K,复杂度 O(n log K),多实例用 Redis 有序集合汇总。导入任务的依赖用拓扑排序确定顺序并检测环。Bad Case 去重先精确去重,再按长度剪枝后算编辑距离,阈值只产生候选,避免把‘退货’和‘退款’这种只差一个字但意思不同的问题合并。”
|
||||
Reference in new issue
Block a user