API_DOCUMENTATION.md 20.4 KB

搜索引擎 API 接口文档

概述

本文档描述了电商搜索 SaaS 系统的 RESTful API 接口。系统提供强大的搜索功能,包括:

  • 多语言搜索:支持中文、英文、俄文等多语言查询和自动翻译
  • 语义搜索:基于 BGE-M3 文本向量和 CN-CLIP 图片向量的语义检索
  • 布尔表达式:支持 AND、OR、RANK、ANDNOT 操作符
  • 灵活过滤:精确匹配过滤器和数值范围过滤器
  • 分面搜索:动态生成过滤选项,提供分组统计
  • 自定义排序:支持按任意字段排序
  • 个性化排序:可配置的相关性排序表达式

基础信息

  • Base URL: http://your-domain:6002 (http://120.76.41.98:6002)
  • 协议: HTTP/HTTPS
  • 数据格式: JSON
  • 字符编码: UTF-8

搜索接口

1. 文本搜索

端点: POST /search/

描述: 执行文本搜索查询,支持多语言、布尔表达式、过滤器和分面搜索。

请求参数

{
  "query": "string (required)",
  "size": 10,
  "from": 0,
  "filters": {},
  "range_filters": {},
  "facets": [],
  "sort_by": "string",
  "sort_order": "desc",
  "min_score": 0.0,
  "debug": false,
  "user_id": "string",
  "session_id": "string"
}

参数说明

参数 类型 必填 默认值 描述
query string Y - 搜索查询字符串,支持布尔表达式(AND, OR, RANK, ANDNOT)
size integer N 10 返回结果数量(1-100)
from integer N 0 分页偏移量
filters object N null 精确匹配过滤器(见下文)
range_filters object N null 数值范围过滤器(见下文)
facets array N null 分面配置(见下文)
sort_by string N null 排序字段名
sort_order string N "desc" 排序方向:ascdesc
min_score float N null 最小相关性分数阈值
debug boolean N false 是否返回调试信息
user_id string N null 用户ID(用于个性化,预留)
session_id string N null 会话ID(用于分析,预留)

过滤器详解

精确匹配过滤器 (filters)

用于精确匹配或多值匹配(OR 逻辑)。

格式:

{
  "filters": {
    "categoryName_keyword": "玩具",           // 单值:精确匹配
    "brandName_keyword": ["乐高", "孩之宝"],  // 数组:匹配任意值(OR)
    "in_stock": true                          // 布尔值
  }
}

支持的值类型:

  • 字符串:精确匹配
  • 整数:精确匹配
  • 布尔值:精确匹配
  • 数组:匹配任意值(OR 逻辑)
范围过滤器 (range_filters)

用于数值字段的范围过滤。

格式:

{
  "range_filters": {
    "price": {
      "gte": 50,    // 大于等于
      "lte": 200    // 小于等于
    },
    "days_since_last_update": {
      "lte": 30     // 最近30天更新
    }
  }
}

支持的操作符:

  • gte: 大于等于 (>=)
  • gt: 大于 (>)
  • lte: 小于等于 (
  • lt: 小于 (

注意: 至少需要指定一个操作符。

分面配置 (facets)

用于生成分面统计(分组聚合)。

简单模式(字符串数组):

{
  "facets": ["categoryName_keyword", "brandName_keyword"]
}

高级模式(配置对象数组):

{
  "facets": [
    {
      "field": "categoryName_keyword",
      "size": 15,
      "type": "terms"
    },
    {
      "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}
      ]
    }
  ]
}

分面配置参数:

  • field: 字段名(必填)
  • size: 返回的分组数量(默认:10,范围:1-100)
  • type: 分面类型,terms(分组统计)或 range(范围统计)
  • ranges: 范围定义(仅当 type='range' 时需要)

响应格式

{
  "hits": [
    {
      "_id": "12345",
      "_score": 8.5,
      "_custom_score": 12.3,
      "_source": {
        "name": "芭比时尚娃娃",
        "price": 89.99,
        "categoryName": "玩具",
        "brandName": "美泰",
        "imageUrl": "https://example.com/image.jpg"
      }
    }
  ],
  "total": 118,
  "max_score": 8.5,
  "took_ms": 45,
  "facets": [
    {
      "field": "categoryName_keyword",
      "label": "商品类目",
      "type": "terms",
      "values": [
        {
          "value": "玩具",
          "label": "玩具",
          "count": 85,
          "selected": false
        },
        {
          "value": "益智玩具",
          "label": "益智玩具",
          "count": 33,
          "selected": false
        }
      ]
    }
  ],
  "query_info": {
    "original_query": "芭比娃娃",
    "detected_language": "zh",
    "translations": {
      "en": "barbie doll"
    }
  },
  "related_queries": null,
  "performance_info": {
    "total_duration": 45.2,
    "stage_durations": {
      "query_parsing": 5.3,
      "elasticsearch_search": 35.1,
      "result_processing": 4.8
    }
  },
  "debug_info": null
}

响应字段说明

字段 类型 描述
hits array 搜索结果列表
hits[]._id string 文档ID
hits[]._score float 相关性分数
hits[]._custom_score float 自定义排序分数(如启用)
hits[]._source object 文档内容
total integer 匹配的总文档数
max_score float 最高相关性分数
took_ms integer 搜索耗时(毫秒)
facets array 分面统计结果(标准化格式)
facets[].field string 字段名
facets[].label string 显示标签
facets[].type string 分面类型:termsrange
facets[].values array 分面值列表
facets[].values[].value any 分面值
facets[].values[].label string 显示标签
facets[].values[].count integer 文档数量
facets[].values[].selected boolean 是否已选中
query_info object 查询处理信息
related_queries array 相关搜索(预留)
performance_info object 性能信息
debug_info object 调试信息(仅当 debug=true)

请求示例

示例 1: 简单搜索

curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "芭比娃娃",
    "size": 20
  }'

