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 | 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 | 45 | curl -X POST http://localhost:6002/search/ \ |
| 104 | 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 | 8 | source /home/tw/miniconda3/etc/profile.d/conda.sh |
| 4 | 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 | ... | ... |