# API 使用示例

本文档提供了搜索引擎 API 的详细使用示例，包括各种常见场景和最佳实践。

---

## 目录

1. [基础搜索](#基础搜索)
2. [过滤器使用](#过滤器使用)
3. [分面搜索](#分面搜索)
4. [排序](#排序)
5. [图片搜索](#图片搜索)
6. [布尔表达式](#布尔表达式)
7. [完整示例](#完整示例)

---

## 基础搜索

### 示例 1：最简单的搜索

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "芭比娃娃"
  }'
```

**响应**：
```json
{
  "hits": [...],
  "total": 118,
  "max_score": 8.5,
  "took_ms": 45,
  "query_info": {
    "original_query": "芭比娃娃",
    "detected_language": "zh",
    "translations": {"en": "barbie doll"}
  }
}
```

### 示例 2：指定返回数量

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "size": 50
  }'
```

### 示例 3：分页查询

```bash
# 第1页（0-19）
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "size": 20,
    "from": 0
  }'

# 第2页（20-39）
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "size": 20,
    "from": 20
  }'
```

---

## 过滤器使用

### 精确匹配过滤器

#### 示例 1：单值过滤

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "filters": {
      "category_name": "手机"
    }
  }'
```

#### 示例 2：多值过滤（OR 逻辑）

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "filters": {
      "category_name": ["手机", "电子产品"]
    }
  }'
```

说明：匹配类目为"玩具" **或** "益智玩具" **或** "儿童玩具"的商品。

#### 示例 3：多字段过滤（AND 逻辑）

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "filters": {
      "category_name": "手机",
      "vendor_zh.keyword": "奇乐"
    }
  }'
```

说明：必须同时满足"类目=手机" **并且** "品牌=奇乐"。

#### 示例 4：Specifications 嵌套过滤（单个规格）

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "filters": {
      "specifications": {
        "name": "color",
        "value": "white"
      }
    }
  }'
```

说明：查询规格名称为"color"且值为"white"的商品。

#### 示例 5：Specifications 嵌套过滤（多个规格，OR逻辑）

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "filters": {
      "specifications": [
        {"name": "color", "value": "white"},
        {"name": "size", "value": "256GB"}
      ]
    }
  }'
```

说明：查询满足任意一个规格的商品（color=white **或** size=256GB）。

#### 示例 6：组合过滤（包含 specifications）

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "filters": {
      "category_name": "手机",
      "specifications": {
        "name": "color",
        "value": "white"
      }
    }
  }'
```

说明：同时满足类目=手机 **并且** color=white。

### 范围过滤器

#### 示例 1：价格范围

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "range_filters": {
      "min_price": {
        "gte": 50,
        "lte": 200
      }
    }
  }'
```

说明：价格在 50-200 元之间（包含边界）。

#### 示例 2：只设置下限

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "range_filters": {
      "min_price": {
        "gte": 100
      }
    }
  }'
```

说明：价格 ≥ 100 元。

#### 示例 3：只设置上限

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "range_filters": {
      "min_price": {
        "lt": 50
      }
    }
  }'
```

说明：价格 < 50 元（不包含50）。

#### 示例 4：多字段范围过滤

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "range_filters": {
      "min_price": {
        "gte": 50,
        "lte": 200
      },
      "days_since_last_update": {
        "lte": 30
      }
    }
  }'
```

说明：价格在 50-200 元 **并且** 最近30天内更新过。

### 组合过滤器

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "filters": {
      "category_name": ["手机", "电子产品"],
      "vendor_zh.keyword": "品牌A"
    },
    "range_filters": {
      "min_price": {
        "gte": 50,
        "lte": 500
      }
    }
  }'
```

说明：类目是"玩具"或"益智玩具" **并且** 品牌是"乐高" **并且** 价格在 50-500 元之间。

---

## 分面搜索

### 简单模式

#### 示例 1：基础分面

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "size": 20,
    "facets": ["category1_name", "category2_name", "specifications"]
  }'
```

