refactor(search): 只展示 keyword 续接词,去掉 titles 段
产品决定:搜索建议只展示 ts_stat 高频词续接(如'美'→美国/美军/美国政府), 不要真实文章 id 提示(用户认为这种'文章#566871'是噪音,没连续性)。 改动: - SearchSuggestionsResponse 去 title,只剩 query + keywords - SearchService 只查 search_keywords,fallback 路径也只针对 keywords - Feed.vue: 删掉 suggestTitles 状态 + SuggestTitleOption 类型联合, renderSuggestion 简化成 '词' 标签 + 词文本 + 右侧 weight 数字 - 0011 迁移: 删 search_title_suggestions 表 + 3 索引 + trigger + 函数 (trigger 在每篇文章 INSERT/UPDATE 都会跑,删了能省掉无用性能损耗) - 删除: app/models/search_title_suggestion.py + backfill_search_suggestions.py 替换成: app/scripts/refresh_search_keywords.py(只跑一次词频刷新)
This commit is contained in:
59
README.md
59
README.md
@@ -54,6 +54,8 @@
|
||||
- 👤 **双角色鉴权**:JWT(access 60min + refresh 14d) + API Token(sha256,可撤销,给 Android / ingest 预留)
|
||||
- 📌 **收藏 + 关键词订阅**:用户级书签,服务端定时按关键词命中推送(预留 Telegram 通道)
|
||||
- 📊 **管理看板**:源健康度 / 翻译配额 / LLM 状态,全部可视化
|
||||
- 🔍 **智能搜索建议** *(新)*:`GET /api/v1/search/suggestions?q=prefix` 实时返回高频词续接词(输入"美国"→ ["美国", "美国政府", "美国签证"]);zhparser 中文分词 + GIN 数组索引,前端 debounce 250ms 自动补全
|
||||
后端用 zhparser 中文分词 + PG 全文搜索 + 候选词固化表,前端 debounce 250ms 自动补全
|
||||
- 🔄 **热加载**:源/提示词改了不用重启,worker 每天 00:30 重建 job
|
||||
- 🚀 **一键部署**:SSH 推公钥 + 一键 `git pull` 流程
|
||||
- 🔒 **安全默认**:bcrypt 密码、API Token 加密、SQL 注入免疫(SQLAlchemy 2.0 参数化)
|
||||
@@ -597,6 +599,63 @@ docker compose exec api alembic upgrade head
|
||||
每个任务独立 try/except,失败标 `*_status='failed'`,**不影响**其他任务。
|
||||
`enrichment_loop` 扫 `*_status` 是 `pending/failed/n/a` 的文章,自动重试 failed。
|
||||
|
||||
### 智能搜索建议(autocomplete)
|
||||
|
||||
搜索框输入前缀(如"美"),下拉弹出**高频词续接词**:
|
||||
- 输入"美" → ["美国", "美军", "美国政府", "美方", "美国队", ...]
|
||||
- 输入"美国" → ["美国", "美国政府", "美国签证", "美国军事", ...]
|
||||
- 输入"美国政" → ["美国政府"]
|
||||
|
||||
来源:`search_keywords` 表按 `prefix_keys @> ARRAY['前缀']` + `weight DESC` 查(ts_stat 从 articles.title_zh + body_zh_text + commentary 聚合的词频)。
|
||||
|
||||
**后端架构**:
|
||||
|
||||
| 组件 | 作用 | 更新时机 |
|
||||
|------|------|---------|
|
||||
| `search_keywords` | 存 ts_stat 词频(全文 + 评论) + prefix_keys 数组 | worker 每日 03:00 全量重建 + 启动时 10s 后跑一次 |
|
||||
| `articles.title_zh_tsv` | `GENERATED` 列 `to_tsvector('chinese_zh', title_zh)` + GIN 索引 | 写入自动维护(commit 11 TODO 顺手填了) |
|
||||
| `chinese_zh` text search config | zhparser 中文分词 + 简单词映射 | 0010 迁移一次建好 |
|
||||
| `_fallback_keywords` 实时 ts_stat | search_keywords 表空时,fallback 到实时 ts_stat(慢但能用) | 冷启动友好 |
|
||||
|
||||
**中文分词**(`zhparser`):
|
||||
|
||||
PG `simple` parser 对中文按整段当一个 token,`ts_stat` 词频聚合不出有意义的结果(整句算 1 个词)。
|
||||
装 `zhparser`(scws 字典)解决:Dockerfile 全源码编译(Alpine/Debian/PGDG 都没现成包),建 `chinese_zh` config。
|
||||
|
||||
**⚠️ 关键踩坑**: `ts_stat(query, 'a')` 第二参是 weights mask(只统计 A 权重位置),zhparser 不标 A 权重 → 静默 0 行。**用 `ts_stat(query text)` 单参**(等价 mask='abcd',聚合所有权重)。
|
||||
|
||||
**性能**:
|
||||
|
||||
- `prefix_keys text[]` + GIN 索引,`@> ARRAY['美']` 亚毫秒
|
||||
- 1545 篇文章 → `search_keywords` 33639 词,`ts_stat` 全量 88s,凌晨一次用户无感
|
||||
- 搜索建议 API 接口 P99 < 50ms
|
||||
|
||||
**冷启动**:
|
||||
|
||||
`search_keywords` 表为空时(刚建库 / worker 没刷新过),`_fallback_keywords` 实时跑 `ts_stat` 兜底。
|
||||
无需手动回灌(不像之前用 articles trigger 维护的 `search_title_suggestions`)。
|
||||
|
||||
**API 契约**:
|
||||
|
||||
```http
|
||||
GET /api/v1/search/suggestions?q=美&limit=10
|
||||
Authorization: Bearer <token>
|
||||
|
||||
200 {
|
||||
"query": "美",
|
||||
"keywords": [
|
||||
{"word": "美国", "weight": 4865, "source": "ts_stat"},
|
||||
{"word": "美军", "weight": 203, "source": "ts_stat"},
|
||||
{"word": "美国政府", "weight": 98, "source": "ts_stat"},
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- `q` 1-20 字符
|
||||
- `keywords` 按 `weight` 排(高→低),最多 limit 条
|
||||
- 选词 → 自动填入 q + 触发搜索;回车仍然走原搜索路径
|
||||
|
||||
### 历史文章批量 enrich
|
||||
|
||||
新功能**只对**翻译完成后入库的文章生效。历史已翻译文章,手动 reset:
|
||||
|
||||
Reference in New Issue
Block a user