使用指南 - SearchEngine
快速启动(推荐)
一键启动所有服务
cd /data/tw/SearchEngine
./start_all.sh
这个脚本会自动完成:
- 设置conda环境
- 检查并导入测试数据(如果需要)
- 启动后端API服务(后台运行)
- 启动前端Web界面
启动完成后,访问:
- 前端界面: http://localhost:6003
- 后端API: http://localhost:6002
- API文档: http://localhost:6002/docs
停止服务
# 停止后端
kill $(cat logs/backend.pid)
# 前端按 Ctrl+C
分步启动(自定义)
1. 环境设置
cd /data/tw/SearchEngine
./setup.sh
这会:
- 创建/激活conda环境
searchengine - 加载配置文件
- 检查Elasticsearch连接
2. 数据导入
2.1 从MySQL导入到Elasticsearch
数据导入脚本需要指定 tenant_id 参数,用于从MySQL中筛选对应租户的数据。
基本用法:
./scripts/ingest.sh <tenant_id> [recreate_index]
参数说明:
tenant_id: 必需,租户ID,用于筛选数据库中的数据recreate_index: 可选,是否删除并重建索引(true/false,默认:false)
示例:
快速测试(tenant_id=2,重建索引):
./scripts/ingest.sh 2 true
增量导入(tenant_id=2,不重建索引):
./scripts/ingest.sh 2 false
检查可用的 tenant_id:
如果导入时显示 "No documents to index",脚本会自动显示调试信息,包括:
- 该 tenant_id 的统计信息(总数、活跃数、已删除数)
- 数据库中存在的其他 tenant_id 列表
2.2 构造测试数据(Mock Data)
mock_data.sh 脚本用于构造完整的测试数据,包含两部分:
- tenant_id=1: 自动生成的mock数据(1000条SPU)
- tenant_id=2: 从CSV文件导入的数据(10000条SPU)
使用方法:
将CSV文件放在 data/customer1/goods_with_pic.5years_congku.csv.shuf.1w,然后直接运行:
./scripts/mock_data.sh
脚本会自动:
- 生成 tenant_id=1 的mock数据并导入MySQL
- 从CSV文件读取数据,生成 tenant_id=2 的数据并导入MySQL
- 自动计算起始ID,避免主键冲突
注意:
- 所有配置(数据库地址、CSV路径等)都写死在脚本中,这是测试数据构造脚本,不需要配置化
- 如果CSV文件路径不同,需要修改
scripts/mock_data.sh中的TENANT2_CSV_FILE变量
手动分步执行(如果需要自定义参数):
生成SQL文件:
python scripts/import_tenant2_csv.py \ --csv-file data/customer1/goods_with_pic.5years_congku.csv.shuf.1w \ --tenant-id 2 \ --output customer1_data.sql \ --db-host 120.79.247.228 \ --db-port 3316 \ --db-database saas \ --db-username saas \ --db-password <密码>导入SQL到MySQL:
python scripts/import_test_data.py \ --db-host 120.79.247.228 \ --db-port 3316 \ --db-database saas \ --db-username saas \ --db-password <密码> \ --sql-file customer1_data.sql \ --tenant-id 2
CSV文件格式要求:
CSV文件需要包含以下列(列名不区分大小写):
skuId- SKU IDname- 商品名称name_pinyin- 拼音(可选)create_time- 创建时间(格式:YYYY-MM-DD HH:MM:SS)ruSkuName- 俄文SKU名称(可选)enSpuName- 英文SPU名称(可选)categoryName- 类别名称supplierName- 供应商名称brandName- 品牌名称file_id- 文件ID(可选)days_since_last_update- 更新天数(可选)id- 商品ID(可选)imageUrl- 图片URL(可选)
注意:
- 首次运行会下载模型文件(BGE-M3和CN-CLIP),大约需要10-30分钟
- 确保MySQL中存在对应 tenant_id 的数据(
shoplazza_product_spu和shoplazza_product_sku表) - 只有
deleted=0的记录会被导入 - CSV导入会先清理该 tenant_id 的旧数据,再导入新数据
3. 启动后端
./scripts/start_backend.sh
后端API会在 http://localhost:6002 启动
4. 启动前端
./scripts/start_frontend.sh
前端界面会在 http://localhost:6003 启动
配置说明
环境配置文件 (.env)
# Elasticsearch配置
ES_HOST=http://localhost:9200
ES_USERNAME=essa
ES_PASSWORD=4hOaLaf41y2VuI8y
# Redis配置(可选,用于缓存)
REDIS_HOST=localhost
REDIS_PORT=6479
REDIS_PASSWORD=BMfv5aI31kgHWtlx
# DeepL翻译API
DEEPL_AUTH_KEY=c9293ab4-ad25-479b-919f-ab4e63b429ed
# 客户配置
TENANT_ID=tenant1
# API服务配置
API_HOST=0.0.0.0
API_PORT=6002
修改配置
- 编辑
.env文件 - 重启相关服务
使用Web界面
搜索功能
简单搜索: 直接输入关键词
- 中文: "芭比娃娃"
- 英文: "fire control set"
- 俄文: "Наборы для пожаротушения"
布尔搜索: 使用操作符
- AND: "toy AND barbie"
- OR: "barbie OR doll"
- ANDNOT: "toy ANDNOT cheap"
- 组合: "toy AND (barbie OR doll) ANDNOT cheap"
域搜索: 指定搜索域
- 品牌: "brand:ZHU LIN"
- 类别: "category:玩具"
搜索选项
- 启用翻译: 自动翻译查询到其他语言
- 启用语义搜索: 使用embedding进行语义匹配
- 启用自定义排序: 使用配置的ranking表达式
- 结果数量: 10/20/50条
API使用
搜索接口(v3.0 更新)
基础搜索(需要指定 tenant_id):
curl -X POST http://localhost:6002/search/ \
-H "Content-Type: application/json" \
-H "X-Tenant-ID: 2" \
-d '{
"query": "芭比娃娃",
"size": 20
}'
或者通过查询参数:
curl -X POST "http://localhost:6002/search/?tenant_id=2" \
-H "Content-Type: application/json" \
-d '{
"query": "芭比娃娃",
"size": 20
}'
带过滤器的搜索:
curl -X POST http://localhost:6002/search/ \
-H "Content-Type: application/json" \
-H "X-Tenant-ID: 2" \
-d '{
"query": "玩具",
"size": 20,
"filters": {
"categoryName_keyword": ["玩具", "益智玩具"]
},
"range_filters": {
"price": {"gte": 50, "lte": 200}
}
}'
带分面搜索:
curl -X POST http://localhost:6002/search/ \
-H "Content-Type: application/json" \
-H "X-Tenant-ID: 2" \
-d '{
"query": "玩具",
"size": 20,
"facets": [
{"field": "categoryName_keyword", "size": 15},
{"field": "brandName_keyword", "size": 15}
]
}'
图片搜索
curl -X POST http://localhost:6002/search/image \
-H "Content-Type: application/json" \
-H "X-Tenant-ID: 2" \
-d '{
"image_url": "https://oss.essa.cn/example.jpg",
"size": 10
}'
注意: 所有搜索接口都需要通过 X-Tenant-ID 请求头或 tenant_id 查询参数指定租户ID。
健康检查
curl http://localhost:6002/admin/health
查看配置
curl http://localhost:6002/admin/config
索引统计
curl http://localhost:6002/admin/stats
常见问题
1. Elasticsearch连接失败
问题: Failed to connect to Elasticsearch
解决:
# 检查ES是否运行
curl http://localhost:9200
# 检查配置
cat .env | grep ES_
2. 导入数据时内存不足
问题: Out of memory
解决:
# 减少batch size或跳过embedding
./scripts/ingest.sh 1000 true
3. 模型下载失败
问题: 模型文件下载超时
解决:
- 检查网络连接
- 使用国内镜像源
- 手动下载模型到指定目录
4. 翻译不工作
问题: 翻译返回原文
解决:
- 检查DEEPL_AUTH_KEY是否正确
- 如果没有API key,系统会使用mock模式(返回原文)
5. 前端无法连接后端
问题: CORS错误
解决:
- 确保后端在 http://localhost:6002 运行
- 检查浏览器控制台错误信息
6. 数据导入时没有数据
问题: WARNING: No documents to index 或 Transformed 0 SPU documents
可能原因:
- 数据库中不存在该 tenant_id 的数据
- 数据都被标记为
deleted=1 - tenant_id 类型不匹配
解决步骤:
查看调试信息: 脚本会自动显示调试信息,包括:
DEBUG: tenant_id=1000: total=0, active=0, deleted=0 DEBUG: Available tenant_ids in shoplazza_product_spu: tenant_id=1: total=100, active=100 tenant_id=2: total=50, active=50检查数据库: 直接查询MySQL确认数据
-- 查看有哪些 tenant_id SELECT tenant_id, COUNT(*) as count, SUM(CASE WHEN deleted = 0 THEN 1 ELSE 0 END) as active FROM shoplazza_product_spu GROUP BY tenant_id;
-- 检查特定 tenant_id 的数据 SELECT COUNT(*) FROM shoplazza_product_spu WHERE tenant_id = 1000 AND deleted = 0;
3. **如果数据库中没有数据,需要先导入数据**:
- 如果有CSV文件,使用CSV导入脚本(见"2.2 从CSV导入数据到MySQL")
- 如果没有CSV文件,可以使用mock数据生成脚本
4. **使用正确的 tenant_id**: 根据调试信息显示的可用 tenant_id,使用正确的值重新导入
```bash
./scripts/ingest.sh 2 true # 使用调试信息中显示的 tenant_id
开发和调试
查看日志
# 后端日志
tail -f logs/backend.log
# 实时日志(如果前台运行)
./scripts/start_backend.sh
Python命令行测试
# 激活环境
source /home/tw/miniconda3/etc/profile.d/conda.sh
conda activate searchengine
# 测试搜索(需要指定 tenant_id)
python -c "
from config import ConfigLoader
from utils.es_client import ESClient
from search.searcher import Searcher
from config.env_config import ES_CONFIG
config_loader = ConfigLoader('config/config.yaml')
config = config_loader.load_config()
es_client = ESClient(hosts=[ES_CONFIG['host']],
username=ES_CONFIG.get('username'),
password=ES_CONFIG.get('password'))
searcher = Searcher(config, es_client)
result = searcher.search('芭比娃娃', tenant_id='2', size=5)
print(f'找到 {result.total} 个结果')
for hit in result.hits:
print(f' - {hit[\"title\"]} (分数: {hit[\"_score\"]:.4f})')
"
重新导入数据
# 删除现有索引并重新导入(需要指定 tenant_id)
./scripts/ingest.sh <tenant_id> true
# 例如:导入 tenant_id=2 的数据并重建索引
./scripts/ingest.sh 2 true
检查数据库中的 tenant_id
如果不知道应该使用哪个 tenant_id,可以:
运行导入脚本查看调试信息(即使没有数据也会显示):
./scripts/ingest.sh 999 true脚本会显示数据库中存在的 tenant_id 列表
直接查询数据库:
mysql -h 120.79.247.228 -P 3316 -u saas -p saas -e \ "SELECT tenant_id, COUNT(*) as count FROM shoplazza_product_spu GROUP BY tenant_id;"
性能优化
1. 使用embedding缓存
首次生成embedding后会自动缓存到 .cache/ 目录,后续导入会更快。
2. 批量大小调整
# 修改批量大小(在ingest_tenant1.py中)
--batch-size 200 # 默认100
3. GPU加速
确保CUDA可用以加速embedding生成:
python -c "import torch; print(f'CUDA available: {torch.cuda.is_available()}')"
项目结构
SearchEngine/
├── .env # 环境配置
├── setup.sh # 环境设置脚本
├── start_all.sh # 一键启动脚本
├── scripts/ # 运行脚本
│ ├── ingest.sh # 数据导入
│ ├── start_backend.sh # 启动后端
│ └── start_frontend.sh # 启动前端
├── frontend/ # Web前端
│ ├── index.html
│ └── static/
├── logs/ # 日志文件
├── config/ # 配置模块
├── indexer/ # 数据导入
├── query/ # 查询处理
├── search/ # 搜索引擎
├── embeddings/ # 向量模型
└── api/ # REST API
支持
遇到问题请查看:
- 日志:
logs/backend.log - API文档: http://localhost:6002/docs
- 配置:
config/schema/tenant1_config.yaml