Commit 670c701f0ec255b609be6d2272e5efd27208bb73
1 parent
331ea682
文档完善
Showing
2 changed files
with
194 additions
and
652 deletions
Show diff stats
README.md
| 1 | -# 电商搜索引擎 SaaS 系统 | 1 | +# 电商搜索引擎 SaaS |
| 2 | 2 | ||
| 3 | -一个可配置的多租户搜索引擎,专为跨境电商独立站(店匠 Shoplazza)设计。 | 3 | +一个针对跨境独立站(店匠 Shoplazza 等)的多租户可配置搜索平台。README 作为项目导航入口,帮助你在不同阶段定位到更详细的文档。 |
| 4 | 4 | ||
| 5 | -## 系统特性 | 5 | +## 核心能力速览 |
| 6 | 6 | ||
| 7 | -- **多语言支持**:支持中文、英文、俄文、阿拉伯文、西班牙文、日文,支持自动翻译 | ||
| 8 | -- **语义搜索**:基于 BGE-M3 文本向量和 CN-CLIP 图片向量的语义检索 | ||
| 9 | -- **混合排序**:结合 BM25 文本相关性和语义相似度 | ||
| 10 | -- **布尔表达式**:支持 AND、OR、RANK、ANDNOT 操作符,支持括号优先级 | ||
| 11 | -- **灵活过滤**:精确匹配过滤器和数值范围过滤器 | ||
| 12 | -- **分面搜索**:动态生成过滤选项,提供分组统计 | ||
| 13 | -- **可配置化**:客户特定的字段定义、分析器、排序表达式 | ||
| 14 | -- **多租户隔离**:通过 `tenant_id` 实现数据隔离,共享统一索引 | ||
| 15 | -- **RESTful API**:基于 FastAPI 的完整 API 服务 | ||
| 16 | -- **前端界面**:提供可视化搜索测试界面 | 7 | +- **多语言 + 自动翻译**:中文、英文、俄文等语言检测与路由(BGE-M3、DeepL) |
| 8 | +- **语义 + 关键词混排**:BM25、dense vector(BGE-M3/CN-CLIP)融合 | ||
| 9 | +- **布尔与分面**:AND / OR / ANDNOT / RANK、Terms & Range facets | ||
| 10 | +- **多租户隔离**:共享 `search_products` 索引,通过 `tenant_id` 严格隔离 | ||
| 11 | +- **可配置化**:字段/索引域/排序表达式/查询改写全部配置驱动 | ||
| 12 | +- **脚本化流水线**:Mock/CSV 数据 → MySQL → Elasticsearch → API/前端 | ||
| 17 | 13 | ||
| 18 | -## 系统架构 | 14 | +## 快速上手(概览) |
| 19 | 15 | ||
| 20 | -### 数据模型 | 16 | +| 步骤 | 去哪里看 | 摘要 | |
| 17 | +|------|---------|------| | ||
| 18 | +| 1. 准备环境 | `环境相关.md` / `USAGE_GUIDE.md` | Conda/依赖、Elasticsearch、MySQL、必需的变量 | | ||
| 19 | +| 2. 构造测试数据 | `TEST_DATA_GUIDE.md` | Tenant1 Mock、Tenant2 CSV、`mock_data.sh` / `ingest.sh` | | ||
| 20 | +| 3. 启动与验证 | `USAGE_GUIDE.md` | `run.sh` 一键启动、分步脚本、日志与健康检查 | | ||
| 21 | +| 4. 理解架构 | `设计文档.md` | 数据流、配置系统、查询/搜索/索引模块 | | ||
| 22 | +| 5. 接入搜索 API | `API_DOCUMENTATION.md` / `API_INTEGRATION_GUIDE.md` | REST 端点、参数、响应、最佳实践 | | ||
| 23 | +| 6. 查字段定义 | `INDEX_FIELDS_DOCUMENTATION.md` | `search_products` 映射、字段来源、类型与用途 | | ||
| 21 | 24 | ||
| 22 | -- **SPU 级别索引**:所有租户共享 `search_products` 索引 | ||
| 23 | -- **嵌套结构**:每个 SPU 文档包含嵌套的 `variants` 数组(SKU 变体) | ||
| 24 | -- **租户隔离**:通过 `tenant_id` 字段实现多租户数据隔离 | ||
| 25 | -- **数据源**:MySQL 数据库(`shoplazza_product_spu` 和 `shoplazza_product_sku` 表) | 25 | +> README 仅保留最常用命令的“索引”。细节以主题文档为准。 |
| 26 | 26 | ||
| 27 | -### 技术栈 | ||
| 28 | - | ||
| 29 | -- **后端框架**:Python 3.8+ / FastAPI | ||
| 30 | -- **搜索引擎**:Elasticsearch 8.x | ||
| 31 | -- **数据库**:MySQL(店匠数据表) | ||
| 32 | -- **向量模型**: | ||
| 33 | - - 文本向量:BGE-M3(1024维) | ||
| 34 | - - 图片向量:CN-CLIP(1024维) | ||
| 35 | -- **翻译服务**:DeepL API | ||
| 36 | -- **前端**:HTML + JavaScript | ||
| 37 | - | ||
| 38 | -## 快速开始 | ||
| 39 | - | ||
| 40 | -### 1. 环境准备 | ||
| 41 | - | ||
| 42 | -#### 安装依赖 | ||
| 43 | - | ||
| 44 | -```bash | ||
| 45 | -pip install -r requirements.txt | ||
| 46 | -``` | ||
| 47 | - | ||
| 48 | -#### 启动 Elasticsearch | ||
| 49 | - | ||
| 50 | -```bash | ||
| 51 | -# 使用 Docker | ||
| 52 | -docker run -d \ | ||
| 53 | - --name elasticsearch \ | ||
| 54 | - -p 9200:9200 \ | ||
| 55 | - -e "discovery.type=single-node" \ | ||
| 56 | - -e "ES_JAVA_OPTS=-Xms2g -Xmx2g" \ | ||
| 57 | - elasticsearch:8.11.0 | ||
| 58 | -``` | ||
| 59 | - | ||
| 60 | -#### 配置环境变量(可选) | ||
| 61 | - | ||
| 62 | -创建 `.env` 文件: | 27 | +### Runtimes & 命令示例 |
| 63 | 28 | ||
| 64 | ```bash | 29 | ```bash |
| 65 | -DB_HOST=120.79.247.228 | ||
| 66 | -DB_PORT=3316 | ||
| 67 | -DB_DATABASE=saas | ||
| 68 | -DB_USERNAME=saas | ||
| 69 | -DB_PASSWORD=your_password | ||
| 70 | -ES_HOST=http://localhost:9200 | ||
| 71 | -``` | ||
| 72 | - | ||
| 73 | -### 2. 脚本体系 | ||
| 74 | - | ||
| 75 | -项目提供统一的脚本系统,管理完整的工作流程: | ||
| 76 | - | ||
| 77 | -#### 脚本说明 | 30 | +# 1. 安装依赖与准备服务 |
| 31 | +pip install -r requirements.txt # 详见 USAGE_GUIDE.md | ||
| 32 | +docker run -d --name es -p 9200:9200 elasticsearch:8.11.0 | ||
| 78 | 33 | ||
| 79 | -| 脚本 | 功能 | 说明 | | ||
| 80 | -|------|------|------| | ||
| 81 | -| `restart.sh` | 重启服务 | 停止并重新启动前后端服务 | | ||
| 82 | -| `run.sh` | 启动服务 | 启动前端和后端服务 | | ||
| 83 | -| `scripts/mock_data.sh` | 数据导入 | 将 Mock 数据或 CSV 数据导入 MySQL | | ||
| 84 | -| `scripts/ingest.sh` | 数据索引 | 从 MySQL 导入数据到 Elasticsearch | | ||
| 85 | - | ||
| 86 | -### 3. 手动启动 API 服务(可选) | ||
| 87 | - | ||
| 88 | -如果不想使用脚本,可以手动启动: | ||
| 89 | - | ||
| 90 | -```bash | ||
| 91 | -python -m api.app \ | ||
| 92 | - --host 0.0.0.0 \ | ||
| 93 | - --port 6002 \ | ||
| 94 | - --es-host http://localhost:9200 \ | ||
| 95 | - --reload | ||
| 96 | -``` | 34 | +# 2. 构造测试数据并导入 MySQL |
| 35 | +./scripts/mock_data.sh # 详见 TEST_DATA_GUIDE.md | ||
| 97 | 36 | ||
| 98 | -### 4. 测试搜索 | 37 | +# 3. 从 MySQL 注入到 Elasticsearch |
| 38 | +./scripts/ingest.sh 1 true | ||
| 39 | +./scripts/ingest.sh 2 true | ||
| 99 | 40 | ||
| 100 | -#### 简单搜索 | 41 | +# 4. 启动服务 |
| 42 | +./run.sh | ||
| 101 | 43 | ||
| 102 | -```bash | 44 | +# 5. 调用文本搜索 API |
| 103 | curl -X POST http://localhost:6002/search/ \ | 45 | curl -X POST http://localhost:6002/search/ \ |
| 104 | -H "Content-Type: application/json" \ | 46 | -H "Content-Type: application/json" \ |
| 105 | - -d '{ | ||
| 106 | - "query": "蓝牙耳机", | ||
| 107 | - "size": 10 | ||
| 108 | - }' | ||
| 109 | -``` | ||
| 110 | - | ||
| 111 | -#### 带过滤器的搜索 | ||
| 112 | - | ||
| 113 | -```bash | ||
| 114 | -curl -X POST http://localhost:6002/search/ \ | ||
| 115 | - -H "Content-Type: application/json" \ | ||
| 116 | - -d '{ | ||
| 117 | - "query": "玩具", | ||
| 118 | - "size": 10, | ||
| 119 | - "filters": { | ||
| 120 | - "categoryName_keyword": "玩具" | ||
| 121 | - }, | ||
| 122 | - "range_filters": { | ||
| 123 | - "min_price": { | ||
| 124 | - "gte": 50, | ||
| 125 | - "lte": 200 | ||
| 126 | - } | ||
| 127 | - } | ||
| 128 | - }' | ||
| 129 | -``` | ||
| 130 | - | ||
| 131 | -#### 布尔表达式搜索 | ||
| 132 | - | ||
| 133 | -```bash | ||
| 134 | -curl -X POST http://localhost:6002/search/ \ | ||
| 135 | - -H "Content-Type: application/json" \ | ||
| 136 | - -d '{ | ||
| 137 | - "query": "蓝牙 AND (耳机 OR 音响)", | ||
| 138 | - "size": 10 | ||
| 139 | - }' | ||
| 140 | -``` | ||
| 141 | - | ||
| 142 | -#### 图片搜索 | ||
| 143 | - | ||
| 144 | -```bash | ||
| 145 | -curl -X POST http://localhost:6002/search/image \ | ||
| 146 | - -H "Content-Type: application/json" \ | ||
| 147 | - -d '{ | ||
| 148 | - "image_url": "https://oss.essa.cn/example.jpg", | ||
| 149 | - "size": 10 | ||
| 150 | - }' | ||
| 151 | -``` | ||
| 152 | - | ||
| 153 | -#### 分面搜索 | ||
| 154 | - | ||
| 155 | -```bash | ||
| 156 | -curl -X POST http://localhost:6002/search/ \ | ||
| 157 | - -H "Content-Type: application/json" \ | ||
| 158 | - -d '{ | ||
| 159 | - "query": "玩具", | ||
| 160 | - "size": 10, | ||
| 161 | - "facets": [ | ||
| 162 | - { | ||
| 163 | - "field": "categoryName_keyword", | ||
| 164 | - "label": "分类" | ||
| 165 | - }, | ||
| 166 | - { | ||
| 167 | - "field": "brandName_keyword", | ||
| 168 | - "label": "品牌" | ||
| 169 | - } | ||
| 170 | - ] | ||
| 171 | - }' | ||
| 172 | -``` | ||
| 173 | - | ||
| 174 | -## 项目结构 | ||
| 175 | - | ||
| 176 | -``` | ||
| 177 | -SearchEngine/ | ||
| 178 | -├── api/ # API 服务 | ||
| 179 | -│ ├── app.py # FastAPI 应用主入口 | ||
| 180 | -│ ├── models.py # 请求/响应模型 | ||
| 181 | -│ └── routes/ # API 路由 | ||
| 182 | -│ ├── search.py # 搜索接口 | ||
| 183 | -│ └── admin.py # 管理接口 | ||
| 184 | -├── config/ # 配置系统 | ||
| 185 | -│ ├── field_types.py # 字段类型定义 | ||
| 186 | -│ ├── config_loader.py # 配置加载器 | ||
| 187 | -│ └── schema/ # 租户配置文件 | ||
| 188 | -│ └── base/ # Base 配置(店匠通用) | ||
| 189 | -│ └── config.yaml | ||
| 190 | -├── indexer/ # 数据索引 | ||
| 191 | -│ ├── mapping_generator.py # ES mapping 生成器 | ||
| 192 | -│ ├── spu_transformer.py # SPU 数据转换器 | ||
| 193 | -│ ├── bulk_indexer.py # 批量索引器 | ||
| 194 | -│ └── ingest_shoplazza.py # 店匠数据导入脚本 | ||
| 195 | -├── query/ # 查询处理 | ||
| 196 | -│ ├── query_parser.py # 查询解析器 | ||
| 197 | -│ ├── language_detector.py # 语言检测 | ||
| 198 | -│ ├── translator.py # 翻译服务 | ||
| 199 | -│ └── query_rewriter.py # 查询改写 | ||
| 200 | -├── search/ # 搜索执行 | ||
| 201 | -│ ├── searcher.py # 主搜索器 | ||
| 202 | -│ ├── multilang_query_builder.py # 多语言查询构建器 | ||
| 203 | -│ ├── boolean_parser.py # 布尔表达式解析器 | ||
| 204 | -│ ├── es_query_builder.py # ES 查询构建器 | ||
| 205 | -│ └── ranking_engine.py # 排序引擎 | ||
| 206 | -├── embeddings/ # 向量编码 | ||
| 207 | -│ ├── text_encoder.py # BGE-M3 文本编码器 | ||
| 208 | -│ └── image_encoder.py # CN-CLIP 图片编码器 | ||
| 209 | -├── utils/ # 工具类 | ||
| 210 | -│ ├── db_connector.py # MySQL 连接器 | ||
| 211 | -│ ├── es_client.py # ES 客户端封装 | ||
| 212 | -│ └── cache.py # 向量缓存 | ||
| 213 | -├── scripts/ # 脚本工具 | ||
| 214 | -│ ├── mock_data.sh # Mock 数据导入脚本 | ||
| 215 | -│ ├── ingest.sh # 数据索引脚本 | ||
| 216 | -│ ├── generate_test_data.py # 生成测试数据 | ||
| 217 | -│ ├── import_tenant2_csv.py # Tenant2 CSV 导入脚本 | ||
| 218 | -│ └── import_test_data.py # 数据导入脚本 | ||
| 219 | -├── frontend/ # 前端界面 | ||
| 220 | -│ └── unified.html # 统一搜索界面 | ||
| 221 | -├── data/ # 数据文件 | ||
| 222 | -│ └── customer1/ # customer1 测试数据 | ||
| 223 | -├── run.sh # 启动脚本 | ||
| 224 | -├── restart.sh # 重启脚本 | ||
| 225 | -└── requirements.txt # Python 依赖 | ||
| 226 | -``` | ||
| 227 | - | ||
| 228 | -## 配置系统 | ||
| 229 | - | ||
| 230 | -### 配置文件结构 | ||
| 231 | - | ||
| 232 | -配置文件位于 `config/schema/{tenant_id}/config.yaml`,Base 配置位于 `config/schema/base/config.yaml`。 | ||
| 233 | - | ||
| 234 | -### 配置内容 | ||
| 235 | - | ||
| 236 | -#### 1. 字段定义 (fields) | ||
| 237 | - | ||
| 238 | -定义 ES 索引的字段结构: | ||
| 239 | - | ||
| 240 | -```yaml | ||
| 241 | -fields: | ||
| 242 | - title_zh: | ||
| 243 | - type: TEXT | ||
| 244 | - analyzer: chinese_ecommerce | ||
| 245 | - index: true | ||
| 246 | - store: true | ||
| 247 | - boost: 2.0 | ||
| 248 | - title_en: | ||
| 249 | - type: TEXT | ||
| 250 | - analyzer: english | ||
| 251 | - index: true | ||
| 252 | - store: true | ||
| 253 | - categoryName_keyword: | ||
| 254 | - type: KEYWORD | ||
| 255 | - index: true | ||
| 256 | - store: true | ||
| 257 | - min_price: | ||
| 258 | - type: FLOAT | ||
| 259 | - index: true | ||
| 260 | - store: true | ||
| 261 | - title_embedding: | ||
| 262 | - type: TEXT_EMBEDDING | ||
| 263 | - dimension: 1024 | ||
| 264 | - similarity: dot_product | ||
| 265 | -``` | ||
| 266 | - | ||
| 267 | -#### 2. 查询域配置 (indexes) | ||
| 268 | - | ||
| 269 | -定义多域查询配置: | ||
| 270 | - | ||
| 271 | -```yaml | ||
| 272 | -indexes: | ||
| 273 | - default: | ||
| 274 | - fields: ["title_zh", "title_en", "title_ru"] | ||
| 275 | - weights: {"title_zh": 2.0, "title_en": 1.5} | ||
| 276 | - title: | ||
| 277 | - fields: ["title_zh", "title_en"] | ||
| 278 | - brand: | ||
| 279 | - fields: ["brandName_keyword"] | ||
| 280 | -``` | ||
| 281 | - | ||
| 282 | -#### 3. 查询配置 (query_config) | ||
| 283 | - | ||
| 284 | -多语言和翻译配置: | ||
| 285 | - | ||
| 286 | -```yaml | ||
| 287 | -query_config: | ||
| 288 | - languages: ["zh", "en", "ru"] | ||
| 289 | - auto_translate: true | ||
| 290 | - translation_api: "deepl" | ||
| 291 | - enable_embeddings: true | ||
| 292 | - embedding_model: "bge-m3" | ||
| 293 | -``` | ||
| 294 | - | ||
| 295 | -#### 4. 排序配置 (ranking) | ||
| 296 | - | ||
| 297 | -相关性排序表达式: | ||
| 298 | - | ||
| 299 | -```yaml | ||
| 300 | -ranking: | ||
| 301 | - expression: "bm25() + 0.2*text_embedding_relevance() + general_score*2" | ||
| 302 | - enable_function_score: true | ||
| 303 | -``` | ||
| 304 | - | ||
| 305 | -#### 5. SPU 配置 (spu_config) | ||
| 306 | - | ||
| 307 | -SPU 聚合配置: | ||
| 308 | - | ||
| 309 | -```yaml | ||
| 310 | -spu_config: | ||
| 311 | - enabled: true | ||
| 312 | - spu_field: "product_id" | ||
| 313 | - inner_hits_size: 3 | ||
| 314 | -``` | ||
| 315 | - | ||
| 316 | -### 字段类型 | ||
| 317 | - | ||
| 318 | -| 类型 | 说明 | 示例 | | ||
| 319 | -|------|------|------| | ||
| 320 | -| `TEXT` | 文本字段,支持分词 | 商品标题、描述 | | ||
| 321 | -| `KEYWORD` | 关键词字段,精确匹配 | 分类、品牌 | | ||
| 322 | -| `TEXT_EMBEDDING` | 文本向量(1024维) | 语义搜索 | | ||
| 323 | -| `IMAGE_EMBEDDING` | 图片向量(1024维) | 图片搜索 | | ||
| 324 | -| `INT/LONG` | 整数类型 | 库存、ID | | ||
| 325 | -| `FLOAT/DOUBLE` | 浮点数类型 | 价格 | | ||
| 326 | -| `DATE` | 日期类型 | 创建时间 | | ||
| 327 | -| `BOOLEAN` | 布尔类型 | 是否上架 | | ||
| 328 | - | ||
| 329 | -### 分析器 | ||
| 330 | - | ||
| 331 | -| 分析器 | 说明 | 适用语言 | | ||
| 332 | -|--------|------|----------| | ||
| 333 | -| `chinese_ecommerce` | 中文电商分词器(Ansj) | 中文 | | ||
| 334 | -| `english` | 英文分析器 | 英文 | | ||
| 335 | -| `russian` | 俄文分析器 | 俄文 | | ||
| 336 | -| `arabic` | 阿拉伯文分析器 | 阿拉伯文 | | ||
| 337 | -| `spanish` | 西班牙文分析器 | 西班牙文 | | ||
| 338 | -| `japanese` | 日文分析器 | 日文 | | ||
| 339 | -| `standard` | 标准分析器 | 通用 | | ||
| 340 | -| `keyword` | 关键词分析器 | 精确匹配 | | ||
| 341 | - | ||
| 342 | -## API 接口 | ||
| 343 | - | ||
| 344 | -### 搜索接口 | ||
| 345 | - | ||
| 346 | -#### 1. 文本搜索 | ||
| 347 | - | ||
| 348 | -**端点**: `POST /search/` | ||
| 349 | - | ||
| 350 | -**请求示例**: | ||
| 351 | - | ||
| 352 | -```json | ||
| 353 | -{ | ||
| 354 | - "query": "蓝牙耳机", | ||
| 355 | - "size": 10, | ||
| 356 | - "from": 0, | ||
| 357 | - "filters": { | ||
| 358 | - "categoryName_keyword": "电子产品" | ||
| 359 | - }, | ||
| 360 | - "range_filters": { | ||
| 361 | - "min_price": { | ||
| 362 | - "gte": 50, | ||
| 363 | - "lte": 500 | ||
| 364 | - } | ||
| 365 | - }, | ||
| 366 | - "facets": [ | ||
| 367 | - { | ||
| 368 | - "field": "categoryName_keyword", | ||
| 369 | - "label": "分类" | ||
| 370 | - } | ||
| 371 | - ], | ||
| 372 | - "sort_by": "min_price", | ||
| 373 | - "sort_order": "asc" | ||
| 374 | -} | 47 | + -H "X-Tenant-ID: 1" \ |
| 48 | + -d '{"query": "玩具", "size": 10}' | ||
| 375 | ``` | 49 | ``` |
| 376 | 50 | ||
| 377 | -#### 2. 图片搜索 | 51 | +## 文档地图 |
| 378 | 52 | ||
| 379 | -**端点**: `POST /search/image` | 53 | +| 文档 | 内容提要 | 适用场景 | |
| 54 | +|------|----------|----------| | ||
| 55 | +| `环境相关.md` | 系统要求、Conda/依赖、外部服务账号、常用端口 | 首次部署、环境核对 | | ||
| 56 | +| `USAGE_GUIDE.md` | 环境准备、服务启动、配置、日志、验证手册 | 日常运维、调试 | | ||
| 57 | +| `TEST_DATA_GUIDE.md` | 两个租户的模拟/CSV数据构造 & MySQL→ES流程 | 数据准备、联调 | | ||
| 58 | +| `设计文档.md` | 架构、配置系统、索引/查询/排序模块细节 | 研发/扩展功能 | | ||
| 59 | +| `INDEX_FIELDS_DOCUMENTATION.md` | `search_products` 字段、类型、来源、嵌套结构 | 新增字段、数据对齐 | | ||
| 60 | +| `API_DOCUMENTATION.md` | REST API(搜索/图片/管理)详解、示例、响应格式 | API 使用、测试 | | ||
| 61 | +| `API_INTEGRATION_GUIDE.md` | 客户对接指引、最佳实践、错误处理、语言说明 | 第三方集成、SDK 开发 | | ||
| 62 | +| `API_QUICK_REFERENCE.md` | 常用请求体速查表 | 支持团队快速查阅 | | ||
| 63 | +| `环境相关.md` + `.env` 模板 | 运行依赖账号、端口、密钥对照表 | 交付 & 运维 | | ||
| 380 | 64 | ||
| 381 | -**请求示例**: | 65 | +更多补充材料: |
| 382 | 66 | ||
| 383 | -```json | ||
| 384 | -{ | ||
| 385 | - "image_url": "https://oss.essa.cn/example.jpg", | ||
| 386 | - "size": 10, | ||
| 387 | - "filters": { | ||
| 388 | - "categoryName_keyword": "玩具" | ||
| 389 | - } | ||
| 390 | -} | ||
| 391 | -``` | ||
| 392 | - | ||
| 393 | -#### 3. 获取文档 | ||
| 394 | - | ||
| 395 | -**端点**: `GET /search/{doc_id}` | ||
| 396 | - | ||
| 397 | -### 管理接口 | ||
| 398 | - | ||
| 399 | -#### 1. 健康检查 | ||
| 400 | - | ||
| 401 | -**端点**: `GET /admin/health` | ||
| 402 | - | ||
| 403 | -#### 2. 获取配置 | ||
| 404 | - | ||
| 405 | -**端点**: `GET /admin/config?tenant_id=1` | ||
| 406 | - | ||
| 407 | -#### 3. 索引统计 | ||
| 408 | - | ||
| 409 | -**端点**: `GET /admin/stats?tenant_id=1` | ||
| 410 | - | ||
| 411 | -#### 4. 查询改写规则 | 67 | +- `TEST_DATA_GUIDE.md`:包含完整工作流脚本示例 |
| 68 | +- `商品数据源入ES配置规范.md`:数据源映射约定 | ||
| 69 | +- `MULTILANG_FEATURE.md`:多语言处理细节 | ||
| 412 | 70 | ||
| 413 | -**端点**: | ||
| 414 | -- `GET /admin/rewrite-rules?tenant_id=1` - 获取规则 | ||
| 415 | -- `POST /admin/rewrite-rules` - 更新规则 | 71 | +## 关键工作流指引 |
| 416 | 72 | ||
| 417 | -详细 API 文档请参考 `API_DOCUMENTATION.md`。 | 73 | +- **数据构建 → MySQL → Elasticsearch** |
| 74 | + - `scripts/mock_data.sh`:Tenant1 Mock + Tenant2 CSV 一条龙 | ||
| 75 | + - `scripts/ingest.sh <tenant_id> [recreate]`:驱动 `indexer/` 模块写入 `search_products` | ||
| 76 | + - 详解:`TEST_DATA_GUIDE.md` | ||
| 418 | 77 | ||
| 419 | -## 高级功能 | ||
| 420 | - | ||
| 421 | -### 布尔表达式 | ||
| 422 | - | ||
| 423 | -支持的操作符(优先级从高到低): | ||
| 424 | - | ||
| 425 | -1. `()` - 括号 | ||
| 426 | -2. `ANDNOT` - 排除 | ||
| 427 | -3. `AND` - 必须全部匹配 | ||
| 428 | -4. `OR` - 任意匹配 | ||
| 429 | -5. `RANK` - 排序提升 | ||
| 430 | - | ||
| 431 | -**示例**: | ||
| 432 | - | ||
| 433 | -``` | ||
| 434 | -蓝牙 AND (耳机 OR 音响) ANDNOT 便宜 | ||
| 435 | -laptop AND (gaming OR professional) ANDNOT cheap | ||
| 436 | -``` | ||
| 437 | - | ||
| 438 | -### 查询改写 | ||
| 439 | - | ||
| 440 | -配置品牌/分类映射: | ||
| 441 | - | ||
| 442 | -```yaml | ||
| 443 | -rewrite_dictionary: | ||
| 444 | - "苹果": "brand:苹果 OR name:iPhone" | ||
| 445 | - "玩具": "category:玩具" | ||
| 446 | -``` | 78 | +- **搜索服务 & API** |
| 79 | + - `api/`(FastAPI)承载 REST API,`search/` + `query/` 负责查询解析与下发 | ||
| 80 | + - API、分页、过滤、Facet、KNN 等:`API_DOCUMENTATION.md` | ||
| 81 | + - 对接案例与错误码:`API_INTEGRATION_GUIDE.md` | ||
| 447 | 82 | ||
| 448 | -### 排序表达式 | 83 | +- **配置驱动能力** |
| 84 | + - `config/schema/{tenant_id}/config.yaml`:字段定义、索引域、排序表达式、SPU 聚合 | ||
| 85 | + - 详解与设计理念:`设计文档.md`、`INDEX_FIELDS_DOCUMENTATION.md` | ||
| 449 | 86 | ||
| 450 | -可配置的相关性排序: | 87 | +## 仓库结构(概览) |
| 451 | 88 | ||
| 452 | ``` | 89 | ``` |
| 453 | -bm25() + 0.2*text_embedding_relevance() + general_score*2 + timeliness(end_time) | 90 | +api/ FastAPI 服务与路由 |
| 91 | +config/ 字段/索引/查询配置体系 | ||
| 92 | +indexer/ MySQL → ES 管道(mapping / transformer / bulk) | ||
| 93 | +query/ 查询解析、改写、翻译、embedding | ||
| 94 | +search/ 多语言构建、布尔解析、排序引擎 | ||
| 95 | +scripts/ 数据/服务脚本(mock_data, ingest, run 等) | ||
| 96 | +frontend/ 简易调试页面 | ||
| 97 | +docs/ 运营及中文资料 | ||
| 454 | ``` | 98 | ``` |
| 455 | 99 | ||
| 456 | -支持的函数: | ||
| 457 | -- `bm25()` - BM25 相关性分数 | ||
| 458 | -- `text_embedding_relevance()` - 文本向量相似度 | ||
| 459 | -- `image_embedding_relevance()` - 图片向量相似度 | ||
| 460 | -- `field_value(field_name)` - 字段值 | ||
| 461 | -- `timeliness(date_field)` - 时间衰减 | ||
| 462 | - | ||
| 463 | -### 多语言查询 | ||
| 464 | - | ||
| 465 | -系统自动检测查询语言,并支持: | ||
| 466 | - | ||
| 467 | -- **自动翻译**:将查询翻译到配置的所有语言 | ||
| 468 | -- **语言路由**:根据语言选择对应的字段 | ||
| 469 | -- **混合查询**:同时查询多个语言字段 | ||
| 470 | - | ||
| 471 | -### SPU 聚合 | ||
| 472 | - | ||
| 473 | -启用 SPU 聚合后,每个 SPU 只返回一个代表性 SKU: | ||
| 474 | - | ||
| 475 | -```yaml | ||
| 476 | -spu_config: | ||
| 477 | - enabled: true | ||
| 478 | - spu_field: "product_id" | ||
| 479 | - inner_hits_size: 3 # 每个 SPU 内部返回的 SKU 数量 | ||
| 480 | -``` | ||
| 481 | - | ||
| 482 | -## 数据导入 | ||
| 483 | - | ||
| 484 | -### MySQL 表结构 | ||
| 485 | - | ||
| 486 | -系统使用店匠的标准表结构: | ||
| 487 | - | ||
| 488 | -- **SPU 表**: `shoplazza_product_spu` | ||
| 489 | -- **SKU 表**: `shoplazza_product_sku` | ||
| 490 | - | ||
| 491 | -### 数据导入流程 | ||
| 492 | - | ||
| 493 | -1. **生成 SQL**:使用 `scripts/generate_test_data.py` 或 `scripts/import_tenant2_csv.py` 生成 SQL 文件 | ||
| 494 | -2. **导入 MySQL**:使用 `scripts/mock_data.sh` 或 `scripts/import_test_data.py` 导入数据 | ||
| 495 | -3. **索引到 ES**:使用 `scripts/ingest.sh` 或 `scripts/ingest_shoplazza.py` 将数据索引到 Elasticsearch | ||
| 496 | - | ||
| 497 | -### CSV 数据格式 | ||
| 498 | - | ||
| 499 | -CSV 文件应包含以下字段: | ||
| 500 | - | ||
| 501 | -- `skuId` - SKU ID | ||
| 502 | -- `name` - 商品名称(中文) | ||
| 503 | -- `name_pinyin` - 拼音 | ||
| 504 | -- `create_time` - 创建时间 | ||
| 505 | -- `ruSkuName` - 俄文名称 | ||
| 506 | -- `enSpuName` - 英文名称 | ||
| 507 | -- `categoryName` - 分类名称 | ||
| 508 | -- `supplierName` - 供应商名称 | ||
| 509 | -- `brandName` - 品牌名称 | ||
| 510 | -- `file_id` - 文件 ID | ||
| 511 | -- `id` - 商品 ID | ||
| 512 | -- `imageUrl` - 图片 URL | ||
| 513 | - | ||
| 514 | -## 性能优化 | ||
| 515 | - | ||
| 516 | -### 1. 向量缓存 | ||
| 517 | - | ||
| 518 | -启用向量缓存可以避免重复计算: | ||
| 519 | - | ||
| 520 | -```python | ||
| 521 | -# 在配置中启用缓存 | ||
| 522 | -cache: | ||
| 523 | - enabled: true | ||
| 524 | - ttl: 3600 # 缓存过期时间(秒) | ||
| 525 | -``` | 100 | +## 常用参考 |
| 526 | 101 | ||
| 527 | -### 2. 批量处理 | ||
| 528 | - | ||
| 529 | -调整批量大小以优化性能: | ||
| 530 | - | ||
| 531 | -- **数据转换批量大小**:默认 100(根据内存调整) | ||
| 532 | -- **索引批量大小**:默认 500(根据 ES 性能调整) | ||
| 533 | - | ||
| 534 | -### 3. GPU 加速 | ||
| 535 | - | ||
| 536 | -使用 GPU 加速向量计算: | ||
| 537 | - | ||
| 538 | -```bash | ||
| 539 | -# 安装 CUDA 版本的 PyTorch | ||
| 540 | -pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 | ||
| 541 | -``` | ||
| 542 | - | ||
| 543 | -### 4. ES 分片配置 | ||
| 544 | - | ||
| 545 | -根据数据量配置 ES 分片: | ||
| 546 | - | ||
| 547 | -```yaml | ||
| 548 | -# 在 mapping 生成器中配置 | ||
| 549 | -settings: | ||
| 550 | - number_of_shards: 3 | ||
| 551 | - number_of_replicas: 1 | ||
| 552 | -``` | ||
| 553 | - | ||
| 554 | -## 开发指南 | ||
| 555 | - | ||
| 556 | -### 运行测试 | ||
| 557 | - | ||
| 558 | -```bash | ||
| 559 | -pytest tests/ | ||
| 560 | -``` | ||
| 561 | - | ||
| 562 | -### 代码格式化 | ||
| 563 | - | ||
| 564 | -```bash | ||
| 565 | -black . | ||
| 566 | -``` | ||
| 567 | - | ||
| 568 | -### 类型检查 | ||
| 569 | - | ||
| 570 | -```bash | ||
| 571 | -mypy . | ||
| 572 | -``` | ||
| 573 | - | ||
| 574 | -### 日志查看 | ||
| 575 | - | ||
| 576 | -```bash | ||
| 577 | -# 查看服务日志 | ||
| 578 | -tail -f logs/search_service.log | ||
| 579 | -``` | ||
| 580 | - | ||
| 581 | -## 常见问题 | ||
| 582 | - | ||
| 583 | -### 1. 如何添加新的租户? | ||
| 584 | - | ||
| 585 | -1. 创建配置文件 `config/schema/{tenant_id}/config.yaml` | ||
| 586 | -2. 导入数据到 MySQL(使用 `scripts/mock_data.sh`) | ||
| 587 | -3. 索引数据到 ES(使用 `scripts/ingest.sh {tenant_id}`) | ||
| 588 | - | ||
| 589 | -### 2. 如何修改排序规则? | ||
| 590 | - | ||
| 591 | -编辑配置文件中的 `ranking.expression` 字段。 | ||
| 592 | - | ||
| 593 | -### 3. 如何添加新的分析器? | ||
| 594 | - | ||
| 595 | -在 `config/field_types.py` 中定义新的分析器,然后在字段配置中使用。 | ||
| 596 | - | ||
| 597 | -### 4. 向量计算很慢怎么办? | ||
| 598 | - | ||
| 599 | -- 启用向量缓存 | ||
| 600 | -- 使用 GPU 加速 | ||
| 601 | -- 减少批量大小 | ||
| 602 | - | ||
| 603 | -### 5. 如何调试搜索查询? | ||
| 604 | - | ||
| 605 | -在 API 请求中设置 `debug: true`,返回详细的调试信息。 | ||
| 606 | - | ||
| 607 | -## 相关文档 | ||
| 608 | - | ||
| 609 | -- **API 文档**: `API_DOCUMENTATION.md` | ||
| 610 | -- **设计文档**: `设计文档.md` | ||
| 611 | -- **部署指南**: `DEPLOYMENT.md` | ||
| 612 | -- **用户指南**: `USER_GUIDE.md` | 102 | +- **运行/排障**:`USAGE_GUIDE.md`、`环境相关.md` |
| 103 | +- **功能设计**:`设计文档.md` | ||
| 104 | +- **字段/数据对齐**:`INDEX_FIELDS_DOCUMENTATION.md` | ||
| 105 | +- **API 对接**:`API_DOCUMENTATION.md`、`API_INTEGRATION_GUIDE.md` | ||
| 106 | +- **测试数据**:`TEST_DATA_GUIDE.md` | ||
| 613 | 107 | ||
| 614 | ## 许可证 | 108 | ## 许可证 |
| 615 | 109 | ||
| 616 | 专有软件 - 保留所有权利 | 110 | 专有软件 - 保留所有权利 |
| 111 | + |
环境相关.md
| 1 | 1 | ||
| 2 | -环境使用: | 2 | + |
| 3 | + | ||
| 4 | +## 2. Python 运行环境 | ||
| 5 | + | ||
| 6 | +```bash | ||
| 7 | +# 1. 激活 Conda | ||
| 3 | source /home/tw/miniconda3/etc/profile.d/conda.sh | 8 | source /home/tw/miniconda3/etc/profile.d/conda.sh |
| 4 | conda activate searchengine | 9 | conda activate searchengine |
| 5 | 10 | ||
| 11 | +# 如果部署到新机器,不存在 searchengine 环境时,需要初始化环境: | ||
| 12 | +cd /home/tw/SearchEngine | ||
| 13 | +pip install -r requirements.txt | ||
| 14 | +``` | ||
| 15 | + | ||
| 16 | +--- | ||
| 17 | + | ||
| 18 | +## 3. 外部服务与端口 | ||
| 19 | + | ||
| 20 | +| 服务 | 默认地址 | 说明 | | ||
| 21 | +|------|----------|------| | ||
| 22 | +| Elasticsearch | `http://localhost:9200` | 可通过 Docker 单节点启动 | | ||
| 23 | +| MySQL | `120.79.247.228:3316` | 存放店匠 SPU/SKU 数据 | | ||
| 24 | +| Redis(可选) | `localhost:6479` | Embedding/翻译缓存 | | ||
| 25 | + | ||
| 26 | +示例:使用 Docker 启动 Elasticsearch | ||
| 27 | + | ||
| 28 | +```bash | ||
| 29 | +docker run -d \ | ||
| 30 | + --name elasticsearch \ | ||
| 31 | + -p 9200:9200 \ | ||
| 32 | + -e "discovery.type=single-node" \ | ||
| 33 | + -e "ES_JAVA_OPTS=-Xms2g -Xmx2g" \ | ||
| 34 | + elasticsearch:8.11.0 | ||
| 35 | +``` | ||
| 36 | + | ||
| 37 | +--- | ||
| 38 | + | ||
| 39 | +## 4. 环境变量与 `.env` 模板 | ||
| 40 | + | ||
| 41 | +在项目根目录创建 `.env`,并根据环境替换敏感信息: | ||
| 42 | + | ||
| 43 | +```env | ||
| 44 | +# MySQL | ||
| 45 | +DB_HOST=120.79.247.228 | ||
| 46 | +DB_PORT=3316 | ||
| 47 | +DB_DATABASE=saas | ||
| 48 | +DB_USERNAME=saas | ||
| 49 | +DB_PASSWORD=P89cZHS5d7dFyc9R | ||
| 50 | + | ||
| 51 | +# Elasticsearch | ||
| 52 | +ES_HOST=http://localhost:9200 | ||
| 53 | +ES_USERNAME=essa | ||
| 54 | +ES_PASSWORD=4hOaLaf41y2VuI8y | ||
| 55 | + | ||
| 56 | +# Redis(可选) | ||
| 57 | +REDIS_HOST=localhost | ||
| 58 | +REDIS_PORT=6479 | ||
| 59 | +REDIS_PASSWORD=BMfv5aI31kgHWtlx | ||
| 60 | + | ||
| 61 | +# DeepL 翻译 | ||
| 62 | +DEEPL_AUTH_KEY=c9293ab4-ad25-479b-919f-ab4e63b429ed | ||
| 63 | + | ||
| 64 | +# API | ||
| 65 | +API_HOST=0.0.0.0 | ||
| 66 | +API_PORT=6002 | ||
| 67 | +``` | ||
| 68 | + | ||
| 69 | +--- | ||
| 70 | + | ||
| 71 | +## 5. 服务凭证速查 | ||
| 72 | + | ||
| 73 | +| 项目 | 值 | | ||
| 74 | +|------|----| | ||
| 75 | +| **MySQL** | host `120.79.247.228`, port `3316`, user `saas`, password `P89cZHS5d7dFyc9R` | | ||
| 76 | +| **Elasticsearch** | host `http://localhost:9200`, user `essa`, password `4hOaLaf41y2VuI8y` | | ||
| 77 | +| **Redis(可选)** | host `localhost`, port `6479`, password `BMfv5aI31kgHWtlx` | | ||
| 78 | +| **DeepL** | `c9293ab4-ad25-479b-919f-ab4e63b429ed` | | ||
| 79 | + | ||
| 80 | +> 所有凭证仅用于本地/测试环境,生产环境需替换并妥善保管。 | ||
| 81 | + | ||
| 82 | +--- | ||
| 83 | + | ||
| 84 | +## 6. 店匠数据源说明 | ||
| 85 | + | ||
| 86 | +SearchEngine 以 MySQL 中的店匠标准表为权威数据源: | ||
| 87 | + | ||
| 88 | +- `shoplazza_product_spu`:SPU 商品主表 | ||
| 89 | +- `shoplazza_product_sku`:SKU 变体表 | ||
| 90 | + | ||
| 91 | +### `shoplazza_product_sku` 字段节选 | ||
| 92 | + | ||
| 93 | +| 字段 | 类型 | 描述 | | ||
| 94 | +|------|------|------| | ||
| 95 | +| `id` | bigint(20) | SKU 主键 | | ||
| 96 | +| `spu_id` | bigint(20) | 对应 SPU | | ||
| 97 | +| `shop_id` | bigint(20) | 店铺 ID | | ||
| 98 | +| `shoplazza_product_id` | varchar(64) | 店匠商品 ID | | ||
| 99 | +| `title` | varchar(500) | 变体标题 | | ||
| 100 | +| `sku` | varchar(100) | SKU 编码 | | ||
| 101 | +| `price` | decimal(10,2) | 售价 | | ||
| 102 | +| `compare_at_price` | decimal(10,2) | 原价 | | ||
| 103 | +| `option1/2/3` | varchar(255) | 颜色/尺码等选项 | | ||
| 104 | +| `inventory_quantity` | int(11) | 库存 | | ||
| 105 | +| `image_src` | varchar(500) | 图片 | | ||
| 106 | +| `tenant_id` | bigint(20) | 租户 | | ||
| 107 | +| `create_time` | datetime | 创建时间 | | ||
| 108 | +| `update_time` | datetime | 更新时间 | | ||
| 109 | +| `deleted` | bit(1) | 逻辑删除标记 | | ||
| 110 | + | ||
| 111 | +> 完整字段、索引映射与 ES 对应关系详见 `INDEX_FIELDS_DOCUMENTATION.md`。 | ||
| 112 | + | ||
| 113 | +--- | ||
| 114 | + | ||
| 115 | +## 7. 相关脚本 | ||
| 116 | + | ||
| 117 | +- `scripts/mock_data.sh`:一次性生成 Tenant1 Mock + Tenant2 CSV 数据并导入 MySQL | ||
| 118 | +- `scripts/ingest.sh <tenant_id> [recreate]`:从 MySQL 写入 Elasticsearch | ||
| 119 | +- `run.sh` / `restart.sh`:服务启动/重启 | ||
| 120 | + | ||
| 121 | +更多脚本参数、日志与验证命令参见 `USAGE_GUIDE.md` 与 `TEST_DATA_GUIDE.md`。 | ||
| 6 | 122 | ||
| 7 | -店匠是类似于shopify的独立站SAAS。我们要为基于店匠的独立站(一般为跨境电商独立站)做搜索SAAS。 | ||
| 8 | - | ||
| 9 | - | ||
| 10 | -## 商品数据 - 数据源 - mysql | ||
| 11 | -店匠的商品结构如下: | ||
| 12 | - | ||
| 13 | -数据库配置: | ||
| 14 | - | ||
| 15 | -## mysql数据源 | ||
| 16 | -host: 120.79.247.228 | ||
| 17 | -port: 3316 | ||
| 18 | -username: saas | ||
| 19 | -password: P89cZHS5d7dFyc9R | ||
| 20 | - | ||
| 21 | - | ||
| 22 | -ES_CONFIG = { | ||
| 23 | - 'host': 'http://localhost:9200', | ||
| 24 | - 'username': 'essa', | ||
| 25 | - 'password': '4hOaLaf41y2VuI8y' | ||
| 26 | -} | ||
| 27 | - | ||
| 28 | -REDIS_CONFIG = { | ||
| 29 | - 'host': 'localhost', | ||
| 30 | - 'port': 6479, | ||
| 31 | - 'password': 'BMfv5aI31kgHWtlx' | ||
| 32 | -} | ||
| 33 | - | ||
| 34 | -DEEPL_AUTH_KEY = "c9293ab4-ad25-479b-919f-ab4e63b429ed" | ||
| 35 | - | ||
| 36 | - | ||
| 37 | - | ||
| 38 | - | ||
| 39 | - | ||
| 40 | -### 店匠主表 | ||
| 41 | -shoplazza_product_sku | ||
| 42 | -shoplazza_product_spu | ||
| 43 | - | ||
| 44 | -主表sku表的结构为: | ||
| 45 | -id bigint(20) | ||
| 46 | -spu_id bigint(20) | ||
| 47 | -shop_id bigint(20) | ||
| 48 | -shoplazza_id varchar(64) | ||
| 49 | -shoplazza_product_id varchar(64) | ||
| 50 | -shoplazza_image_id varchar(64) | ||
| 51 | -title varchar(500) | ||
| 52 | -sku varchar(100) | ||
| 53 | -barcode varchar(100) | ||
| 54 | -position int(11) | ||
| 55 | -price decimal(10,2) | ||
| 56 | -compare_at_price decimal(10,2) | ||
| 57 | -cost_price decimal(10,2) | ||
| 58 | -option1 varchar(255) | ||
| 59 | -option2 varchar(255) | ||
| 60 | -option3 varchar(255) | ||
| 61 | -inventory_quantity int(11) | ||
| 62 | -weight decimal(10,2) | ||
| 63 | -weight_unit varchar(10) | ||
| 64 | -image_src varchar(500) | ||
| 65 | -wholesale_price json | ||
| 66 | -note text | ||
| 67 | -extend json | ||
| 68 | -shoplazza_created_at datetime | ||
| 69 | -shoplazza_updated_at datetime | ||
| 70 | -tenant_id bigint(20) | ||
| 71 | -creator varchar(64) | ||
| 72 | -create_time datetime | ||
| 73 | -updater varchar(64) | ||
| 74 | -update_time datetime | ||
| 75 | -deleted bit(1) | ||
| 76 | 123 |