**响应**：
```json
{
  "results": [...],
  "total": 118,
  "facets": [
    {
      "field": "category1_name",
      "label": "category1_name",
      "type": "terms",
      "values": [
        {"value": "手机", "count": 85, "selected": false},
        {"value": "电子产品", "count": 33, "selected": false}
      ]
    },
    {
      "field": "specifications.color",
      "label": "color",
      "type": "terms",
      "values": [
        {"value": "white", "count": 50, "selected": false},
        {"value": "black", "count": 30, "selected": false}
      ]
    },
    {
      "field": "specifications.size",
      "label": "size",
      "type": "terms",
      "values": [
        {"value": "256GB", "count": 40, "selected": false},
        {"value": "512GB", "count": 20, "selected": false}
      ]
    }
  ]
}
```

#### 示例 2：Specifications 分面（所有规格名称）

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "facets": ["specifications"]
  }'
```

说明：返回所有规格名称（name）及其对应的值（value）列表。

#### 示例 3：Specifications 分面（指定规格名称）

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "facets": ["specifications.color", "specifications.size"]
  }'
```

说明：只返回指定规格名称的值列表。

### 高级模式

#### 示例 1：自定义分面大小

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "facets": [
      {
        "field": "category1_name",
        "size": 20,
        "type": "terms"
      },
      {
        "field": "category2_name",
        "size": 30,
        "type": "terms"
      }
    ]
  }'
```

#### 示例 2：范围分面

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "facets": [
      {
        "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}
        ]
      }
    ]
  }'
```

**响应**：
```json
{
  "facets": [
    {
      "field": "price",
      "label": "price",
      "type": "range",
      "values": [
        {"value": "0-50", "count": 23, "selected": false},
        {"value": "50-100", "count": 45, "selected": false},
        {"value": "100-200", "count": 38, "selected": false},
        {"value": "200+", "count": 12, "selected": false}
      ]
    }
  ]
}
```

#### 示例 3：混合分面（Terms + Range）

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "facets": [
      {"field": "category.keyword", "size": 15},
      {"field": "vendor.keyword", "size": 15},
      {
        "field": "price",
        "type": "range",
        "ranges": [
          {"key": "低价", "to": 50},
          {"key": "中价", "from": 50, "to": 200},
          {"key": "高价", "from": 200}
        ]
      }
    ]
  }'
```

---

## 排序

### 示例 1：按价格排序（升序）

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "size": 20,
    "sort_by": "min_price",
    "sort_order": "asc"
  }'
```

### 示例 2：按创建时间排序（降序）

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "size": 20,
    "sort_by": "create_time",
    "sort_order": "desc"
  }'
```

### 示例 3：排序+过滤

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "filters": {
      "category.keyword": "益智玩具"
    },
    "sort_by": "min_price",
    "sort_order": "asc"
  }'
```

---

## 图片搜索

### 示例 1：基础图片搜索

```bash
curl -X POST "http://localhost:6002/search/image" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "image_url": "https://example.com/barbie.jpg",
    "size": 20
  }'
```

### 示例 2：图片搜索+过滤器

```bash
curl -X POST "http://localhost:6002/search/image" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "image_url": "https://example.com/barbie.jpg",
    "size": 20,
    "filters": {
      "category_name": "手机"
    },
    "range_filters": {
      "min_price": {
        "lte": 100
      }
    }
  }'
```

---

## 布尔表达式

### 示例 1：AND 查询

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "玩具 AND 乐高"
  }'
```

说明：必须同时包含"玩具"和"乐高"。

### 示例 2：OR 查询

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "芭比 OR 娃娃"
  }'
```

说明：包含"芭比"或"娃娃"即可。

### 示例 3：ANDNOT 查询（排除）

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "玩具 ANDNOT 电动"
  }'
```

说明：包含"玩具"但不包含"电动"。

### 示例 4：复杂布尔表达式

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "玩具 AND (乐高 OR 芭比) ANDNOT 电动"
  }'
```

说明：必须包含"玩具"，并且包含"乐高"或"芭比"，但不包含"电动"。

### 示例 5：域查询

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "brand:乐高"
  }'
