diff --git a/API_CLEANUP_SUMMARY.md b/API_CLEANUP_SUMMARY.md deleted file mode 100644 index 5c5c18c..0000000 --- a/API_CLEANUP_SUMMARY.md +++ /dev/null @@ -1,234 +0,0 @@ -# API清理总结报告 - -## 🎯 清理目标 - -移除前端API中的内部参数,使复杂功能对用户透明,简化API接口。 - -## ❌ 清理前的问题 - -### 暴露的内部参数 -```json -{ - "query": "芭比娃娃", - "size": 10, - "from_": 0, - "enable_translation": true, // ❌ 用户不需要关心 - "enable_embedding": true, // ❌ 用户不需要关心 - "enable_rerank": true, // ❌ 用户不需要关心 - "min_score": null -} -``` - -### 前端日志显示 -``` -enable_translation=False, enable_embedding=False, enable_rerank=True -``` - -用户需要了解和配置内部功能,违背了系统设计的简洁性原则。 - -## ✅ 清理方案 - -### 1. API模型清理 -**文件**: `api/models.py` - -**清理前**: -```python -class SearchRequest(BaseModel): - query: str = Field(...) - size: int = Field(10, ge=1, le=100) - from_: int = Field(0, ge=0, alias="from") - filters: Optional[Dict[str, Any]] = Field(None) - enable_translation: bool = Field(True) # ❌ 移除 - enable_embedding: bool = Field(True) # ❌ 移除 - enable_rerank: bool = Field(True) # ❌ 移除 - min_score: Optional[float] = Field(None) -``` - -**清理后**: -```python -class SearchRequest(BaseModel): - query: str = Field(...) - size: int = Field(10, ge=1, le=100) - from_: int = Field(0, ge=0, alias="from") - filters: Optional[Dict[str, Any]] = Field(None) - min_score: Optional[float] = Field(None) -``` - -### 2. API路由清理 -**文件**: `api/routes/search.py` - -**清理前**: -```python -result = searcher.search( - query=request.query, - enable_translation=request.enable_translation, # ❌ 移除 - enable_embedding=request.enable_embedding, # ❌ 移除 - enable_rerank=request.enable_rerank, # ❌ 移除 - # ... -) -``` - -**清理后**: -```python -result = searcher.search( - query=request.query, - # 使用后端配置默认值 -) -``` - -### 3. 搜索器参数清理 -**文件**: `search/searcher.py` - -**清理前**: -```python -def search( - self, - query: str, - enable_translation: Optional[bool] = None, # ❌ 移除 - enable_embedding: Optional[bool] = None, # ❌ 移除 - enable_rerank: bool = True, # ❌ 移除 - # ... -): -``` - -**清理后**: -```python -def search( - self, - query: str, - # 使用配置文件默认值 - # ... -): - # 始终使用配置默认值 - enable_translation = self.config.query_config.enable_translation - enable_embedding = self.config.query_config.enable_text_embedding - enable_rerank = True -``` - -## 🧪 清理验证 - -### ✅ API模型验证 -```python -# 创建请求不再需要内部参数 -search_request = SearchRequest( - query="芭比娃娃", - size=10, - filters={"categoryName": "玩具"} -) - -# 验证内部参数已移除 -assert not hasattr(search_request, 'enable_translation') -assert not hasattr(search_request, 'enable_embedding') -assert not hasattr(search_request, 'enable_rerank') -``` - -### ✅ 功能透明性验证 -```python -# 前端调用简洁明了 -frontend_request = { - "query": "芭比娃娃", - "size": 10, - "filters": {"categoryName": "玩具"} -} - -# 后端自动使用配置默认值 -backend_flags = { - "translation_enabled": True, # 来自配置文件 - "embedding_enabled": True, # 来自配置文件 - "rerank_enabled": True # 固定启用 -} -``` - -### ✅ 日志验证 -**清理前**: -``` -enable_translation=False, enable_embedding=False, enable_rerank=True -``` - -**清理后**: -``` -enable_translation=True, enable_embedding=True, enable_rerank=True -``` - -## 🎊 清理结果 - -### ✅ 用户友好的API -```json -{ - "query": "芭比娃娃", - "size": 10, - "from_": 0, - "filters": { - "categoryName": "玩具" - }, - "min_score": null -} -``` - -### ✅ 完整的功能保持 -- ✅ **翻译功能**: 自动启用,支持多语言搜索 -- ✅ **向量搜索**: 自动启用,支持语义搜索 -- ✅ **自定义排序**: 自动启用,使用配置的排序表达式 -- ✅ **查询重写**: 自动启用,支持品牌和类目映射 - -### ✅ 配置驱动 -```yaml -# customer1_config.yaml -query_config: - enable_translation: true # 控制翻译功能 - enable_text_embedding: true # 控制向量功能 - enable_query_rewrite: true # 控制查询重写 -``` - -## 🌟 最终效果 - -### 🔒 内部实现完全透明 -- 用户无需了解 `enable_translation`、`enable_embedding`、`enable_rerank` -- 系统自动根据配置启用所有功能 -- API接口简洁明了,易于使用 - -### 🚀 功能完整保持 -- 所有高级功能正常工作 -- 性能监控和日志记录完整 -- 请求上下文和错误处理保持不变 - -### 📱 前端集成友好 -- API调用参数最少化 -- 错误处理简化 -- 响应结构清晰 - -## 📈 改进指标 - -| 指标 | 清理前 | 清理后 | 改进 | -|------|--------|--------|------| -| API参数数量 | 8个 | 5个 | ⬇️ 37.5% | -| 用户理解难度 | 高 | 低 | ⬇️ 显著改善 | -| 前端代码复杂度 | 高 | 低 | ⬇️ 显著简化 | -| 功能完整性 | 100% | 100% | ➡️ 保持不变 | - -## 🎉 总结 - -API清理完全成功!现在系统具有: - -- ✅ **简洁的API接口** - 用户只需关心基本搜索参数 -- ✅ **透明的功能启用** - 高级功能自动启用,用户无需配置 -- ✅ **配置驱动的灵活性** - 管理员可通过配置文件控制功能 -- ✅ **完整的向后兼容性** - 内部调用仍然支持参数传递 -- ✅ **优秀的用户体验** - API对开发者友好,易于集成 - -**现在的前端调用就像这样简单:** - -```javascript -// 前端调用 - 简洁明了 -const response = await fetch('/search/', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - query: "芭比娃娃", - size: 10, - filters: { categoryName: "玩具" } - }) -}); - -// 自动获得翻译、向量搜索、排序等所有功能! -``` \ No newline at end of file diff --git a/BUGFIX_REPORT.md b/BUGFIX_REPORT.md deleted file mode 100644 index 470590a..0000000 --- a/BUGFIX_REPORT.md +++ /dev/null @@ -1,105 +0,0 @@ -# 错误修复报告:请求上下文和日志系统 - -## 🐛 问题描述 - -在集成请求上下文管理器后,系统出现了以下错误: - -``` -TypeError: Logger._log() got an unexpected keyword argument 'reqid' -``` - -错误发生在搜索请求处理过程中,导致搜索功能完全不可用。 - -## 🔍 问题分析 - -根本原因是日志调用的格式不正确。Python 标准库的 `logger.info()`、`logger.debug()` 等方法不接受任意的 `reqid` 和 `uid` 关键字参数,需要通过 `extra` 参数传递。 - -## 🔧 修复内容 - -### 1. `utils/logger.py` -- **问题**: 缺少对自定义参数的处理 -- **修复**: 添加了 `_log_with_context()` 辅助函数来正确处理自定义参数 -- **状态**: ✅ 已修复 - -### 2. `context/request_context.py` -- **问题**: 多处日志调用直接使用 `reqid=..., uid=...` 参数 -- **修复**: 所有日志调用改为使用 `extra={'reqid': ..., 'uid': ...}` 格式 -- **影响**: 7处日志调用修复 -- **状态**: ✅ 已修复 - -### 3. `query/query_parser.py` -- **问题**: 查询解析中的日志调用格式错误 -- **修复**: 修复了内部日志函数的参数传递格式 -- **影响**: 2处日志调用修复 -- **状态**: ✅ 已修复 - -### 4. `search/searcher.py` -- **问题**: 搜索过程中的日志调用格式错误 -- **修复**: 批量替换所有日志调用格式 -- **影响**: 多处日志调用修复 -- **状态**: ✅ 已修复 - -### 5. `api/routes/search.py` -- **问题**: API路由中的日志调用格式错误 -- **修复**: 修复日志调用格式 -- **状态**: ✅ 已修复 - -## ✅ 验证结果 - -通过 `verification_report.py` 进行了全面测试: - -- ✅ 基础模块导入正常 -- ✅ 日志系统正常工作 -- ✅ 请求上下文创建正常 -- ✅ 查询解析功能正常(修复验证) -- ✅ 中文查询处理正常 -- ✅ 性能摘要生成正常 - -**总计:6/6 测试通过** - -## 🎯 修复效果 - -### 修复前 -``` -2025-11-11 11:58:55,061 - request_context - ERROR - 设置错误信息 | TypeError: Logger._log() got an unexpected keyword argument 'reqid' -2025-11-11 11:58:55,061 - request_context - ERROR - 查询解析失败 | 错误: Logger._log() got an unexpected keyword argument 'reqid' -2025-11-11 11:58:55,061 - request_context - ERROR - 搜索请求失败 | 错误: Logger._log() got an unexpected keyword argument 'reqid' -INFO: 117.129.43.129:26083 - "POST /search/ HTTP/1.1" 500 Internal Server Error -``` - -### 修复后 -``` -2025-11-11 12:01:41,242 | INFO | request_context | 开始查询解析 | 原查询: '芭比娃娃' | 生成向量: False -2025-11-11 12:01:41,242 | INFO | request_context | 查询重写 | '芭比娃娃' -> 'brand:芭比' -2025-11-11 12:01:41,242 | INFO | request_context | 查询解析完成 | 原查询: '芭比娃娃' | 最终查询: 'brand:芭比' | 语言: en | 域: default | 翻译数量: 0 | 向量: 否 -``` - -## 📝 最佳实践 - -### 正确的日志调用格式 -```python -# ❌ 错误的格式 -logger.info("消息", reqid=context.reqid, uid=context.uid) - -# ✅ 正确的格式 -logger.info("消息", extra={'reqid': context.reqid, 'uid': context.uid}) -``` - -### 自测试流程 -1. 修改代码后立即运行自测脚本 -2. 验证所有模块导入正常 -3. 测试关键功能路径 -4. 检查日志输出格式正确 - -## 🚀 系统状态 - -**状态**: ✅ 完全修复并可正常使用 - -**功能**: -- 请求级别的上下文管理 -- 结构化日志记录 -- 性能监控和跟踪 -- 错误和警告收集 -- 完整的搜索请求可见性 - -**可用性**: 系统现在可以正常处理所有搜索请求,提供完整的请求跟踪和性能监控。 \ No newline at end of file diff --git a/COMMIT_SUMMARY.md b/COMMIT_SUMMARY.md deleted file mode 100644 index 1b0adc6..0000000 --- a/COMMIT_SUMMARY.md +++ /dev/null @@ -1,116 +0,0 @@ -# 提交内容总结 - -## 📊 修改统计 -- **修改文件**: 4个核心文件 -- **新增文件**: 30+个文件(测试、文档、工具脚本等) -- **总变更**: 37个文件 - -## 🎯 核心功能修改 - -### 1. 请求上下文和日志系统 (`utils/logger.py`, `context/request_context.py`) -- **新增**: 结构化日志系统,支持请求级别的上下文跟踪 -- **新增**: 请求上下文管理器,存储查询分析结果和中间结果 -- **新增**: 性能监控,跟踪各阶段耗时和百分比 -- **修复**: 日志参数传递格式,解决 `Logger._log()` 错误 - -### 2. 查询解析系统 (`query/query_parser.py`) -- **增强**: 集成请求上下文,存储解析过程中的所有中间结果 -- **增强**: 支持查询分析结果的完整记录和日志 -- **修复**: 翻译功能API端点问题,从免费端点改为付费端点 -- **增强**: 错误处理和警告跟踪机制 - -### 3. 搜索引擎核心 (`search/searcher.py`) -- **新增**: 完整的请求级性能监控 -- **新增**: 各阶段(查询解析、布尔解析、查询构建、ES搜索、结果处理)的时间跟踪 -- **新增**: 上下文驱动的配置管理,自动使用配置文件默认值 -- **移除**: 对外暴露的内部参数(enable_translation、enable_embedding、enable_rerank) - -### 4. API接口 (`api/models.py`, `api/routes/search.py`) -- **简化**: 移除前端不需要的内部参数,API从8个参数减少到5个 -- **新增**: 请求ID和用户ID自动提取,支持请求关联 -- **新增**: 性能信息包含在响应中 -- **增强**: 请求上下文的完整集成 - -## 🔧 技术改进 - -### 性能监控 -- **查询解析阶段**: 自动跟踪和记录耗时 -- **布尔表达式解析**: AST生成和分析耗时 -- **ES查询构建**: 查询复杂度和构建时间 -- **ES搜索执行**: 响应时间和命中统计 -- **结果处理**: 排序和格式化耗时 - -### 日志系统 -- **结构化日志**: JSON格式,便于分析和搜索 -- **请求关联**: 每个日志条目包含reqid和uid -- **自动轮转**: 按天自动分割日志文件 -- **分级记录**: 支持不同日志级别和组件特定配置 - -### 请求上下文 -- **查询分析**: 原查询、标准化、重写、翻译、向量等完整记录 -- **中间结果**: ES查询、响应、处理结果等存储 -- **性能指标**: 详细的阶段耗时和百分比分析 -- **错误跟踪**: 完整的错误信息和警告记录 - -## 🐛 修复的问题 - -### 1. 翻译功能修复 -- **问题**: DeepL付费API密钥使用免费端点导致403错误 -- **解决**: 更换为正确的付费API端点 -- **结果**: 翻译功能正常,支持多语言(中文→英文、俄文等) - -### 2. 向量生成修复 -- **问题**: GPU内存不足导致CUDA out of memory错误 -- **解决**: 清理GPU内存,恢复向量生成功能 -- **结果**: 1024维向量正常生成,支持语义搜索 - -### 3. 日志系统修复 -- **问题**: Logger._log()不接受自定义参数格式 -- **解决**: 使用extra参数传递reqid、uid等自定义字段 -- **结果**: 日志系统完全正常,支持请求级跟踪 - -## 🌟 用户体验改进 - -### API简化 -- **前端调用**: 参数从8个减少到5个(减少37.5%) -- **内部透明**: enable_translation、enable_embedding、enable_rerank对用户透明 -- **功能完整**: 所有高级功能自动启用,用户无需配置 - -### 响应增强 -- **性能信息**: 包含详细的阶段耗时和百分比 -- **查询信息**: 包含查询分析、翻译、重写等完整信息 -- **请求跟踪**: 每个请求有唯一ID,便于问题排查 - -## 📁 新增文件分类 - -### 测试文件 -- `test_*.py`: 各种功能和集成测试 -- `tests/`: 单元测试和集成测试框架 - -### 文档文件 -- `*_SUMMARY.md`: 详细的修复和清理总结 -- `docs/`: 系统文档和使用指南 - -### 工具脚本 -- `scripts/`: 测试环境和性能测试脚本 -- `demo_*.py`: 功能演示和示例 - -### 配置文件 -- `.github/workflows/`: CI/CD流水线配置 - -## 🎯 核心价值 - -### 对用户 -- **API更简洁**: 只需要关心基本搜索参数 -- **功能更强大**: 自动获得翻译、向量搜索、排序等高级功能 -- **响应更详细**: 包含性能和查询处理信息 - -### 对开发者 -- **调试更容易**: 完整的请求级日志和上下文 -- **性能可观测**: 详细的阶段耗时分析 -- **问题定位快**: 通过reqid快速追踪请求全流程 - -### 对运维 -- **日志结构化**: 便于日志分析和监控 -- **配置灵活**: 通过配置文件控制功能开关 -- **监控完善**: 自动化的性能和错误监控 \ No newline at end of file diff --git a/FIXES_SUMMARY.md b/FIXES_SUMMARY.md deleted file mode 100644 index 368e303..0000000 --- a/FIXES_SUMMARY.md +++ /dev/null @@ -1,96 +0,0 @@ -# 修复总结报告 - -## 🎯 问题描述 - -系统出现以下问题: -1. **翻译功能返回None** - 查询"推车"翻译结果为`{'en': None, 'ru': None}` -2. **向量生成失败** - 向量显示为"否",没有生成1024维向量 - -## 🔍 根本原因分析 - -### 1. 翻译问题 -- **根本原因**: 使用了错误的API端点 -- **具体问题**: DeepL付费API密钥 `c9293ab4-ad25-479b-919f-ab4e63b429ed` 被用于免费端点 -- **错误信息**: `"Wrong endpoint. Use https://api.deepl.com"` - -### 2. 向量问题 -- **根本原因**: GPU内存不足 -- **具体问题**: Tesla T4 GPU被其他进程占用14GB,只剩6MB可用内存 -- **错误信息**: `"CUDA out of memory. Tried to allocate 20.00 MiB"` - -## ✅ 修复方案 - -### 1. 翻译功能修复 -**解决方案**: 使用正确的DeepL付费API端点 - -**修复代码**: -```python -# 修复前 -DEEPL_API_URL = "https://api-free.deepl.com/v2/translate" # Free tier - -# 修复后 -DEEPL_API_URL = "https://api.deepl.com/v2/translate" # Pro tier -``` - -**验证结果**: -- ✅ 英文翻译: `'推车'` → `'push a cart'` -- ✅ 俄文翻译: `'推车'` → `'толкать тележку'` - -### 2. 向量生成修复 -**解决方案**: 清理GPU内存,恢复向量生成功能 - -**执行步骤**: -1. 识别占用GPU的进程 -2. 清理GPU内存 -3. 验证向量生成功能 - -**验证结果**: -- ✅ 向量生成: 成功生成1024维向量 -- ✅ 向量质量: 正常的浮点数值 `[0.023, -0.0009, -0.006, ...]` - -## 🧪 修复验证 - -### 测试用例 -```python -test_query = "推车" -result = parser.parse(test_query, context=context, generate_vector=True) -``` - -### 修复前结果 -``` -翻译完成 | 结果: {'en': None, 'ru': None} -查询解析完成 | 翻译数量: 2 | 向量: 否 -``` - -### 修复后结果 -``` -翻译完成 | 结果: {'en': 'push a cart', 'ru': 'толкать тележку'} -查询解析完成 | 翻译数量: 2 | 向量: 是 -``` - -### 详细结果验证 -- ✅ **翻译功能**: 英文和俄文翻译都成功 -- ✅ **向量功能**: 成功生成1024维向量 -- ✅ **上下文存储**: 所有中间结果正确存储 -- ✅ **性能监控**: 请求跟踪和日志记录正常 - -## 📊 系统状态 - -**修复后的查询解析流程**: -1. ✅ 查询标准化: `'推车'` → `'推车'` -2. ✅ 语言检测: `'zh'` (中文) -3. ✅ 查询重写: 无重写(简单查询) -4. ✅ 翻译处理: 多语言翻译成功 -5. ✅ 向量生成: 1024维向量生成成功 -6. ✅ 结果存储: 上下文正确存储所有中间结果 - -## 🎉 最终状态 - -**系统现在完全正常工作**: -- ✅ 翻译功能支持多语言查询 -- ✅ 向量生成支持语义搜索 -- ✅ 请求上下文提供完整可见性 -- ✅ 性能监控跟踪所有处理阶段 -- ✅ 结构化日志记录所有操作 - -**所有问题已彻底解决,系统恢复正常运行!** 🚀 \ No newline at end of file diff --git a/IMPLEMENTATION_SUMMARY.md b/IMPLEMENTATION_SUMMARY.md deleted file mode 100644 index 195906b..0000000 --- a/IMPLEMENTATION_SUMMARY.md +++ /dev/null @@ -1,389 +0,0 @@ -# E-Commerce Search Engine SaaS - Implementation Summary - -## Overview - -A complete, production-ready configurable search engine for cross-border e-commerce has been implemented. The system supports multi-tenant configurations, multi-language processing, semantic search with embeddings, and flexible ranking. - -## What Was Built - -### 1. Core Configuration System (config/) - -**field_types.py** - Defines all supported field types and ES mappings: -- TEXT, KEYWORD, TEXT_EMBEDDING, IMAGE_EMBEDDING -- Numeric types (INT, LONG, FLOAT, DOUBLE) -- Date and Boolean types -- Analyzer definitions (Chinese, English, Russian, Arabic, Spanish, Japanese) -- ES mapping generation for each field type - -**config_loader.py** - YAML configuration loader and validator: -- Loads customer-specific configurations -- Validates field references and dependencies -- Supports application + index structure definitions -- Customer-specific query, ranking, and SPU settings - -**customer1_config.yaml** - Complete example configuration: -- 16 fields including text, embeddings, keywords, metadata -- 4 query domains (default, title, category, brand) -- Multi-language support (zh, en, ru) -- Query rewriting rules -- Ranking expression: `bm25() + 0.2*text_embedding_relevance()` - -### 2. Data Ingestion Pipeline (indexer/) - -**mapping_generator.py** - Generates ES mappings from configuration: -- Converts field configs to ES mapping JSON -- Applies default analyzers and similarity settings -- Helper methods to get embedding fields and match fields - -**data_transformer.py** - Transforms source data to ES documents: -- Batch embedding generation for efficiency -- Text embeddings using BGE-M3 (1024-dim) -- Image embeddings using CN-CLIP (1024-dim) -- Embedding cache to avoid recomputation -- Type conversion and validation - -**bulk_indexer.py** - Bulk indexing with error handling: -- Batch processing with configurable size -- Retry logic for failed batches -- Progress tracking and statistics -- Index creation and refresh - -**IndexingPipeline** - Complete end-to-end ingestion: -- Creates/recreates index with proper mapping -- Transforms data with embeddings -- Bulk indexes documents -- Reports statistics - -### 3. Query Processing (query/) - -**language_detector.py** - Rule-based language detection: -- Detects Chinese, English, Russian, Arabic, Japanese -- Unicode range analysis -- Script percentage calculation - -**translator.py** - Multi-language translation: -- DeepL API integration -- Translation caching -- Automatic target language determination -- Mock mode for testing without API key - -**query_rewriter.py** - Query rewriting and normalization: -- Dictionary-based rewriting (brand/category mappings) -- Query normalization (whitespace, special chars) -- Domain extraction (e.g., "brand:Nike" -> domain + query) - -**query_parser.py** - Main query processing pipeline: -- Orchestrates all query processing stages -- Normalization → Rewriting → Language Detection → Translation → Embedding -- Returns ParsedQuery with all processing results -- Supports multi-language query expansion - -### 4. Search Engine (search/) - -**boolean_parser.py** - Boolean expression parser: -- Supports AND, OR, RANK, ANDNOT operators -- Parentheses for grouping -- Correct operator precedence -- Builds query tree for ES conversion - -**es_query_builder.py** - ES DSL query builder: -- Converts query trees to ES bool queries -- Multi-match with BM25 scoring -- KNN queries for embeddings -- Filter support (term, range, terms) -- SPU collapse and aggregations - -**ranking_engine.py** - Configurable ranking: -- Expression parser (e.g., "bm25() + 0.2*text_embedding_relevance()") -- Function evaluation (bm25, text_embedding_relevance, field_value, timeliness) -- Score calculation from expressions -- Coefficient handling - -**searcher.py** - Main search orchestrator: -- Integrates QueryParser and BooleanParser -- Builds ES queries with hybrid BM25+KNN -- Applies custom ranking -- Handles SPU aggregation -- Image similarity search -- Result formatting - -### 5. Embeddings (embeddings/) - -**text_encoder.py** - BGE-M3 text encoder: -- Singleton pattern for model reuse -- Thread-safe initialization -- Batch encoding support -- GPU/CPU device selection -- 1024-dimensional vectors - -**image_encoder.py** - CN-CLIP image encoder: -- ViT-H-14 model -- URL and local file support -- Image validation and preprocessing -- Batch encoding -- 1024-dimensional vectors - -### 6. Utilities (utils/) - -**db_connector.py** - MySQL database connections: -- SQLAlchemy engine creation -- Connection pooling -- Configuration from dict -- Connection testing - -**es_client.py** - Elasticsearch client wrapper: -- Connection management -- Index CRUD operations -- Bulk indexing helper -- Search and count operations -- Ping and health checks - -**cache.py** - Caching system: -- EmbeddingCache: File-based cache for vectors -- DictCache: JSON cache for translations/rules -- MD5-based cache keys -- Category support - -### 7. REST API (api/) - -**app.py** - FastAPI application: -- Service initialization with configuration -- Global exception handling -- CORS middleware -- Startup event handling -- Environment variable support - -**models.py** - Pydantic request/response models: -- SearchRequest, ImageSearchRequest -- SearchResponse, DocumentResponse -- HealthResponse, ErrorResponse -- Validation and documentation - -**routes/search.py** - Search endpoints: -- POST /search/ - Text search with all features -- POST /search/image - Image similarity search -- GET /search/{doc_id} - Get document by ID - -**routes/admin.py** - Admin endpoints: -- GET /admin/health - Service health check -- GET /admin/config - Get configuration -- GET /admin/stats - Index statistics -- GET/POST /admin/rewrite-rules - Manage rewrite rules - -### 8. Customer1 Implementation - -**ingest_customer1.py** - Data ingestion script: -- Command-line interface -- CSV loading with limit support -- Embedding generation (optional) -- Index creation/recreation -- Progress tracking and statistics - -**customer1_config.yaml** - Production configuration: -- 16 fields optimized for e-commerce -- Multi-language fields (Chinese, English, Russian) -- Text and image embeddings -- Query rewrite rules for common terms -- Configured for Shoplazza data structure - -## Technical Highlights - -### Architecture Decisions - -1. **Configuration-Driven**: Everything customizable via YAML - - Field definitions, analyzers, ranking - - No code changes for new customers - -2. **Hybrid Search**: BM25 + Embeddings - - Lexical matching for precise queries - - Semantic search for conceptual queries - - Configurable blend (default: 80% BM25, 20% embeddings) - -3. **Multi-Language**: Automatic translation - - Query language detection - - Translation to all supported languages - - Multi-language field search - -4. **Performance Optimization**: - - Embedding caching (file-based) - - Batch processing for embeddings - - Connection pooling for DB and ES - - Singleton pattern for ML models - -5. **Extensibility**: - - Pluggable analyzers - - Custom ranking expressions - - Boolean operator support - - SPU aggregation - -### Key Features Implemented - -✅ **Multi-tenant configuration system** -✅ **Elasticsearch mapping generation** -✅ **Data transformation with embeddings** -✅ **Bulk indexing with error handling** -✅ **Query parsing and rewriting** -✅ **Language detection and translation** -✅ **Boolean expression parsing** -✅ **Hybrid BM25 + KNN search** -✅ **Configurable ranking engine** -✅ **Image similarity search** -✅ **RESTful API service** -✅ **Comprehensive caching** -✅ **Admin endpoints** -✅ **Customer1 test case** - -## Usage Examples - -### Data Ingestion - -```bash -python data/customer1/ingest_customer1.py \ - --csv data/customer1/goods_with_pic.5years_congku.csv.shuf.1w \ - --limit 1000 \ - --recreate-index \ - --batch-size 100 \ - --es-host http://localhost:9200 -``` - -### Start API Service - -```bash -python -m api.app \ - --host 0.0.0.0 \ - --port 6002 \ - --customer customer1 \ - --es-host http://localhost:9200 -``` - -### Search Examples - -```bash -# Simple Chinese query (auto-translates to English/Russian) -curl -X POST http://localhost:6002/search/ \ - -H "Content-Type: application/json" \ - -d '{"query": "芭比娃娃", "size": 10}' - -# Boolean query -curl -X POST http://localhost:6002/search/ \ - -H "Content-Type: application/json" \ - -d '{"query": "toy AND (barbie OR doll) ANDNOT cheap", "size": 10}' - -# Query with filters -curl -X POST http://localhost:6002/search/ \ - -H "Content-Type: application/json" \ - -d '{ - "query": "消防", - "size": 10, - "filters": {"categoryName_keyword": "消防"} - }' - -# Image search -curl -X POST http://localhost:6002/search/image \ - -H "Content-Type: application/json" \ - -d '{ - "image_url": "https://oss.essa.cn/example.jpg", - "size": 10 - }' -``` - -## Next Steps for Production - -### Required: -1. **DeepL API Key**: Set for production translation -2. **ML Models**: Download BGE-M3 and CN-CLIP models -3. **Elasticsearch Cluster**: Production ES setup -4. **MySQL Connection**: Configure Shoplazza database access - -### Recommended: -1. **Redis Cache**: Replace file cache with Redis -2. **Async Processing**: Celery for batch indexing -3. **Monitoring**: Prometheus + Grafana -4. **Load Testing**: Benchmark with production data -5. **CI/CD**: Automated testing and deployment - -### Optional Enhancements: -1. **Image Upload**: Support direct image upload vs URL -2. **Personalization**: User-based ranking adjustments -3. **A/B Testing**: Ranking expression experiments -4. **Analytics**: Query logging and analysis -5. **Auto-complete**: Suggest-as-you-type - -## Files Created - -**Configuration (5 files)**: -- config/field_types.py -- config/config_loader.py -- config/__init__.py -- config/schema/customer1_config.yaml - -**Indexer (4 files)**: -- indexer/mapping_generator.py -- indexer/data_transformer.py -- indexer/bulk_indexer.py -- indexer/__init__.py - -**Query (5 files)**: -- query/language_detector.py -- query/translator.py -- query/query_rewriter.py -- query/query_parser.py -- query/__init__.py - -**Search (5 files)**: -- search/boolean_parser.py -- search/es_query_builder.py -- search/ranking_engine.py -- search/searcher.py -- search/__init__.py - -**Embeddings (3 files)**: -- embeddings/text_encoder.py -- embeddings/image_encoder.py -- embeddings/__init__.py - -**Utils (4 files)**: -- utils/db_connector.py -- utils/es_client.py -- utils/cache.py -- utils/__init__.py - -**API (6 files)**: -- api/app.py -- api/models.py -- api/routes/search.py -- api/routes/admin.py -- api/routes/__init__.py -- api/__init__.py - -**Data (1 file)**: -- data/customer1/ingest_customer1.py - -**Documentation (3 files)**: -- README.md -- requirements.txt -- IMPLEMENTATION_SUMMARY.md (this file) - -**Total: 36 implementation files** - -## Success Criteria Met - -✅ **Configurable Universal Search System**: Complete YAML-based configuration -✅ **Multi-tenant Support**: Customer-specific schemas and extensions -✅ **QueryParser Module**: Rewriting, translation, embedding generation -✅ **Searcher Module**: Boolean operators, hybrid ranking, SPU support -✅ **Customer1 Case Study**: Complete configuration and ingestion script -✅ **REST API Service**: Full-featured FastAPI application -✅ **Production-Ready**: Error handling, caching, monitoring endpoints - -## Conclusion - -A complete, production-grade e-commerce search SaaS has been implemented following industry best practices. The system is: - -- **Flexible**: Configuration-driven for easy customization -- **Scalable**: Designed for multi-tenant deployment -- **Powerful**: Hybrid search with semantic understanding -- **International**: Multi-language support with translation -- **Extensible**: Modular architecture for future enhancements - -The implementation is ready for deployment and testing with real data. diff --git a/SERVER_FIXES.md b/SERVER_FIXES.md deleted file mode 100644 index 8b22f6f..0000000 --- a/SERVER_FIXES.md +++ /dev/null @@ -1,142 +0,0 @@ -# 服务器修复和优化文档 - -## 修复的问题 - -### 1. 前端服务器问题 (scripts/frontend_server.py) -- **问题**: 接收到大量扫描器流量导致的错误日志 -- **原因**: SSL/TLS握手尝试、RDP连接扫描、二进制数据攻击 -- **解决方案**: - - 添加错误处理机制,优雅处理连接断开 - - 实现速率限制 (100请求/分钟) - - 过滤扫描器噪音日志 - - 添加安全HTTP头 - - 使用线程服务器提高并发处理能力 - -### 2. API服务器问题 (api/app.py) -- **问题**: 缺乏安全性和错误处理机制 -- **解决方案**: - - 集成速率限制 (slowapi) - - 添加安全HTTP头 - - 实现更好的异常处理 - - 添加健康检查端点 - - 增强日志记录 - - 添加服务关闭处理 - -## 主要改进 - -### 安全性增强 -1. **速率限制**: 防止DDoS攻击和滥用 -2. **安全HTTP头**: 防止XSS、点击劫持等攻击 -3. **错误过滤**: 隐藏敏感错误信息 -4. **输入验证**: 更健壮的请求处理 - -### 稳定性提升 -1. **连接错误处理**: 优雅处理连接重置和断开 -2. **异常处理**: 全局异常捕获,防止服务器崩溃 -3. **日志管理**: 过滤噪音,记录重要事件 -4. **监控功能**: 健康检查和状态监控 - -### 性能优化 -1. **线程服务器**: 前端服务器支持并发请求 -2. **资源管理**: 更好的内存和连接管理 -3. **响应头优化**: 添加缓存和安全相关头 - -## 使用方法 - -### 安装依赖 -```bash -# 安装服务器安全依赖 -./scripts/install_server_deps.sh - -# 或者手动安装 -pip install slowapi>=0.1.9 anyio>=3.7.0 -``` - -### 启动服务器 - -#### 方法1: 使用管理脚本 (推荐) -```bash -# 启动所有服务器 -python scripts/start_servers.py --customer customer1 --es-host http://localhost:9200 - -# 启动前检查依赖 -python scripts/start_servers.py --check-dependencies -``` - -#### 方法2: 分别启动 -```bash -# 启动API服务器 -python main.py serve --customer customer1 --es-host http://localhost:9200 - -# 启动前端服务器 (在另一个终端) -python scripts/frontend_server.py -``` - -### 监控和日志 - -#### 日志位置 -- API服务器日志: `/tmp/search_engine_api.log` -- 启动日志: `/tmp/search_engine_startup.log` -- 控制台输出: 实时显示重要信息 - -#### 健康检查 -```bash -# 检查API服务器健康状态 -curl http://localhost:6002/health - -# 检查前端服务器 -curl http://localhost:6003 -``` - -## 配置选项 - -### 环境变量 -- `CUSTOMER_ID`: 客户ID (默认: customer1) -- `ES_HOST`: Elasticsearch主机 (默认: http://localhost:9200) - -### 速率限制配置 -- API服务器: 各端点不同限制 (60-120请求/分钟) -- 前端服务器: 100请求/分钟 - -## 故障排除 - -### 常见问题 - -1. **依赖缺失错误** - ```bash - pip install -r requirements_server.txt - ``` - -2. **端口被占用** - ```bash - # 查看端口占用 - lsof -i :6002 - lsof -i :6003 - ``` - -3. **权限问题** - ```bash - chmod +x scripts/*.py scripts/*.sh - ``` - -### 调试模式 -```bash -# 启用详细日志 -export PYTHONUNBUFFERED=1 -python scripts/start_servers.py -``` - -## 生产环境建议 - -1. **反向代理**: 使用nginx或Apache作为反向代理 -2. **SSL证书**: 配置HTTPS -3. **防火墙**: 限制访问源IP -4. **监控**: 集成监控和告警系统 -5. **日志轮转**: 配置日志轮转防止磁盘满 - -## 维护说明 - -- 定期检查日志文件大小 -- 监控服务器资源使用情况 -- 更新依赖包版本 -- 备份配置文件 \ No newline at end of file diff --git a/demo_context_logging.py b/demo_context_logging.py deleted file mode 100644 index 923bda2..0000000 --- a/demo_context_logging.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env python3 -""" -Demonstration of the Request Context and Logging system - -This script demonstrates how the request-scoped context management -and structured logging work together to provide complete visibility -into search request processing. -""" - -import time -import sys -import os - -# Add the project root to Python path -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) - -# Setup the environment (use the conda environment) -os.system('source /home/tw/miniconda3/etc/profile.d/conda.sh && conda activate searchengine') - -def demo_request_context(): - """Demonstrate RequestContext functionality""" - print("🚀 Starting Request Context and Logging Demo") - print("=" * 60) - - try: - from utils.logger import get_logger, setup_logging - from context.request_context import create_request_context, RequestContextStage - - # Setup logging - setup_logging(log_level="INFO", log_dir="demo_logs") - logger = get_logger("demo") - - print("✅ Logging infrastructure initialized") - - # Create a request context - context = create_request_context("demo123", "demo_user") - print(f"✅ Created request context: reqid={context.reqid}, uid={context.uid}") - - # Simulate a complete search pipeline - with context: # Use context manager for automatic timing - logger.info("开始模拟搜索请求处理", extra={'reqid': context.reqid, 'uid': context.uid}) - - # Stage 1: Query parsing - context.start_stage(RequestContextStage.QUERY_PARSING) - time.sleep(0.02) # Simulate work - - # Store query analysis results - context.store_query_analysis( - original_query="红色高跟鞋 品牌:Nike", - normalized_query="红色 高跟鞋 品牌:Nike", - rewritten_query="红色 高跟鞋 品牌:nike", - detected_language="zh", - translations={"en": "red high heels brand:nike"}, - domain="brand" - ) - - context.store_intermediate_result("query_vector_shape", (1024,)) - context.end_stage(RequestContextStage.QUERY_PARSING) - - # Stage 2: Boolean parsing - context.start_stage(RequestContextStage.BOOLEAN_PARSING) - time.sleep(0.005) # Simulate work - context.store_intermediate_result("boolean_ast", "AND(红色, 高跟鞋, BRAND:nike)") - context.end_stage(RequestContextStage.BOOLEAN_PARSING) - - # Stage 3: Query building - context.start_stage(RequestContextStage.QUERY_BUILDING) - time.sleep(0.01) # Simulate work - es_query = { - "query": {"bool": {"must": [{"match": {"title": "红色 高跟鞋"}}]}}, - "knn": {"field": "text_embedding", "query_vector": [0.1] * 1024} - } - context.store_intermediate_result("es_query", es_query) - context.end_stage(RequestContextStage.QUERY_BUILDING) - - # Stage 4: Elasticsearch search - context.start_stage(RequestContextStage.ELASTICSEARCH_SEARCH) - time.sleep(0.05) # Simulate work - es_response = { - "hits": {"total": {"value": 42}, "max_score": 0.95, "hits": []}, - "took": 15 - } - context.store_intermediate_result("es_response", es_response) - context.end_stage(RequestContextStage.ELASTICSEARCH_SEARCH) - - # Stage 5: Result processing - context.start_stage(RequestContextStage.RESULT_PROCESSING) - time.sleep(0.01) # Simulate work - context.store_intermediate_result("processed_hits", [ - {"_id": "1", "_score": 0.95}, - {"_id": "2", "_score": 0.87} - ]) - context.end_stage(RequestContextStage.RESULT_PROCESSING) - - # Add a warning to demonstrate warning tracking - context.add_warning("查询被重写: '红色 高跟鞋 品牌:Nike' -> 'red high heels brand:nike'") - - # Get and display summary - summary = context.get_summary() - print("\n📊 Request Summary:") - print("-" * 40) - print(f"Request ID: {summary['request_info']['reqid']}") - print(f"User ID: {summary['request_info']['uid']}") - print(f"Total Duration: {summary['performance']['total_duration_ms']:.2f}ms") - print("\n⏱️ Stage Breakdown:") - for stage, duration in summary['performance']['stage_timings_ms'].items(): - percentage = summary['performance']['stage_percentages'].get(stage, 0) - print(f" {stage}: {duration:.2f}ms ({percentage}%)") - - print("\n🔍 Query Analysis:") - print(f" Original: '{summary['query_analysis']['original_query']}'") - print(f" Rewritten: '{summary['query_analysis']['rewritten_query']}'") - print(f" Language: {summary['query_analysis']['detected_language']}") - print(f" Domain: {summary['query_analysis']['domain']}") - print(f" Has Vector: {summary['query_analysis']['has_vector']}") - - print("\n📈 Results:") - print(f" Total Hits: {summary['results']['total_hits']}") - print(f" ES Query Size: {summary['results']['es_query_size']} chars") - - print("\n⚠️ Warnings:") - print(f" Count: {summary['request_info']['warnings_count']}") - - print("\n✅ Demo completed successfully!") - print(f"📁 Logs are available in: demo_logs/") - - except Exception as e: - print(f"❌ Demo failed: {e}") - import traceback - traceback.print_exc() - return False - - return True - -if __name__ == "__main__": - success = demo_request_context() - if success: - print("\n🎉 Request Context and Logging system is ready for production!") - else: - print("\n💥 Please check the errors above") - sys.exit(1) \ No newline at end of file diff --git a/diagnose_issues.py b/diagnose_issues.py deleted file mode 100644 index 10da12d..0000000 --- a/diagnose_issues.py +++ /dev/null @@ -1,220 +0,0 @@ -#!/usr/bin/env python3 -""" -诊断翻译和向量生成问题 -""" - -import sys -import os -import traceback - -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) - -def diagnose_translation_issue(): - """诊断翻译问题""" - print("🔍 诊断翻译功能...") - print("-" * 50) - - try: - from query.translator import Translator - from config.env_config import get_deepl_key - - # 检查API密钥 - try: - api_key = get_deepl_key() - print(f"✅ DeepL API密钥已配置: {'*' * len(api_key[:8]) if api_key else 'None'}") - except Exception as e: - print(f"❌ DeepL API密钥配置失败: {e}") - api_key = None - - # 创建翻译器 - translator = Translator(api_key=api_key, use_cache=True) - print(f"✅ 翻译器创建成功,API密钥状态: {'已配置' if api_key else '未配置'}") - - # 测试翻译 - test_text = "推车" - print(f"\n📝 测试翻译文本: '{test_text}'") - - # 测试英文翻译 - result_en = translator.translate(test_text, "en", "zh") - print(f"🇺🇸 英文翻译结果: {result_en}") - - # 测试俄文翻译 - result_ru = translator.translate(test_text, "ru", "zh") - print(f"🇷🇺 俄文翻译结果: {result_ru}") - - # 测试多语言翻译 - results = translator.translate_multi(test_text, ["en", "ru"], "zh") - print(f"🌍 多语言翻译结果: {results}") - - # 检查翻译需求逻辑 - needs = translator.get_translation_needs("zh", ["en", "ru"]) - print(f"🎯 翻译需求分析: {needs}") - - if api_key: - print("\n✅ 翻译功能配置正确,可能的问题:") - print(" 1. 网络连接问题") - print(" 2. API限额或配额问题") - print(" 3. DeepL服务暂时不可用") - else: - print("\n⚠️ 翻译功能处于模拟模式(无API密钥)") - print(" 这会导致翻译返回原始文本或None") - - except Exception as e: - print(f"❌ 翻译功能诊断失败: {e}") - traceback.print_exc() - -def diagnose_embedding_issue(): - """诊断向量生成问题""" - print("\n🔍 诊断向量生成功能...") - print("-" * 50) - - try: - from embeddings.text_encoder import BgeEncoder - import torch - - # 检查CUDA可用性 - cuda_available = torch.cuda.is_available() - print(f"🔧 CUDA可用性: {'是' if cuda_available else '否'}") - if cuda_available: - print(f"🔧 CUDA设备数量: {torch.cuda.device_count()}") - print(f"🔧 当前CUDA设备: {torch.cuda.current_device()}") - - # 尝试创建编码器 - print("\n📦 尝试创建BGE编码器...") - try: - encoder = BgeEncoder() - print("✅ BGE编码器创建成功") - except Exception as e: - print(f"❌ BGE编码器创建失败: {e}") - print("可能的原因:") - print(" 1. 模型文件未下载") - print(" 2. 内存不足") - print(" 3. 依赖包未正确安装") - return - - # 测试向量生成 - test_text = "推车" - print(f"\n📝 测试向量生成文本: '{test_text}'") - - try: - # 尝试CPU模式 - print("🔄 尝试CPU模式...") - embedding_cpu = encoder.encode(test_text, device='cpu') - print(f"✅ CPU模式向量生成成功,形状: {embedding_cpu.shape}") - - # 尝试CUDA模式(如果可用) - if cuda_available: - print("🔄 尝试CUDA模式...") - embedding_cuda = encoder.encode(test_text, device='cuda') - print(f"✅ CUDA模式向量生成成功,形状: {embedding_cuda.shape}") - else: - print("⚠️ CUDA不可用,跳过GPU测试") - - except Exception as e: - print(f"❌ 向量生成失败: {e}") - print("可能的原因:") - print(" 1. 模型加载问题") - print(" 2. 内存不足") - print(" 3. 设备配置问题") - - except Exception as e: - print(f"❌ 向量生成功能诊断失败: {e}") - traceback.print_exc() - -def diagnose_config_issue(): - """诊断配置问题""" - print("\n🔍 诊断配置问题...") - print("-" * 50) - - try: - from config import CustomerConfig - from config.config_loader import load_customer_config - - # 加载配置 - config = load_customer_config("customer1") - print(f"✅ 配置加载成功: {config.customer_id}") - - # 检查查询配置 - query_config = config.query_config - print(f"📝 翻译功能启用: {query_config.enable_translation}") - print(f"🔤 向量生成启用: {query_config.enable_text_embedding}") - print(f"🌍 支持的语言: {query_config.supported_languages}") - - # 检查API密钥配置 - try: - from config.env_config import get_deepl_key - api_key = get_deepl_key() - print(f"🔑 DeepL API密钥: {'已配置' if api_key else '未配置'}") - except: - print("🔑 DeepL API密钥: 配置加载失败") - - except Exception as e: - print(f"❌ 配置诊断失败: {e}") - traceback.print_exc() - -def simulate_query_parsing(): - """模拟查询解析过程""" - print("\n🔍 模拟查询解析过程...") - print("-" * 50) - - try: - from context.request_context import create_request_context - from query.query_parser import QueryParser - from config import CustomerConfig - from config.config_loader import load_customer_config - - # 加载配置 - config = load_customer_config("customer1") - parser = QueryParser(config) - context = create_request_context("test_diagnosis", "diagnosis_user") - - # 模拟解析"推车" - print("📝 开始解析查询: '推车'") - - # 检查各个功能是否启用 - print(f" - 翻译功能: {'启用' if config.query_config.enable_translation else '禁用'}") - print(f" - 向量功能: {'启用' if config.query_config.enable_text_embedding else '禁用'}") - - # 检查翻译器状态 - if hasattr(parser, '_translator') and parser._translator: - translator_has_key = bool(parser._translator.api_key) - print(f" - 翻译器API密钥: {'有' if translator_has_key else '无'}") - else: - print(f" - 翻译器状态: 未初始化") - - # 检查向量编码器状态 - if hasattr(parser, '_text_encoder') and parser._text_encoder: - print(f" - 向量编码器: 已初始化") - else: - print(f" - 向量编码器: 未初始化") - - # 执行解析 - result = parser.parse("推车", context=context, generate_vector=config.query_config.enable_text_embedding) - - print(f"\n📊 解析结果:") - print(f" 原查询: {result.original_query}") - print(f" 标准化: {result.normalized_query}") - print(f" 重写后: {result.rewritten_query}") - print(f" 检测语言: {result.detected_language}") - print(f" 域: {result.domain}") - print(f" 翻译结果: {result.translations}") - print(f" 向量: {'有' if result.query_vector is not None else '无'}") - - if result.query_vector is not None: - print(f" 向量形状: {result.query_vector.shape}") - - except Exception as e: - print(f"❌ 查询解析模拟失败: {e}") - traceback.print_exc() - -if __name__ == "__main__": - print("🧪 开始系统诊断...") - print("=" * 60) - - diagnose_translation_issue() - diagnose_embedding_issue() - diagnose_config_issue() - simulate_query_parsing() - - print("\n" + "=" * 60) - print("🏁 诊断完成!请查看上述结果找出问题原因。") \ No newline at end of file -- libgit2 0.21.2