Commit b0ad8e894c2d3bd149ae8cdfd2ff02becfaf56c6

Authored by tangwang
1 parent ddc4abd1

文档完善

Showing 1 changed file with 28 additions and 272 deletions   Show diff stats
docs/搜索API对接指南.md
@@ -35,31 +35,36 @@ curl -X POST "http://localhost:6002/search/" \ @@ -35,31 +35,36 @@ curl -X POST "http://localhost:6002/search/" \
35 }' 35 }'
36 ``` 36 ```
37 37
38 -### Python示例 38 +### curl示例:带过滤与分页
39 39
40 -```python  
41 -import requests  
42 -  
43 -url = "http://localhost:6002/search/"  
44 -response = requests.post(url, json={"query": "芭比娃娃"})  
45 -data = response.json()  
46 -print(f"找到 {data['total']} 个结果") 40 +```bash
  41 +curl -X POST "http://localhost:6002/search/" \
  42 + -H "Content-Type: application/json" \
  43 + -d '{
  44 + "tenant_id": "demo-tenant",
  45 + "query": "芭比娃娃 AND 配件",
  46 + "size": 5,
  47 + "from": 10,
  48 + "filters": {
  49 + "vendor_keyword": ["乐高", "孩之宝"]
  50 + },
  51 + "sort_by": "min_price",
  52 + "sort_order": "asc"
  53 + }'
47 ``` 54 ```
48 55
49 -### JavaScript示例 56 +### curl示例:开启调试与分面
50 57
51 -```javascript  
52 -const response = await fetch('http://localhost:6002/search/', {  
53 - method: 'POST',  
54 - headers: {  
55 - 'Content-Type': 'application/json'  
56 - },  
57 - body: JSON.stringify({  
58 - query: '芭比娃娃'  
59 - })  
60 -});  
61 -const data = await response.json();  
62 -console.log(`找到 ${data.total} 个结果`); 58 +```bash
  59 +curl -X POST "http://localhost:6002/search/" \
  60 + -H "Content-Type: application/json" \
  61 + -d '{
  62 + "tenant_id": "demo-tenant",
  63 + "query": "芭比娃娃",
  64 + "facets": ["category_keyword", "vendor_keyword"],
  65 + "min_score": 0.2,
  66 + "debug": true
  67 + }'
