Commit 11237cf2218f281a55e60066a28c1f035f33ef7f

Authored by tangwang
1 parent 3c1f8031

搜索API对接指南.md

Showing 1 changed file with 526 additions and 512 deletions   Show diff stats
docs/搜索API对接指南.md
@@ -5,16 +5,61 @@ @@ -5,16 +5,61 @@
5 ## 目录 5 ## 目录
6 6
7 1. [快速开始](#快速开始) 7 1. [快速开始](#快速开始)
  8 + - 1.1 [基础信息](#11-基础信息)
  9 + - 1.2 [最简单的搜索请求](#12-最简单的搜索请求)
  10 + - 1.3 [带过滤与分页的搜索](#13-带过滤与分页的搜索)
  11 + - 1.4 [开启分面的搜索](#14-开启分面的搜索)
  12 +
8 2. [接口概览](#接口概览) 13 2. [接口概览](#接口概览)
  14 +
9 3. [搜索接口](#搜索接口) 15 3. [搜索接口](#搜索接口)
  16 + - 3.1 [接口信息](#31-接口信息)
  17 + - 3.2 [请求参数](#32-请求参数)
  18 + - 3.3 [过滤器详解](#33-过滤器详解)
  19 + - 3.4 [分面配置](#34-分面配置)
  20 + - 3.5 [SKU筛选维度](#35-sku筛选维度)
  21 + - 3.6 [布尔表达式语法](#36-布尔表达式语法)
  22 + - 3.7 [搜索建议接口](#37-搜索建议接口)
  23 + - 3.8 [即时搜索接口](#38-即时搜索接口)
  24 + - 3.9 [获取单个文档](#39-获取单个文档)
  25 +
10 4. [响应格式说明](#响应格式说明) 26 4. [响应格式说明](#响应格式说明)
11 -5. [常见场景示例](#常见场景示例) 27 + - 4.1 [标准响应结构](#41-标准响应结构)
  28 + - 4.2 [响应字段说明](#42-响应字段说明)
  29 + - 4.3 [SpuResult字段说明](#43-spuresult字段说明)
  30 + - 4.4 [SkuResult字段说明](#44-skuresult字段说明)
  31 + - 4.5 [多语言字段说明](#45-多语言字段说明)
  32 +
  33 +5. [索引接口](#索引接口)
  34 + - 5.1 [全量索引接口](#51-全量索引接口)
  35 + - 5.2 [SPU索引接口](#52-spu索引接口)
  36 + - 5.3 [索引健康检查接口](#53-索引健康检查接口)
  37 +
  38 +6. [管理接口](#管理接口)
  39 + - 6.1 [健康检查](#61-健康检查)
  40 + - 6.2 [获取配置](#62-获取配置)
  41 + - 6.3 [索引统计](#63-索引统计)
  42 +
  43 +7. [常见场景示例](#常见场景示例)
  44 + - 7.1 [基础搜索与排序](#71-基础搜索与排序)
  45 + - 7.2 [过滤搜索](#72-过滤搜索)
  46 + - 7.3 [分面搜索](#73-分面搜索)
  47 + - 7.4 [规格过滤与分面](#74-规格过滤与分面)
  48 + - 7.5 [SKU筛选](#75-sku筛选)
  49 + - 7.6 [布尔表达式搜索](#76-布尔表达式搜索)
  50 + - 7.7 [分页查询](#77-分页查询)
  51 +
  52 +8. [数据模型](#数据模型)
  53 + - 8.1 [商品字段定义](#81-商品字段定义)
  54 + - 8.2 [字段类型速查](#82-字段类型速查)
  55 + - 8.3 [常用字段列表](#83-常用字段列表)
  56 + - 8.4 [支持的分析器](#84-支持的分析器)
12 57
13 --- 58 ---
14 59
15 ## 快速开始 60 ## 快速开始
16 61
17 -### 基础信息 62 +### 1.1 基础信息
18 63
19 - **Base URL**: `http://your-domain:6002` 或 `http://120.76.41.98:6002` 64 - **Base URL**: `http://your-domain:6002` 或 `http://120.76.41.98:6002`
20 - **协议**: HTTP/HTTPS 65 - **协议**: HTTP/HTTPS
@@ -22,7 +67,9 @@ @@ -22,7 +67,9 @@
22 - **字符编码**: UTF-8 67 - **字符编码**: UTF-8
23 - **请求方法**: POST(搜索接口) 68 - **请求方法**: POST(搜索接口)
24 69
25 -### 最简单的搜索请求 70 +**重要提示**: `tenant_id` 通过 HTTP Header `X-Tenant-ID` 传递,不在请求体中。
  71 +
  72 +### 1.2 最简单的搜索请求
26 73
27 ```bash 74 ```bash
28 curl -X POST "http://120.76.41.98:6002/search/" \ 75 curl -X POST "http://120.76.41.98:6002/search/" \
@@ -31,7 +78,7 @@ curl -X POST "http://120.76.41.98:6002/search/" \ @@ -31,7 +78,7 @@ curl -X POST "http://120.76.41.98:6002/search/" \
31 -d '{"query": "芭比娃娃"}' 78 -d '{"query": "芭比娃娃"}'
32 ``` 79 ```
33 80
34 -### curl示例:带过滤与分页 81 +### 1.3 带过滤与分页的搜索
35 82
36 ```bash 83 ```bash
37 curl -X POST "http://120.76.41.98:6002/search/" \ 84 curl -X POST "http://120.76.41.98:6002/search/" \
@@ -41,21 +88,21 @@ curl -X POST "http://120.76.41.98:6002/search/" \ @@ -41,21 +88,21 @@ curl -X POST "http://120.76.41.98:6002/search/" \
41 "query": "芭比娃娃", 88 "query": "芭比娃娃",
42 "size": 5, 89 "size": 5,
43 "from": 10, 90 "from": 10,
44 - "range_filters": {  
45 - "min_price": {  
46 - "gte": 50,  
47 - "lte": 200 91 + "range_filters": {
  92 + "min_price": {
  93 + "gte": 50,
  94 + "lte": 200
  95 + },
  96 + "create_time": {
  97 + "gte": "2020-01-01T00:00:00Z"
  98 + }
48 }, 99 },
49 - "create_time": {  
50 - "gte": "2020-01-01T00:00:00Z"  
51 - }  
52 - },  
53 "sort_by": "price", 100 "sort_by": "price",
54 "sort_order": "asc" 101 "sort_order": "asc"
55 }' 102 }'
56 ``` 103 ```
57 104
58 -### curl示例:开启分面 105 +### 1.4 开启分面的搜索
59 106
60 ```bash 107 ```bash
61 curl -X POST "http://120.76.41.98:6002/search/" \ 108 curl -X POST "http://120.76.41.98:6002/search/" \
@@ -79,199 +126,26 @@ curl -X POST "http://120.76.41.98:6002/search/" \ @@ -79,199 +126,26 @@ curl -X POST "http://120.76.41.98:6002/search/" \
79 | 接口 | HTTP Method | Endpoint | 说明 | 126 | 接口 | HTTP Method | Endpoint | 说明 |
80 |------|------|------|------| 127 |------|------|------|------|
81 | 搜索 | POST | `/search/` | 执行搜索查询 | 128 | 搜索 | POST | `/search/` | 执行搜索查询 |
  129 +| 搜索建议 | GET | `/search/suggestions` | 搜索建议(框架,暂未实现) ⚠️ TODO |
  130 +| 即时搜索 | GET | `/search/instant` | 边输入边搜索(框架) ⚠️ TODO |
  131 +| 获取文档 | GET | `/search/{doc_id}` | 获取单个文档 |
82 | 全量索引 | POST | `/indexer/bulk` | 全量索引接口 | 132 | 全量索引 | POST | `/indexer/bulk` | 全量索引接口 |
83 | SPU索引 | POST | `/indexer/spus` | 获取SPU文档(支持单个或批量) | 133 | SPU索引 | POST | `/indexer/spus` | 获取SPU文档(支持单个或批量) |
84 | 索引健康检查 | GET | `/indexer/health` | 检查索引服务状态 | 134 | 索引健康检查 | GET | `/indexer/health` | 检查索引服务状态 |
85 -| 搜索建议(框架,暂未实现) | GET | `/search/suggestions` | 搜索建议 |  
86 -| 获取文档 | GET | `/search/{doc_id}` | 获取单个文档 |  
87 | 健康检查 | GET | `/admin/health` | 服务健康检查 | 135 | 健康检查 | GET | `/admin/health` | 服务健康检查 |
88 -  
89 ----  
90 -  
91 -## 索引接口  
92 -  
93 -### 全量索引接口  
94 -  
95 -- **端点**: `POST /indexer/bulk`  
96 -- **描述**: 将指定租户的所有SPU数据导入到ES索引  
97 -  
98 -#### 请求参数  
99 -  
100 -```json  
101 -{  
102 - "tenant_id": "162",  
103 - "recreate_index": false,  
104 - "batch_size": 500  
105 -}  
106 -```  
107 -  
108 -| 参数 | 类型 | 必填 | 默认值 | 说明 |  
109 -|------|------|------|--------|------|  
110 -| `tenant_id` | string | Y | - | 租户ID |  
111 -| `recreate_index` | boolean | N | false | 是否重建索引(删除旧索引后创建新索引) |  
112 -| `batch_size` | integer | N | 500 | 批量导入大小 |  
113 -  
114 -#### 响应格式  
115 -  
116 -**成功响应(200 OK)**:  
117 -```json  
118 -{  
119 - "success": true,  
120 - "total": 1000,  
121 - "indexed": 1000,  
122 - "failed": 0,  
123 - "elapsed_time": 12.34,  
124 - "index_name": "search_products",  
125 - "tenant_id": "162"  
126 -}  
127 -```  
128 -  
129 -**错误响应**:  
130 -- `400 Bad Request`: 参数错误  
131 -- `503 Service Unavailable`: 服务未初始化  
132 -  
133 -#### 请求示例  
134 -  
135 -**首次索引(重建索引)**:  
136 -```bash  
137 -curl -X POST "http://localhost:6002/indexer/bulk" \  
138 - -H "Content-Type: application/json" \  
139 - -d '{  
140 - "tenant_id": "162",  
141 - "recreate_index": true,  
142 - "batch_size": 500  
143 - }'  
144 -```  
145 -  
146 -**查看日志**:  
147 -```bash  
148 -# 查看API日志(包含索引操作日志)  
149 -tail -f logs/api.log  
150 -  
151 -# 或者查看所有日志文件  
152 -tail -f logs/*.log  
153 -```  
154 -  
155 -**增量更新(不重建索引)**:  
156 -```bash  
157 -curl -X POST "http://localhost:6002/indexer/bulk" \  
158 - -H "Content-Type: application/json" \  
159 - -d '{  
160 - "tenant_id": "162",  
161 - "recreate_index": false,  
162 - "batch_size": 500  
163 - }'  
164 -```  
165 -  
166 ----  
167 -  
168 -### SPU索引接口  
169 -  
170 -- **端点**: `POST /indexer/spus`  
171 -- **描述**: 获取SPU的ES文档数据(支持单个或批量)  
172 -  
173 -#### 请求参数  
174 -  
175 -```json  
176 -{  
177 - "tenant_id": "162",  
178 - "spu_ids": ["123", "456", "789"]  
179 -}  
180 -```  
181 -  
182 -| 参数 | 类型 | 必填 | 说明 |  
183 -|------|------|------|------|  
184 -| `tenant_id` | string | Y | 租户ID |  
185 -| `spu_ids` | array[string] | Y | SPU ID列表(1-100个) |  
186 -  
187 -#### 响应格式  
188 -  
189 -```json  
190 -{  
191 - "success": [  
192 - {  
193 - "spu_id": "123",  
194 - "document": {  
195 - "tenant_id": "162",  
196 - "spu_id": "123",  
197 - "title_zh": "商品标题",  
198 - ...  
199 - }  
200 - },  
201 - {  
202 - "spu_id": "456",  
203 - "document": {...}  
204 - }  
205 - ],  
206 - "failed": [  
207 - {  
208 - "spu_id": "789",  
209 - "error": "SPU not found or deleted"  
210 - }  
211 - ],  
212 - "total": 3,  
213 - "success_count": 2,  
214 - "failed_count": 1  
215 -}  
216 -```  
217 -  
218 -#### 请求示例  
219 -  
220 -**单个SPU**:  
221 -```bash  
222 -curl -X POST "http://localhost:6002/indexer/spus" \  
223 - -H "Content-Type: application/json" \  
224 - -d '{  
225 - "tenant_id": "162",  
226 - "spu_ids": ["123"]  
227 - }'  
228 -```  
229 -  
230 -**批量SPU**:  
231 -```bash  
232 -curl -X POST "http://localhost:6002/indexer/spus" \  
233 - -H "Content-Type: application/json" \  
234 - -d '{  
235 - "tenant_id": "162",  
236 - "spu_ids": ["123", "456", "789"]  
237 - }'  
238 -```  
239 -  
240 ----  
241 -  
242 -### 索引健康检查接口  
243 -  
244 -- **端点**: `GET /indexer/health`  
245 -- **描述**: 检查索引服务的健康状态  
246 -  
247 -#### 响应格式  
248 -  
249 -```json  
250 -{  
251 - "status": "available",  
252 - "database": "connected",  
253 - "preloaded_data": {  
254 - "category_mappings": 150  
255 - }  
256 -}  
257 -```  
258 -  
259 -#### 请求示例  
260 -  
261 -```bash  
262 -curl -X GET "http://localhost:6002/indexer/health"  
263 -``` 136 +| 获取配置 | GET | `/admin/config` | 获取租户配置 |
  137 +| 索引统计 | GET | `/admin/stats` | 获取索引统计信息 |
264 138
265 --- 139 ---
266 140
267 ## 搜索接口 141 ## 搜索接口
268 142
269 -### 接口信息 143 +### 3.1 接口信息
270 144
271 - **端点**: `POST /search/` 145 - **端点**: `POST /search/`
272 - **描述**: 执行文本搜索查询,支持多语言、布尔表达式、过滤器和分面搜索 146 - **描述**: 执行文本搜索查询,支持多语言、布尔表达式、过滤器和分面搜索
273 147
274 -### 请求参数 148 +### 3.2 请求参数
275 149
276 #### 完整请求体结构 150 #### 完整请求体结构
277 151
@@ -294,8 +168,6 @@ curl -X GET "http://localhost:6002/indexer/health" @@ -294,8 +168,6 @@ curl -X GET "http://localhost:6002/indexer/health"
294 } 168 }
295 ``` 169 ```
296 170
297 -**注意**: `tenant_id` 通过 HTTP Header `X-Tenant-ID` 传递,不在请求体中。  
298 -  
299 #### 参数详细说明 171 #### 参数详细说明
300 172
301 | 参数 | 类型 | 必填 | 默认值 | 说明 | 173 | 参数 | 类型 | 必填 | 默认值 | 说明 |
@@ -304,22 +176,22 @@ curl -X GET "http://localhost:6002/indexer/health" @@ -304,22 +176,22 @@ curl -X GET "http://localhost:6002/indexer/health"
304 | `size` | integer | N | 10 | 返回结果数量(1-100) | 176 | `size` | integer | N | 10 | 返回结果数量(1-100) |
305 | `from` | integer | N | 0 | 分页偏移量(用于分页) | 177 | `from` | integer | N | 0 | 分页偏移量(用于分页) |
306 | `language` | string | N | "zh" | 返回语言:`zh`(中文)或 `en`(英文)。后端会根据此参数选择对应的中英文字段返回 | 178 | `language` | string | N | "zh" | 返回语言:`zh`(中文)或 `en`(英文)。后端会根据此参数选择对应的中英文字段返回 |
307 -| `filters` | object | N | null | 精确匹配过滤器(见下文) |  
308 -| `range_filters` | object | N | null | 数值范围过滤器(见下文) |  
309 -| `facets` | array | N | null | 分面配置(见下文) | 179 +| `filters` | object | N | null | 精确匹配过滤器(见[过滤器详解](#33-过滤器详解)) |
  180 +| `range_filters` | object | N | null | 数值范围过滤器(见[过滤器详解](#33-过滤器详解)) |
  181 +| `facets` | array | N | null | 分面配置(见[分面配置](#34-分面配置)) |
310 | `sort_by` | string | N | null | 排序字段名。支持:`price`(价格)、`sales`(销量)、`create_time`(创建时间)、`update_time`(更新时间)。默认按相关性排序 | 182 | `sort_by` | string | N | null | 排序字段名。支持:`price`(价格)、`sales`(销量)、`create_time`(创建时间)、`update_time`(更新时间)。默认按相关性排序 |
311 | `sort_order` | string | N | "desc" | 排序方向:`asc`(升序)或 `desc`(降序)。注意:`price`+`asc`=价格从低到高,`price`+`desc`=价格从高到低(后端自动映射为min_price或max_price) | 183 | `sort_order` | string | N | "desc" | 排序方向:`asc`(升序)或 `desc`(降序)。注意:`price`+`asc`=价格从低到高,`price`+`desc`=价格从高到低(后端自动映射为min_price或max_price) |
312 | `min_score` | float | N | null | 最小相关性分数阈值 | 184 | `min_score` | float | N | null | 最小相关性分数阈值 |
313 -| `sku_filter_dimension` | array[string] | N | null | 子SKU筛选维度列表(店铺配置)。指定后,每个SPU下的SKU将按这些维度的组合进行分组,每个组合只返回第一个SKU。支持的值:`option1`、`option2`、`option3` 或选项名称(如 `color`、`size`)。详见下文说明 | 185 +| `sku_filter_dimension` | array[string] | N | null | 子SKU筛选维度列表(见[SKU筛选维度](#35-sku筛选维度)) |
314 | `debug` | boolean | N | false | 是否返回调试信息 | 186 | `debug` | boolean | N | false | 是否返回调试信息 |
315 | `user_id` | string | N | null | 用户ID(用于个性化,预留) | 187 | `user_id` | string | N | null | 用户ID(用于个性化,预留) |
316 | `session_id` | string | N | null | 会话ID(用于分析,预留) | 188 | `session_id` | string | N | null | 会话ID(用于分析,预留) |
317 189
318 -### 过滤器详解 190 +### 3.3 过滤器详解
319 191
320 -#### 1. 精确匹配过滤器 (filters) 192 +#### 3.3.1 精确匹配过滤器 (filters)
321 193
322 -用于精确匹配或多值匹配。对于普通字段,数组表示 OR 逻辑(匹配任意一个值);对于 specifications 字段,按维度分组处理(见下文) 194 +用于精确匹配或多值匹配。对于普通字段,数组表示 OR 逻辑(匹配任意一个值);对于 specifications 字段,按维度分组处理
323 195
324 **格式**: 196 **格式**:
325 ```json 197 ```json
@@ -396,7 +268,7 @@ curl -X GET "http://localhost:6002/indexer/health" @@ -396,7 +268,7 @@ curl -X GET "http://localhost:6002/indexer/health"
396 - **不同维度**(不同的 `name`)之间是 **AND** 关系(求交集) 268 - **不同维度**(不同的 `name`)之间是 **AND** 关系(求交集)
397 - **相同维度**(相同的 `name`)的多个值之间是 **OR** 关系(求并集) 269 - **相同维度**(相同的 `name`)的多个值之间是 **OR** 关系(求并集)
398 270
399 -**常用过滤字段**: 271 +**常用过滤字段**(详见[常用字段列表](#83-常用字段列表)):
400 - `category_name`: 类目名称 272 - `category_name`: 类目名称
401 - `category1_name`, `category2_name`, `category3_name`: 多级类目 273 - `category1_name`, `category2_name`, `category3_name`: 多级类目
402 - `category_id`: 类目ID 274 - `category_id`: 类目ID
@@ -405,7 +277,7 @@ curl -X GET "http://localhost:6002/indexer/health" @@ -405,7 +277,7 @@ curl -X GET "http://localhost:6002/indexer/health"
405 - `option1_name`, `option2_name`, `option3_name`: 选项名称 277 - `option1_name`, `option2_name`, `option3_name`: 选项名称
406 - `specifications`: 规格过滤(嵌套字段,格式见上文) 278 - `specifications`: 规格过滤(嵌套字段,格式见上文)
407 279
408 -#### 2. 范围过滤器 (range_filters) 280 +#### 3.3.2 范围过滤器 (range_filters)
409 281
410 用于数值字段的范围过滤。 282 用于数值字段的范围过滤。
411 283
@@ -435,18 +307,18 @@ curl -X GET "http://localhost:6002/indexer/health" @@ -435,18 +307,18 @@ curl -X GET "http://localhost:6002/indexer/health"
435 307
436 **注意**: 至少需要指定一个操作符。 308 **注意**: 至少需要指定一个操作符。
437 309
438 -**常用范围字段**: 310 +**常用范围字段**(详见[常用字段列表](#83-常用字段列表)):
439 - `min_price`: 最低价格 311 - `min_price`: 最低价格
440 - `max_price`: 最高价格 312 - `max_price`: 最高价格
441 - `compare_at_price`: 原价 313 - `compare_at_price`: 原价
442 - `create_time`: 创建时间 314 - `create_time`: 创建时间
443 - `update_time`: 更新时间 315 - `update_time`: 更新时间
444 316
445 -#### 3. 分面配置 (facets) 317 +### 3.4 分面配置
446 318
447 用于生成分面统计(分组聚合),常用于构建筛选器UI。 319 用于生成分面统计(分组聚合),常用于构建筛选器UI。
448 320
449 -**配置格式**(对象数组): 321 +#### 3.4.1 配置格式
450 322
451 ```json 323 ```json
452 { 324 {
@@ -483,7 +355,7 @@ curl -X GET "http://localhost:6002/indexer/health" @@ -483,7 +355,7 @@ curl -X GET "http://localhost:6002/indexer/health"
483 } 355 }
484 ``` 356 ```
485 357
486 -**Facet 字段说明**: 358 +#### 3.4.2 Facet 字段说明
487 359
488 | 字段 | 类型 | 必填 | 默认值 | 说明 | 360 | 字段 | 类型 | 必填 | 默认值 | 说明 |
489 |------|------|------|--------|------| 361 |------|------|------|--------|------|
@@ -493,22 +365,21 @@ curl -X GET "http://localhost:6002/indexer/health" @@ -493,22 +365,21 @@ curl -X GET "http://localhost:6002/indexer/health"
493 | `disjunctive` | bool | 否 | false | **是否支持多选模式**(见下文详细说明) | 365 | `disjunctive` | bool | 否 | false | **是否支持多选模式**(见下文详细说明) |
494 | `ranges` | array | 否 | null | 范围配置(仅 `type="range"` 时需要) | 366 | `ranges` | array | 否 | null | 范围配置(仅 `type="range"` 时需要) |
495 367
496 -#### 🆕 Multi-Select Faceting(多选分面) 368 +#### 3.4.3 Multi-Select Faceting(多选分面)
497 369
498 **重要特性**: `disjunctive` 字段控制分面的行为模式。 370 **重要特性**: `disjunctive` 字段控制分面的行为模式。
499 371
500 -  
501 -##### 标准模式 (disjunctive: false) 372 +**标准模式 (disjunctive: false)**:
502 - **行为**: 选中某个分面值后,该分面只显示选中的值 373 - **行为**: 选中某个分面值后,该分面只显示选中的值
503 - **适用场景**: 层级类目、互斥选择 374 - **适用场景**: 层级类目、互斥选择
504 - **示例**: 类目下钻(玩具 > 娃娃 > 芭比) 375 - **示例**: 类目下钻(玩具 > 娃娃 > 芭比)
505 376
506 -##### Multi-Select 模式 (disjunctive: true) ⭐ 377 +**Multi-Select 模式 (disjunctive: true)** ⭐:
507 - **行为**: 选中某个分面值后,该分面仍显示所有可选项 378 - **行为**: 选中某个分面值后,该分面仍显示所有可选项
508 - **适用场景**: 颜色、品牌、尺码等可切换属性 379 - **适用场景**: 颜色、品牌、尺码等可切换属性
509 - **示例**: 选择了"红色"后,仍能看到"蓝色"、"绿色"等选项 380 - **示例**: 选择了"红色"后,仍能看到"蓝色"、"绿色"等选项
510 381
511 -##### 推荐配置 382 +**推荐配置**:
512 383
513 | 分面类型 | disjunctive | 原因 | 384 | 分面类型 | disjunctive | 原因 |
514 |---------|-------------|------| 385 |---------|-------------|------|
@@ -518,7 +389,7 @@ curl -X GET "http://localhost:6002/indexer/health" @@ -518,7 +389,7 @@ curl -X GET "http://localhost:6002/indexer/health"
518 | 类目 | `false` | 层级下钻 | 389 | 类目 | `false` | 层级下钻 |
519 | 价格区间 | `false` | 互斥选择 | 390 | 价格区间 | `false` | 互斥选择 |
520 391
521 -**规格分面说明**: 392 +#### 3.4.4 规格分面说明
522 393
523 `specifications` 是嵌套字段,支持两种分面模式: 394 `specifications` 是嵌套字段,支持两种分面模式:
524 395
@@ -584,13 +455,7 @@ curl -X GET "http://localhost:6002/indexer/health" @@ -584,13 +455,7 @@ curl -X GET "http://localhost:6002/indexer/health"
584 } 455 }
585 ``` 456 ```
586 457
587 -**分面配置参数**:  
588 -- `field`: 字段名(必填)  
589 -- `size`: 返回的分组数量(默认:10,范围:1-100)  
590 -- `type`: 分面类型,`terms`(分组统计)或 `range`(范围统计)  
591 -- `ranges`: 范围定义(仅当 type='range' 时需要)  
592 -  
593 -### SKU筛选维度 (sku_filter_dimension) 458 +### 3.5 SKU筛选维度
594 459
595 **功能说明**: 460 **功能说明**:
596 `sku_filter_dimension` 用于控制搜索列表页中 **每个 SPU 下方可切换的子款式(子 SKU)维度**,为字符串列表。 461 `sku_filter_dimension` 用于控制搜索列表页中 **每个 SPU 下方可切换的子款式(子 SKU)维度**,为字符串列表。
@@ -630,9 +495,7 @@ curl -X GET "http://localhost:6002/indexer/health" @@ -630,9 +495,7 @@ curl -X GET "http://localhost:6002/indexer/health"
630 } 495 }
631 ``` 496 ```
632 497
633 ----  
634 -  
635 -### 布尔表达式语法 498 +### 3.6 布尔表达式语法
636 499
637 搜索查询支持布尔表达式,提供更灵活的搜索能力。 500 搜索查询支持布尔表达式,提供更灵活的搜索能力。
638 501
@@ -662,63 +525,151 @@ curl -X GET "http://localhost:6002/indexer/health" @@ -662,63 +525,151 @@ curl -X GET "http://localhost:6002/indexer/health"
662 "玩具 AND (乐高 OR 芭比)" // 复杂查询 525 "玩具 AND (乐高 OR 芭比)" // 复杂查询
663 ``` 526 ```
664 527
665 ---- 528 +### 3.7 搜索建议接口
666 529
667 -## 响应格式说明 530 +> ⚠️ **TODO**: 此接口当前为框架实现,功能暂未实现,仅返回空结果。接口和响应格式已经固定,可平滑扩展。
  531 +
  532 +- **端点**: `GET /search/suggestions`
  533 +- **描述**: 返回搜索建议(自动补全/热词)。当前为框架实现,接口和响应格式已经固定,可平滑扩展。
  534 +
  535 +#### 查询参数
  536 +
  537 +| 参数 | 类型 | 必填 | 默认值 | 描述 |
  538 +|------|------|------|--------|------|
  539 +| `q` | string | Y | - | 查询字符串(至少 1 个字符) |
  540 +| `size` | integer | N | 5 | 返回建议数量(1-20) |
  541 +| `types` | string | N | `query` | 建议类型(逗号分隔):`query`, `product`, `category`, `brand` |
668 542
669 -### 标准响应结构 543 +#### 响应示例
670 544
671 ```json 545 ```json
672 { 546 {
673 - "results": [ 547 + "query": "芭",
  548 + "suggestions": [
674 { 549 {
675 - "spu_id": "12345",  
676 - "title": "芭比时尚娃娃",  
677 - "brief": "高品质芭比娃娃",  
678 - "description": "详细描述...",  
679 - "vendor": "美泰",  
680 - "category": "玩具",  
681 - "category_path": "玩具/娃娃/时尚",  
682 - "category_name": "时尚",  
683 - "category_id": "cat_001",  
684 - "category_level": 3,  
685 - "category1_name": "玩具",  
686 - "category2_name": "娃娃",  
687 - "category3_name": "时尚",  
688 - "tags": ["娃娃", "玩具", "女孩"],  
689 - "price": 89.99,  
690 - "compare_at_price": 129.99,  
691 - "currency": "USD",  
692 - "image_url": "https://example.com/image.jpg",  
693 - "in_stock": true,  
694 - "sku_prices": [89.99, 99.99, 109.99],  
695 - "sku_weights": [100, 150, 200],  
696 - "sku_weight_units": ["g", "g", "g"],  
697 - "total_inventory": 500,  
698 - "option1_name": "color",  
699 - "option2_name": "size",  
700 - "option3_name": null,  
701 - "specifications": [  
702 - {"sku_id": "sku_001", "name": "color", "value": "pink"},  
703 - {"sku_id": "sku_001", "name": "size", "value": "standard"}  
704 - ],  
705 - "skus": [  
706 - {  
707 - "sku_id": "67890",  
708 - "price": 89.99,  
709 - "compare_at_price": 129.99,  
710 - "sku": "BARBIE-001",  
711 - "stock": 100,  
712 - "weight": 0.1,  
713 - "weight_unit": "kg",  
714 - "option1_value": "pink",  
715 - "option2_value": "standard",  
716 - "option3_value": null,  
717 - "image_src": "https://example.com/sku1.jpg"  
718 - }  
719 - ],  
720 - "relevance_score": 8.5  
721 - } 550 + "text": "芭比娃娃",
  551 + "type": "query",
  552 + "highlight": "<em>芭</em>比娃娃",
  553 + "popularity": 850
  554 + }
  555 + ],
  556 + "took_ms": 5
  557 +}
  558 +```
  559 +
  560 +#### 请求示例
  561 +
  562 +```bash
  563 +curl "http://localhost:6002/search/suggestions?q=芭&size=5&types=query,product"
  564 +```
  565 +
  566 +### 3.8 即时搜索接口
  567 +
  568 +> ⚠️ **TODO**: 此接口当前为框架实现,功能暂未实现,调用标准搜索接口。后续需要优化即时搜索性能(添加防抖/节流、实现结果缓存、简化返回字段)。
  569 +
  570 +- **端点**: `GET /search/instant`
  571 +- **描述**: 边输入边搜索,采用轻量参数响应当前输入。底层复用标准搜索能力。
  572 +
  573 +#### 查询参数
  574 +
  575 +| 参数 | 类型 | 必填 | 默认值 | 描述 |
  576 +|------|------|------|--------|------|
  577 +| `q` | string | Y | - | 搜索查询(至少 2 个字符) |
  578 +| `size` | integer | N | 5 | 返回结果数量(1-20) |
  579 +
  580 +#### 请求示例
  581 +
  582 +```bash
  583 +curl "http://localhost:6002/search/instant?q=玩具&size=5"
  584 +```
  585 +
  586 +### 3.9 获取单个文档
  587 +
  588 +- **端点**: `GET /search/{doc_id}`
  589 +- **描述**: 根据文档 ID 获取单个商品详情,用于点击结果后的详情页或排查问题。
  590 +
  591 +#### 路径参数
  592 +
  593 +| 参数 | 类型 | 描述 |
  594 +|------|------|------|
  595 +| `doc_id` | string | 商品或文档 ID |
  596 +
  597 +#### 响应示例
  598 +
  599 +```json
  600 +{
  601 + "id": "12345",
  602 + "source": {
  603 + "title_zh": "芭比时尚娃娃",
  604 + "min_price": 89.99,
  605 + "category1_name": "玩具"
  606 + }
  607 +}
  608 +```
  609 +
  610 +#### 请求示例
  611 +
  612 +```bash
  613 +curl "http://localhost:6002/search/12345"
  614 +```
  615 +
  616 +---
  617 +
  618 +## 响应格式说明
  619 +
  620 +### 4.1 标准响应结构
  621 +
  622 +```json
  623 +{
  624 + "results": [
  625 + {
  626 + "spu_id": "12345",
  627 + "title": "芭比时尚娃娃",
  628 + "brief": "高品质芭比娃娃",
  629 + "description": "详细描述...",
  630 + "vendor": "美泰",
  631 + "category": "玩具",
  632 + "category_path": "玩具/娃娃/时尚",
  633 + "category_name": "时尚",
  634 + "category_id": "cat_001",
  635 + "category_level": 3,
  636 + "category1_name": "玩具",
  637 + "category2_name": "娃娃",
  638 + "category3_name": "时尚",
  639 + "tags": ["娃娃", "玩具", "女孩"],
  640 + "price": 89.99,
  641 + "compare_at_price": 129.99,
  642 + "currency": "USD",
  643 + "image_url": "https://example.com/image.jpg",
  644 + "in_stock": true,
  645 + "sku_prices": [89.99, 99.99, 109.99],
  646 + "sku_weights": [100, 150, 200],
  647 + "sku_weight_units": ["g", "g", "g"],
  648 + "total_inventory": 500,
  649 + "option1_name": "color",
  650 + "option2_name": "size",
  651 + "option3_name": null,
  652 + "specifications": [
  653 + {"sku_id": "sku_001", "name": "color", "value": "pink"},
  654 + {"sku_id": "sku_001", "name": "size", "value": "standard"}
  655 + ],
  656 + "skus": [
  657 + {
  658 + "sku_id": "67890",
  659 + "price": 89.99,
  660 + "compare_at_price": 129.99,
  661 + "sku": "BARBIE-001",
  662 + "stock": 100,
  663 + "weight": 0.1,
  664 + "weight_unit": "kg",
  665 + "option1_value": "pink",
  666 + "option2_value": "standard",
  667 + "option3_value": null,
  668 + "image_src": "https://example.com/sku1.jpg"
  669 + }
  670 + ],
  671 + "relevance_score": 8.5
  672 + }
722 ], 673 ],
723 "total": 118, 674 "total": 118,
724 "max_score": 8.5, 675 "max_score": 8.5,
@@ -765,7 +716,7 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot; @@ -765,7 +716,7 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot;
765 } 716 }
766 ``` 717 ```
767 718
768 -### 响应字段说明 719 +### 4.2 响应字段说明
769 720
770 | 字段 | 类型 | 说明 | 721 | 字段 | 类型 | 说明 |
771 |------|------|------| 722 |------|------|------|
@@ -781,7 +732,7 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot; @@ -781,7 +732,7 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot;
781 | `query_info` | object | 查询处理信息 | 732 | `query_info` | object | 查询处理信息 |
782 | `took_ms` | integer | 搜索耗时(毫秒) | 733 | `took_ms` | integer | 搜索耗时(毫秒) |
783 734
784 -### SpuResult字段说明 735 +### 4.3 SpuResult字段说明
785 736
786 | 字段 | 类型 | 说明 | 737 | 字段 | 类型 | 说明 |
787 |------|------|------| 738 |------|------|------|
@@ -816,35 +767,255 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot; @@ -816,35 +767,255 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot;
816 | `skus` | array | SKU 列表 | 767 | `skus` | array | SKU 列表 |
817 | `relevance_score` | float | 相关性分数 | 768 | `relevance_score` | float | 相关性分数 |
818 769
819 -**多语言字段说明**:  
820 -- `title`, `brief`, `description`, `vendor`, `category_path`, `category_name` 会根据请求的 `language` 参数自动选择对应的中英文字段  
821 -- `language="zh"`: 优先返回 `*_zh` 字段,如果为空则回退到 `*_en` 字段  
822 -- `language="en"`: 优先返回 `*_en` 字段,如果为空则回退到 `*_zh` 字段 770 +### 4.4 SkuResult字段说明
  771 +
  772 +| 字段 | 类型 | 说明 |
  773 +|------|------|------|
  774 +| `sku_id` | string | SKU ID |
  775 +| `price` | float | 价格 |
  776 +| `compare_at_price` | float | 原价 |
  777 +| `sku` | string | SKU编码(sku_code) |
  778 +| `stock` | integer | 库存数量 |
  779 +| `weight` | float | 重量 |
  780 +| `weight_unit` | string | 重量单位 |
  781 +| `option1_value` | string | 选项1取值(如color值) |
  782 +| `option2_value` | string | 选项2取值(如size值) |
  783 +| `option3_value` | string | 选项3取值 |
  784 +| `image_src` | string | SKU图片地址 |
  785 +
  786 +### 4.5 多语言字段说明
  787 +
  788 +- `title`, `brief`, `description`, `vendor`, `category_path`, `category_name` 会根据请求的 `language` 参数自动选择对应的中英文字段
  789 +- `language="zh"`: 优先返回 `*_zh` 字段,如果为空则回退到 `*_en` 字段
  790 +- `language="en"`: 优先返回 `*_en` 字段,如果为空则回退到 `*_zh` 字段
  791 +
  792 +---
  793 +
  794 +## 索引接口
  795 +
  796 +### 5.1 全量索引接口
  797 +
  798 +- **端点**: `POST /indexer/bulk`
  799 +- **描述**: 将指定租户的所有SPU数据导入到ES索引
  800 +
  801 +#### 请求参数
  802 +
  803 +```json
  804 +{
  805 + "tenant_id": "162",
  806 + "recreate_index": false,
  807 + "batch_size": 500
  808 +}
  809 +```
  810 +
  811 +| 参数 | 类型 | 必填 | 默认值 | 说明 |
  812 +|------|------|------|--------|------|
  813 +| `tenant_id` | string | Y | - | 租户ID |
  814 +| `recreate_index` | boolean | N | false | 是否重建索引(删除旧索引后创建新索引) |
  815 +| `batch_size` | integer | N | 500 | 批量导入大小 |
  816 +
  817 +#### 响应格式
  818 +
  819 +**成功响应(200 OK)**:
  820 +```json
  821 +{
  822 + "success": true,
  823 + "total": 1000,
  824 + "indexed": 1000,
  825 + "failed": 0,
  826 + "elapsed_time": 12.34,
  827 + "index_name": "search_products",
  828 + "tenant_id": "162"
  829 +}
  830 +```
  831 +
  832 +**错误响应**:
  833 +- `400 Bad Request`: 参数错误
  834 +- `503 Service Unavailable`: 服务未初始化
  835 +
  836 +#### 请求示例
  837 +
  838 +**首次索引(重建索引)**:
  839 +```bash
  840 +curl -X POST "http://localhost:6002/indexer/bulk" \
  841 + -H "Content-Type: application/json" \
  842 + -d '{
  843 + "tenant_id": "162",
  844 + "recreate_index": true,
  845 + "batch_size": 500
  846 + }'
  847 +```
  848 +
  849 +**查看日志**:
  850 +```bash
  851 +# 查看API日志(包含索引操作日志)
  852 +tail -f logs/api.log
  853 +
  854 +# 或者查看所有日志文件
  855 +tail -f logs/*.log
  856 +```
  857 +
  858 +**增量更新(不重建索引)**:
  859 +```bash
  860 +curl -X POST "http://localhost:6002/indexer/bulk" \
  861 + -H "Content-Type: application/json" \
  862 + -d '{
  863 + "tenant_id": "162",
  864 + "recreate_index": false,
  865 + "batch_size": 500
  866 + }'
  867 +```
  868 +
  869 +### 5.2 SPU索引接口
  870 +
  871 +- **端点**: `POST /indexer/spus`
  872 +- **描述**: 获取SPU的ES文档数据(支持单个或批量)
  873 +
  874 +#### 请求参数
  875 +
  876 +```json
  877 +{
  878 + "tenant_id": "162",
  879 + "spu_ids": ["123", "456", "789"]
  880 +}
  881 +```
  882 +
  883 +| 参数 | 类型 | 必填 | 说明 |
  884 +|------|------|------|------|
  885 +| `tenant_id` | string | Y | 租户ID |
  886 +| `spu_ids` | array[string] | Y | SPU ID列表(1-100个) |
  887 +
  888 +#### 响应格式
  889 +
  890 +```json
  891 +{
  892 + "success": [
  893 + {
  894 + "spu_id": "123",
  895 + "document": {
  896 + "tenant_id": "162",
  897 + "spu_id": "123",
  898 + "title_zh": "商品标题",
  899 + ...
  900 + }
  901 + },
  902 + {
  903 + "spu_id": "456",
  904 + "document": {...}
  905 + }
  906 + ],
  907 + "failed": [
  908 + {
  909 + "spu_id": "789",
  910 + "error": "SPU not found or deleted"
  911 + }
  912 + ],
  913 + "total": 3,
  914 + "success_count": 2,
  915 + "failed_count": 1
  916 +}
  917 +```
  918 +
  919 +#### 请求示例
  920 +
  921 +**单个SPU**:
  922 +```bash
  923 +curl -X POST "http://localhost:6002/indexer/spus" \
  924 + -H "Content-Type: application/json" \
  925 + -d '{
  926 + "tenant_id": "162",
  927 + "spu_ids": ["123"]
  928 + }'
  929 +```
  930 +
  931 +**批量SPU**:
  932 +```bash
  933 +curl -X POST "http://localhost:6002/indexer/spus" \
  934 + -H "Content-Type: application/json" \
  935 + -d '{
  936 + "tenant_id": "162",
  937 + "spu_ids": ["123", "456", "789"]
  938 + }'
  939 +```
  940 +
  941 +### 5.3 索引健康检查接口
  942 +
  943 +- **端点**: `GET /indexer/health`
  944 +- **描述**: 检查索引服务的健康状态
  945 +
  946 +#### 响应格式
  947 +
  948 +```json
  949 +{
  950 + "status": "available",
  951 + "database": "connected",
  952 + "preloaded_data": {
  953 + "category_mappings": 150
  954 + }
  955 +}
  956 +```
  957 +
  958 +#### 请求示例
  959 +
  960 +```bash
  961 +curl -X GET "http://localhost:6002/indexer/health"
  962 +```
  963 +
  964 +---
  965 +
  966 +## 管理接口
  967 +
  968 +### 6.1 健康检查
  969 +
  970 +- **端点**: `GET /admin/health`
  971 +- **描述**: 检查服务与依赖(如 Elasticsearch)状态。
  972 +
  973 +```json
  974 +{
  975 + "status": "healthy",
  976 + "elasticsearch": "connected",
  977 + "tenant_id": "tenant1"
  978 +}
  979 +```
  980 +
  981 +### 6.2 获取配置
  982 +
  983 +- **端点**: `GET /admin/config`
  984 +- **描述**: 返回当前租户的脱敏配置,便于核对索引及排序表达式。
  985 +
  986 +```json
  987 +{
  988 + "tenant_id": "tenant1",
  989 + "tenant_name": "Tenant1 Test Instance",
  990 + "es_index_name": "search_tenant1",
  991 + "num_fields": 20,
  992 + "num_indexes": 4,
  993 + "supported_languages": ["zh", "en", "ru"],
  994 + "ranking_expression": "bm25() + 0.2*text_embedding_relevance()",
  995 + "spu_enabled": false
  996 +}
  997 +```
  998 +
  999 +### 6.3 索引统计
823 1000
824 -### SkuResult字段说明 1001 +- **端点**: `GET /admin/stats`
  1002 +- **描述**: 获取索引文档数量与磁盘大小,方便监控。
825 1003
826 -| 字段 | 类型 | 说明 |  
827 -|------|------|------|  
828 -| `sku_id` | string | SKU ID |  
829 -| `price` | float | 价格 |  
830 -| `compare_at_price` | float | 原价 |  
831 -| `sku` | string | SKU编码(sku_code) |  
832 -| `stock` | integer | 库存数量 |  
833 -| `weight` | float | 重量 |  
834 -| `weight_unit` | string | 重量单位 |  
835 -| `option1_value` | string | 选项1取值(如color值) |  
836 -| `option2_value` | string | 选项2取值(如size值) |  
837 -| `option3_value` | string | 选项3取值 |  
838 -| `image_src` | string | SKU图片地址 | 1004 +```json
  1005 +{
  1006 + "index_name": "search_tenant1",
  1007 + "document_count": 10000,
  1008 + "size_mb": 523.45
  1009 +}
  1010 +```
839 1011
840 --- 1012 ---
841 1013
842 ## 常见场景示例 1014 ## 常见场景示例
843 1015
844 -### 场景1:商品列表页搜索  
845 -  
846 -**需求**: 搜索"玩具",按价格从低到高排序,显示前20个结果 1016 +### 7.1 基础搜索与排序
847 1017
  1018 +**按价格从低到高排序**:
848 ```json 1019 ```json
849 { 1020 {
850 "query": "玩具", 1021 "query": "玩具",
@@ -855,8 +1026,7 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot; @@ -855,8 +1026,7 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot;
855 } 1026 }
856 ``` 1027 ```
857 1028
858 -**需求**: 搜索"玩具",按价格从高到低排序  
859 - 1029 +**按价格从高到低排序**:
860 ```json 1030 ```json
861 { 1031 {
862 "query": "玩具", 1032 "query": "玩具",
@@ -867,8 +1037,7 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot; @@ -867,8 +1037,7 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot;
867 } 1037 }
868 ``` 1038 ```
869 1039
870 -**需求**: 搜索"玩具",按销量从高到低排序  
871 - 1040 +**按销量从高到低排序**:
872 ```json 1041 ```json
873 { 1042 {
874 "query": "玩具", 1043 "query": "玩具",
@@ -879,8 +1048,7 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot; @@ -879,8 +1048,7 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot;
879 } 1048 }
880 ``` 1049 ```
881 1050
882 -**需求**: 搜索"玩具",按默认(相关性)排序  
883 - 1051 +**按默认(相关性)排序**:
884 ```json 1052 ```json
885 { 1053 {
886 "query": "玩具", 1054 "query": "玩具",
@@ -889,34 +1057,36 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot; @@ -889,34 +1057,36 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot;
889 } 1057 }
890 ``` 1058 ```
891 1059
892 -### 场景2:SKU筛选(按维度过滤) 1060 +### 7.2 过滤搜索
893 1061
894 -**需求**: 搜索"芭比娃娃",每个SPU下按颜色筛选,每种颜色只显示一个SKU 1062 +**需求**: 搜索"玩具",筛选类目为"益智玩具",价格在50-200之间
895 1063
896 ```json 1064 ```json
897 { 1065 {
898 - "query": "芭比娃娃", 1066 + "query": "玩具",
899 "size": 20, 1067 "size": 20,
900 - "sku_filter_dimension": "color" 1068 + "language": "zh",
  1069 + "filters": {
  1070 + "category_name": "益智玩具"
  1071 + },
  1072 + "range_filters": {
  1073 + "min_price": {
  1074 + "gte": 50,
  1075 + "lte": 200
  1076 + }
  1077 + }
901 } 1078 }
902 ``` 1079 ```
903 1080
904 -**说明**:  
905 -- 如果 `option1_name` 为 `"color"`,则使用 `sku_filter_dimension: "color"` 可以按颜色分组  
906 -- 每个SPU下,每种颜色只会返回第一个SKU  
907 -- 如果维度不匹配,返回所有SKU(不进行过滤)  
908 -  
909 -### 场景3:带筛选的商品搜索  
910 -  
911 -**需求**: 搜索"玩具",筛选类目为"益智玩具",价格在50-200之间 1081 +**需求**: 搜索"手机",筛选多个品牌,价格范围
912 1082
913 ```json 1083 ```json
914 { 1084 {
915 - "query": "玩具", 1085 + "query": "手机",
916 "size": 20, 1086 "size": 20,
917 "language": "zh", 1087 "language": "zh",
918 "filters": { 1088 "filters": {
919 - "category_name": "益智玩具" 1089 + "vendor_zh.keyword": ["品牌A", "品牌B"]
920 }, 1090 },
921 "range_filters": { 1091 "range_filters": {
922 "min_price": { 1092 "min_price": {
@@ -927,7 +1097,7 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot; @@ -927,7 +1097,7 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot;
927 } 1097 }
928 ``` 1098 ```
929 1099
930 -### 场景4:带分面的商品搜索 1100 +### 7.3 分面搜索
931 1101
932 **需求**: 搜索"玩具",获取类目和规格的分面统计,用于构建筛选器 1102 **需求**: 搜索"玩具",获取类目和规格的分面统计,用于构建筛选器
933 1103
@@ -944,31 +1114,15 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot; @@ -944,31 +1114,15 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot;
944 } 1114 }
945 ``` 1115 ```
946 1116
947 -### 场景5:多条件组合搜索  
948 -  
949 -**需求**: 搜索"手机",筛选多个品牌,价格范围,并获取分面统计 1117 +**需求**: 搜索"手机",获取价格区间和规格的分面统计
950 1118
951 ```json 1119 ```json
952 { 1120 {
953 "query": "手机", 1121 "query": "手机",
954 "size": 20, 1122 "size": 20,
955 "language": "zh", 1123 "language": "zh",
956 - "filters": {  
957 - "vendor_zh.keyword": ["品牌A", "品牌B"]  
958 - },  
959 - "range_filters": {  
960 - "min_price": {  
961 - "gte": 50,  
962 - "lte": 200  
963 - }  
964 - },  
965 "facets": [ 1124 "facets": [
966 { 1125 {
967 - "field": "category1_name",  
968 - "size": 15,  
969 - "type": "terms"  
970 - },  
971 - {  
972 "field": "min_price", 1126 "field": "min_price",
973 "type": "range", 1127 "type": "range",
974 "ranges": [ 1128 "ranges": [
@@ -983,13 +1137,11 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot; @@ -983,13 +1137,11 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot;
983 "size": 10, 1137 "size": 10,
984 "type": "terms" 1138 "type": "terms"
985 } 1139 }
986 - ],  
987 - "sort_by": "min_price",  
988 - "sort_order": "asc" 1140 + ]
989 } 1141 }
990 ``` 1142 ```
991 1143
992 -### 场景6:规格过滤搜索 1144 +### 7.4 规格过滤与分面
993 1145
994 **需求**: 搜索"手机",筛选color为"white"的商品 1146 **需求**: 搜索"手机",筛选color为"white"的商品
995 1147
@@ -1007,8 +1159,6 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot; @@ -1007,8 +1159,6 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot;
1007 } 1159 }
1008 ``` 1160 ```
1009 1161
1010 -### 场景7:多个规格过滤(不同维度AND,相同维度OR)  
1011 -  
1012 **需求**: 搜索"手机",筛选color为"white"且size为"256GB"的商品 1162 **需求**: 搜索"手机",筛选color为"white"且size为"256GB"的商品
1013 1163
1014 ```json 1164 ```json
@@ -1043,8 +1193,6 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot; @@ -1043,8 +1193,6 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot;
1043 } 1193 }
1044 ``` 1194 ```
1045 1195
1046 -### 场景8:规格分面搜索  
1047 -  
1048 **需求**: 搜索"手机",获取所有规格的分面统计 1196 **需求**: 搜索"手机",获取所有规格的分面统计
1049 1197
1050 ```json 1198 ```json
@@ -1072,8 +1220,6 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot; @@ -1072,8 +1220,6 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot;
1072 } 1220 }
1073 ``` 1221 ```
1074 1222
1075 -### 场景9:组合过滤和分面  
1076 -  
1077 **需求**: 搜索"手机",筛选类目和规格,并获取对应的分面统计 1223 **需求**: 搜索"手机",筛选类目和规格,并获取对应的分面统计
1078 1224
1079 ```json 1225 ```json
@@ -1097,172 +1243,43 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot; @@ -1097,172 +1243,43 @@ curl -X GET &quot;http://localhost:6002/indexer/health&quot;
1097 } 1243 }
1098 ``` 1244 ```
1099 1245
1100 -### 场景10:布尔表达式搜索  
1101 -  
1102 -**需求**: 搜索包含"手机"和"智能"的商品,排除"二手"  
1103 -  
1104 -```json  
1105 -{  
1106 - "query": "手机 AND 智能 ANDNOT 二手",  
1107 - "size": 20  
1108 -}  
1109 -```  
1110 -  
1111 -### 场景11:分页查询 1246 +### 7.5 SKU筛选
1112 1247
1113 -**需求**: 获取第2页结果(每页20条) 1248 +**需求**: 搜索"芭比娃娃",每个SPU下按颜色筛选,每种颜色只显示一个SKU
1114 1249
1115 ```json 1250 ```json
1116 { 1251 {
1117 - "query": "手机", 1252 + "query": "芭比娃娃",
1118 "size": 20, 1253 "size": 20,
1119 - "from": 20  
1120 -}  
1121 -```  
1122 -  
1123 ----  
1124 -  
1125 ----  
1126 -  
1127 -## 其他接口  
1128 -  
1129 -### 搜索建议(框架)  
1130 -  
1131 -- **端点**: `GET /search/suggestions`  
1132 -- **描述**: 返回搜索建议(自动补全/热词)。当前为框架实现,接口和响应格式已经固定,可平滑扩展。  
1133 -  
1134 -#### 查询参数  
1135 -  
1136 -| 参数 | 类型 | 必填 | 默认值 | 描述 |  
1137 -|------|------|------|--------|------|  
1138 -| `q` | string | Y | - | 查询字符串(至少 1 个字符) |  
1139 -| `size` | integer | N | 5 | 返回建议数量(1-20) |  
1140 -| `types` | string | N | `query` | 建议类型(逗号分隔):`query`, `product`, `category`, `brand` |  
1141 -  
1142 -#### 响应示例  
1143 -  
1144 -```json  
1145 -{  
1146 - "query": "芭",  
1147 - "suggestions": [  
1148 - {  
1149 - "text": "芭比娃娃",  
1150 - "type": "query",  
1151 - "highlight": "<em>芭</em>比娃娃",  
1152 - "popularity": 850  
1153 - }  
1154 - ],  
1155 - "took_ms": 5  
1156 -}  
1157 -```  
1158 -  
1159 -#### 请求示例  
1160 -  
1161 -```bash  
1162 -curl "http://localhost:6002/search/suggestions?q=芭&size=5&types=query,product"  
1163 -```  
1164 -  
1165 ----  
1166 -  
1167 -### 即时搜索(框架)  
1168 -  
1169 -- **端点**: `GET /search/instant`  
1170 -- **描述**: 边输入边搜索,采用轻量参数响应当前输入。底层复用标准搜索能力。  
1171 -  
1172 -#### 查询参数  
1173 -  
1174 -| 参数 | 类型 | 必填 | 默认值 | 描述 |  
1175 -|------|------|------|--------|------|  
1176 -| `q` | string | Y | - | 搜索查询(至少 2 个字符) |  
1177 -| `size` | integer | N | 5 | 返回结果数量(1-20) |  
1178 -  
1179 -#### 请求示例  
1180 -  
1181 -```bash  
1182 -curl "http://localhost:6002/search/instant?q=玩具&size=5"  
1183 -```  
1184 -  
1185 ----  
1186 -  
1187 -### 获取单个文档  
1188 -  
1189 -- **端点**: `GET /search/{doc_id}`  
1190 -- **描述**: 根据文档 ID 获取单个商品详情,用于点击结果后的详情页或排查问题。  
1191 -  
1192 -#### 路径参数  
1193 -  
1194 -| 参数 | 类型 | 描述 |  
1195 -|------|------|------|  
1196 -| `doc_id` | string | 商品或文档 ID |  
1197 -  
1198 -#### 响应示例  
1199 -  
1200 -```json  
1201 -{  
1202 - "id": "12345",  
1203 - "source": {  
1204 - "title_zh": "芭比时尚娃娃",  
1205 - "min_price": 89.99,  
1206 - "category1_name": "玩具"  
1207 - }  
1208 -}  
1209 -```  
1210 -  
1211 -#### 请求示例  
1212 -  
1213 -```bash  
1214 -curl "http://localhost:6002/search/12345"  
1215 -```  
1216 -  
1217 ----  
1218 -  
1219 -## 管理接口  
1220 -  
1221 -### 健康检查  
1222 -  
1223 -- **端点**: `GET /admin/health`  
1224 -- **描述**: 检查服务与依赖(如 Elasticsearch)状态。  
1225 -  
1226 -```json  
1227 -{  
1228 - "status": "healthy",  
1229 - "elasticsearch": "connected",  
1230 - "tenant_id": "tenant1" 1254 + "sku_filter_dimension": ["color"]
1231 } 1255 }
1232 ``` 1256 ```
1233 1257
1234 ---- 1258 +**说明**:
  1259 +- 如果 `option1_name` 为 `"color"`,则使用 `sku_filter_dimension: ["color"]` 可以按颜色分组
  1260 +- 每个SPU下,每种颜色只会返回第一个SKU
  1261 +- 如果维度不匹配,返回所有SKU(不进行过滤)
1235 1262
1236 -### 获取配置 1263 +### 7.6 布尔表达式搜索
1237 1264
1238 -- **端点**: `GET /admin/config`  
1239 -- **描述**: 返回当前租户的脱敏配置,便于核对索引及排序表达式。 1265 +**需求**: 搜索包含"手机"和"智能"的商品,排除"二手"
1240 1266
1241 ```json 1267 ```json
1242 { 1268 {
1243 - "tenant_id": "tenant1",  
1244 - "tenant_name": "Tenant1 Test Instance",  
1245 - "es_index_name": "search_tenant1",  
1246 - "num_fields": 20,  
1247 - "num_indexes": 4,  
1248 - "supported_languages": ["zh", "en", "ru"],  
1249 - "ranking_expression": "bm25() + 0.2*text_embedding_relevance()",  
1250 - "spu_enabled": false 1269 + "query": "手机 AND 智能 ANDNOT 二手",
  1270 + "size": 20
1251 } 1271 }
1252 ``` 1272 ```
1253 1273
1254 ----  
1255 -  
1256 -### 索引统计 1274 +### 7.7 分页查询
1257 1275
1258 -- **端点**: `GET /admin/stats`  
1259 -- **描述**: 获取索引文档数量与磁盘大小,方便监控。 1276 +**需求**: 获取第2页结果(每页20条)
1260 1277
1261 ```json 1278 ```json
1262 { 1279 {
1263 - "index_name": "search_tenant1",  
1264 - "document_count": 10000,  
1265 - "size_mb": 523.45 1280 + "query": "手机",
  1281 + "size": 20,
  1282 + "from": 20
1266 } 1283 }
1267 ``` 1284 ```
1268 1285
@@ -1270,7 +1287,7 @@ curl &quot;http://localhost:6002/search/12345&quot; @@ -1270,7 +1287,7 @@ curl &quot;http://localhost:6002/search/12345&quot;
1270 1287
1271 ## 数据模型 1288 ## 数据模型
1272 1289
1273 -### 商品字段 1290 +### 8.1 商品字段定义
1274 1291
1275 | 字段名 | 类型 | 描述 | 1292 | 字段名 | 类型 | 描述 |
1276 |--------|------|------| 1293 |--------|------|------|
@@ -1303,11 +1320,20 @@ curl &quot;http://localhost:6002/search/12345&quot; @@ -1303,11 +1320,20 @@ curl &quot;http://localhost:6002/search/12345&quot;
1303 1320
1304 > 所有租户共享统一的索引结构。文本字段支持中英文双语,后端根据 `language` 参数自动选择对应字段返回。 1321 > 所有租户共享统一的索引结构。文本字段支持中英文双语,后端根据 `language` 参数自动选择对应字段返回。
1305 1322
1306 ---- 1323 +### 8.2 字段类型速查
1307 1324
1308 -## 附录 1325 +| 类型 | ES Mapping | 用途 |
  1326 +|------|------------|------|
  1327 +| `text` | `text` | 全文检索(支持中英文分析器) |
  1328 +| `keyword` | `keyword` | 精确匹配、聚合、排序 |
  1329 +| `integer` | `integer` | 整数 |
  1330 +| `long` | `long` | 长整数 |
  1331 +| `float` | `float` | 浮点数 |
  1332 +| `date` | `date` | 日期时间 |
  1333 +| `nested` | `nested` | 嵌套对象(specifications, skus, image_embedding) |
  1334 +| `dense_vector` | `dense_vector` | 向量字段(title_embedding,仅用于搜索) |
1309 1335
1310 -### 常用字段列表 1336 +### 8.3 常用字段列表
1311 1337
1312 #### 过滤字段 1338 #### 过滤字段
1313 1339
@@ -1317,6 +1343,7 @@ curl &quot;http://localhost:6002/search/12345&quot; @@ -1317,6 +1343,7 @@ curl &quot;http://localhost:6002/search/12345&quot;
1317 - `vendor_zh.keyword`, `vendor_en.keyword`: 供应商/品牌(使用keyword子字段) 1343 - `vendor_zh.keyword`, `vendor_en.keyword`: 供应商/品牌(使用keyword子字段)
1318 - `tags`: 标签(keyword类型) 1344 - `tags`: 标签(keyword类型)
1319 - `option1_name`, `option2_name`, `option3_name`: 选项名称 1345 - `option1_name`, `option2_name`, `option3_name`: 选项名称
  1346 +- `specifications`: 规格过滤(嵌套字段,格式见[过滤器详解](#33-过滤器详解))
1320 1347
1321 #### 范围字段 1348 #### 范围字段
1322 1349
@@ -1338,26 +1365,13 @@ curl &quot;http://localhost:6002/search/12345&quot; @@ -1338,26 +1365,13 @@ curl &quot;http://localhost:6002/search/12345&quot;
1338 - `sort_by: "price"` + `sort_order: "asc"` → 按 `min_price` 升序(价格从低到高) 1365 - `sort_by: "price"` + `sort_order: "asc"` → 按 `min_price` 升序(价格从低到高)
1339 - `sort_by: "price"` + `sort_order: "desc"` → 按 `max_price` 降序(价格从高到低) 1366 - `sort_by: "price"` + `sort_order: "desc"` → 按 `max_price` 降序(价格从高到低)
1340 1367
1341 -### 支持的分析器 1368 +### 8.4 支持的分析器
1342 1369
1343 | 分析器 | 语言 | 描述 | 1370 | 分析器 | 语言 | 描述 |
1344 |--------|------|------| 1371 |--------|------|------|
1345 | `index_ansj` | 中文 | 中文索引分析器(用于中文字段) | 1372 | `index_ansj` | 中文 | 中文索引分析器(用于中文字段) |
1346 | `query_ansj` | 中文 | 中文查询分析器(用于中文字段) | 1373 | `query_ansj` | 中文 | 中文查询分析器(用于中文字段) |
1347 -| `hanlp_index`(暂不支持) | 中文 | 中文索引分析器(用于中文字段) |  
1348 -| `hanlp_standard`(暂不支持) | 中文 | 中文查询分析器(用于中文字段) | 1374 +| `hanlp_index` ⚠️ TODO(暂不支持) | 中文 | 中文索引分析器(用于中文字段) |
  1375 +| `hanlp_standard` ⚠️ TODO(暂不支持) | 中文 | 中文查询分析器(用于中文字段) |
1349 | `english` | 英文 | 标准英文分析器(用于英文字段) | 1376 | `english` | 英文 | 标准英文分析器(用于英文字段) |
1350 | `lowercase` | - | 小写标准化器(用于keyword子字段) | 1377 | `lowercase` | - | 小写标准化器(用于keyword子字段) |
1351 -  
1352 -### 字段类型速查  
1353 -  
1354 -| 类型 | ES Mapping | 用途 |  
1355 -|------|------------|------|  
1356 -| `text` | `text` | 全文检索(支持中英文分析器) |  
1357 -| `keyword` | `keyword` | 精确匹配、聚合、排序 |  
1358 -| `integer` | `integer` | 整数 |  
1359 -| `long` | `long` | 长整数 |  
1360 -| `float` | `float` | 浮点数 |  
1361 -| `date` | `date` | 日期时间 |  
1362 -| `nested` | `nested` | 嵌套对象(specifications, skus, image_embedding) |  
1363 -| `dense_vector` | `dense_vector` | 向量字段(title_embedding,仅用于搜索) |