diff --git a/activate.sh b/activate.sh new file mode 100644 index 0000000..317b5f4 --- /dev/null +++ b/activate.sh @@ -0,0 +1,12 @@ +#!/bin/bash +source /home/tw/miniconda3/etc/profile.d/conda.sh +conda activate searchengine + +# 如果需要加载 .env 中的环境变量 +if [ -f .env ]; then + set -a # 自动导出所有变量 + source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/\r$//') + set +a # 关闭自动导出 +fi + +echo "Environment activated: searchengine" diff --git a/api/models.py b/api/models.py index 730a05a..e592be4 100644 --- a/api/models.py +++ b/api/models.py @@ -110,31 +110,34 @@ class SearchRequest(BaseModel): ) # 排序 - sort_by: Optional[str] = Field(None, description="排序字段名(如 'min_price', 'max_price', 'title')") - sort_order: Optional[str] = Field("desc", description="排序方向: 'asc'(升序)或 'desc'(降序)") + sort_by: Optional[str] = Field(None, description="排序字段名。支持:'price'(价格,自动根据sort_order选择min_price或max_price)、'sales'(销量)、'create_time'(创建时间)、'update_time'(更新时间)") + sort_order: Optional[str] = Field("desc", description="排序方向: 'asc'(升序)或 'desc'(降序)。注意:price+asc=价格从低到高,price+desc=价格从高到低") - # 分面搜索 - 简化接口 - facets: Optional[List[Union[str, FacetConfig]]] = Field( + # 分面搜索 + facets: Optional[List[FacetConfig]] = Field( None, - description="分面配置。可以是字段名列表(使用默认配置)或详细的分面配置对象。支持 specifications 分面:\"specifications\"(所有name)或 \"specifications.color\"(指定name)", + description="分面配置对象列表。支持 specifications 分面:field=\"specifications\"(所有规格名称)或 field=\"specifications.color\"(指定规格名称)", json_schema_extra={ "examples": [ - # 简单模式:只指定字段名,使用默认配置 - ["category1_name", "category2_name", "specifications"], - # 指定specifications的某个name - ["specifications.颜色", "specifications.尺寸"], - # 高级模式:详细配置 [ - {"field": "category1_name", "size": 15}, + {"field": "category1_name", "size": 15, "type": "terms"}, + {"field": "category2_name", "size": 10, "type": "terms"}, + {"field": "specifications.color", "size": 20, "type": "terms"}, + {"field": "specifications.size", "size": 15, "type": "terms"} + ], + [ + {"field": "category1_name", "size": 15, "type": "terms"}, { "field": "min_price", "type": "range", "ranges": [ {"key": "0-50", "to": 50}, - {"key": "50-100", "from": 50, "to": 100} + {"key": "50-100", "from": 50, "to": 100}, + {"key": "100-200", "from": 100, "to": 200}, + {"key": "200+", "from": 200} ] }, - "specifications" # 所有specifications name的分面 + {"field": "specifications", "size": 10, "type": "terms"} ] ] } diff --git a/docs/搜索API对接指南.md b/docs/搜索API对接指南.md index 94ce520..e679f9a 100644 --- a/docs/搜索API对接指南.md +++ b/docs/搜索API对接指南.md @@ -50,7 +50,7 @@ curl -X POST "http://120.76.41.98:6002/search/" \ "gte": "2020-01-01T00:00:00Z" } }, - "sort_by": "min_price", + "sort_by": "price", "sort_order": "asc" }' ``` @@ -63,7 +63,11 @@ curl -X POST "http://120.76.41.98:6002/search/" \ -H "X-Tenant-ID: 162" \ -d '{ "query": "芭比娃娃", - "facets": ["category1_name", "specifications.color", "specifications.size", "specifications.material"], + "facets": [ + {"field": "category1_name", "size": 10, "type": "terms"}, + {"field": "specifications.color", "size": 10, "type": "terms"}, + {"field": "specifications.size", "size": 10, "type": "terms"} + ], "min_score": 0.2 }' ``` @@ -124,8 +128,8 @@ curl -X POST "http://120.76.41.98:6002/search/" \ | `filters` | object | N | null | 精确匹配过滤器(见下文) | | `range_filters` | object | N | null | 数值范围过滤器(见下文) | | `facets` | array | N | null | 分面配置(见下文) | -| `sort_by` | string | N | null | 排序字段名(如 `min_price`, `max_price`) | -| `sort_order` | string | N | "desc" | 排序方向:`asc`(升序)或 `desc`(降序) | +| `sort_by` | string | N | null | 排序字段名。支持:`price`(价格)、`sales`(销量)、`create_time`(创建时间)、`update_time`(更新时间)。默认按相关性排序 | +| `sort_order` | string | N | "desc" | 排序方向:`asc`(升序)或 `desc`(降序)。注意:`price`+`asc`=价格从低到高,`price`+`desc`=价格从高到低(后端自动映射为min_price或max_price) | | `min_score` | float | N | null | 最小相关性分数阈值 | | `sku_filter_dimension` | array[string] | N | null | 子SKU筛选维度列表(店铺配置)。指定后,每个SPU下的SKU将按这些维度的组合进行分组,每个组合只返回第一个SKU。支持的值:`option1`、`option2`、`option3` 或选项名称(如 `color`、`size`)。详见下文说明 | | `debug` | boolean | N | false | 是否返回调试信息 | @@ -263,14 +267,8 @@ curl -X POST "http://120.76.41.98:6002/search/" \ 用于生成分面统计(分组聚合),常用于构建筛选器UI。 -**简单模式**(字符串数组): -```json -{ - "facets": ["category1_name", "category2_name", "category3_name", "specifications"] -} -``` +**配置格式**(对象数组): -**高级模式**(配置对象数组): ```json { "facets": [ @@ -280,6 +278,16 @@ curl -X POST "http://120.76.41.98:6002/search/" \ "type": "terms" }, { + "field": "category2_name", + "size": 10, + "type": "terms" + }, + { + "field": "specifications.color", + "size": 20, + "type": "terms" + }, + { "field": "min_price", "type": "range", "ranges": [ @@ -288,8 +296,7 @@ curl -X POST "http://120.76.41.98:6002/search/" \ {"key": "100-200", "from": 100, "to": 200}, {"key": "200+", "from": 200} ] - }, - "specifications" // 规格分面(特殊处理:嵌套聚合,按name分组,然后按value聚合) + } ] } ``` @@ -298,18 +305,35 @@ curl -X POST "http://120.76.41.98:6002/search/" \ `specifications` 是嵌套字段,支持两种分面模式: -**模式1:所有规格名称的分面** (`"specifications"`): +**模式1:所有规格名称的分面**: ```json { - "facets": ["specifications"] + "facets": [ + { + "field": "specifications", + "size": 10, + "type": "terms" + } + ] } ``` 返回所有规格名称(name)及其对应的值(value)列表。每个 name 会生成一个独立的分面结果。 -**模式2:指定规格名称的分面** (`"specifications.color"`): +**模式2:指定规格名称的分面**: ```json { - "facets": ["specifications.color", "specifications.size", "specifications.material"] + "facets": [ + { + "field": "specifications.color", + "size": 20, + "type": "terms" + }, + { + "field": "specifications.size", + "size": 15, + "type": "terms" + } + ] } ``` 只返回指定规格名称的值列表。格式:`specifications.{name}`,其中 `{name}` 是规格名称(如"color"、"size"、"material")。 @@ -564,6 +588,7 @@ curl -X POST "http://120.76.41.98:6002/search/" \ | `sku_weights` | array[integer] | 所有SKU重量列表 | | `sku_weight_units` | array[string] | 所有SKU重量单位列表 | | `total_inventory` | integer | 总库存 | +| `sales` | integer | 销量(展示销量) | | `option1_name` | string | 选项1名称(如"color") | | `option2_name` | string | 选项2名称(如"size") | | `option3_name` | string | 选项3名称 | @@ -605,11 +630,45 @@ curl -X POST "http://120.76.41.98:6002/search/" \ "query": "玩具", "size": 20, "from": 0, - "sort_by": "min_price", + "sort_by": "price", "sort_order": "asc" } ``` +**需求**: 搜索"玩具",按价格从高到低排序 + +```json +{ + "query": "玩具", + "size": 20, + "from": 0, + "sort_by": "price", + "sort_order": "desc" +} +``` + +**需求**: 搜索"玩具",按销量从高到低排序 + +```json +{ + "query": "玩具", + "size": 20, + "from": 0, + "sort_by": "sales", + "sort_order": "desc" +} +``` + +**需求**: 搜索"玩具",按默认(相关性)排序 + +```json +{ + "query": "玩具", + "size": 20, + "from": 0 +} +``` + ### 场景2:SKU筛选(按维度过滤) **需求**: 搜索"芭比娃娃",每个SPU下按颜色筛选,每种颜色只显示一个SKU @@ -650,7 +709,7 @@ curl -X POST "http://120.76.41.98:6002/search/" \ ### 场景4:带分面的商品搜索 -**需求**: 搜索"玩具",获取类目和品牌的分面统计,用于构建筛选器 +**需求**: 搜索"玩具",获取类目和规格的分面统计,用于构建筛选器 ```json { @@ -658,9 +717,9 @@ curl -X POST "http://120.76.41.98:6002/search/" \ "size": 20, "language": "zh", "facets": [ - "category1_name", - "category2_name", - "specifications" + {"field": "category1_name", "size": 15, "type": "terms"}, + {"field": "category2_name", "size": 10, "type": "terms"}, + {"field": "specifications", "size": 10, "type": "terms"} ] } ``` @@ -686,7 +745,8 @@ curl -X POST "http://120.76.41.98:6002/search/" \ "facets": [ { "field": "category1_name", - "size": 15 + "size": 15, + "type": "terms" }, { "field": "min_price", @@ -698,7 +758,11 @@ curl -X POST "http://120.76.41.98:6002/search/" \ {"key": "200+", "from": 200} ] }, - "specifications" + { + "field": "specifications", + "size": 10, + "type": "terms" + } ], "sort_by": "min_price", "sort_order": "asc" @@ -768,18 +832,23 @@ curl -X POST "http://120.76.41.98:6002/search/" \ "query": "手机", "size": 20, "language": "zh", - "facets": ["specifications"] + "facets": [ + {"field": "specifications", "size": 10, "type": "terms"} + ] } ``` -**需求**: 只获取"color"规格的分面统计 +**需求**: 只获取"color"和"size"规格的分面统计 ```json { "query": "手机", "size": 20, "language": "zh", - "facets": ["specifications.color", "specifications.size"] + "facets": [ + {"field": "specifications.color", "size": 20, "type": "terms"}, + {"field": "specifications.size", "size": 15, "type": "terms"} + ] } ``` @@ -800,10 +869,10 @@ curl -X POST "http://120.76.41.98:6002/search/" \ } }, "facets": [ - "category1_name", - "category2_name", - "specifications.color", - "specifications.size" + {"field": "category1_name", "size": 15, "type": "terms"}, + {"field": "category2_name", "size": 10, "type": "terms"}, + {"field": "specifications.color", "size": 20, "type": "terms"}, + {"field": "specifications.size", "size": 15, "type": "terms"} ] } ``` @@ -1006,6 +1075,7 @@ curl "http://localhost:6002/search/12345" | `sku_weights` | long | SKU重量列表(数组) | | `sku_weight_units` | keyword | SKU重量单位列表(数组) | | `total_inventory` | long | 总库存 | +| `sales` | long | 销量(展示销量) | | `skus` | nested | SKU详细信息(嵌套对象数组) | | `create_time`, `update_time` | date | 创建/更新时间 | | `title_embedding` | dense_vector | 标题向量(1024维,仅用于搜索) | @@ -1038,11 +1108,15 @@ curl "http://localhost:6002/search/12345" #### 排序字段 -- `min_price`: 最低价格 -- `max_price`: 最高价格 +- `price`: 价格(后端自动根据sort_order映射:asc→min_price,desc→max_price) +- `sales`: 销量 - `create_time`: 创建时间 - `update_time`: 更新时间 -- `relevance_score`: 相关性分数(默认) +- `relevance_score`: 相关性分数(默认,不指定sort_by时使用) + +**注意**: 前端只需传 `price`,后端会自动处理: +- `sort_by: "price"` + `sort_order: "asc"` → 按 `min_price` 升序(价格从低到高) +- `sort_by: "price"` + `sort_order: "desc"` → 按 `max_price` 降序(价格从高到低) ### 支持的分析器 diff --git a/docs/系统设计文档.md b/docs/系统设计文档.md index 2dff803..a06f5d6 100644 --- a/docs/系统设计文档.md +++ b/docs/系统设计文档.md @@ -699,45 +699,44 @@ Elasticsearch #### 8.3.2 Facets 配置数据流 -**输入格式**:`List[Union[str, FacetConfig]]` +**输入格式**:`List[FacetConfig]` -- **简单模式**:字符串列表(字段名),使用默认配置 - ```json - ["category1_name", "category2_name", "specifications"] - ``` - -- **Specifications分面**: - - 所有规格名称:`"specifications"` - 返回所有name及其value列表 - - 指定规格名称:`"specifications.color"` - 只返回指定name的value列表 +**配置对象列表**:所有分面配置必须使用 FacetConfig 对象 +```json +[ + { + "field": "category1_name", + "size": 15, + "type": "terms" + }, + { + "field": "specifications.color", + "size": 20, + "type": "terms" + }, + { + "field": "min_price", + "type": "range", + "ranges": [ + {"key": "0-50", "to": 50}, + {"key": "50-100", "from": 50, "to": 100} + ] + } +] +``` -- **高级模式**:FacetConfig 对象列表,支持自定义配置 - ```json - [ - { - "field": "category1_name", - "size": 15, - "type": "terms" - }, - { - "field": "min_price", - "type": "range", - "ranges": [ - {"key": "0-50", "to": 50}, - {"key": "50-100", "from": 50, "to": 100} - ] - }, - "specifications.color" // 指定规格名称的分面 - ] - ``` +**Specifications 分面支持**: +- 所有规格名称:`field: "specifications"` - 返回所有 name 及其 value 列表 +- 指定规格名称:`field: "specifications.color"` - 只返回指定 name 的 value 列表 **数据流**: -1. API 层:接收 `List[Union[str, FacetConfig]]` -2. Searcher 层:透传,不做转换 -3. ES Query Builder:只接受 `str` 或 `FacetConfig`,自动处理两种格式 +1. API 层:接收 `List[FacetConfig]`,Pydantic 验证参数 +2. Searcher 层:透传 FacetConfig 对象列表 +3. ES Query Builder:解析 FacetConfig 对象 - 检测 `"specifications"` 或 `"specifications.{name}"` 格式 - - 构建对应的嵌套聚合查询 -4. 输出:转换为 ES 聚合查询(包括specifications嵌套聚合) -5. Result Formatter:格式化ES聚合结果,处理specifications嵌套结构 + - 构建对应的嵌套聚合查询或普通聚合查询 +4. 输出:转换为 ES 聚合查询(包括 specifications 嵌套聚合) +5. Result Formatter:格式化 ES 聚合结果,处理 specifications 嵌套结构 #### 8.3.3 Range Filters 数据流 diff --git a/docs/索引字段说明v2.md b/docs/索引字段说明v2.md index a019379..5705e45 100644 --- a/docs/索引字段说明v2.md +++ b/docs/索引字段说明v2.md @@ -284,11 +284,12 @@ | `sku_weights` | long | 所有 SKU 重量列表(数组) | 从所有 SKU 重量汇总 | | `sku_weight_units` | keyword | 所有 SKU 重量单位列表(数组) | 从所有 SKU 重量单位汇总 | -### 9. 库存字段 +### 9. 库存与销量字段 | 字段名 | ES类型 | 说明 | 数据来源 | |--------|--------|------|----------| | `total_inventory` | long | 总库存(所有 SKU 库存之和) | 从所有 SKU 库存汇总 | +| `sales` | long | 销量(展示销量) | MySQL: `shoplazza_product_spu.fake_sales` | ### 10. SKU 嵌套字段 @@ -363,6 +364,16 @@ - `vendor_zh.keyword`, `vendor_en.keyword` - `specifications` (嵌套查询) - `min_price`, `max_price` (范围过滤) +- `sales` (范围过滤) +- `total_inventory` (范围过滤) + +### 排序字段 + +- `price`: 价格(前端传入,后端自动映射:asc→min_price,desc→max_price) +- `sales`: 销量 +- `create_time`: 创建时间 +- `update_time`: 更新时间 +- `relevance_score`: 相关性分数(默认) ### 分面字段(聚合统计) diff --git a/frontend/index.html b/frontend/index.html index 27db381..27001c6 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -94,11 +94,18 @@ ▼ - + By Price - ▲ - ▼ + ▲ + ▼ + + + + By Sales + + ▲ + ▼ @@ -135,6 +142,6 @@ SearchEngine © 2025 | API: Loading... - +
SearchEngine © 2025 | API: Loading...