63 ``` 68 ```
64 69
65 --- 70 ---
@@ -89,6 +94,7 @@ console.log(`找到 ${data.total} 个结果`); @@ -89,6 +94,7 @@ console.log(`找到 ${data.total} 个结果`);
89 94
90 ```json 95 ```json
91 { 96 {
  97 + "tenant_id": "string (required)",
92 "query": "string (required)", 98 "query": "string (required)",
93 "size": 10, 99 "size": 10,
94 "from": 0, 100 "from": 0,
@@ -108,6 +114,7 @@ console.log(`找到 ${data.total} 个结果`); @@ -108,6 +114,7 @@ console.log(`找到 ${data.total} 个结果`);
108 114
109 | 参数 | 类型 | 必填 | 默认值 | 说明 | 115 | 参数 | 类型 | 必填 | 默认值 | 说明 |
110 |------|------|------|--------|------| 116 |------|------|------|--------|------|
  117 +| `tenant_id` | string | ✅ | - | 租户ID,用于隔离不同站点或客户的数据 |
111 | `query` | string | ✅ | - | 搜索查询字符串,支持布尔表达式(AND, OR, RANK, ANDNOT) | 118 | `query` | string | ✅ | - | 搜索查询字符串,支持布尔表达式(AND, OR, RANK, ANDNOT) |
112 | `size` | integer | ❌ | 10 | 返回结果数量(1-100) | 119 | `size` | integer | ❌ | 10 | 返回结果数量(1-100) |
113 | `from` | integer | ❌ | 0 | 分页偏移量(用于分页) | 120 | `from` | integer | ❌ | 0 | 分页偏移量(用于分页) |
@@ -539,226 +546,6 @@ curl -X POST "http://localhost:6002/search/image" \ @@ -539,226 +546,6 @@ curl -X POST "http://localhost:6002/search/image" \
539 546
540 --- 547 ---
541 548
542 -## 错误处理  
543 -  
544 -### 错误响应格式  
545 -  
546 -```json  
547 -{  
548 - "error": "错误信息",  
549 - "detail": "详细错误信息(可选)"  
550 -}  
551 -```  
552 -  
553 -### 常见错误码  
554 -  
555 -| HTTP状态码 | 说明 | 处理建议 |  
556 -|-----------|------|---------|  
557 -| 200 | 成功 | - |  
558 -| 400 | 请求参数错误 | 检查请求参数格式和必填字段 |  
559 -| 404 | 接口不存在 | 检查接口路径 |  
560 -| 500 | 服务器内部错误 | 联系技术支持 |  
561 -  
562 -### 错误处理示例  
563 -  
564 -**Python**:  
565 -```python  
566 -import requests  
567 -  
568 -try:  
569 - response = requests.post(url, json=payload, timeout=10)  
570 - response.raise_for_status()  
571 - data = response.json()  
572 -except requests.exceptions.HTTPError as e:  
573 - print(f"HTTP错误: {e}")  
574 - if response.status_code == 400:  
575 - error_data = response.json()  
576 - print(f"错误详情: {error_data.get('detail')}")  
577 -except requests.exceptions.RequestException as e:  
578 - print(f"请求异常: {e}")  
579 -```  
580 -  
581 -**JavaScript**:  
582 -```javascript  
583 -try {  
584 - const response = await fetch(url, {  
585 - method: 'POST',  
586 - headers: { 'Content-Type': 'application/json' },  
587 - body: JSON.stringify(payload)  
588 - });  
589 -  
590 - if (!response.ok) {  
591 - const error = await response.json();  
592 - throw new Error(error.error || `HTTP ${response.status}`);  
593 - }  
594 -  
595 - const data = await response.json();  
596 -} catch (error) {  
597 - console.error('搜索失败:', error.message);  
598 -}  
599 -```  
600 -  
601 ----  
602 -  
603 -### 5. 代码示例  
604 -  
605 -**完整的搜索函数(Python)**:  
606 -  
607 -```python  
608 -import requests  
609 -from typing import Dict, Any, Optional, List  
610 -  
611 -class SearchClient:  
612 - def __init__(self, base_url: str = "http://localhost:6002"):  
613 - self.base_url = base_url  
614 - self.timeout = 10  
615 -  
616 - def search(  
617 - self,  
618 - query: str,  
619 - size: int = 20,  
620 - from_: int = 0,  
621 - filters: Optional[Dict] = None,  
622 - range_filters: Optional[Dict] = None,  
623 - facets: Optional[List] = None,  
624 - sort_by: Optional[str] = None,  
625 - sort_order: str = "desc"  
626 - ) -> Dict[str, Any]:  
627 - """  
628 - 执行搜索查询  
629 -  
630 - Args:  
631 - query: 搜索查询字符串  
632 - size: 返回结果数量  
633 - from_: 分页偏移量  
634 - filters: 精确匹配过滤器  
635 - range_filters: 范围过滤器  
636 - facets: 分面配置  
637 - sort_by: 排序字段  
638 - sort_order: 排序方向  
639 -  
640 - Returns:  
641 - 搜索结果字典  
642 - """  
643 - url = f"{self.base_url}/search/"  
644 - payload = {  
645 - "query": query,  
646 - "size": size,  
647 - "from": from_,  
648 - }  
649 -  
650 - if filters:  
651 - payload["filters"] = filters  
652 - if range_filters:  
653 - payload["range_filters"] = range_filters  
654 - if facets:  
655 - payload["facets"] = facets  
656 - if sort_by:  
657 - payload["sort_by"] = sort_by  
658 - payload["sort_order"] = sort_order  
659 -  
660 - try:  
661 - response = requests.post(  
662 - url,  
663 - json=payload,  
664 - timeout=self.timeout  
665 - )  
666 - response.raise_for_status()  
667 - return response.json()  
668 - except requests.exceptions.RequestException as e:  
669 - raise Exception(f"搜索请求失败: {e}")  
670 -  
671 -# 使用示例  
672 -client = SearchClient()  
673 -result = client.search(  
674 - query="玩具",  
675 - size=20,  
676 - filters={"category_keyword": "益智玩具"},  
677 - range_filters={"min_price": {"gte": 50, "lte": 200}},  
678 - facets=["category_keyword", "vendor_keyword"],  
679 - sort_by="min_price",  
680 - sort_order="asc"  
681 -)  
682 -  
683 -print(f"找到 {result['total']} 个结果")  
684 -for product in result['results']:  
685 - print(f"{product['title']} - ¥{product['price']}")  
686 -```  
687 -  
688 -**完整的搜索函数(JavaScript)**:  
689 -  
690 -```javascript  
691 -class SearchClient {  
692 - constructor(baseUrl = 'http://localhost:6002') {  
693 - this.baseUrl = baseUrl;  
694 - this.timeout = 10000;  
695 - }  
696 -  
697 - async search({  
698 - query,  
699 - size = 20,  
700 - from = 0,  
701 - filters = null,  
702 - rangeFilters = null,  
703 - facets = null,  
704 - sortBy = null,  
705 - sortOrder = 'desc'  
706 - }) {  
707 - const url = `${this.baseUrl}/search/`;  
708 - const payload = {  
709 - query,  
710 - size,  
711 - from,  
712 - };  
713 -  
714 - if (filters) payload.filters = filters;  
715 - if (rangeFilters) payload.range_filters = rangeFilters;  
716 - if (facets) payload.facets = facets;  
717 - if (sortBy) {  
718 - payload.sort_by = sortBy;  
719 - payload.sort_order = sortOrder;  
720 - }  
721 -  
722 - try {  
723 - const response = await fetch(url, {  
724 - method: 'POST',  
725 - headers: {  
726 - 'Content-Type': 'application/json'  
727 - },  
728 - body: JSON.stringify(payload),  
729 - signal: AbortSignal.timeout(this.timeout)  
730 - });  
731 -  
732 - if (!response.ok) {  
733 - const error = await response.json();  
734 - throw new Error(error.error || `HTTP ${response.status}`);  
735 - }  
736 -  
737 - return await response.json();  
738 - } catch (error) {  
739 - throw new Error(`搜索请求失败: ${error.message}`);  
740 - }  
741 - }  
742 -}  
743 -  
744 -// 使用示例  
745 -const client = new SearchClient();  
746 -const result = await client.search({  
747 - query: '玩具',  
748 - size: 20,  
749 - filters: { category_keyword: '益智玩具' },  
750 - rangeFilters: { min_price: { gte: 50, lte: 200 } },  
751 - facets: ['category_keyword', 'vendor_keyword'],  
752 - sortBy: 'min_price',  
753 - sortOrder: 'asc'  
754 -});  
755 -  
756 -console.log(`找到 ${result.total} 个结果`);  
757 -result.results.forEach(product => {  
758 - console.log(`${product.title} - ¥${product.price}`);  
759 -});  
760 -```  
761 -  
762 --- 549 ---
763 550
764 ## 其他接口 551 ## 其他接口
@@ -933,37 +720,6 @@ curl "http://localhost:6002/search/12345" @@ -933,37 +720,6 @@ curl "http://localhost:6002/search/12345"
933 720
934 --- 721 ---
935 722
936 -## 常见问题(FAQ)  
937 -  
938 -**Q1: 如何判断一个字段应该用哪种过滤器?**  
939 -`filters` 针对 keyword/布尔/整数字段做精确匹配;`range_filters` 针对数值或日期字段做区间查询。  
940 -  
941 -**Q2: 可以同时使用多个过滤器吗?**  
942 -可以,所有过滤条件为 AND 关系。例如:  
943 -  
944 -```json  
945 -{  
946 - "filters": {  
947 - "category_keyword": "玩具",  
948 - "vendor_keyword": "乐高"  
949 - },  
950 - "range_filters": {  
951 - "min_price": {"gte": 50, "lte": 200}  
952 - }  
953 -}  
954 -```  
955 -  
956 -**Q4: 分面结果里的 `selected` 字段含义是什么?**  
957 -指示该分面值是否已在当前过滤条件中,前端可据此高亮。  
958 -  
959 -**Q5: 如何自定义排序?**  
960 -设置 `sort_by` 和 `sort_order`,常用字段包括 `min_price`, `max_price`, `title`, `create_time`, `update_time`, `relevance_score`。  
961 -  
962 -**Q6: 如何启用调试模式?**  
963 -添加 `debug: true`,即可在响应中看到 `debug_info`(ES DSL、阶段耗时、打分细节)。  
964 -  
965 ----  
966 -  
967 ## 附录 723 ## 附录
968 724
969 ### 常用字段列表 725 ### 常用字段列表