# 使用指南 - saas-search(运行与运维) 本文档聚焦运行与运维:服务启动/停止、日志查看、多环境切换、故障排查、Suggestion 索引运维。 开发与配置(环境入口、配置体系、Provider 架构、模块扩展规范)请优先阅读 `docs/QUICKSTART.md`。 ## 目录 1. [环境准备](#环境准备) 2. [服务启动](#服务启动) 3. [服务管理总览](#全盘串讲服务管理方式) 4. [配置说明](#配置说明) 5. [查看日志](#查看日志) 6. [测试验证](#测试验证) 7. [常见问题](#常见问题) --- ## 环境准备 ### 系统要求 - **操作系统**: Linux (推荐 CentOS 7+ / Ubuntu 18.04+) - **Python**: 3.8+ - **内存**: 建议 8GB+ - **磁盘**: 10GB+ (包含模型文件) - **Elasticsearch**: 8.x (可通过Docker运行) ### 安装依赖 #### 1. 安装 Python 依赖与激活环境 **推荐**:使用项目根目录的 `activate.sh` 激活环境(会加载 `.env`)。当前仅支持 venv(`.venv`),不存在 Conda 回退。系统要求、Python 环境、生产凭证与 `.env` 模板见 [QUICKSTART.md](./QUICKSTART.md) §1.4–1.8。 ```bash cd /data/saas-search ./scripts/create_venv.sh # 首次创建 venv(只需执行一次) source activate.sh ``` 模型服务采用独立环境(推荐): ```bash cd /data/saas-search ./scripts/setup_embedding_venv.sh # .venv-embedding ./scripts/setup_reranker_venv.sh # .venv-reranker ./scripts/setup_cnclip_venv.sh # .venv-cnclip ``` TEI 文本向量服务使用 Docker 容器: ```bash # GPU(需 nvidia-container-toolkit) TEI_DEVICE=cuda ./scripts/start_tei_service.sh # CPU TEI_DEVICE=cpu ./scripts/start_tei_service.sh ``` 专项说明: - `docs/TEI_SERVICE说明文档.md` - `docs/CNCLIP_SERVICE说明文档.md` #### 2. 启动Elasticsearch **方式1: 使用Docker(推荐)** ```bash docker run -d \ --name elasticsearch \ -p 9200:9200 \ -e "discovery.type=single-node" \ -e "ES_JAVA_OPTS=-Xms2g -Xmx2g" \ elasticsearch:8.11.0 ``` **方式2: 本地安装** 参考 [Elasticsearch官方文档](https://www.elastic.co/guide/en/elasticsearch/reference/8.11/install-elasticsearch.html) #### 3. 配置环境变量(支持多环境) 创建 `.env` 文件(以本地 / prod 环境为例): ```bash # MySQL配置 DB_HOST=120.79.247.228 DB_PORT=3316 DB_DATABASE=saas DB_USERNAME=saas DB_PASSWORD=your_password # Elasticsearch配置 ES_HOST=http://localhost:9200 ES_USERNAME=essa ES_PASSWORD=your_es_password # Redis配置(可选,用于缓存) REDIS_HOST=localhost REDIS_PORT=6479 REDIS_PASSWORD=your_redis_password # DeepL翻译API(可选) DEEPL_AUTH_KEY=your_deepl_auth_key # 运行环境(用于区分 prod / uat / test / dev) RUNTIME_ENV=prod # ES 索引命名空间前缀(用于按环境隔离索引,prod 通常留空) ES_INDEX_NAMESPACE= # API服务配置 API_HOST=0.0.0.0 API_PORT=6002 ``` --- ## 服务启动 ### 方式1: 一键启动(推荐) ```bash cd /data/saas-search ./run.sh ``` 这个脚本会自动: 1. 创建日志目录 2. 启动核心服务(backend/indexer/frontend) 3. 写入 PID 到 `logs/*.pid` 4. 执行健康检查 启动完成后,访问: - **前端界面**: http://localhost:6003 - **后端API**: http://localhost:6002 - **API文档**: http://localhost:6002/docs - **索引API**: http://localhost:6004/docs 可选:全功能模式(同时启动 embedding/translator/reranker/tei/cnclip): ```bash TEI_DEVICE=cuda CNCLIP_DEVICE=cuda ./scripts/service_ctl.sh start tei cnclip embedding translator reranker ``` ### 方式2: 统一控制脚本(推荐) ```bash # 查看状态 ./scripts/service_ctl.sh status # 启动核心服务(默认) ./scripts/service_ctl.sh start # 启动指定服务 ./scripts/service_ctl.sh start backend indexer frontend translator reranker tei cnclip # 停止全部服务(含可选服务) ./scripts/service_ctl.sh stop # 重启 ./scripts/service_ctl.sh restart ``` ### 方式3: 分步启动(单环境) #### 启动后端服务 ```bash ./scripts/start_backend.sh ``` 后端API会在 http://localhost:6002 启动(使用当前 `.env` 中的 ES_HOST / DB_HOST / RUNTIME_ENV / ES_INDEX_NAMESPACE) #### 启动前端服务 ```bash ./scripts/start_frontend.sh ``` 前端界面会在 http://localhost:6003 启动 ### 方式4: 多环境示例(prod / uat) 假设有两套环境: - **prod**:正式环境,RUNTIME_ENV=prod,ES_INDEX_NAMESPACE 为空 - **uat**:联调环境,RUNTIME_ENV=uat,ES_INDEX_NAMESPACE=uat_ 可以在项目根目录准备两个配置文件: - `.env.prod`: ```bash RUNTIME_ENV=prod ES_INDEX_NAMESPACE= ES_HOST=http://prod-es:9200 DB_HOST=prod-mysql ... ``` - `.env.uat`: ```bash RUNTIME_ENV=uat ES_INDEX_NAMESPACE=uat_ ES_HOST=http://uat-es:9200 DB_HOST=uat-mysql ... ``` 启动不同环境时: ```bash # 启动 UAT 后端 + 索引服务 cp .env.uat .env ./scripts/start_backend.sh ./scripts/start_indexer.sh # 启动 PROD 后端 + 索引服务 cp .env.prod .env ./scripts/start_backend.sh ./scripts/start_indexer.sh ``` ### 方式5: 手动启动 #### 启动后端API服务 ```bash python -m api.app \ --host 0.0.0.0 \ --port 6002 \ --es-host http://localhost:9200 \ --reload ``` #### 启动前端服务(可选) ```bash # 使用Python简单HTTP服务器 cd frontend python -m http.server 6003 ``` ## 服务管理总览 ### 1) 入口脚本职责 - `./run.sh`:仅启动核心服务(`backend/indexer/frontend`)。 - `./restart.sh`:重启逻辑为“先停所有已知服务,再启动核心服务”。 - `./scripts/stop.sh`:停止所有已知服务。 - `./scripts/service_ctl.sh`:统一控制器,支持 `start/stop/restart/status`,是唯一推荐入口。 ### 2) `service_ctl.sh` 的默认行为 - `start`(不带服务名):启动核心服务 `backend/indexer/frontend`。 - `stop`(不带服务名):停止全部已知服务(含可选服务)。 - `restart`(不带服务名):先停全部,再只启动核心服务。 - `status`(不带服务名):显示全部已知服务状态。 ### 3) 全量服务一键拉起 ```bash TEI_DEVICE=cuda CNCLIP_DEVICE=cuda ./scripts/service_ctl.sh start tei cnclip embedding translator reranker ``` 说明: - `TEI_DEVICE` / `CNCLIP_DEVICE` 统一使用 `cuda|cpu`。 - 显式把 `tei`、`cnclip` 放在前面,避免 `embedding` 因依赖未就绪启动失败。 ### 4) 常用运维命令 ```bash # 先重启核心,再拉起可选服务(最常用) ./restart.sh TEI_DEVICE=cuda CNCLIP_DEVICE=cuda ./scripts/service_ctl.sh start tei cnclip embedding translator reranker # 查看全量状态 ./scripts/service_ctl.sh status # 仅重启某个服务 ./scripts/service_ctl.sh restart embedding # 停止全部 ./scripts/service_ctl.sh stop ``` ### 停止服务 ```bash # 推荐:统一停止 ./scripts/stop.sh # 或使用统一控制脚本 ./scripts/service_ctl.sh stop ``` ### 服务端口 | 服务 | 端口 | URL | |------|------|-----| | Elasticsearch | 9200 | http://localhost:9200 | | Backend API | 6002 | http://localhost:6002 | | Indexer API | 6004 | http://localhost:6004 | | Frontend Web | 6003 | http://localhost:6003 | | Embedding (optional) | 6005 | http://localhost:6005 | | TEI (optional) | 8080 | http://localhost:8080 | | Translation (optional) | 6006 | http://localhost:6006 | | Reranker (optional) | 6007 | http://localhost:6007 | | API Docs | 6002 / 6004 | http://localhost:6002/docs / http://localhost:6004/docs | --- ## 配置说明 ### 环境配置文件 (.env) 主要配置项说明: ```bash # Elasticsearch配置 ES_HOST=http://localhost:9200 ES_USERNAME=essa ES_PASSWORD=your_es_password # MySQL配置 DB_HOST=120.79.247.228 DB_PORT=3316 DB_DATABASE=saas DB_USERNAME=saas DB_PASSWORD=your_password # Redis配置(可选,用于缓存) REDIS_HOST=localhost REDIS_PORT=6479 REDIS_PASSWORD=your_redis_password # DeepL翻译API DEEPL_AUTH_KEY=your_deepl_auth_key # API服务配置 API_HOST=0.0.0.0 API_PORT=6002 # Indexer服务配置 INDEXER_HOST=0.0.0.0 INDEXER_PORT=6004 # Optional service ports FRONTEND_PORT=6003 EMBEDDING_PORT=6005 TEI_PORT=8080 CNCLIP_PORT=51000 TRANSLATION_PORT=6006 RERANKER_PORT=6007 ``` ### 修改配置 1. 编辑 `.env` 文件 2. 重启相关服务 --- ## 查看日志 ### 日志文件位置 日志文件存储在 `logs/` 目录下: - `logs/backend.log` - 后端服务日志 - `logs/indexer.log` - 索引服务日志 - `logs/frontend.log` - 前端服务日志 - `logs/embedding.log` - 向量服务日志(可选) - `logs/translator.log` - 翻译服务日志(可选) - `logs/reranker.log` - 重排服务日志(可选) - `logs/tei.log` - TEI 启停日志(可选) - `logs/cnclip.log` - CN-CLIP 启停日志(可选) - `logs/search_engine.log` - 应用主日志(按天轮转) - `logs/errors.log` - 错误日志(按天轮转) ### 查看实时日志 ```bash # 查看后端日志 tail -f logs/backend.log # 查看前端日志 tail -f logs/frontend.log # 查看应用主日志 tail -f logs/search_engine.log # 查看错误日志 tail -f logs/errors.log ``` ### 日志级别 日志级别可以通过环境变量 `LOG_LEVEL` 设置: ```bash # 在 .env 文件中设置 LOG_LEVEL=DEBUG # DEBUG, INFO, WARNING, ERROR, CRITICAL ``` ### 日志轮转 日志文件按天自动轮转,保留30天的历史日志。 --- ## 测试验证 ### 1. 健康检查 ```bash curl http://localhost:6002/admin/health ``` **预期响应**: ```json { "status": "healthy", "elasticsearch": "connected" } ``` ### 2. 索引统计 ```bash curl http://localhost:6002/admin/stats -H "X-Tenant-ID: 162" ``` ### 3. 简单搜索测试 ```bash curl -X POST http://localhost:6002/search/ \ -H "Content-Type: application/json" \ -H "X-Tenant-ID: 162" \ -d '{ "query": "玩具", "size": 10 }' ``` 或者通过查询参数: ```bash curl -X POST "http://localhost:6002/search/?tenant_id=2" \ -H "Content-Type: application/json" \ -d '{ "query": "玩具", "size": 10 }' ``` ### 4. 带过滤器的搜索 ```bash curl -X POST http://localhost:6002/search/ \ -H "Content-Type: application/json" \ -H "X-Tenant-ID: 162" \ -d '{ "query": "玩具", "size": 10, "filters": { "category.keyword": ["玩具", "益智玩具"] }, "range_filters": { "price": {"gte": 50, "lte": 200} } }' ``` ### 5. 分面搜索测试 ```bash curl -X POST http://localhost:6002/search/ \ -H "Content-Type: application/json" \ -H "X-Tenant-ID: 162" \ -d '{ "query": "玩具", "size": 10, "facets": [ {"field": "category.keyword", "size": 15}, {"field": "vendor.keyword", "size": 15} ] }' ``` ### 6. 图片搜索测试 ```bash curl -X POST http://localhost:6002/search/image \ -H "Content-Type: application/json" \ -H "X-Tenant-ID: 162" \ -d '{ "image_url": "https://oss.essa.cn/example.jpg", "size": 10 }' ``` ### 7. 前端界面测试 访问 http://localhost:6003 或 http://localhost:6002/ 进行可视化测试。 **注意**: 所有搜索接口都需要通过 `X-Tenant-ID` 请求头或 `tenant_id` 查询参数指定租户ID。 --- ## 8. Suggestion 索引与接口使用 ### 8.1 构建 Suggestion 索引(Phase 2:全量 + 增量) Suggestion 索引会从: - ES 商品索引:`title.{lang}`, `qanchors.{lang}` - MySQL 日志表:`shoplazza_search_log.query`(含 `language`、`request_params`) 聚合生成版本化索引并发布 alias: - 物理索引:`{ES_INDEX_NAMESPACE}search_suggestions_tenant_{tenant_id}_v` - 读别名:`{ES_INDEX_NAMESPACE}search_suggestions_tenant_{tenant_id}_current` 在项目根目录执行(以 tenant_id=162 为例): ```bash # 1) 全量重建(版本化 + alias 发布) ./scripts/build_suggestions.sh 162 \ --mode full \ --days 30 \ --publish-alias \ --keep-versions 2 # 2) 增量更新(watermark + overlap) ./scripts/build_suggestions.sh 162 \ --mode incremental \ --overlap-minutes 30 ``` 可选参数: - `--days`:回溯日志天数(默认 30) - `--batch-size`:扫描商品索引的批大小(默认 500) - `--min-query-len`:参与 suggestion 的最小查询长度(默认 1) - `--overlap-minutes`:增量窗口重叠分钟数(默认 30) - `--bootstrap-if-missing`:增量模式下若缺少 active index 则自动全量初始化(默认 true) > 建议在商品索引构建完成、日志正常写入一段时间后执行一次全量构建,然后按天/小时增加增量构建任务。 ### 8.2 调用 Suggestion 接口 全量构建完成后,可直接通过 `/search/suggestions` 获取自动补全结果: ```bash # UAT 环境(本地或 UAT 集群) curl "http://localhost:6002/search/suggestions?q=iph&size=5&language=en" \ -H "X-Tenant-ID: 162" # PROD 环境(域名 / 端口按实际部署调整) curl "https://api.yourdomain.com/search/suggestions?q=iph&size=5&language=en" \ -H "X-Tenant-ID: 162" ``` ### 8.3 商品索引构建(search_products,多环境例子) 以 tenant_id=162 为例,分别在 UAT / PROD 构建商品索引。 #### UAT 环境(索引前缀 uat_) ```bash cd /data/saas-search # 1. 切换到 UAT 环境配置 cp .env.uat .env # 2. 启动 indexer 服务(如尚未启动) ./scripts/start_indexer.sh # 3. 可选:重建索引结构(会删除旧索引) ./scripts/create_tenant_index.sh 162 # 实际创建的索引名为:uat_search_products_tenant_162 # 4. 导入商品数据(全量索引) curl -X POST "http://localhost:6004/indexer/reindex" \ -H "Content-Type: application/json" \ -d '{ "tenant_id": "162", "batch_size": 500 }' ``` #### PROD 环境(无前缀) ```bash cd /data/saas-search # 1. 切换到 PROD 环境配置 cp .env.prod .env # 2. 启动 indexer 服务 ./scripts/start_indexer.sh # 3. 可选:重建索引结构(search_products_tenant_162) ./scripts/create_tenant_index.sh 162 # 4. 导入商品数据 curl -X POST "http://localhost:6004/indexer/reindex" \ -H "Content-Type: application/json" \ -d '{ "tenant_id": "162", "batch_size": 500 }' ``` 完成后: - UAT 环境商品索引:`uat_search_products_tenant_162` - PROD 环境商品索引:`search_products_tenant_162` 两套环境的搜索 / suggestion API 调用完全一致,只是连接到各自的后端 / ES。 接口返回结构详见 `docs/搜索API对接指南.md` 的“3.7 搜索建议接口”章节。 --- ## 常见问题 ### Q1: MySQL连接失败 **症状**: `Failed to connect to MySQL` **解决方案**: ```bash # 检查MySQL服务状态 mysql -h 120.79.247.228 -P 3316 -u saas -p -e "SELECT 1" # 检查配置 cat .env | grep DB_ ``` ### Q2: Elasticsearch连接失败 **症状**: `Failed to connect to Elasticsearch` **解决方案**: ```bash # 检查ES服务状态 curl http://localhost:9200 # 检查ES版本 curl http://localhost:9200 | grep version # 确认配置 cat .env | grep ES_ ``` ### Q3: 服务启动失败 **症状**: `Address already in use` 或端口被占用 **解决方案**: ```bash # 查看占用端口的进程 lsof -i :6002 # 后端 lsof -i :6003 # 前端 lsof -i :9200 # ES # 杀掉进程 kill -9 # 或修改端口配置 ``` ### Q4: 搜索无结果 **症状**: 搜索返回空结果 **解决方案**: ```bash # 检查ES中是否有数据 curl http://localhost:9200/search_products/_count # 检查tenant_id过滤是否正确 curl -X POST http://localhost:6002/search/ \ -H "Content-Type: application/json" \ -H "X-Tenant-ID: 162" \ -d '{"query": "*", "size": 10, "debug": true}' ``` ### Q5: 前端无法连接后端 **症状**: CORS错误 **解决方案**: - 确保后端在 http://localhost:6002 运行 - 检查浏览器控制台错误信息 - 检查后端日志中的CORS配置 ### Q6: 翻译不工作 **症状**: 翻译返回原文 **解决方案**: - 检查DEEPL_AUTH_KEY是否正确 - 如果没有API key,系统会使用mock模式(返回原文) --- ## 相关文档 - **测试数据构造文档**: `TEST_DATA_GUIDE.md` - 如何构造和导入测试数据 - **API接口文档**: `API_INTEGRATION_GUIDE.md` - 完整的API对接指南 - **字段说明文档**: `INDEX_FIELDS_DOCUMENTATION.md` - 索引字段详细说明 - **设计文档**: `设计文档.md` - 系统架构和设计说明 - **README**: `README.md` - 项目概述和快速开始 --- **文档版本**: v2.0 **最后更新**: 2024-12