示例 2: 带过滤器的搜索

curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "玩具",
    "size": 20,
    "filters": {
      "categoryName_keyword": ["玩具", "益智玩具"],
      "in_stock": true
    },
    "range_filters": {
      "price": {
        "gte": 50,
        "lte": 200
      }
    }
  }'

示例 3: 带分面搜索(简单模式)

curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "玩具",
    "size": 20,
    "facets": ["categoryName_keyword", "brandName_keyword"]
  }'

示例 4: 带分面搜索(高级模式)

curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "玩具",
    "size": 20,
    "facets": [
      {
        "field": "categoryName_keyword",
        "size": 15,
        "type": "terms"
      },
      {
        "field": "brandName_keyword",
        "size": 15,
        "type": "terms"
      },
      {
        "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}
        ]
      }
    ]
  }'

示例 5: 复杂搜索(布尔表达式+过滤+排序)

curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "玩具 AND (乐高 OR 芭比)",
    "size": 20,
    "filters": {
      "categoryName_keyword": "玩具"
    },
    "range_filters": {
      "price": {
        "gte": 50,
        "lte": 200
      },
      "days_since_last_update": {
        "lte": 30
      }
    },
    "facets": [
      {"field": "brandName_keyword", "size": 15},
      {"field": "supplierName_keyword", "size": 10}
    ],
    "sort_by": "price",
    "sort_order": "asc",
    "debug": false
  }'

2. 图片搜索

端点: POST /search/image

描述: 基于图片相似度进行搜索,使用图片向量进行语义匹配。

请求参数

{
  "image_url": "string (required)",
  "size": 10,
  "filters": {},
  "range_filters": {}
}

参数说明

参数 类型 必填 默认值 描述
image_url string - 查询图片的 URL
size integer 10 返回结果数量(1-100)
filters object null 精确匹配过滤器
range_filters object null 数值范围过滤器

响应格式

与文本搜索相同,但 query_info 包含图片信息:

{
  "hits": [...],
  "total": 50,
  "max_score": 0.95,
  "took_ms": 120,
  "query_info": {
    "image_url": "https://example.com/image.jpg",
    "search_type": "image_similarity"
  }
}

请求示例

curl -X POST "http://localhost:6002/search/image" \
  -H "Content-Type: application/json" \
  -d '{
    "image_url": "https://example.com/barbie.jpg",
    "size": 20,
    "filters": {
      "categoryName_keyword": "玩具"
    },
    "range_filters": {
      "price": {
        "lte": 100
      }
    }
  }'

3. 搜索建议(框架)

端点: GET /search/suggestions

描述: 获取搜索建议(自动补全)。

注意: 此功能暂未实现,仅返回框架响应。

查询参数

参数 类型 必填 默认值 描述
q string - 搜索查询字符串(最少1个字符)
size integer 5 建议数量(1-20)
types string "query" 建议类型(逗号分隔):query, product, category, brand

响应格式

{
  "query": "芭",
  "suggestions": [
    {
      "text": "芭比娃娃",
      "type": "query",
      "highlight": "<em>芭</em>比娃娃",
      "popularity": 850
    }
  ],
  "took_ms": 5
}

请求示例

curl "http://localhost:6002/search/suggestions?q=芭&size=5&types=query,product"

4. 即时搜索(框架)

端点: GET /search/instant

描述: 即时搜索,边输入边搜索。

注意: 此功能暂未实现,调用标准搜索接口。

查询参数

