diff --git a/config/config.yaml b/config/config.yaml index 1a3f322..5467cac 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -114,7 +114,7 @@ function_score: # 重排配置(provider/URL 在 services.rerank) rerank: enabled: true - rerank_window: 1000 + rerank_window: 384 timeout_sec: 15.0 weight_es: 0.4 weight_ai: 0.6 diff --git a/config/config_loader.py b/config/config_loader.py index afa64fb..29614d5 100644 --- a/config/config_loader.py +++ b/config/config_loader.py @@ -107,7 +107,7 @@ class RankingConfig: class RerankConfig: """重排配置(provider/URL 在 services.rerank)""" enabled: bool = True - rerank_window: int = 1000 + rerank_window: int = 384 timeout_sec: float = 15.0 weight_es: float = 0.4 weight_ai: float = 0.6 @@ -312,7 +312,7 @@ class ConfigLoader: rerank_data = config_data.get("rerank", {}) rerank = RerankConfig( enabled=bool(rerank_data.get("enabled", True)), - rerank_window=int(rerank_data.get("rerank_window", 1000)), + rerank_window=int(rerank_data.get("rerank_window", 384)), timeout_sec=float(rerank_data.get("timeout_sec", 15.0)), weight_es=float(rerank_data.get("weight_es", 0.4)), weight_ai=float(rerank_data.get("weight_ai", 0.6)), diff --git a/docs/性能测试报告.md b/docs/性能测试报告.md index 211dc95..74390c2 100644 --- a/docs/性能测试报告.md +++ b/docs/性能测试报告.md @@ -72,6 +72,9 @@ curl -u 'saas:4hOaLaf41y2VuI8y' -X GET 'http://localhost:9200/search_products_te }' ``` +主要配置: +rerank_window=384 + ## 5. 执行前准备(可复现步骤) ### 5.1 环境与依赖 @@ -228,3 +231,89 @@ cd /data/saas-search - 压测脚本:`scripts/perf_api_benchmark.py` - 本次结果:`perf_reports/2026-03-12/perf_matrix_report.json` +- Search 多租户补测:`perf_reports/2026-03-12/search_tenant_matrix/` + +## 12. Search 多租户补测(2026-03-12) + +补测背景: +- 原报告中的 search 数据来自 `tenant_id=162` +- 该租户文档量偏小,无法覆盖不同数据规模下的性能趋势 +- 本节补充 `backend_search` 在不同租户文档规模上的对比结果 + +租户与文档数(按需求方提供): +- `tenant 0`: `10000` +- `tenant 1`: `500` +- `tenant 2`: `1000` +- `tenant 3`: `2000` +- `tenant 4`: `5000` + +测试口径: +- 场景:`backend_search`(`POST /search/`) +- 并发:`1 / 5 / 10 / 20` +- 每档时长:`20s` +- 执行时间:`2026-03-12 10:15:01` 到 `2026-03-12 10:22:26`(CST) + +执行命令(逐租户复现): + +```bash +cd /data/saas-search +mkdir -p perf_reports/2026-03-12/search_tenant_matrix +for t in 0 1 2 3 4; do + .venv/bin/python scripts/perf_api_benchmark.py \ + --scenario backend_search \ + --concurrency-list 1,5,10,20 \ + --duration 20 \ + --tenant-id ${t} \ + --backend-base http://127.0.0.1:6002 \ + --embedding-base http://127.0.0.1:6005 \ + --translator-base http://127.0.0.1:6006 \ + --reranker-base http://127.0.0.1:6007 \ + --output perf_reports/2026-03-12/search_tenant_matrix/tenant_${t}.json +done +``` + +结果文件: +- `perf_reports/2026-03-12/search_tenant_matrix/tenant_0.json` +- `perf_reports/2026-03-12/search_tenant_matrix/tenant_1.json` +- `perf_reports/2026-03-12/search_tenant_matrix/tenant_2.json` +- `perf_reports/2026-03-12/search_tenant_matrix/tenant_3.json` +- `perf_reports/2026-03-12/search_tenant_matrix/tenant_4.json` + +### 12.1 按租户汇总(overall) + +| Tenant | 文档数 | 总请求 | 总成功率 | 汇总RPS | 加权平均延迟(ms) | +|---:|---:|---:|---:|---:|---:| +| 0 | 10000 | 195 | 87.18% | 2.00 | 4644.66 | +| 1 | 500 | 548 | 100.00% | 6.73 | 1346.28 | +| 2 | 1000 | 449 | 100.00% | 5.32 | 1731.96 | +| 3 | 2000 | 314 | 100.00% | 3.58 | 2605.60 | +| 4 | 5000 | 256 | 100.00% | 2.76 | 3491.67 | + +### 12.2 按并发明细(backend_search) + +| Tenant | 文档数 | 并发 | 请求数 | 成功率 | 吞吐(RPS) | Avg(ms) | P95(ms) | Max(ms) | +|---:|---:|---:|---:|---:|---:|---:|---:|---:| +| 0 | 10000 | 1 | 42 | 100.00% | 2.09 | 475.85 | 893.82 | 1034.47 | +| 0 | 10000 | 5 | 41 | 100.00% | 1.91 | 2558.69 | 4109.76 | 4532.22 | +| 0 | 10000 | 10 | 51 | 100.00% | 1.94 | 4816.46 | 5250.89 | 6729.64 | +| 0 | 10000 | 20 | 61 | 59.02% | 2.05 | 8773.39 | 10037.65 | 10156.94 | +| 1 | 500 | 1 | 120 | 100.00% | 5.99 | 166.04 | 312.03 | 1064.41 | +| 1 | 500 | 5 | 136 | 100.00% | 6.76 | 735.79 | 1291.69 | 1543.71 | +| 1 | 500 | 10 | 151 | 100.00% | 7.37 | 1349.03 | 2014.22 | 2020.32 | +| 1 | 500 | 20 | 141 | 100.00% | 6.77 | 2936.65 | 5295.54 | 5313.42 | +| 2 | 1000 | 1 | 110 | 100.00% | 5.47 | 182.13 | 353.14 | 465.31 | +| 2 | 1000 | 5 | 106 | 100.00% | 5.18 | 960.47 | 1333.72 | 2163.98 | +| 2 | 1000 | 10 | 112 | 100.00% | 5.26 | 1868.63 | 2352.51 | 2964.84 | +| 2 | 1000 | 20 | 121 | 100.00% | 5.38 | 3690.26 | 4101.46 | 4112.53 | +| 3 | 2000 | 1 | 68 | 100.00% | 3.39 | 294.03 | 650.96 | 1704.33 | +| 3 | 2000 | 5 | 85 | 100.00% | 3.99 | 1237.05 | 1663.36 | 2144.39 | +| 3 | 2000 | 10 | 80 | 100.00% | 3.56 | 2748.00 | 4102.92 | 4463.57 | +| 3 | 2000 | 20 | 81 | 100.00% | 3.41 | 5841.66 | 8352.47 | 8356.66 | +| 4 | 5000 | 1 | 60 | 100.00% | 2.92 | 341.68 | 650.83 | 838.99 | +| 4 | 5000 | 5 | 56 | 100.00% | 2.70 | 1813.34 | 2339.49 | 3073.57 | +| 4 | 5000 | 10 | 60 | 100.00% | 2.48 | 3900.04 | 5529.86 | 5533.53 | +| 4 | 5000 | 20 | 80 | 100.00% | 2.93 | 6722.73 | 7613.28 | 7620.42 | + +异常说明: +- `tenant 0` 在并发 `20` 出现 `ReadTimeout`(25 次),该档成功率下降到 `59.02%` +- 其他租户在本轮口径下均为 `100%` 成功率 diff --git a/docs/搜索API对接指南.md b/docs/搜索API对接指南.md index ef4a0c7..c3e9c68 100644 --- a/docs/搜索API对接指南.md +++ b/docs/搜索API对接指南.md @@ -225,7 +225,7 @@ response = requests.post(url, headers=headers, json={"query": "芭比娃娃"}) | `min_score` | float | N | null | 最小相关性分数阈值 | | `sku_filter_dimension` | array[string] | N | null | 子SKU筛选维度列表(见[SKU筛选维度](#35-sku筛选维度)) | | `debug` | boolean | N | false | 是否返回调试信息 | -| `enable_rerank` | boolean/null | N | null | 是否开启重排(调用外部重排服务对 ES 结果进行二次排序)。不传/传 null 使用服务端 `rerank.enabled`(默认开启)。开启后会先对 ES Top1000(`rerank_window`)重排,再按分页截取;若 `from+size>1000`,则不重排,直接按分页从 ES 返回 | +| `enable_rerank` | boolean/null | N | null | 是否开启重排(调用外部重排服务对 ES 结果进行二次排序)。不传/传 null 使用服务端 `rerank.enabled`(默认开启)。开启后会先对 ES TopN(`rerank_window`)重排,再按分页截取;若 `from+size>1000`,则不重排,直接按分页从 ES 返回 | | `rerank_query_template` | string | N | null | 重排 query 模板(可选)。支持 `{query}` 占位符;不传则使用服务端配置 | | `rerank_doc_template` | string | N | null | 重排 doc 模板(可选)。支持 `{title} {brief} {vendor} {description} {category_path}`;不传则使用服务端配置 | | `user_id` | string | N | null | 用户ID(用于个性化,预留) | diff --git a/search/searcher.py b/search/searcher.py index c5642ff..2afa588 100644 --- a/search/searcher.py +++ b/search/searcher.py @@ -282,7 +282,7 @@ class Searcher: # 重排开关优先级:请求参数显式传值 > 服务端配置(默认开启) rerank_enabled_by_config = bool(rc.enabled) do_rerank = rerank_enabled_by_config if enable_rerank is None else bool(enable_rerank) - rerank_window = rc.rerank_window or 1000 + rerank_window = rc.rerank_window # 若开启重排且请求范围在窗口内:从 ES 取前 rerank_window 条、重排后再按 from/size 分页;否则不重排,按原 from/size 查 ES in_rerank_window = do_rerank and (from_ + size) <= rerank_window es_fetch_from = 0 if in_rerank_window else from_ diff --git a/tests/conftest.py b/tests/conftest.py index e192ef0..a861c60 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -191,7 +191,7 @@ def temp_config_file() -> Generator[str, None, None]: "functions": [] }, "rerank": { - "rerank_window": 1000 + "rerank_window": 400 } } diff --git a/tests/test_search_rerank_window.py b/tests/test_search_rerank_window.py index 77f6006..84c2a8b 100644 --- a/tests/test_search_rerank_window.py +++ b/tests/test_search_rerank_window.py @@ -136,7 +136,7 @@ class _FakeESClient: } -def _build_search_config(*, rerank_enabled: bool = True, rerank_window: int = 1000): +def _build_search_config(*, rerank_enabled: bool = True, rerank_window: int = 384): return SearchConfig( field_boosts={"title.en": 3.0}, indexes=[IndexConfig(name="default", label="default", fields=["title.en"])], @@ -171,7 +171,7 @@ def test_config_loader_rerank_enabled_defaults_true(tmp_path: Path): "spu_config": {"enabled": False}, "ranking": {"expression": "bm25()", "description": "test"}, "function_score": {"score_mode": "sum", "boost_mode": "multiply", "functions": []}, - "rerank": {"rerank_window": 1000}, + "rerank": {"rerank_window": 384}, } config_path = tmp_path / "config.yaml" config_path.write_text(yaml.safe_dump(config_data), encoding="utf-8") @@ -283,7 +283,7 @@ def test_searcher_skips_rerank_when_request_explicitly_false(monkeypatch): def test_searcher_skips_rerank_when_page_exceeds_window(monkeypatch): es_client = _FakeESClient() - searcher = _build_searcher(_build_search_config(rerank_enabled=True, rerank_window=1000), es_client) + searcher = _build_searcher(_build_search_config(rerank_enabled=True, rerank_window=384), es_client) context = create_request_context(reqid="t3", uid="u3") monkeypatch.setattr( -- libgit2 0.21.2