```

说明：在品牌域中搜索"乐高"。

---

## 完整示例

### Python 完整示例

```python
#!/usr/bin/env python3
import requests
import json

API_URL = "http://localhost:6002/search/"

def search_products(
    query,
    size=20,
    from_=0,
    filters=None,
    range_filters=None,
    facets=None,
    sort_by=None,
    sort_order="desc",
    debug=False
):
    """执行搜索查询"""
    payload = {
        "query": query,
        "size": size,
        "from": from_
    }
    
    if filters:
        payload["filters"] = filters
    if range_filters:
        payload["range_filters"] = range_filters
    if facets:
        payload["facets"] = facets
    if sort_by:
        payload["sort_by"] = sort_by
        payload["sort_order"] = sort_order
    if debug:
        payload["debug"] = debug
    
    response = requests.post(API_URL, json=payload)
    response.raise_for_status()
    return response.json()


# 示例 1：简单搜索
result = search_products("芭比娃娃", size=10)
print(f"找到 {result['total']} 个结果")
for hit in result['hits'][:3]:
    product = hit['_source']
    print(f"  - {product['name']}: ¥{product.get('price', 'N/A')}")

# 示例 2：带过滤和分面的搜索
result = search_products(
    query="手机",
    size=20,
    language="zh",
    filters={
        "category_name": "手机",
        "specifications": {"name": "color", "value": "white"}
    },
    range_filters={
        "min_price": {"gte": 50, "lte": 200}
    },
    facets=[
        {"field": "category1_name", "size": 15},
        {"field": "category2_name", "size": 15},
        "specifications.color",
        "specifications.size",
        {
            "field": "min_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}
            ]
        }
    ],
    sort_by="min_price",
    sort_order="asc"
)

# 显示分面结果
print(f"\n分面统计：")
for facet in result.get('facets', []):
    print(f"\n{facet['label']} ({facet['type']}):")
    for value in facet['values'][:5]:
        selected_mark = "✓" if value['selected'] else " "
        print(f"  [{selected_mark}] {value['label']}: {value['count']}")

# 示例 3：分页查询
page = 1
page_size = 20
total_pages = 5

for page in range(1, total_pages + 1):
    result = search_products(
        query="玩具",
        size=page_size,
        from_=(page - 1) * page_size
    )
    print(f"\n第 {page} 页：")
    for hit in result['hits']:
        product = hit['_source']
        print(f"  - {product['name']}")
```

### JavaScript 完整示例

```javascript
// 搜索引擎客户端
class SearchClient {
    constructor(baseUrl) {
        this.baseUrl = baseUrl;
    }
    
    async search({
        query,
        size = 20,
        from = 0,
        filters = null,
        rangeFilters = null,
        facets = null,
        sortBy = null,
        sortOrder = 'desc',
        debug = false
    }) {
        const payload = {
            query,
            size,
            from
        };
        
        if (filters) payload.filters = filters;
        if (rangeFilters) payload.range_filters = rangeFilters;
        if (facets) payload.facets = facets;
        if (sortBy) {
            payload.sort_by = sortBy;
            payload.sort_order = sortOrder;
        }
        if (debug) payload.debug = debug;
        
        const response = await fetch(`${this.baseUrl}/search/`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(payload)
        });
        
        if (!response.ok) {
            throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }
        
        return await response.json();
    }
    
    async searchByImage(imageUrl, options = {}) {
        const payload = {
            image_url: imageUrl,
            size: options.size || 20,
            filters: options.filters || null,
            range_filters: options.rangeFilters || null
        };
        
        const response = await fetch(`${this.baseUrl}/search/image`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(payload)
        });
        
        if (!response.ok) {
            throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }
        
        return await response.json();
    }
}

// 使用示例
const client = new SearchClient('http://localhost:6002');

// 简单搜索
const result1 = await client.search({
    query: "芭比娃娃",
    size: 20
});
console.log(`找到 ${result1.total} 个结果`);