参数 类型 必填 默认值 描述
q string - 搜索查询(最少2个字符)
size integer 5 结果数量(1-20)

请求示例

curl "http://localhost:6002/search/instant?q=玩具&size=5"

5. 获取单个文档

端点: GET /search/{doc_id}

描述: 根据文档ID获取单个文档详情。

路径参数

参数 类型 描述
doc_id string 文档ID

响应格式

{
  "id": "12345",
  "source": {
    "name": "芭比时尚娃娃",
    "price": 89.99,
    "categoryName": "玩具"
  }
}

请求示例

curl "http://localhost:6002/search/12345"

管理接口

1. 健康检查

端点: GET /admin/health

描述: 检查服务健康状态。

响应格式

{
  "status": "healthy",
  "elasticsearch": "connected",
  "tenant_id": "tenant1"
}

2. 获取配置

端点: GET /admin/config

描述: 获取当前客户配置(脱敏)。

响应格式

{
  "tenant_id": "tenant1",
  "tenant_name": "Tenant1 Test Instance",
  "es_index_name": "search_tenant1",
  "num_fields": 20,
  "num_indexes": 4,
  "supported_languages": ["zh", "en", "ru"],
  "ranking_expression": "bm25() + 0.2*text_embedding_relevance()",
  "spu_enabled": false
}

3. 索引统计

端点: GET /admin/stats

描述: 获取索引统计信息。

响应格式

{
  "index_name": "search_tenant1",
  "document_count": 10000,
  "size_mb": 523.45
}

4. 查询改写规则

端点: GET /admin/rewrite-rules

描述: 获取当前的查询改写规则。

响应格式

{
  "rules": {
    "乐高": "brand:乐高 OR name:乐高",
    "玩具": "category:玩具"
  },
  "count": 2
}

端点: POST /admin/rewrite-rules

描述: 更新查询改写规则。

请求格式

{
  "乐高": "brand:乐高 OR name:乐高",
  "芭比": "brand:芭比 OR name:芭比"
}

使用示例

Python 示例

import requests

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

# 简单搜索
response = requests.post(API_URL, json={
    "query": "芭比娃娃",
    "size": 20
})
data = response.json()
print(f"找到 {data['total']} 个结果")

# 带过滤器和分面的搜索
response = requests.post(API_URL, json={
    "query": "玩具",
    "size": 20,
    "filters": {
        "categoryName_keyword": ["玩具", "益智玩具"]
    },
    "range_filters": {
        "price": {"gte": 50, "lte": 200}
    },
    "facets": [
        {"field": "brandName_keyword", "size": 15},
        {"field": "categoryName_keyword", "size": 15}
    ],
    "sort_by": "price",
    "sort_order": "asc"
})
result = response.json()

# 处理分面结果
for facet in result.get('facets', []):
    print(f"\n{facet['label']}:")
    for value in facet['values']:
        print(f"  - {value['label']}: {value['count']}")

JavaScript 示例

// 搜索函数
async function searchProducts(query, filters, rangeFilters, facets) {
    const response = await fetch('http://localhost:6002/search/', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            query: query,
            size: 20,
            filters: filters,
            range_filters: rangeFilters,
            facets: facets
        })
    });

    const data = await response.json();
    return data;
}

// 使用示例
const result = await searchProducts(
    "玩具",
    { categoryName_keyword: ["玩具"] },
    { price: { gte: 50, lte: 200 } },
    [
        { field: "brandName_keyword", size: 15 },
        { field: "categoryName_keyword", size: 15 }
    ]
);

// 显示分面结果
result.facets.forEach(facet => {
    console.log(`${facet.label}:`);
    facet.values.forEach(value => {
        console.log(`  - ${value.label}: ${value.count}`);
    });
});

// 显示搜索结果
result.hits.forEach(hit => {
    const product = hit._source;
    console.log(`${product.name} - ¥${product.price}`);
});

cURL 示例

# 简单搜索
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -d '{"query": "芭比娃娃", "size": 20}'

# 带过滤和排序
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "玩具",
    "size": 20,
    "filters": {"categoryName_keyword": "玩具"},
    "range_filters": {"price": {"gte": 50, "lte": 200}},
    "sort_by": "price",
    "sort_order": "asc"
  }'

# 带分面搜索
curl -X POST "http://localhost:6002/search/" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "玩具",
    "size": 20,
    "facets": [
      {"field": "categoryName_keyword", "size": 15},
      {"field": "brandName_keyword", "size": 15}
    ]
  }'

布尔表达式语法

支持的操作符

