smart_rag 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.env.example +252 -0
  3. data/.rspec +2 -0
  4. data/AGENTS.md +33 -0
  5. data/API_DOCUMENTATION.md +828 -0
  6. data/CHANGELOG.md +11 -1
  7. data/ER-diagram.mmd +144 -0
  8. data/Gemfile +50 -0
  9. data/Gemfile.lock +381 -0
  10. data/Hybrid_Reranking.md +171 -0
  11. data/README.en.md +420 -28
  12. data/README.md +534 -63
  13. data/Rakefile +268 -0
  14. data/SETUP_GUIDE.md +650 -0
  15. data/SmartChunking.md +180 -0
  16. data/USAGE_EXAMPLES.md +1002 -0
  17. data/config/llm_config.yml +4 -2
  18. data/config/smart_rag.yml +45 -1
  19. data/config.ru +15 -0
  20. data/db/migrations/006_create_text_search_configs.rb +3 -2
  21. data/db/migrations/008_create_embeddings.rb +5 -4
  22. data/db/migrations/012_add_metadata_to_source_sections.rb +11 -0
  23. data/db/migrations/013_create_media_jobs.rb +25 -0
  24. data/db/migrations/014_add_media_job_operations_indexes.rb +11 -0
  25. data/db/migrations/015_add_media_leases_and_objects.rb +80 -0
  26. data/db/migrations/016_add_document_principals_and_staging_references.rb +38 -0
  27. data/db/migrations/017_add_media_job_request_fingerprint.rb +48 -0
  28. data/db/seeds/text_search_configs.sql +3 -3
  29. data/design.md +1057 -0
  30. data/docs/API_DOCUMENTATION.md +838 -0
  31. data/docs/DOCUMENTATION_INDEX.en.md +60 -0
  32. data/docs/DOCUMENTATION_INDEX.md +65 -0
  33. data/docs/FIX_SUMMARY.md +256 -0
  34. data/docs/FIX_SUMMARY_COMPLETE.md +273 -0
  35. data/docs/Hybrid_Reranking.md +171 -0
  36. data/docs/MIGRATION_GUIDE.md +151 -0
  37. data/docs/PERFORMANCE_GUIDE.md +58 -0
  38. data/docs/SETUP_GUIDE.md +659 -0
  39. data/docs/SmartChunking.md +180 -0
  40. data/docs/USAGE_EXAMPLES.md +1008 -0
  41. data/docs/design.md +1057 -0
  42. data/docs/evidence_pack.md +211 -0
  43. data/docs/requirements.md +376 -0
  44. data/docs/retrieval_plan.md +251 -0
  45. data/docs/smartrag_improvement_plan.md +201 -0
  46. data/docs/smartrag_refactor.md +216 -0
  47. data/docs/todo.md +931 -0
  48. data/examples/common.rb +1 -1
  49. data/exe/smart-rag-db +163 -0
  50. data/exe/smart-rag-media-worker +34 -0
  51. data/lib/smart_rag/config.rb +12 -0
  52. data/lib/smart_rag/core/document_processor.rb +80 -16
  53. data/lib/smart_rag/core/local_content_store.rb +51 -0
  54. data/lib/smart_rag/core/media_extractors.rb +140 -0
  55. data/lib/smart_rag/core/media_job_queue.rb +353 -0
  56. data/lib/smart_rag/core/media_metadata_extractor.rb +188 -0
  57. data/lib/smart_rag/core/media_object_registry.rb +79 -0
  58. data/lib/smart_rag/core/media_processor.rb +228 -0
  59. data/lib/smart_rag/core/media_safety_policy.rb +61 -0
  60. data/lib/smart_rag/core/s3_content_store.rb +78 -0
  61. data/lib/smart_rag/core/transcript_normalizer.rb +44 -0
  62. data/lib/smart_rag/core/video_semantic_extractor.rb +130 -0
  63. data/lib/smart_rag/http_access_policy.rb +86 -0
  64. data/lib/smart_rag/http_app.rb +188 -0
  65. data/lib/smart_rag/models/embedding.rb +1 -1
  66. data/lib/smart_rag/models/research_topic.rb +1 -1
  67. data/lib/smart_rag/models/research_topic_section.rb +5 -0
  68. data/lib/smart_rag/models/research_topic_tag.rb +5 -0
  69. data/lib/smart_rag/models/search_log.rb +1 -1
  70. data/lib/smart_rag/models/section_fts.rb +5 -0
  71. data/lib/smart_rag/models/section_tag.rb +5 -0
  72. data/lib/smart_rag/models/source_document.rb +1 -1
  73. data/lib/smart_rag/models/source_section.rb +1 -1
  74. data/lib/smart_rag/models/tag.rb +1 -1
  75. data/lib/smart_rag/models/text_search_config.rb +5 -0
  76. data/lib/smart_rag/retrieve.rb +72 -1
  77. data/lib/smart_rag/services/embedding_service.rb +1 -1
  78. data/lib/smart_rag/services/fulltext_search_service.rb +11 -13
  79. data/lib/smart_rag/services/hybrid_search_service.rb +15 -11
  80. data/lib/smart_rag/services/summarization_service.rb +1 -1
  81. data/lib/smart_rag/services/tag_service.rb +1 -1
  82. data/lib/smart_rag/version.rb +1 -1
  83. data/lib/smart_rag.rb +264 -30
  84. data/patch_language.rb +27 -0
  85. data/requirements.md +376 -0
  86. data/source_documents_export.json +11072 -0
  87. data/todo.md +931 -0
  88. data/workers/analyze_content.rb +6 -2
  89. data/workers/get_embedding.rb +1 -1
  90. metadata +151 -38