// 带过滤和分面的搜索（包含规格）
const result2 = await client.search({
    query: "手机",
    language: "zh",
    size: 20,
    filters: {
        category_name: "手机",
        specifications: { name: "color", value: "white" }
    },
    rangeFilters: {
        min_price: { gte: 50, lte: 200 }
    },
    facets: [
        "category1_name",
        "specifications.color",
        "specifications.size"
    ],
    sortBy: "min_price",
    sortOrder: "asc"
});

// 显示分面结果
result2.facets.forEach(facet => {
    console.log(`\n${facet.label}:`);
    facet.values.forEach(value => {
        const selected = value.selected ? '✓' : ' ';
        console.log(`  [${selected}] ${value.label}: ${value.count}`);
    });
});

// 显示商品
result2.hits.forEach(hit => {
    const product = hit._source;
    console.log(`${product.name} - ¥${product.price}`);
});
```

### 前端完整示例（Vue.js 风格）

```javascript
// 搜索组件
const SearchComponent = {
    data() {
        return {
            query: '',
            results: [],
            facets: [],
            filters: {},
            rangeFilters: {},
            total: 0,
            currentPage: 1,
            pageSize: 20
        };
    },
    methods: {
        async search() {
            const response = await fetch('http://localhost:6002/search/', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    query: this.query,
                    size: this.pageSize,
                    from: (this.currentPage - 1) * this.pageSize,
                    filters: this.filters,
                    range_filters: this.rangeFilters,
                    facets: [
                        { field: 'category.keyword', size: 15 },
                        { field: 'vendor.keyword', size: 15 }
                    ]
                })
            });
            
            const data = await response.json();
            this.results = data.hits;
            this.facets = data.facets || [];
            this.total = data.total;
        },
        
        toggleFilter(field, value) {
            if (!this.filters[field]) {
                this.filters[field] = [];
            }
            
            const index = this.filters[field].indexOf(value);
            if (index > -1) {
                this.filters[field].splice(index, 1);
                if (this.filters[field].length === 0) {
                    delete this.filters[field];
                }
            } else {
                this.filters[field].push(value);
            }
            
            this.currentPage = 1;
            this.search();
        },
        
        setPriceRange(min, max) {
            if (min !== null || max !== null) {
                this.rangeFilters.price = {};
                if (min !== null) this.rangeFilters.price.gte = min;
                if (max !== null) this.rangeFilters.price.lte = max;
            } else {
                delete this.rangeFilters.price;
            }
            this.currentPage = 1;
            this.search();
        }
    }
};
```

---

## 调试与优化

### 启用调试模式

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "debug": true
  }'
```

**响应包含调试信息**：
```json
{
  "hits": [...],
  "total": 118,
  "debug_info": {
    "query_analysis": {
      "original_query": "玩具",
      "normalized_query": "玩具",
      "rewritten_query": "玩具",
      "detected_language": "zh",
      "translations": {"en": "toy"}
    },
    "es_query": {
      "query": {...},
      "size": 10
    },
    "stage_timings": {
      "query_parsing": 5.3,
      "elasticsearch_search": 35.1,
      "result_processing": 4.8
    }
  }
}
```

### 设置最小分数阈值

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "min_score": 5.0
  }'
```

说明：只返回相关性分数 ≥ 5.0 的结果。

---

## 常见使用场景

### 场景 1：电商分类页

```bash
# 显示某个类目下的所有商品，按价格排序，提供品牌筛选
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "*",
    "filters": {
      "category_name": "手机"
    },
    "facets": [
      {"field": "vendor.keyword", "size": 20},
      {
        "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}
        ]
      }
    ],
    "sort_by": "min_price",
    "sort_order": "asc",
    "size": 24
  }'
```

### 场景 2：搜索结果页

```bash
# 用户搜索关键词，提供筛选和排序（包含规格分面）
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "facets": [
      {"field": "category1_name", "size": 10},
      {"field": "category2_name", "size": 10},
      "specifications.color",
      "specifications.size",
      {
        "field": "min_price",
        "type": "range",
        "ranges": [
        {"key": "0-50", "to": 50},
        {"key": "50-100", "from": 50, "to": 100},
        {"key": "100+", "from": 100}
        ]
      }
    ],
    "size": 20
  }'