操作符 描述 示例
AND 所有词必须匹配 玩具 AND 乐高
OR 任意词匹配 芭比 OR 娃娃
ANDNOT 排除特定词 玩具 ANDNOT 电动
RANK 排序加权(不强制匹配) 玩具 RANK 乐高
() 分组 玩具 AND (乐高 OR 芭比)

操作符优先级

从高到低:

  1. () - 括号
  2. ANDNOT - 排除
  3. AND - 与
  4. OR - 或
  5. RANK - 排序

查询示例

# 简单查询
"芭比娃娃"

# AND 查询
"玩具 AND 乐高"

# OR 查询
"芭比 OR 娃娃"

# 排除查询
"玩具 ANDNOT 电动"

# 复杂查询
"玩具 AND (乐高 OR 芭比) ANDNOT 电动"

# 域查询
"brand:乐高"
"category:玩具"
"title:芭比娃娃"

数据模型

商品字段

常见的商品字段包括:

字段名 类型 描述
skuId long SKU ID(主键)
name text 商品名称(中文)
enSpuName text 商品名称(英文)
ruSkuName text 商品名称(俄文)
categoryName text 类目名称
categoryName_keyword keyword 类目名称(精确匹配)
brandName text 品牌名称
brandName_keyword keyword 品牌名称(精确匹配)
supplierName text 供应商名称
supplierName_keyword keyword 供应商名称(精确匹配)
price double 价格
imageUrl keyword 商品图片URL
create_time date 创建时间
days_since_last_update int 距上次更新天数

注意: 不同客户可能有不同的字段配置。


常见问题

Q1: 如何判断一个字段应该用哪种过滤器?

A:

  • 精确匹配过滤器 (filters): 用于 KEYWORD 类型字段(如类目、品牌、标签等)
  • 范围过滤器 (range_filters): 用于数值类型字段(如价格、库存、时间等)

Q2: 可以同时使用多个过滤器吗?

A: 可以。多个过滤器之间是 AND 关系(必须同时满足)。

{
  "filters": {
    "categoryName_keyword": "玩具",
    "brandName_keyword": "乐高"
  },
  "range_filters": {
    "price": {"gte": 50, "lte": 200}
  }
}

结果:类目是"玩具" 并且 品牌是"乐高" 并且 价格在50-200之间。

Q3: 如何实现"价格小于50或大于200"的过滤?

A: 当前版本不支持单字段多个不连续范围。建议分两次查询或使用布尔查询。

Q4: 分面搜索返回的 selected 字段是什么意思?

A: selected 表示该分面值是否在当前的过滤器中。前端可以用它来高亮已选中的过滤项。

Q5: 如何使用自定义排序?

A: 使用 sort_bysort_order 参数:

{
  "query": "玩具",
  "sort_by": "price",
  "sort_order": "asc"  // 价格从低到高
}

常用排序字段:

  • price: 价格
  • create_time: 创建时间
  • days_since_last_update: 更新时间

Q6: 如何启用调试模式?

A: 设置 debug: true,响应中会包含 debug_info 字段,包含:

  • 查询分析过程
  • ES 查询 DSL
  • ES 响应详情
  • 各阶段耗时

版本历史

v3.0 (2024-11-12)

重大更新

  • ✅ 移除硬编码的 price_ranges 逻辑
  • ✅ 新增 range_filters 参数,支持任意数值字段的范围过滤
  • ✅ 新增 facets 参数,替代 aggregations,提供简化接口
  • ✅ 标准化分面搜索响应格式
  • ✅ 新增 /search/suggestions 端点(框架)
  • ✅ 新增 /search/instant 端点(框架)
  • 移除 aggregations 参数(不向后兼容)

迁移指南

旧接口:

{
  "filters": {
    "price_ranges": ["0-50", "50-100"]
  },
  "aggregations": {
    "category_stats": {"terms": {"field": "categoryName_keyword", "size": 15}}
  }
}

新接口:

{
  "range_filters": {
    "price": {"gte": 50, "lte": 100}
  },
  "facets": [
    {"field": "categoryName_keyword", "size": 15}
  ]
}

附录

A. 支持的分析器

分析器 语言 描述
chinese_ecommerce 中文 Ansj 中文分词器(电商优化)
english 英文 标准英文分析器
russian 俄文 俄文分析器
arabic 阿拉伯文 阿拉伯文分析器
spanish 西班牙文 西班牙文分析器
japanese 日文 日文分析器

B. 字段类型

类型 ES 映射 用途
TEXT text 全文检索
KEYWORD keyword 精确匹配、聚合、排序
LONG long 整数
DOUBLE double 浮点数
DATE date 日期时间
BOOLEAN boolean 布尔值
TEXT_EMBEDDING dense_vector 文本向量(1024维)
IMAGE_EMBEDDING dense_vector 图片向量(1024维)