@@ -0,0 +1,60 @@
1
+ # Documentation Index
2
+
3
+ [中文版](DOCUMENTATION_INDEX.md)
4
+
5
+ This document provides a consolidated map of the current documentation set, including purpose, audience, and suggested reading order.
6
+
7
+ ## Recommended Reading Path
8
+
9
+ 1. `../README.en.md`
10
+ Project entry and quick start
11
+ 2. `SETUP_GUIDE.md`
12
+ Detailed environment and deployment setup
13
+ 3. `API_DOCUMENTATION.md`
14
+ API reference
15
+ 4. `USAGE_EXAMPLES.md` + `../examples/README.md`
16
+ Practical patterns and runnable examples
17
+ 5. `PERFORMANCE_GUIDE.md` and `Hybrid_Reranking.md`
18
+ Performance tuning and ranking strategy
19
+ 6. `MIGRATION_GUIDE.md`
20
+ Upgrade and compatibility notes
21
+
22
+ ## Document Catalog
23
+
24
+ | File | Language | Purpose | Primary Audience |
25
+ |---|---|---|---|
26
+ | `../README.md` | Chinese | Project overview, quick start, command entry | All users |
27
+ | `../README.en.md` | English | Project overview and quick start | English readers |
28
+ | `SETUP_GUIDE.md` | Chinese | Environment setup and deployment | DevOps / backend engineers |
29
+ | `API_DOCUMENTATION.md` | Chinese | API descriptions and examples | Integrators / backend developers |
30
+ | `USAGE_EXAMPLES.md` | English | End-to-end usage patterns and best practices | Application developers |
31
+ | `../examples/README.md` | English | Runnable script map and usage | New adopters |
32
+ | `PERFORMANCE_GUIDE.md` | English | Search and DB performance guidance | Performance engineers |
33
+ | `Hybrid_Reranking.md` | English | Hybrid retrieval and reranking notes | Search relevance engineers |
34
+ | `SmartChunking.md` | English | Chunking strategy details | Ingestion pipeline developers |
35
+ | `MIGRATION_GUIDE.md` | English | Version migration process | Maintainers |
36
+ | `../test/README.md` | Chinese | Test dataset notes | QA / developers |
37
+ | `../test/TEST_GUIDE.md` | Chinese | Manual testing scripts and scenarios | QA / developers |
38
+ | `design.md` | English | System design notes | Architects / maintainers |
39
+ | `requirements.md` | English | Requirement definition | Product / architecture reviewers |
40
+ | `FIX_SUMMARY.md` | English | Intermediate fix summary | Maintainers |
41
+ | `FIX_SUMMARY_COMPLETE.md` | English | Consolidated fix report | Maintainers |
42
+ | `todo.md` | English | Backlog and pending tasks | Maintainers |
43
+
44
+ ## Gaps and Alignment Notes
45
+
46
+ - Some docs still use older defaults (for example OpenAI snippets). Runtime source of truth is `../config/smart_rag.yml`.
47
+ - Language coverage is currently uneven: some docs are Chinese-only, some are English-only. Add translated counterparts by priority.
48
+
49
+ ## Maintenance Policy
50
+
51
+ - When API signatures change, update at least:
52
+ - `../lib/smart_rag.rb`
53
+ - `API_DOCUMENTATION.md`
54
+ - `USAGE_EXAMPLES.md`
55
+ - `../examples/*.rb`
56
+ - When default configuration changes, update at least:
57
+ - `../.env.example`
58
+ - `../config/smart_rag.yml`
59
+ - `../README.md`
60
+ - `../README.en.md`
@@ -0,0 +1,65 @@
1
+ # 文档总览
2
+
3
+ [English Version](DOCUMENTATION_INDEX.en.md)
4
+
5
+ 本文档用于统一梳理当前文档,说明用途、目标读者与推荐阅读顺序。
6
+
7
+ ## 推荐阅读路径
8
+
9
+ 1. `../README.md`
10
+ 项目入口与快速启动
11
+ 2. `SETUP_GUIDE.md`
12
+ 环境与部署详细安装指南
13
+ 3. `API_DOCUMENTATION.md`
14
+ API 参考说明
15
+ 4. `USAGE_EXAMPLES.md` + `../examples/README.md`
16
+ 实战用法与可运行示例
17
+ 5. `PERFORMANCE_GUIDE.md` 与 `Hybrid_Reranking.md`
18
+ 性能调优与排序策略
19
+ 6. `MIGRATION_GUIDE.md`
20
+ 版本迁移与兼容说明
21
+ 7. `smartrag_improvement_plan.md` + `retrieval_plan.md` + `evidence_pack.md`
22
+ SmartRAG 重构计划与检索契约
23
+
24
+ ## 文档目录梳理
25
+
26
+ | 文件 | 语言 | 用途 | 主要读者 |
27
+ |---|---|---|---|
28
+ | `../README.md` | 中文 | 项目概览、快速开始、命令入口 | 所有用户 |
29
+ | `../README.en.md` | 英文 | Project overview and quick start | English readers |
30
+ | `SETUP_GUIDE.md` | 中文 | 环境安装与部署 | DevOps / 后端工程师 |
31
+ | `API_DOCUMENTATION.md` | 中文 | API 说明与示例 | 接入开发者 |
32
+ | `USAGE_EXAMPLES.md` | 英文 | 端到端用法与最佳实践 | 应用开发者 |
33
+ | `../examples/README.md` | 英文 | 示例脚本导航与运行说明 | 新用户 |
34
+ | `PERFORMANCE_GUIDE.md` | 英文 | 搜索与数据库性能指南 | 性能优化工程师 |
35
+ | `Hybrid_Reranking.md` | 英文 | 混合检索与重排设计说明 | 搜索相关性工程师 |
36
+ | `SmartChunking.md` | 英文 | 分块策略说明 | 数据导入/切分开发者 |
37
+ | `MIGRATION_GUIDE.md` | 英文 | 版本迁移说明 | 维护者 |
38
+ | `smartrag_improvement_plan.md` | 中文 | 1-2 天改进执行计划 | 维护者/负责人 |
39
+ | `retrieval_plan.md` | 中文 | RetrievalPlan 契约规范 | SmartBrain/检索接入开发者 |
40
+ | `evidence_pack.md` | 中文 | EvidencePack 契约规范 | SmartBrain/检索接入开发者 |
41
+ | `../test/README.md` | 中文 | 测试文档数据集说明 | QA / 开发者 |
42
+ | `../test/TEST_GUIDE.md` | 中文 | 手工测试脚本与场景说明 | QA / 开发者 |
43
+ | `design.md` | 英文 | 系统设计说明 | 架构/维护者 |
44
+ | `requirements.md` | 英文 | 需求定义 | 产品/架构评审 |
45
+ | `FIX_SUMMARY.md` | 英文 | 阶段性修复总结 | 维护者 |
46
+ | `FIX_SUMMARY_COMPLETE.md` | 英文 | 完整修复报告 | 维护者 |
47
+ | `todo.md` | 英文 | 待办与规划 | 维护者 |
48
+
49
+ ## 当前缺口与对齐说明
50
+
51
+ - 部分文档仍使用旧默认值示例(如 OpenAI)。运行时配置以 `../config/smart_rag.yml` 为准。
52
+ - 当前文档语言分布不均:部分仅中文、部分仅英文。后续可按优先级补齐对应翻译版本。
53
+
54
+ ## 文档维护建议
55
+
56
+ - API 发生变更时,至少同步更新:
57
+ - `../lib/smart_rag.rb`
58
+ - `API_DOCUMENTATION.md`
59
+ - `USAGE_EXAMPLES.md`
60
+ - `../examples/*.rb`
61
+ - 默认配置调整时,至少同步更新:
62
+ - `../.env.example`
63
+ - `../config/smart_rag.yml`
64
+ - `../README.md`
65
+ - `../README.en.md`
@@ -0,0 +1,256 @@
1
+ # SmartRAG 搜索问题修复总结
2
+
3
+ ## 修复日期
4
+ 2026-01-05
5
+
6
+ ## 用户报告的问题
7
+ 用户报告:"老人情感"在搜索时会被识别为英文?"
8
+
9
+ ## 根本原因分析
10
+
11
+ 发现了 **5 个 Bug** 导致搜索失败:
12
+
13
+ ## 问题描述
14
+ 搜索功能无法返回任何结果,即使数据库中有匹配的中文内容。
15
+
16
+ ## 根本原因分析
17
+
18
+ 发现了 **4 个 Bug** 导致搜索失败:
19
+
20
+ ### Bug 1: 数据库配置名称错误
21
+ **位置**: `/root/smart_rag/db/seeds/text_search_configs.sql` (第 12-14 行)
22
+
23
+ **问题**: PostgreSQL 中 pg_jieba 扩展的配置名称是 `'jiebacfg'`,但种子数据中使用的是 `'jieba'`
24
+
25
+ **影响**: 中文全文搜索时使用错误的分词器配置名,导致搜索失败
26
+
27
+ **修复**:
28
+ ```sql
29
+ -- 修改前
30
+ ('zh', 'jieba', true),
31
+
32
+ -- 修改后
33
+ ('zh', 'jiebacfg', true),
34
+ ```
35
+
36
+ ### Bug 2: 语言检测错误
37
+ **位置**: `/root/smart_rag/lib/smart_rag/core/document_processor.rb` (第 463-490 行)
38
+
39
+ **问题**: `extract_html_metadata` 方法没有提取内容用于语言检测,导致所有文档的语言默认为 `'en'`
40
+
41
+ **影响**:
42
+ - `source_documents.language = 'en'`(实际应为 'zh')
43
+ - `section_fts.language = 'en'`(通过触发器继承)
44
+ - 使用英文分词器索引中文内容
45
+
46
+ **修复**: 添加了内容提取逻辑
47
+ ```ruby
48
+ # Extract body content for language detection
49
+ body_content = content.gsub(/<script[^>]*>.*?<\/script>/mi, '')
50
+ .gsub(/<style[^>]*>.*?<\/style>/mi, '')
51
+ if body_content =~ /<body[^>]*>(.*?)<\/body>/mi
52
+ metadata[:content] = $1.gsub(/<[^>]+>/, ' ').strip.gsub(/\s+/, ' ')
53
+ ```
54
+
55
+ ### Bug 3: 数据库数据不一致
56
+ **位置**: 数据库中的 `source_documents` 和 `section_fts` 表
57
+
58
+ **问题**: 现有数据的 language 字段为 `'en'`,但内容为中文
59
+
60
+ **影响**: 使用英文分词器索引,中文内容无法被正确分词
61
+
62
+ **修复**: 执行数据库修复脚本
63
+ ```sql
64
+ -- 更新中文文档的语言
65
+ UPDATE source_documents sd
66
+ SET language = 'zh'
67
+ WHERE sd.id IN (SELECT document_id FROM source_sections WHERE content ~ '[\u4e00-\u9fff]')
68
+ AND (sd.language = 'en' OR sd.language IS NULL OR sd.language = '');
69
+
70
+ -- 重建全文索引
71
+ DELETE FROM section_fts;
72
+ -- 触发器会自动使用正确的语言和分词器重建索引
73
+ ```
74
+
75
+ ### Bug 4: 传入错误的数据库连接对象
76
+ **位置**: `/root/smart_rag/lib/smart_rag.rb` (第 289 行)
77
+
78
+ **问题**: 传递给 FulltextManager 的是数据库配置 hash,而不是 Sequel::Database 对象
79
+
80
+ **影响**: `db[:section_fts]` 操作失败,因为 hash 没有 table 方法
81
+
82
+ **修复**:
83
+ ```ruby
84
+ # 修改前
85
+ fulltext_manager = ::SmartRAG::Core::FulltextManager.new(@config[:database], @config[:fulltext] || {})
86
+
87
+ # 修改后
88
+ db_connection = ::SmartRAG.db
89
+ fulltext_manager = ::SmartRAG::Core::FulltextManager.new(db_connection, @config[:fulltext] || {})
90
+ ```
91
+
92
+ ### Bug 5: section_fts 索引数据不完整(**核心问题**)
93
+ **位置**: 数据库中的 `section_fts` 表
94
+
95
+ **问题**:
96
+ - `fts_title` 字段有数据(通过触发器填充)
97
+ - `fts_content` 和 `fts_combined` 字段为空
98
+
99
+ **影响**:
100
+ - 搜索"老人情感"等关键词时无法匹配到内容
101
+ - 因为 `fts_combined` 是空字符串,全文搜索失败
102
+
103
+ **原因**:
104
+ - 触发器只在部分情况下更新 fts_content 和 fts_combined
105
+ - 当通过 `ON CONFLICT` 更新时,fts_content 未被正确设置
106
+
107
+ **修复**: 执行完整的索引重建脚本
108
+ ```sql
109
+ -- db/rebuild_fts_complete.sql
110
+ DELETE FROM section_fts;
111
+ INSERT INTO section_fts (section_id, document_id, language)
112
+ SELECT ss.id, ss.document_id, COALESCE(sd.language, 'zh')
113
+ FROM source_sections ss
114
+ JOIN source_documents sd ON sd.id = ss.document_id;
115
+
116
+ -- 触发更新所有 section
117
+ UPDATE source_sections SET updated_at = CURRENT_TIMESTAMP;
118
+ ```
119
+
120
+ **验证**:
121
+ ```sql
122
+ -- 重建前:fts_content 和 fts_combined 为空
123
+ -- 重建后:所有字段都有数据
124
+ SELECT COUNT(*) as sections_with_complete_fts
125
+ FROM section_fts
126
+ WHERE fts_combined IS NOT NULL;
127
+ -- 结果:10 个 section 都有完整的索引
128
+ ```
129
+
130
+ ## 修复文件清单
131
+
132
+ ### 1. 配置文件
133
+ - ✅ `/root/smart_rag/db/seeds/text_search_configs.sql`
134
+ - 将 `'jieba'` 改为 `'jiebacfg'`
135
+
136
+ ### 2. 代码文件
137
+ - ✅ `/root/smart_rag/lib/smart_rag/core/document_processor.rb`
138
+ - 添加 HTML 内容提取逻辑用于语言检测
139
+ - ✅ `/root/smart_rag/lib/smart_rag/core/fulltext_manager.rb`
140
+ - 添加调试日志输出 SQL 和 tsquery
141
+
142
+ ### 3. 数据库修复
143
+ - ✅ `/root/smart_rag/db/fix_search_issues.sql`
144
+ - 更新 text_search_configs 配置
145
+ - 更新 source_documents 语言
146
+ - 重建 section_fts 全文索引
147
+
148
+ ### 4. 核心文件
149
+ - ✅ `/root/smart_rag/lib/smart_rag.rb`
150
+ - 修复传递给 FulltextManager 的数据库连接对象
151
+
152
+ ## 验证结果
153
+
154
+ ### 修复前(Bug 5 未修复)
155
+ 搜索"老人情感"返回 0 个结果,即使数据库中包含相关内容。
156
+
157
+ ### 修复后(Bug 5 已修复)
158
+
159
+ **测试 1: 搜索"老人情感"(全文搜索)**
160
+ ```bash
161
+ Results: 3
162
+ 1. 宠物比子女还亲 小动物承担了老人情感需求 (Part 2)
163
+ 2. 宠物比子女还亲 小动物承担了老人情感需求
164
+ 3. 相关文章
165
+ ```
166
+
167
+ **测试 2: 混合搜索**
168
+ ```bash
169
+ Results: 3
170
+ 1. 宠物比子女还亲 小动物承担了老人情感需求 (Part 2) (score: 0.005)
171
+ ,这些对于老年人来说,都是负性因素。”
172
+
173
+   人虽然老了,但是他们对情感的需求还在,他们希望孩子能常陪在自己的身边...
174
+
175
+ 2. 宠物比子女还亲 小动物承担了老人情感需求 (score: 0.005)
176
+ **作者:贾晓宏** **来源:北京晚报**
177
+ 发布时间:2016-08-19
178
+ 字号:\+-14
179
+ 浏览次数:
180
+   **小狗病逝,老人抑郁了**
181
+ ...
182
+
183
+ 3. 相关文章 (score: 0.005)
184
+ * [2020年北大六院发表SCI论文一览](...)
185
+ * [北京大学第六医院精神科临床进修班招生简章](...)
186
+ ```
187
+
188
+ **数据库验证**:
189
+ ```sql
190
+ SELECT COUNT(*) as sections_with_complete_fts
191
+ FROM section_fts
192
+ WHERE fts_combined IS NOT NULL;
193
+ -- 结果:10 个 section 都有完整的索引
194
+
195
+ -- 验证中文分词
196
+ SELECT to_tsvector('jiebacfg', '老人情感');
197
+ -- 结果:'老人':2 '情感':3
198
+ ```
199
+
200
+ ## 技术细节
201
+
202
+ ### 全文搜索查询
203
+ ```sql
204
+ SELECT "section_fts"."section_id", "section_fts"."language",
205
+ ts_rank("section_fts"."fts_combined",
206
+ plainto_tsquery('jiebacfg', '小动物承担了老人情感需求')) AS "rank_score",
207
+ ts_headline("source_sections"."content",
208
+ plainto_tsquery('jiebacfg', '小动物承担了老人情感需求'),
209
+ 'MaxWords=50, MinWords=15, MaxFragments=3') AS "highlight"
210
+ FROM "section_fts"
211
+ INNER JOIN "source_sections" ON ("source_sections"."id" = "section_fts"."section_id")
212
+ WHERE (section_fts.fts_combined @@ plainto_tsquery('jiebacfg', '小动物承担了老人情感需求'))
213
+ ORDER BY "rank_score" DESC
214
+ LIMIT 10
215
+ ```
216
+
217
+ ### 中文分词测试
218
+ ```sql
219
+ -- 使用 jiebacfg 配置
220
+ SELECT to_tsvector('jiebacfg', '小动物承担了老人情感需求');
221
+ -- 结果: '动物':2 '情感':6 '承担':3 '老人':5 '需求':7
222
+
223
+ -- 构建查询
224
+ SELECT plainto_tsquery('jiebacfg', '小动物承担了老人情感需求');
225
+ -- 结果: '动物' & '承担' & '老人' & '情感' & '需求'
226
+ ```
227
+
228
+ ## 后续建议
229
+
230
+ ### 1. 添加单元测试
231
+ 建议为以下功能添加单元测试:
232
+ - 语言检测功能
233
+ - 全文搜索构建
234
+ - 数据库触发器逻辑
235
+
236
+ ### 2. 添加数据库迁移
237
+ 将修复脚本转换为正式的数据库迁移文件,以便在部署时自动执行
238
+
239
+ ### 3. 改进错误处理
240
+ - 添加更好的错误提示
241
+ - 在分词器不可用时提供降级方案
242
+
243
+ ### 4. 性能优化
244
+ - 为中文内容添加专门的 GIN 索引
245
+ - 考虑使用分区表按语言分区
246
+
247
+ ## 结论
248
+
249
+ 所有 4 个 Bug 已成功修复,中文全文搜索功能现在正常工作。用户可以搜索中文内容并获得准确的结果。
250
+
251
+ 修复涉及的系统:
252
+ - ✅ 数据库配置和迁移
253
+ - ✅ 文档处理和语言检测
254
+ - ✅ 全文搜索功能
255
+ - ✅ 混合搜索功能
256
+ - ✅ 数据库连接管理
@@ -0,0 +1,273 @@
1
+ # SmartRAG 搜索问题修复总结
2
+
3
+ ## 修复日期
4
+ 2026-01-05
5
+
6
+ ## 用户报告的问题
7
+ 用户报告:"老人情感"在搜索时会被识别为英文?
8
+
9
+ ## 根本原因分析
10
+
11
+ 发现了 **5 个 Bug** 导致搜索失败:
12
+
13
+ ### Bug 1: 数据库配置名称错误
14
+ **位置**: `/root/smart_rag/db/seeds/text_search_configs.sql` (第 12-14 行)
15
+
16
+ **问题**: PostgreSQL 中 pg_jieba 扩展的配置名称是 `'jiebacfg'`,但种子数据中使用的是 `'jieba'`
17
+
18
+ **影响**: 中文全文搜索时使用错误的分词器配置名,导致搜索失败
19
+
20
+ **修复**:
21
+ ```sql
22
+ -- 修改前
23
+ ('zh', 'jieba', true),
24
+
25
+ -- 修改后
26
+ ('zh', 'jiebacfg', true),
27
+ ```
28
+
29
+ ### Bug 2: 语言检测错误
30
+ **位置**: `/root/smart_rag/lib/smart_rag/core/document_processor.rb` (第 463-490 行)
31
+
32
+ **问题**: `extract_html_metadata` 方法没有提取内容用于语言检测,导致所有文档的语言默认为 `'en'`
33
+
34
+ **影响**:
35
+ - `source_documents.language = 'en'`(实际应为 'zh')
36
+ - `section_fts.language = 'en'`(通过触发器继承)
37
+ - 使用英文分词器索引中文内容
38
+
39
+ **修复**: 添加了内容提取逻辑
40
+ ```ruby
41
+ # Extract body content for language detection
42
+ body_content = content.gsub(/<script[^>]*>.*?<\/script>/mi, '')
43
+ .gsub(/<style[^>]*>.*?<\/style>/mi, '')
44
+ if body_content =~ /<body[^>]*>(.*?)<\/body>/mi
45
+ metadata[:content] = $1.gsub(/<[^>]+>/, ' ').strip.gsub(/\s+/, ' ')
46
+ ```
47
+
48
+ ### Bug 3: 数据库数据不一致
49
+ **位置**: 数据库中的 `source_documents` 和 `section_fts` 表
50
+
51
+ **问题**: 现有数据的 language 字段为 `'en'`,但内容为中文
52
+
53
+ **影响**: 使用英文分词器索引,中文内容无法被正确分词
54
+
55
+ **修复**: 执行数据库修复脚本
56
+ ```sql
57
+ -- 更新中文文档的语言
58
+ UPDATE source_documents sd
59
+ SET language = 'zh'
60
+ WHERE sd.id IN (SELECT document_id FROM source_sections WHERE content ~ '[\u4e00-\u9fff]')
61
+ AND (sd.language = 'en' OR sd.language IS NULL OR sd.language = '');
62
+
63
+ -- 重建全文索引
64
+ DELETE FROM section_fts;
65
+ -- 触发器会自动使用正确的语言和分词器重建索引
66
+ ```
67
+
68
+ ### Bug 4: 传入错误的数据库连接对象
69
+ **位置**: `/root/smart_rag/lib/smart_rag.rb` (第 289 行)
70
+
71
+ **问题**: 传递给 FulltextManager 的是数据库配置 hash,而不是 Sequel::Database 对象
72
+
73
+ **影响**: `db[:section_fts]` 操作失败,因为 hash 没有 table 方法
74
+
75
+ **修复**:
76
+ ```ruby
77
+ # 修改前
78
+ fulltext_manager = ::SmartRAG::Core::FulltextManager.new(@config[:database], @config[:fulltext] || {})
79
+
80
+ # 修改后
81
+ db_connection = ::SmartRAG.db
82
+ fulltext_manager = ::SmartRAG::Core::FulltextManager.new(db_connection, @config[:fulltext] || {})
83
+ ```
84
+
85
+ ### Bug 5: section_fts 索引数据不完整(**核心问题**)
86
+ **位置**: 数据库中的 `section_fts` 表
87
+
88
+ **问题**:
89
+ - `fts_title` 字段有数据(通过触发器填充)
90
+ - `fts_content` 和 `fts_combined` 字段为空
91
+
92
+ **影响**:
93
+ - 搜索"老人情感"等关键词时无法匹配到内容
94
+ - 因为 `fts_combined` 是空字符串,全文搜索失败
95
+
96
+ **原因**:
97
+ - 触发器在部分情况下只更新了 `fts_title`
98
+ - 当通过 `ON CONFLICT` 更新时,`fts_content` 未被正确设置
99
+
100
+ **修复**: 执行完整的索引重建脚本
101
+ ```sql
102
+ -- db/rebuild_fts_complete.sql
103
+ -- 1. 删除所有 fts 数据
104
+ DELETE FROM section_fts;
105
+
106
+ -- 2. 重新插入所有 section 基础信息
107
+ INSERT INTO section_fts (section_id, document_id, language)
108
+ SELECT
109
+ ss.id,
110
+ ss.document_id,
111
+ COALESCE(sd.language, 'zh') as language
112
+ FROM source_sections ss
113
+ JOIN source_documents sd ON sd.id = ss.document_id;
114
+
115
+ -- 3. 触发更新所有 section 以重建 fts 字段
116
+ UPDATE source_sections SET updated_at = CURRENT_TIMESTAMP;
117
+
118
+ -- 验证
119
+ SELECT COUNT(*) as sections_with_complete_fts
120
+ FROM section_fts
121
+ WHERE fts_combined IS NOT NULL;
122
+ -- 结果:10 个 section 都有完整的索引
123
+ ```
124
+
125
+ ## 修复文件清单
126
+
127
+ ### 1. 配置文件
128
+ - ✅ `/root/smart_rag/db/seeds/text_search_configs.sql`
129
+ - 将 `'jieba'` 改为 `'jiebacfg'`
130
+
131
+ ### 2. 代码文件
132
+ - ✅ `/root/smart_rag/lib/smart_rag/core/document_processor.rb`
133
+ - 添加 HTML 内容提取逻辑用于语言检测
134
+ - ✅ `/root/smart_rag/lib/smart_rag/core/fulltext_manager.rb`
135
+ - 添加调试日志输出 SQL 和 tsquery
136
+ - ✅ `/root/smart_rag/lib/smart_rag/parsers/query_parser.rb`
137
+ - 添加语言检测的调试日志
138
+
139
+ ### 3. 数据库修复
140
+ - ✅ `/root/smart_rag/db/fix_search_issues.sql`(第一次修复)
141
+ - 更新 text_search_configs 配置
142
+ - 更新 source_documents 语言
143
+ - 删除并重新插入 section_fts 数据
144
+ - ✅ `/root/smart_rag/db/rebuild_fts_complete.sql`(第二次修复)
145
+ - 完整重建所有 section_fts 索引
146
+ - 确保 fts_content 和 fts_combined 正确填充
147
+ - 触发所有 section 更新以重建 fts 向量
148
+
149
+ ### 4. 核心文件
150
+ - ✅ `/root/smart_rag/lib/smart_rag.rb`
151
+ - 修复传递给 FulltextManager 的数据库连接对象
152
+
153
+ ## 验证结果
154
+
155
+ ### 修复前(Bug 5 未修复)
156
+ 搜索"老人情感"返回 0 个结果,即使数据库中包含相关内容。
157
+
158
+ ### 修复后(Bug 5 已修复)
159
+
160
+ **测试 1: 搜索"老人情感"(全文搜索)**
161
+ ```bash
162
+ Results: 3
163
+ 1. 宠物比子女还亲 小动物承担了老人情感需求 (Part 2)
164
+ 2. 宠物比子女还亲 小动物承担了老人情感需求
165
+ 3. 相关文章
166
+ ```
167
+
168
+ **测试 2: 混合搜索**
169
+ ```bash
170
+ Results: 3
171
+ 1. 宠物比子女还亲 小动物承担了老人情感需求 (Part 2) (score: 0.005)
172
+ ,这些对于老年人来说,都是负性因素。
173
+
174
+   人虽然老了,但是他们对情感的需求还在...
175
+
176
+ 2. 宠物比子女还亲 小动物承担了老人情感需求 (score: 0.005)
177
+ **作者:贾晓宏** **来源:北京晚报**
178
+ 发布时间:2016-08-19
179
+ 字号:\+-14
180
+ 浏览次数:
181
+
182
+   **小狗病逝,老人抑郁了**
183
+
184
+ 3. 相关文章 (score: 0.005)
185
+ * [2020年北大六院发表SCI论文一览](...)
186
+ * [北京大学第六医院精神科临床进修班招生简章](...)
187
+ ```
188
+
189
+ **数据库验证**:
190
+ ```sql
191
+ -- 验证所有 section 都有完整索引
192
+ SELECT COUNT(*) as sections_with_complete_fts
193
+ FROM section_fts
194
+ WHERE fts_combined IS NOT NULL;
195
+ -- 结果:10 个 section 都有完整的索引
196
+
197
+ -- 验证中文分词
198
+ SELECT to_tsvector('jiebacfg', '老人情感');
199
+ -- 结果:'老人':2 '情感':3
200
+ ```
201
+
202
+ ## 技术细节
203
+
204
+ ### 中文全文搜索配置
205
+ ```sql
206
+ -- 使用 jiebacfg 配置
207
+ SELECT plainto_tsquery('jiebacfg', '老人情感');
208
+ -- 结果:'老人' & '情感'
209
+
210
+ -- 实际分词结果
211
+ SELECT to_tsvector('jiebacfg', '老人情感');
212
+ -- 结果:'老人':2 '情感':3
213
+ ```
214
+
215
+ ### 搜索查询示例
216
+ ```sql
217
+ -- 完整的全文搜索查询
218
+ SELECT ss.section_title, ssf.language
219
+ FROM section_fts ssf
220
+ JOIN source_sections ss ON ss.id = ssf.section_id
221
+ WHERE ssf.fts_combined @@ plainto_tsquery('jiebacfg', '老人情感')
222
+ AND ssf.language = 'zh'
223
+ ORDER BY ts_rank(ssf.fts_combined, plainto_tsquery('jiebacfg', '老人情感')) DESC
224
+ LIMIT 5;
225
+ ```
226
+
227
+ ### 数据库触发器
228
+ 触发器在 section 插入或更新时自动维护全文索引:
229
+ 1. 从文档获取语言
230
+ 2. 获取对应的分词器配置(jiebacfg for zh)
231
+ 3. 生成 fts_title(权重 A)、fts_content(权重 B)、fts_combined
232
+ 4. 更新 section_fts 表
233
+
234
+ ## 后续建议
235
+
236
+ ### 1. 添加单元测试
237
+ 建议为以下功能添加单元测试:
238
+ - 语言检测功能
239
+ - 全文搜索构建
240
+ - 数据库触发器逻辑
241
+ - 索引重建逻辑
242
+
243
+ ### 2. 添加数据库迁移
244
+ 将修复脚本转换为正式的数据库迁移文件,以便在部署时自动执行
245
+
246
+ ### 3. 改进触发器逻辑
247
+ - 确保 `ON CONFLICT` 更新时正确设置所有 fts 字段
248
+ - 添加触发器失败的错误处理和日志记录
249
+
250
+ ### 4. 添加索引健康检查
251
+ 实现定期检查索引完整性的功能:
252
+ ```sql
253
+ -- 查找空索引的 section
254
+ SELECT section_id
255
+ FROM section_fts
256
+ WHERE fts_combined IS NULL OR fts_combined = '';
257
+ ```
258
+
259
+ ## 结论
260
+
261
+ 所有 5 个 Bug 已成功修复,中文全文搜索功能现在正常工作。
262
+
263
+ **关键修复**:Bug 5 是用户报告问题的根本原因。通过完整重建 `section_fts` 表的全文索引,确保了 `fts_content` 和 `fts_combined` 字段都被正确填充,从而使中文搜索能够正常工作。
264
+
265
+ 修复涉及的系统:
266
+ - ✅ 数据库配置和迁移
267
+ - ✅ 文档处理和语言检测
268
+ - ✅ 全文搜索功能
269
+ - ✅ 混合搜索功能
270
+ - ✅ 数据库连接管理
271
+ - ✅ 全文索引完整性和重建
272
+
273
+ 用户现在可以搜索中文内容并获得准确的结果。