# 搜索引擎 API 接口文档 ## 概述 本文档描述了电商搜索 SaaS 系统的 RESTful API 接口。系统提供强大的搜索功能,包括: - **多语言搜索**:支持中文、英文、俄文等多语言查询和自动翻译 - **语义搜索**:基于 BGE-M3 文本向量和 CN-CLIP 图片向量的语义检索 - **布尔表达式**:支持 AND、OR、RANK、ANDNOT 操作符 - **灵活过滤**:精确匹配过滤器和数值范围过滤器 - **分面搜索**:动态生成过滤选项,提供分组统计 - **自定义排序**:支持按任意字段排序 - **个性化排序**:可配置的相关性排序表达式 ## 基础信息 - **Base URL**: `http://your-domain:6002` (http://120.76.41.98:6002) - **协议**: HTTP/HTTPS - **数据格式**: JSON - **字符编码**: UTF-8 ## 搜索接口 ### 1. 文本搜索 **端点**: `POST /search/` **描述**: 执行文本搜索查询,支持多语言、布尔表达式、过滤器和分面搜索。 #### 请求参数 ```json { "query": "string (required)", "size": 10, "from": 0, "filters": {}, "range_filters": {}, "facets": [], "sort_by": "string", "sort_order": "desc", "min_score": 0.0, "debug": false, "user_id": "string", "session_id": "string" } ``` #### 参数说明 | 参数 | 类型 | 必填 | 默认值 | 描述 | |------|------|------|--------|------| | `query` | string | Y | - | 搜索查询字符串,支持布尔表达式(AND, OR, RANK, ANDNOT) | | `size` | integer | N | 10 | 返回结果数量(1-100) | | `from` | integer | N | 0 | 分页偏移量 | | `filters` | object | N | null | 精确匹配过滤器(见下文) | | `range_filters` | object | N | null | 数值范围过滤器(见下文) | | `facets` | array | N | null | 分面配置(见下文) | | `sort_by` | string | N | null | 排序字段名 | | `sort_order` | string | N | "desc" | 排序方向:`asc` 或 `desc` | | `min_score` | float | N | null | 最小相关性分数阈值 | | `debug` | boolean | N | false | 是否返回调试信息 | | `user_id` | string | N | null | 用户ID(用于个性化,预留) | | `session_id` | string | N | null | 会话ID(用于分析,预留) | #### 过滤器详解 ##### 精确匹配过滤器 (filters) 用于精确匹配或多值匹配(OR 逻辑)。 **格式**: ```json { "filters": { "categoryName_keyword": "玩具", // 单值:精确匹配 "brandName_keyword": ["乐高", "孩之宝"], // 数组:匹配任意值(OR) "in_stock": true // 布尔值 } } ``` **支持的值类型**: - 字符串:精确匹配 - 整数:精确匹配 - 布尔值:精确匹配 - 数组:匹配任意值(OR 逻辑) ##### 范围过滤器 (range_filters) 用于数值字段的范围过滤。 **格式**: ```json { "range_filters": { "price": { "gte": 50, // 大于等于 "lte": 200 // 小于等于 }, "days_since_last_update": { "lte": 30 // 最近30天更新 } } } ``` **支持的操作符**: - `gte`: 大于等于 (>=) - `gt`: 大于 (>) - `lte`: 小于等于 (<=) - `lt`: 小于 (<) **注意**: 至少需要指定一个操作符。 ##### 分面配置 (facets) 用于生成分面统计(分组聚合)。 **简单模式**(字符串数组): ```json { "facets": ["categoryName_keyword", "brandName_keyword"] } ``` **高级模式**(配置对象数组): ```json { "facets": [ { "field": "categoryName_keyword", "size": 15, "type": "terms" }, { "field": "price", "type": "range", "ranges": [ {"key": "0-50", "to": 50}, {"key": "50-100", "from": 50, "to": 100}, {"key": "100-200", "from": 100, "to": 200}, {"key": "200+", "from": 200} ] } ] } ``` **分面配置参数**: - `field`: 字段名(必填) - `size`: 返回的分组数量(默认:10,范围:1-100) - `type`: 分面类型,`terms`(分组统计)或 `range`(范围统计) - `ranges`: 范围定义(仅当 type='range' 时需要) #### 响应格式 ```json { "hits": [ { "_id": "12345", "_score": 8.5, "_custom_score": 12.3, "_source": { "name": "芭比时尚娃娃", "price": 89.99, "categoryName": "玩具", "brandName": "美泰", "imageUrl": "https://example.com/image.jpg" } } ], "total": 118, "max_score": 8.5, "took_ms": 45, "facets": [ { "field": "categoryName_keyword", "label": "商品类目", "type": "terms", "values": [ { "value": "玩具", "label": "玩具", "count": 85, "selected": false }, { "value": "益智玩具", "label": "益智玩具", "count": 33, "selected": false } ] } ], "query_info": { "original_query": "芭比娃娃", "detected_language": "zh", "translations": { "en": "barbie doll" } }, "related_queries": null, "performance_info": { "total_duration": 45.2, "stage_durations": { "query_parsing": 5.3, "elasticsearch_search": 35.1, "result_processing": 4.8 } }, "debug_info": null } ``` #### 响应字段说明 | 字段 | 类型 | 描述 | |------|------|------| | `hits` | array | 搜索结果列表 | | `hits[]._id` | string | 文档ID | | `hits[]._score` | float | 相关性分数 | | `hits[]._custom_score` | float | 自定义排序分数(如启用) | | `hits[]._source` | object | 文档内容 | | `total` | integer | 匹配的总文档数 | | `max_score` | float | 最高相关性分数 | | `took_ms` | integer | 搜索耗时(毫秒) | | `facets` | array | 分面统计结果(标准化格式) | | `facets[].field` | string | 字段名 | | `facets[].label` | string | 显示标签 | | `facets[].type` | string | 分面类型:`terms` 或 `range` | | `facets[].values` | array | 分面值列表 | | `facets[].values[].value` | any | 分面值 | | `facets[].values[].label` | string | 显示标签 | | `facets[].values[].count` | integer | 文档数量 | | `facets[].values[].selected` | boolean | 是否已选中 | | `query_info` | object | 查询处理信息 | | `related_queries` | array | 相关搜索(预留) | | `performance_info` | object | 性能信息 | | `debug_info` | object | 调试信息(仅当 debug=true) | #### 请求示例 **示例 1: 简单搜索** ```bash curl -X POST "http://localhost:6002/search/" \ -H "Content-Type: application/json" \ -d '{ "query": "芭比娃娃", "size": 20 }' ``` **示例 2: 带过滤器的搜索** ```bash curl -X POST "http://localhost:6002/search/" \ -H "Content-Type: application/json" \ -d '{ "query": "玩具", "size": 20, "filters": { "categoryName_keyword": ["玩具", "益智玩具"], "in_stock": true }, "range_filters": { "price": { "gte": 50, "lte": 200 } } }' ``` **示例 3: 带分面搜索(简单模式)** ```bash curl -X POST "http://localhost:6002/search/" \ -H "Content-Type: application/json" \ -d '{ "query": "玩具", "size": 20, "facets": ["categoryName_keyword", "brandName_keyword"] }' ``` **示例 4: 带分面搜索(高级模式)** ```bash curl -X POST "http://localhost:6002/search/" \ -H "Content-Type: application/json" \ -d '{ "query": "玩具", "size": 20, "facets": [ { "field": "categoryName_keyword", "size": 15, "type": "terms" }, { "field": "brandName_keyword", "size": 15, "type": "terms" }, { "field": "price", "type": "range", "ranges": [ {"key": "0-50", "to": 50}, {"key": "50-100", "from": 50, "to": 100}, {"key": "100-200", "from": 100, "to": 200}, {"key": "200+", "from": 200} ] } ] }' ``` **示例 5: 复杂搜索(布尔表达式+过滤+排序)** ```bash curl -X POST "http://localhost:6002/search/" \ -H "Content-Type: application/json" \ -d '{ "query": "玩具 AND (乐高 OR 芭比)", "size": 20, "filters": { "categoryName_keyword": "玩具" }, "range_filters": { "price": { "gte": 50, "lte": 200 }, "days_since_last_update": { "lte": 30 } }, "facets": [ {"field": "brandName_keyword", "size": 15}, {"field": "supplierName_keyword", "size": 10} ], "sort_by": "price", "sort_order": "asc", "debug": false }' ``` --- ### 2. 图片搜索 **端点**: `POST /search/image` **描述**: 基于图片相似度进行搜索,使用图片向量进行语义匹配。 #### 请求参数 ```json { "image_url": "string (required)", "size": 10, "filters": {}, "range_filters": {} } ``` #### 参数说明 | 参数 | 类型 | 必填 | 默认值 | 描述 | |------|------|------|--------|------| | `image_url` | string | ✅ | - | 查询图片的 URL | | `size` | integer | ❌ | 10 | 返回结果数量(1-100) | | `filters` | object | ❌ | null | 精确匹配过滤器 | | `range_filters` | object | ❌ | null | 数值范围过滤器 | #### 响应格式 与文本搜索相同,但 `query_info` 包含图片信息: ```json { "hits": [...], "total": 50, "max_score": 0.95, "took_ms": 120, "query_info": { "image_url": "https://example.com/image.jpg", "search_type": "image_similarity" } } ``` #### 请求示例 ```bash curl -X POST "http://localhost:6002/search/image" \ -H "Content-Type: application/json" \ -d '{ "image_url": "https://example.com/barbie.jpg", "size": 20, "filters": { "categoryName_keyword": "玩具" }, "range_filters": { "price": { "lte": 100 } } }' ``` --- ### 3. 搜索建议(框架) **端点**: `GET /search/suggestions` **描述**: 获取搜索建议(自动补全)。 **注意**: 此功能暂未实现,仅返回框架响应。 #### 查询参数 | 参数 | 类型 | 必填 | 默认值 | 描述 | |------|------|------|--------|------| | `q` | string | ✅ | - | 搜索查询字符串(最少1个字符) | | `size` | integer | ❌ | 5 | 建议数量(1-20) | | `types` | string | ❌ | "query" | 建议类型(逗号分隔):query, product, category, brand | #### 响应格式 ```json { "query": "芭", "suggestions": [ { "text": "芭比娃娃", "type": "query", "highlight": "比娃娃", "popularity": 850 } ], "took_ms": 5 } ``` #### 请求示例 ```bash curl "http://localhost:6002/search/suggestions?q=芭&size=5&types=query,product" ``` --- ### 4. 即时搜索(框架) **端点**: `GET /search/instant` **描述**: 即时搜索,边输入边搜索。 **注意**: 此功能暂未实现,调用标准搜索接口。 #### 查询参数 | 参数 | 类型 | 必填 | 默认值 | 描述 | |------|------|------|--------|------| | `q` | string | ✅ | - | 搜索查询(最少2个字符) | | `size` | integer | ❌ | 5 | 结果数量(1-20) | #### 请求示例 ```bash curl "http://localhost:6002/search/instant?q=玩具&size=5" ``` --- ### 5. 获取单个文档 **端点**: `GET /search/{doc_id}` **描述**: 根据文档ID获取单个文档详情。 #### 路径参数 | 参数 | 类型 | 描述 | |------|------|------| | `doc_id` | string | 文档ID | #### 响应格式 ```json { "id": "12345", "source": { "name": "芭比时尚娃娃", "price": 89.99, "categoryName": "玩具" } } ``` #### 请求示例 ```bash curl "http://localhost:6002/search/12345" ``` --- ## 管理接口 ### 1. 健康检查 **端点**: `GET /admin/health` **描述**: 检查服务健康状态。 #### 响应格式 ```json { "status": "healthy", "elasticsearch": "connected", "tenant_id": "tenant1" } ``` --- ### 2. 获取配置 **端点**: `GET /admin/config` **描述**: 获取当前客户配置(脱敏)。 #### 响应格式 ```json { "tenant_id": "tenant1", "tenant_name": "Tenant1 Test Instance", "es_index_name": "search_tenant1", "num_fields": 20, "num_indexes": 4, "supported_languages": ["zh", "en", "ru"], "ranking_expression": "bm25() + 0.2*text_embedding_relevance()", "spu_enabled": false } ``` --- ### 3. 索引统计 **端点**: `GET /admin/stats` **描述**: 获取索引统计信息。 #### 响应格式 ```json { "index_name": "search_tenant1", "document_count": 10000, "size_mb": 523.45 } ``` --- ### 4. 查询改写规则 **端点**: `GET /admin/rewrite-rules` **描述**: 获取当前的查询改写规则。 #### 响应格式 ```json { "rules": { "乐高": "brand:乐高 OR name:乐高", "玩具": "category:玩具" }, "count": 2 } ``` **端点**: `POST /admin/rewrite-rules` **描述**: 更新查询改写规则。 #### 请求格式 ```json { "乐高": "brand:乐高 OR name:乐高", "芭比": "brand:芭比 OR name:芭比" } ``` --- ## 使用示例 ### Python 示例 ```python import requests API_URL = "http://localhost:6002/search/" # 简单搜索 response = requests.post(API_URL, json={ "query": "芭比娃娃", "size": 20 }) data = response.json() print(f"找到 {data['total']} 个结果") # 带过滤器和分面的搜索 response = requests.post(API_URL, json={ "query": "玩具", "size": 20, "filters": { "categoryName_keyword": ["玩具", "益智玩具"] }, "range_filters": { "price": {"gte": 50, "lte": 200} }, "facets": [ {"field": "brandName_keyword", "size": 15}, {"field": "categoryName_keyword", "size": 15} ], "sort_by": "price", "sort_order": "asc" }) result = response.json() # 处理分面结果 for facet in result.get('facets', []): print(f"\n{facet['label']}:") for value in facet['values']: print(f" - {value['label']}: {value['count']}") ``` ### JavaScript 示例 ```javascript // 搜索函数 async function searchProducts(query, filters, rangeFilters, facets) { const response = await fetch('http://localhost:6002/search/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: query, size: 20, filters: filters, range_filters: rangeFilters, facets: facets }) }); const data = await response.json(); return data; } // 使用示例 const result = await searchProducts( "玩具", { categoryName_keyword: ["玩具"] }, { price: { gte: 50, lte: 200 } }, [ { field: "brandName_keyword", size: 15 }, { field: "categoryName_keyword", size: 15 } ] ); // 显示分面结果 result.facets.forEach(facet => { console.log(`${facet.label}:`); facet.values.forEach(value => { console.log(` - ${value.label}: ${value.count}`); }); }); // 显示搜索结果 result.hits.forEach(hit => { const product = hit._source; console.log(`${product.name} - ¥${product.price}`); }); ``` ### cURL 示例 ```bash # 简单搜索 curl -X POST "http://localhost:6002/search/" \ -H "Content-Type: application/json" \ -d '{"query": "芭比娃娃", "size": 20}' # 带过滤和排序 curl -X POST "http://localhost:6002/search/" \ -H "Content-Type: application/json" \ -d '{ "query": "玩具", "size": 20, "filters": {"categoryName_keyword": "玩具"}, "range_filters": {"price": {"gte": 50, "lte": 200}}, "sort_by": "price", "sort_order": "asc" }' # 带分面搜索 curl -X POST "http://localhost:6002/search/" \ -H "Content-Type: application/json" \ -d '{ "query": "玩具", "size": 20, "facets": [ {"field": "categoryName_keyword", "size": 15}, {"field": "brandName_keyword", "size": 15} ] }' ``` --- ## 布尔表达式语法 ### 支持的操作符 | 操作符 | 描述 | 示例 | |--------|------|------| | `AND` | 所有词必须匹配 | `玩具 AND 乐高` | | `OR` | 任意词匹配 | `芭比 OR 娃娃` | | `ANDNOT` | 排除特定词 | `玩具 ANDNOT 电动` | | `RANK` | 排序加权(不强制匹配) | `玩具 RANK 乐高` | | `()` | 分组 | `玩具 AND (乐高 OR 芭比)` | ### 操作符优先级 从高到低: 1. `()` - 括号 2. `ANDNOT` - 排除 3. `AND` - 与 4. `OR` - 或 5. `RANK` - 排序 ### 查询示例 ``` # 简单查询 "芭比娃娃" # AND 查询 "玩具 AND 乐高" # OR 查询 "芭比 OR 娃娃" # 排除查询 "玩具 ANDNOT 电动" # 复杂查询 "玩具 AND (乐高 OR 芭比) ANDNOT 电动" # 域查询 "brand:乐高" "category:玩具" "title:芭比娃娃" ``` --- ## 数据模型 ### 商品字段 常见的商品字段包括: | 字段名 | 类型 | 描述 | |--------|------|------| | `skuId` | long | SKU ID(主键) | | `name` | text | 商品名称(中文) | | `enSpuName` | text | 商品名称(英文) | | `ruSkuName` | text | 商品名称(俄文) | | `categoryName` | text | 类目名称 | | `categoryName_keyword` | keyword | 类目名称(精确匹配) | | `brandName` | text | 品牌名称 | | `brandName_keyword` | keyword | 品牌名称(精确匹配) | | `supplierName` | text | 供应商名称 | | `supplierName_keyword` | keyword | 供应商名称(精确匹配) | | `price` | double | 价格 | | `imageUrl` | keyword | 商品图片URL | | `create_time` | date | 创建时间 | | `days_since_last_update` | int | 距上次更新天数 | **注意**: 不同客户可能有不同的字段配置。 --- ## 常见问题 ### Q1: 如何判断一个字段应该用哪种过滤器? **A**: - **精确匹配过滤器** (`filters`): 用于 KEYWORD 类型字段(如类目、品牌、标签等) - **范围过滤器** (`range_filters`): 用于数值类型字段(如价格、库存、时间等) ### Q2: 可以同时使用多个过滤器吗? **A**: 可以。多个过滤器之间是 AND 关系(必须同时满足)。 ```json { "filters": { "categoryName_keyword": "玩具", "brandName_keyword": "乐高" }, "range_filters": { "price": {"gte": 50, "lte": 200} } } ``` 结果:类目是"玩具" **并且** 品牌是"乐高" **并且** 价格在50-200之间。 ### Q3: 如何实现"价格小于50或大于200"的过滤? **A**: 当前版本不支持单字段多个不连续范围。建议分两次查询或使用布尔查询。 ### Q4: 分面搜索返回的 selected 字段是什么意思? **A**: `selected` 表示该分面值是否在当前的过滤器中。前端可以用它来高亮已选中的过滤项。 ### Q5: 如何使用自定义排序? **A**: 使用 `sort_by` 和 `sort_order` 参数: ```json { "query": "玩具", "sort_by": "price", "sort_order": "asc" // 价格从低到高 } ``` 常用排序字段: - `price`: 价格 - `create_time`: 创建时间 - `days_since_last_update`: 更新时间 ### Q6: 如何启用调试模式? **A**: 设置 `debug: true`,响应中会包含 `debug_info` 字段,包含: - 查询分析过程 - ES 查询 DSL - ES 响应详情 - 各阶段耗时 --- ## 版本历史 ### v3.0 (2024-11-12) **重大更新**: - ✅ 移除硬编码的 `price_ranges` 逻辑 - ✅ 新增 `range_filters` 参数,支持任意数值字段的范围过滤 - ✅ 新增 `facets` 参数,替代 `aggregations`,提供简化接口 - ✅ 标准化分面搜索响应格式 - ✅ 新增 `/search/suggestions` 端点(框架) - ✅ 新增 `/search/instant` 端点(框架) - ❌ **移除** `aggregations` 参数(不向后兼容) **迁移指南**: 旧接口: ```json { "filters": { "price_ranges": ["0-50", "50-100"] }, "aggregations": { "category_stats": {"terms": {"field": "categoryName_keyword", "size": 15}} } } ``` 新接口: ```json { "range_filters": { "price": {"gte": 50, "lte": 100} }, "facets": [ {"field": "categoryName_keyword", "size": 15} ] } ``` --- ## 附录 ### A. 支持的分析器 | 分析器 | 语言 | 描述 | |--------|------|------| | `chinese_ecommerce` | 中文 | Ansj 中文分词器(电商优化) | | `english` | 英文 | 标准英文分析器 | | `russian` | 俄文 | 俄文分析器 | | `arabic` | 阿拉伯文 | 阿拉伯文分析器 | | `spanish` | 西班牙文 | 西班牙文分析器 | | `japanese` | 日文 | 日文分析器 | ### B. 字段类型 | 类型 | ES 映射 | 用途 | |------|---------|------| | `TEXT` | text | 全文检索 | | `KEYWORD` | keyword | 精确匹配、聚合、排序 | | `LONG` | long | 整数 | | `DOUBLE` | double | 浮点数 | | `DATE` | date | 日期时间 | | `BOOLEAN` | boolean | 布尔值 | | `TEXT_EMBEDDING` | dense_vector | 文本向量(1024维) | | `IMAGE_EMBEDDING` | dense_vector | 图片向量(1024维) |