```

### 场景 2.1：带规格过滤的搜索结果页

```bash
# 用户搜索并选择了规格筛选条件
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "filters": {
      "category_name": "手机",
      "specifications": {
        "name": "color",
        "value": "white"
      }
    },
    "facets": [
      "category1_name",
      "specifications.color",
      "specifications.size"
    ],
    "size": 20
  }'
```

### 场景 3：促销专区

```bash
# 显示特定价格区间的商品
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "*",
    "range_filters": {
      "min_price": {
        "gte": 50,
        "lte": 100
      }
    },
    "facets": ["category1_name", "category2_name", "specifications"],
    "sort_by": "min_price",
    "sort_order": "asc",
    "size": 50
  }'
```

### 场景 4：新品推荐

```bash
# 最近更新的商品
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "*",
    "range_filters": {
      "days_since_last_update": {
        "lte": 7
      }
    },
    "sort_by": "create_time",
    "sort_order": "desc",
    "size": 20
  }'
```

---

## 错误处理

### 示例 1：参数错误

```bash
# 错误：range_filters 缺少操作符
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "range_filters": {
      "min_price": {}
    }
  }'
```

**响应**：
```json
{
  "error": "Validation error",
  "detail": "至少需要指定一个范围边界（gte, gt, lte, lt）",
  "timestamp": 1699800000
}
```

### 示例 2：空查询

```bash
# 错误：query 为空
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": ""
  }'
```

**响应**：
```json
{
  "error": "Validation error",
  "detail": "query field required",
  "timestamp": 1699800000
}
```

---

## 性能优化建议

### 1. 合理使用分面

```bash
# ❌ 不推荐：请求太多分面
{
  "facets": [
    {"field": "field1", "size": 100},
    {"field": "field2", "size": 100},
    {"field": "field3", "size": 100},
    // ... 10+ facets
  ]
}

# ✅ 推荐：只请求必要的分面
{
  "facets": [
    {"field": "category.keyword", "size": 15},
    {"field": "vendor.keyword", "size": 15}
  ]
}
```

### 2. 控制返回数量

```bash
# ❌ 不推荐：一次返回太多
{
  "size": 100
}

# ✅ 推荐：分页查询
{
  "size": 20,
  "from": 0
}
```

### 3. 使用适当的过滤器

```bash
# ✅ 推荐：先过滤后搜索
{
  "query": "玩具",
  "filters": {
    "category.keyword": "玩具"
  }
}
```

---

## 高级技巧

### 技巧 1：获取所有类目

```bash
# 使用通配符查询 + 分面
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "*",
    "size": 0,
    "facets": [
      {"field": "category.keyword", "size": 100}
    ]
  }'
```

### 技巧 2：价格分布统计

```bash
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "手机",
    "language": "zh",
    "size": 0,
    "facets": [
      {
        "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-500", "from": 200, "to": 500},
          {"key": "500+", "from": 500}
        ]
      }
    ]
  }'
```

### 技巧 3：组合多种查询类型

```bash
# 布尔表达式 + 过滤器 + 分面 + 排序
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{
    "query": "(玩具 OR 游戏) AND 儿童 ANDNOT 电子",
    "filters": {
      "category.keyword": ["玩具", "益智玩具"]
    },
    "range_filters": {
      "min_price": {"gte": 20, "lte": 100},
      "days_since_last_update": {"lte": 30}
    },
    "facets": [
      {"field": "vendor.keyword", "size": 20}
    ],
    "sort_by": "min_price",
    "sort_order": "asc",
    "size": 20
  }'
```

---

## 测试数据

如果你需要测试数据，可以使用以下查询：

```bash
# 测试类目：玩具
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{"query": "玩具", "size": 5}'

# 测试品牌：乐高
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{"query": "brand:乐高", "size": 5}'

# 测试布尔表达式
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: 162" \
  -d '{"query": "玩具 AND 乐高", "size": 5}'
```

---

**文档版本**: 3.0  
**最后更新**: 2024-11-12  
**相关文档**: `API_DOCUMENTATION.md`

