# schedule-embedding-api 接口文档 ## 📋 文档概述 **项目名称**: schedule-embedding-api **文档版本**: v2.2 **最后更新**: 2026-03-13 **服务地址**: http://localhost:8084 ### 功能简介 本系统提供基于 Elasticsearch 8.x 和 Embedding API 的智能文档向量化与检索服务,主要功能包括: - 📄 **文档入库**: 支持单个文档和批量文档的向量化入库 - 🔍 **向量搜索**: 基于 4096 维向量的语义搜索 - 🎯 **混合搜索**: 支持向量搜索与业务字段过滤相结合 - 📊 **文档管理**: 提供文档查询和删除功能 - 🔄 **完全动态**: 支持任意类型数据(合同、音频、视频、图片等) ### 技术栈 - **Embedding 模型**: Qwen3-Embedding-8B (4096维向量) - **搜索引擎**: Elasticsearch 8.x (原生 KNN 支持) - **开发框架**: Spring Boot 2.7.18 - **JDK 版本**: Java 17 ### 核心设计理念 **ES动态映射 + 业务字段完全动态** - ✅ **核心字段(固定)**: docId, chunkId, content, embedding, createTime, updateTime - ✅ **动态映射**: 使用 ES DynamicMapping.True,自动识别任意新字段 - ✅ **metadata完全动态**: 所有业务数据通过 `metadata` 动态扩展,支持任意类型和字段 - ✅ **零代码扩展**: 新增字段无需修改代码,完全动态化 - ✅ **类型无关**: 支持合同、音频、视频、图片等任意数据类型 --- ## 🔗 接口列表 | 序号 | 接口名称 | 请求方法 | 接口路径 | 功能说明 | |-----|---------|---------|---------|---------| | 1 | 健康检查 | GET | /actuator/health | 检查服务健康状态 | | 2 | 单个文档入库 | POST | /api/v1/documents/index | 将单个文档向量化后存入ES | | 3 | 批量文档入库 | POST | /api/v1/documents/batch-index | 批量将文档向量化后存入ES | | 4 | 向量搜索 | POST | /api/v1/search | 基于语义的向量搜索 | | 5 | 混合搜索 | POST | /api/v1/search/hybrid | 向量搜索 + 业务字段过滤 | | 6 | 查询文档 | GET | /api/v1/documents/{docId} | 查询文档的所有chunks | | 7 | 删除文档 | DELETE | /api/v1/documents/{docId} | 删除文档的所有chunks | | 8 | 删除Chunk | DELETE | /api/v1/documents/chunk/{chunkId} | 删除单个chunk | --- ## 📖 接口详情 ### 1. 健康检查接口 #### 基本信息 - **接口名称**: 健康检查 - **接口路径**: `/actuator/health` - **请求方法**: `GET` - **Content-Type**: 无需设置 #### 请求示例 ```bash curl -X GET http://localhost:8084/actuator/health ``` #### 响应示例 **状态码**: 200 OK ```json { "status": "UP", "components": { "diskSpace": { "status": "UP", "details": { "total": 994662584320, "free": 110714380288, "threshold": 10485760, "exists": true } }, "elasticsearch": { "status": "UP", "details": { "cluster_name": "docker-cluster", "status": "yellow", "number_of_nodes": 1, "number_of_data_nodes": 1 } }, "ping": { "status": "UP" } } } ``` #### 测试用例 | 用例编号 | 测试场景 | 预期结果 | |---------|---------|---------| | TC-001 | 正常访问健康检查接口 | 返回200,status为UP | --- ### 2. 单个文档入库接口 #### 基本信息 - **接口名称**: 单个文档入库 - **接口路径**: `/api/v1/documents/index` - **请求方法**: `POST` - **Content-Type**: `application/json` #### 请求参数 | 参数名 | 类型 | 必填 | 说明 | 示例值 | |-------|------|------|------|--------| | docId | String | 是 | 文档唯一标识 | "contract-001" | | fileName | String | 否 | 文件名 | "合同.pdf" | | fullText | String | 是 | 文档全文内容 | "这是合同内容..." | | filePath | String | 否 | 文件路径 | "/data/contracts/001.pdf" | | fileSize | Long | 否 | 文件大小(字节) | 1024000 | | fileType | String | 否 | 文件类型 | "pdf" | | metadata | Map | 否 | **完全动态的业务元数据** | 见下方示例 | #### metadata 字段说明 **重要**: `metadata` 是完全动态的,支持任意字段! **合同类文档示例**: ```json { "contractType": "消费贷贷款合同", "partyA": "A公司", "partyB": "B公司", "contractAmount": 1000000.00, "signDate": "2026-01-15" } ``` **音频类文档示例**: ```json { "duration": 1800, "speaker": "张三", "language": "zh-CN", "sampleRate": 44100, "bitrate": 128000, "format": "MP3", "transcript": "音频转写文本..." } ``` **视频类文档示例**: ```json { "duration": 3600, "resolution": "1920x1080", "frameRate": 30, "codec": "H.264", "bitrate": 5000000, "subtitles": ["中文字幕", "英文字幕"] } ``` **图片类文档示例**: ```json { "width": 1920, "height": 1080, "format": "JPEG", "colorSpace": "RGB", "dpi": 300, "description": "图片描述..." } ``` #### 请求示例 **示例 1: 合同类文档入库** ```bash curl -X POST http://localhost:8084/api/v1/documents/index \ -H "Content-Type: application/json" \ -d '{ "docId": "contract-001", "fileName": "永续贷产品贷款合同.pdf", "fullText": "永续贷产品贷款合同\n\n第一章:总则\n本合同由甲方A公司与乙方B公司签订,合同金额为100万元。\n\n第二章:贷款条款\n2.1 贷款利率按照央行基准利率执行。\n2.2 贷款期限为36个月。\n2.3 还款方式为等额本息。", "filePath": "/home/data/contracts/contract-001.pdf", "fileSize": 1289748, "fileType": "pdf", "metadata": { "contractType": "消费贷贷款合同", "partyA": "A公司", "partyB": "B公司", "contractAmount": 1000000.00, "signDate": "2026-01-15" } }' ``` **示例 2: 音频类文档入库** ```bash curl -X POST http://localhost:8084/api/v1/documents/index \ -H "Content-Type: application/json" \ -d '{ "docId": "audio-001", "fileName": "会议录音.mp3", "fullText": "这是会议的完整转写文本内容,包含所有发言人的讲话记录...", "filePath": "/home/data/audio/meeting_001.mp3", "fileSize": 5120000, "fileType": "mp3", "metadata": { "duration": 1800, "speaker": "张三", "language": "zh-CN", "sampleRate": 44100, "format": "MP3" } }' ``` **示例 3: 视频类文档入库** ```bash curl -X POST http://localhost:8084/api/v1/documents/index \ -H "Content-Type: application/json" \ -d '{ "docId": "video-001", "fileName": "培训课程.mp4", "fullText": "这是视频的字幕文本内容...", "filePath": "/home/data/video/training_001.mp4", "fileSize": 51200000, "fileType": "mp4", "metadata": { "duration": 3600, "resolution": "1920x1080", "frameRate": 30, "codec": "H.264", "subtitles": ["中文字幕", "英文字幕"] } }' ``` #### 响应示例 **成功响应** - 200 OK ```json { "success": true, "docId": "contract-001", "chunkCount": 1, "message": "文档入库成功", "error": null } ``` **失败响应** - 400 Bad Request ```json { "code": 400, "success": false, "message": "参数校验失败", "errors": { "docId": "文档ID不能为空" }, "timestamp": 1773306699906 } ``` ```json { "code": 400, "success": false, "message": "参数校验失败", "errors": { "fullText": "全文内容不能为空" }, "timestamp": 1773306699937 } ``` #### 测试用例 | 用例编号 | 测试场景 | 请求参数 | 预期结果 | |---------|---------|---------|---------| | TC-002 | 正常数据入库(合同) | 完整的合同信息 | 200,chunkCount=1 | | TC-003 | 缺少docId | 不传docId字段 | 400,提示"文档ID不能为空" | | TC-004 | 空文本内容 | fullText为空字符串 | 400,提示"全文内容不能为空" | | TC-005 | 音频数据入库 | 音频元数据(duration、speaker等) | 200,正常入库 | | TC-006 | 视频数据入库 | 视频元数据(resolution、codec等) | 200,正常入库 | | TC-007 | 动态字段扩展 | 新增任意自定义字段 | 200,零代码扩展成功 | --- ### 3. 批量文档入库接口 #### 基本信息 - **接口名称**: 批量文档入库 - **接口路径**: `/api/v1/documents/batch-index` - **请求方法**: `POST` - **Content-Type**: `application/json` #### 请求参数 | 参数名 | 类型 | 必填 | 说明 | 示例值 | |-------|------|------|------|--------| | items | Array\ | 是 | 文档列表(最多100个) | 见下方示例 | IndexRequest 结构同"单个文档入库"接口。 #### 请求示例 ```bash curl -X POST http://localhost:8084/api/v1/documents/batch-index \ -H "Content-Type: application/json" \ -d '{ "items": [ { "docId": "batch-doc-001", "fileName": "合同1.pdf", "fullText": "这是第一个合同文档的内容。包含重要条款和条件。", "fileType": "pdf", "metadata": { "contractType": "消费贷", "partyA": "A公司" } }, { "docId": "batch-doc-002", "fileName": "音频1.mp3", "fullText": "这是音频的转写文本内容。", "fileType": "mp3", "metadata": { "duration": 1800, "speaker": "张三" } }, { "docId": "batch-doc-003", "fileName": "视频1.mp4", "fullText": "这是视频的字幕内容。", "fileType": "mp4", "metadata": { "duration": 3600, "resolution": "1920x1080" } } ] }' ``` #### 响应示例 **成功响应** - 200 OK ```json { "totalCount": 3, "successCount": 3, "failedCount": 0, "failedItems": [] } ``` **部分失败响应** - 200 OK ```json { "totalCount": 3, "successCount": 2, "failedCount": 1, "failedItems": [ { "docId": "batch-doc-003", "error": "全文内容不能为空" } ] } ``` **失败响应** - 400 Bad Request ```json { "code": 400, "success": false, "message": "参数校验失败", "errors": { "items": "文档列表不能为空" }, "timestamp": 1773306700683 } ``` #### 测试用例 | 用例编号 | 测试场景 | 请求参数 | 预期结果 | |---------|---------|---------|---------| | TC-008 | 正常批量入库 | 3个不同类型文档 | 200,successCount=3 | | TC-009 | 空列表 | items=[] | 400,提示"文档列表不能为空" | | TC-010 | 大批量入库 | 10个文档 | 200,successCount=10 | | TC-011 | 部分失败 | 3个文档,1个缺少fullText | 200,successCount=2,failedCount=1 | --- ### 4. 向量搜索接口 #### 基本信息 - **接口名称**: 向量搜索 - **接口路径**: `/api/v1/search` - **请求方法**: `POST` - **Content-Type**: `application/json` #### 功能说明 基于语义的向量搜索,使用 Embedding 模型将查询文本转换为 4096 维向量,然后在 ES 中进行 KNN 搜索,返回最相似的结果。 #### 请求参数 | 参数名 | 类型 | 必填 | 说明 | 示例值 | 默认值 | |-------|------|------|------|--------|-------| | query | String | 是 | 查询文本 | "A公司的消费贷合同利率是多少" | - | | topK | Integer | 否 | 返回结果数量 | 5 | 10 | #### 请求示例 ```bash curl -X POST http://localhost:8084/api/v1/search \ -H "Content-Type: application/json" \ -d '{ "query": "A公司的消费贷合同利率是多少", "topK": 5 }' ``` #### 响应示例 **成功响应** - 200 OK ```json [ { "docId": "company-a-test", "chunkId": "company-a-test_chunk_0", "chunkIndex": 0, "content": "A公司与B公司签订消费贷合同,合同金额100万元,贷款利率按照央行基准利率执行,贷款期限36个月", "score": 0.8871919, "metadata": { "chunk_index": 0, "file_path": "/tmp/test.pdf", "create_time": "2026-03-12T17:06:51", "doc_id": "company-a-test", "chunk_id": "company-a-test_chunk_0", "content": "A公司与B公司签订消费贷合同,合同金额100万元,贷款利率按照央行基准利率执行,贷款期限36个月", "file_size": 1024, "file_size_mb": 0.0009765625, "chunk_count": 0, "update_time": "2026-03-12T17:06:51", "file_type": "pdf", "contract_type": "消费贷贷款合同", "party_a": "A公司", "party_b": "B公司" } } ] ``` **注意**: 响应中**不包含** `embedding` 字段,以节省带宽和提高性能。 **无结果响应** - 200 OK ```json [] ``` **失败响应** - 400 Bad Request ```json { "code": 400, "success": false, "message": "参数校验失败", "errors": { "query": "查询文本不能为空" }, "timestamp": 1773306701000 } ``` #### 响应字段说明 | 字段名 | 类型 | 说明 | |-------|------|------| | docId | String | 文档ID | | chunkId | String | 分片ID | | chunkIndex | Integer | 分片序号 | | content | String | 匹配的内容片段 | | score | Float | 相似度分数(0-1,越高越相似) | | metadata | Map | 完整的元数据信息(不包含embedding) | #### 测试用例 | 用例编号 | 测试场景 | 请求参数 | 预期结果 | |---------|---------|---------|---------| | TC-012 | 语义搜索 | query="合同利率", topK=5 | 200,返回相关合同片段 | | TC-013 | 空查询 | 不传query | 400,提示"查询文本不能为空" | | TC-014 | 指定topK | query="贷款", topK=3 | 200,返回最多3条结果 | | TC-015 | 无匹配结果 | query="不存在的特定内容" | 200,返回空数组[] | | TC-016 | 中文模糊搜索 | query="多少钱" | 200,返回包含金额信息的片段 | --- ### 5. 混合搜索接口 #### 基本信息 - **接口名称**: 混合搜索(向量 + 业务过滤) - **接口路径**: `/api/v1/search/hybrid` - **请求方法**: `POST` - **Content-Type**: `application/json` #### 功能说明 结合向量搜索和业务字段过滤,先进行 KNN 搜索,再根据指定的业务字段过滤结果。 #### 请求参数 | 参数名 | 类型 | 必填 | 说明 | 示例值 | 默认值 | |-------|------|------|------|--------|-------| | query | String | 是 | 查询文本 | "贷款利率和还款方式" | - | | topK | Integer | 否 | 返回结果数量 | 10 | 10 | | filters | Map | 否 | **动态过滤条件,支持任意字段** | 见下方示例 | - | #### filters 字段说明 **重要**: `filters` 是完全动态的,可以根据入库时的 metadata 任意过滤! **合同过滤示例**: ```json { "contractType": "消费贷贷款合同", "partyA": "A公司" } ``` **音频过滤示例**: ```json { "speaker": "张三", "language": "zh-CN" } ``` **视频过滤示例**: ```json { "resolution": "1920x1080", "codec": "H.264" } ``` #### 请求示例 **示例 1: 合同过滤** ```bash curl -X POST http://localhost:8084/api/v1/search/hybrid \ -H "Content-Type: application/json" \ -d '{ "query": "贷款利率和还款方式", "topK": 10, "filters": { "contractType": "消费贷贷款合同", "partyA": "A公司" } }' ``` **示例 2: 音频过滤** ```bash curl -X POST http://localhost:8084/api/v1/search/hybrid \ -H "Content-Type: application/json" \ -d '{ "query": "会议讨论的重点内容", "topK": 5, "filters": { "speaker": "张三", "language": "zh-CN" } }' ``` **示例 3: 视频过滤** ```bash curl -X POST http://localhost:8084/api/v1/search/hybrid \ -H "Content-Type: application/json" \ -d '{ "query": "培训课程的核心要点", "topK": 10, "filters": { "resolution": "1920x1080", "codec": "H.264" } }' ``` #### 响应示例 **成功响应** - 200 OK ```json [ { "docId": "test-doc-001", "chunkId": "test-doc-001_chunk_0", "chunkIndex": 0, "content": "永续贷产品贷款合同\n\n第二章:贷款条款\n2.1 贷款利率按照央行基准利率执行。\n2.2 贷款期限为36个月。\n2.3 还款方式为等额本息。", "score": 0.8512345, "metadata": { "contract_type": "消费贷贷款合同", "party_a": "A公司", "party_b": "B公司", "contract_amount": 1000000.0 } } ] ``` **无匹配结果** - 200 OK ```json [] ``` #### 测试用例 | 用例编号 | 测试场景 | 请求参数 | 预期结果 | |---------|---------|---------|---------| | TC-017 | 合同字段过滤 | query="贷款利率", filters={contractType:"消费贷",partyA:"A公司"} | 200,返回A公司的消费贷合同 | | TC-018 | 音频字段过滤 | query="会议记录", filters={speaker:"张三"} | 200,返回张三发言的音频 | | TC-019 | 视频字段过滤 | query="课程", filters={resolution:"1920x1080"} | 200,返回高清视频 | | TC-020 | 无匹配过滤 | query="利率", filters={contractType:"不存在的类型"} | 200,返回空数组[] | | TC-021 | 无过滤条件 | query="合同", 不传filters | 200,等同于普通向量搜索 | --- ### 6. 查询文档接口 #### 基本信息 - **接口名称**: 查询文档的所有chunks - **接口路径**: `/api/v1/documents/{docId}` - **请求方法**: `GET` - **Content-Type**: 无需设置 #### 请求参数 | 参数名 | 类型 | 必填 | 说明 | 示例值 | |-------|------|------|------|--------| | docId | String | 是 | 文档ID(路径参数) | "contract-001" | #### 请求示例 ```bash curl -X GET http://localhost:8084/api/v1/documents/contract-001 ``` #### 响应示例 **成功响应** - 200 OK ```json [ { "docId": "contract-001", "chunkId": "contract-001_chunk_0", "chunkIndex": 0, "content": "永续贷产品贷款合同\n\n第一章:总则\n本合同由甲方A公司与乙方B公司签订。", "filePath": "/data/contracts/contract-001.pdf", "fileType": "pdf", "createTime": "2026-03-12 17:10:15", "updateTime": "2026-03-12 17:10:15", "extendedFields": { "contractType": "消费贷贷款合同", "partyA": "A公司", "partyB": "B公司" } } ] ``` **文档不存在** - 200 OK ```json [] ``` #### 测试用例 | 用例编号 | 测试场景 | 请求参数 | 预期结果 | |---------|---------|---------|---------| | TC-022 | 查询存在的文档 | docId="contract-001" | 200,返回文档的所有chunks | | TC-023 | 查询不存在的文档 | docId="non-existent" | 200,返回空数组[] | --- ### 7. 删除文档接口 #### 基本信息 - **接口名称**: 删除文档的所有chunks - **接口路径**: `/api/v1/documents/{docId}` - **请求方法**: `DELETE` - **Content-Type**: 无需设置 #### 请求参数 | 参数名 | 类型 | 必填 | 说明 | 示例值 | |-------|------|------|------|--------| | docId | String | 是 | 文档ID(路径参数) | "contract-001" | #### 请求示例 ```bash curl -X DELETE http://localhost:8084/api/v1/documents/contract-001 ``` #### 响应示例 **成功响应** - 200 OK ```json { "success": true, "docId": "contract-001", "deletedCount": 1, "message": "删除成功" } ``` **文档不存在** - 200 OK ```json { "success": true, "docId": "non-existent-doc", "deletedCount": 0, "message": "删除成功" } ``` #### 测试用例 | 用例编号 | 测试场景 | 请求参数 | 预期结果 | |---------|---------|---------|---------| | TC-024 | 删除存在的文档 | docId="contract-001" | 200,deletedCount>0 | | TC-025 | 删除不存在的文档 | docId="non-existent" | 200,deletedCount=0 | --- ### 8. 删除Chunk接口 #### 基本信息 - **接口名称**: 删除单个chunk - **接口路径**: `/api/v1/documents/chunk/{chunkId}` - **请求方法**: `DELETE` - **Content-Type**: 无需设置 #### 请求参数 | 参数名 | 类型 | 必填 | 说明 | 示例值 | |-------|------|------|------|--------| | chunkId | String | 是 | 分片ID(路径参数) | "contract-001_chunk_0" | #### 请求示例 ```bash curl -X DELETE http://localhost:8084/api/v1/documents/chunk/contract-001_chunk_0 ``` #### 响应示例 **成功响应** - 200 OK ```json { "success": true, "chunkId": "contract-001_chunk_0", "message": "删除成功" } ``` **chunk不存在** - 200 OK ```json { "success": false, "chunkId": "non-existent-chunk", "message": "删除失败" } ``` #### 测试用例 | 用例编号 | 测试场景 | 请求参数 | 预期结果 | |---------|---------|---------|---------| | TC-026 | 删除存在的chunk | chunkId="contract-001_chunk_0" | 200,success=true | | TC-027 | 删除不存在的chunk | chunkId="non-existent-chunk" | 200,success=false | --- ## 🔒 错误码说明 ### HTTP 状态码 | 状态码 | 说明 | |-------|------| | 200 | 请求成功 | | 400 | 请求参数错误 | | 500 | 服务器内部错误 | ### 业务错误码 | 错误码 | 说明 | 示例 | |-------|------|------| | 400 | 参数校验失败 | 缺少必填字段、字段格式错误 | ### 错误响应格式 ```json { "code": 400, "success": false, "message": "参数校验失败", "errors": { "fieldName": "具体错误信息" }, "timestamp": 1773306699906 } ``` --- ## 📊 数据模型 ### Elasticsearch 索引结构 本系统使用 **ES动态映射(DynamicMapping.True)**,索引结构如下: #### 固定字段(必须显式定义) | 字段名 | 类型 | 说明 | |-------|------|------| | doc_id | keyword | 文档唯一标识 | | chunk_id | keyword | 分片唯一标识 | | chunk_index | long | 分片序号 | | content | text | 文档内容(支持全文搜索) | | embedding | dense_vector | 4096维向量(用于KNN搜索) | | create_time | date | 创建时间 | | update_time | date | 更新时间 | #### 动态字段(自动识别) 除上述固定字段外,**所有其他字段都是动态的**,包括: - 文件元数据:file_path, file_size, file_type 等 - 业务元数据:任意自定义字段(通过 metadata 传入) - ES会根据传入值自动推断类型:字符串→text/keyword,数字→long/double,日期→date等 **示例**:传入以下 metadata: ```json { "contractType": "贷款合同", "partyA": "A公司", "contractAmount": 1000000, "signDate": "2026-01-15" } ``` ES会自动创建并索引这些字段,无需修改代码。 ### IndexRequest(文档入库请求) ```json { "docId": "string (必填)", "fileName": "string (可选)", "fullText": "string (必填)", "filePath": "string (可选)", "fileSize": "long (可选)", "fileType": "string (可选)", "metadata": { "任意业务字段": "任意值(完全动态)" } } ``` ### SearchRequest(搜索请求) ```json { "query": "string (必填)", "topK": "integer (可选, 默认10)", "filters": { "任意字段": "任意值(完全动态)" } } ``` ### SearchResult(搜索结果) ```json { "docId": "string", "chunkId": "string", "chunkIndex": "integer", "content": "string", "score": "float", "metadata": { "所有文档元数据字段(不包含embedding)" } } ``` **注意**: metadata 中不包含 `embedding` 字段,以节省带宽。 --- ## 🧪 完整测试用例清单 ### 测试环境要求 - ✅ Elasticsearch 8.x 运行正常 - ✅ Embedding API 服务可用 - ✅ 应用服务运行在 http://localhost:8084 ### 执行测试 ```bash # 运行完整测试套件 bash test_api.sh # 查看测试结果 cat api_test_results.txt ``` ### 测试用例总览 | 模块 | 用例数 | 涵盖场景 | |------|-------|---------| | 健康检查 | 1 | 服务状态检查 | | 文档入库 | 6 | 正常入库、参数校验、多数据类型、动态字段 | | 批量入库 | 4 | 正常批量、空列表、大批量、部分失败 | | 向量搜索 | 5 | 语义搜索、空查询、指定数量、无结果 | | 混合搜索 | 5 | 合同过滤、音频过滤、视频过滤、多条件 | | 文档管理 | 5 | 查询、删除文档和chunk | | **合计** | **26** | **覆盖所有核心场景** | --- ## 📝 附录 ### A. 快速开始 #### 1. 启动服务 ```bash # 启动应用 java -jar schedule-embedding-api.jar # 或使用 Maven mvn spring-boot:run ``` #### 2. 验证服务 ```bash curl http://localhost:8084/actuator/health ``` #### 3. 测试文档入库 ```bash curl -X POST http://localhost:8084/api/v1/documents/index \ -H "Content-Type: application/json" \ -d '{ "docId": "test-001", "fullText": "测试文档内容" }' ``` #### 4. 测试向量搜索 ```bash curl -X POST http://localhost:8084/api/v1/search \ -H "Content-Type: application/json" \ -d '{ "query": "测试", "topK": 5 }' ``` ### B. 常见问题 #### Q1: 为什么向量搜索返回空数组? **A**: 可能的原因: 1. ES 中还没有相关文档,先执行文档入库 2. 查询文本与现有文档语义差异较大 3. ES 索引延迟,等待几秒后重试 #### Q2: 如何提高搜索准确度? **A**: 建议: 1. 入库时提供完整的文档内容 2. 使用与文档风格相似的查询文本 3. 调整 topK 参数获取更多结果 4. 使用混合搜索添加业务过滤条件 #### Q3: 批量入库有限制吗? **A**: - 单次批量请求建议不超过 100 个文档 - 超长文本会自动分片处理 - 建议分批次大批量数据 #### Q4: metadata 支持哪些字段? **A**: - **支持任意自定义字段**,完全动态化 - 合同类:contractType, partyA, partyB, contractAmount 等 - 音频类:duration, speaker, language, sampleRate 等 - 视频类:resolution, frameRate, codec, duration 等 - 图片类:width, height, format, dpi 等 - 任意其他自定义字段 #### Q5: 新增字段需要修改代码吗? **A**: - **完全不需要**! - 直接在 metadata 中添加任意字段即可 - 系统会自动识别、存储、索引 - 搜索时也可以直接使用新字段过滤 ### C. 性能指标 | 指标 | 数值 | 说明 | |------|------|------| | 单文档入库 | < 2s | 包含向量化时间 | | 批量入库(10个) | < 5s | 并发处理 | | 向量搜索 | < 1s | topK=10 | | 混合搜索 | < 1.5s | 包含过滤 | | 向量维度 | 4096 | Qwen3-Embedding-8B | | 响应大小优化 | ~16KB/结果 | 移除embedding字段 | ### D. 设计优势 ### 1. ES动态映射(DynamicMapping) 本系统使用 Elasticsearch 的 **动态映射** 功能,实现真正的零代码扩展: ```java // 创建索引时启用动态映射 .mappings(m -> m .dynamic(DynamicMapping.True) // 关键配置! .properties("doc_id", p -> p.keyword(k -> k)) .properties("chunk_id", p -> p.keyword(k -> k)) // ... 核心字段 // 其他字段自动识别! ) ``` **效果**: - 传入任意 metadata 字段,ES 自动创建索引 - 自动推断字段类型(字符串、数字、日期等) - 无需修改代码,新增字段即生效 ### 2. 完全动态化(代码层面) **旧设计**: ```java // 每个字段都要判断 if (metadata.containsKey("contractType")) { doc.setContractType((String) metadata.get("contractType")); } if (metadata.containsKey("duration")) { doc.setDuration((Integer) metadata.get("duration")); } // ... 无穷无尽的 if ``` **新设计**: ```java // 所有字段自动处理,只有 1 行代码! doc.addExtendedFields(request.getMetadata()); ``` ### 3. 类型无关 - ✅ 合同文档、音频、视频、图片等任意类型 - ✅ 每种类型有自己独特的业务字段 - ✅ 无需为每种类型定义不同的实体类 ### 4. 零代码扩展 | 操作 | 旧设计 | 新设计 | |------|-------|--------| | 新增合同字段 | 修改 ES Mapping + 代码 | 直接在 metadata 加字段 | | 新增音频字段 | 修改 ES Mapping + 代码 | 直接在 metadata 加字段 | | 新增视频字段 | 修改 ES Mapping + 代码 | 直接在 metadata 加字段 | | 新增任意字段 | 修改 ES Mapping + 代码 | 直接在 metadata 加字段 | ### E. 联系方式 - **项目地址**: /Users/Vova/Gitee/four-level-schedule/schedule-embedding-api - **测试脚本**: test_api.sh(基础测试), test_complete.sh(完整功能测试) - **数据模型文档**: 数据模型设计文档.md --- ## 📝 实际使用示例 基于解析结果示例材料的典型入库请求: ### 示例1:银行流水文档 ```bash curl -X POST http://localhost:8084/api/v1/documents/index \ -H "Content-Type: application/json" \ -d '{ "docId": "bank-flow-001", "fileName": "111111133.png", "fullText": "账户明细...交易记录...", "filePath": "/data/files/20260313_8f9e7d6c5b4a.png", "fileSize": 102400, "fileType": "png", "metadata": { "file_unique_id": "20260313_8f9e7d6c5b4a", "business_topic": "金融-信贷审批", "document_type": "银行流水", "belong_department": "风控部", "tags": ["信贷", "流水", "合规", "农业"] } }' ``` ### 示例2:操作手册文档 ```bash curl -X POST http://localhost:8084/api/v1/documents/index \ -H "Content-Type: application/json" \ -d '{ "docId": "manual-001", "fileName": "宇信科技操作手册.docx", "fullText": "宇信科技管理数智化星云平台 快速入门操作手册...", "filePath": "/data/files/manual.docx", "fileSize": 2048000, "fileType": "docx", "metadata": { "business_topic": "金融-系统文件", "document_type": "操作手册", "belong_department": "产品部", "tags": ["金融", "企管", "星云", "操作手册"] } }' ``` ### 典型metadata字段说明 | 字段名 | 类型 | 说明 | 示例值 | |-------|------|------|--------| | file_unique_id | String | 文件唯一标识 | "20260313_8f9e7d6c5b4a" | | business_topic | String | 业务主题 | "金融-信贷审批" | | document_type | String | 文档类型 | "银行流水"、"操作手册"、"贷款合同" | | belong_department | String | 所属部门 | "风控部"、"信贷部"、"审计部" | | tags | Array | 标签数组 | ["信贷", "流水", "合规"] | ### 搜索示例 **向量搜索**: ```bash curl -X POST http://localhost:8084/api/v1/search \ -H "Content-Type: application/json" \ -d '{ "query": "银行流水交易记录", "topK": 5 }' ``` **混合搜索(按业务维度过滤)**: ```bash curl -X POST http://localhost:8084/api/v1/search/hybrid \ -H "Content-Type: application/json" \ -d '{ "query": "风险评估", "topK": 5, "filters": { "business_topic": "金融-风险管理", "belong_department": "风控部" } }' ``` --- **文档结束**