feat(phase1): 支持上传时指定文档类别

功能增强:
- DocumentController 新增 category 参数
  POST /api/documents/upload?category=api

- DocumentUploadRequest 新增 category 字段
  - 支持用户指定:api、domain、troubleshoot 等
  - 默认值:upload(未指定时)

- VectorIndexService.indexDocumentChunks 接收 category
  - 将用户指定的类别存入 Milvus metadata
  - metadata.category = 用户指定值 或 "upload"

使用示例:
```bash
# 上传 API 文档
curl -X POST /api/documents/upload \
  -F "file=@redis-api.md" \
  -F "category=api"

# 上传领域知识文档
curl -X POST /api/documents/upload \
  -F "file=@cache-theory.md" \
  -F "category=domain"

# 检索时按类别过滤
searchSimilarDocuments("Redis接口", 5, "api")
```

完整流程:
1. 文件索引:自动从路径提取(aiops-docs/api/ → "api")
2. 用户上传:从接口参数获取(category=api)
3. 检索时:可按类别过滤(category 参数)

编译验证:BUILD SUCCESS
This commit is contained in:
zhuyongxin
2026-06-23 16:43:47 +08:00
parent 075cc36270
commit 24101a8d66
4 changed files with 22 additions and 10 deletions
@@ -28,6 +28,7 @@ public class DocumentController {
@PostMapping("/upload")
public Result<String> uploadDocument(
@RequestParam("file") MultipartFile file,
@RequestParam(value = "category", required = false) String category,
@RequestParam(value = "faultCategory", required = false) String faultCategory,
@RequestParam(value = "faultSource", required = false) String faultSource,
@RequestParam(value = "apiName", required = false) String apiName,
@@ -38,6 +39,7 @@ public class DocumentController {
try {
DocumentUploadRequest request = DocumentUploadRequest.builder()
.file(file)
.category(category)
.faultCategory(faultCategory)
.faultSource(faultSource)
.apiName(apiName)
@@ -20,6 +20,11 @@ public class DocumentUploadRequest {
*/
private MultipartFile file;
/**
* 文档类别(api、domain、troubleshoot 等,默认 upload)
*/
private String category;
/**
* 故障类别(默认 EXTERNAL_API)
*/
@@ -110,11 +110,15 @@ public class DocumentManagementService {
// 6. 向量化并索引
try {
vectorIndexService.indexDocumentChunks(docId, chunks);
String category = request.getCategory();
if (category == null || category.isBlank()) {
category = "upload"; // 默认类别
}
vectorIndexService.indexDocumentChunks(docId, chunks, category);
document.setStatus("INDEXED");
document.setIndexedAt(LocalDateTime.now());
apiDocumentRepository.save(document);
log.info("文档索引完成,docId: {}", docId);
log.info("文档索引完成,docId: {}, 类别: {}", docId, category);
} catch (Exception e) {
log.error("文档索引失败,docId: {}", docId, e);
@@ -172,14 +172,15 @@ public class VectorIndexService {
*
* @param docId 文档ID
* @param chunks 文档分块列表
* @param category 文档类别(api、domain、troubleshoot 等)
* @throws Exception 索引失败时抛出异常
*/
public void indexDocumentChunks(String docId, List<DocumentChunk> chunks) throws Exception {
public void indexDocumentChunks(String docId, List<DocumentChunk> chunks, String category) throws Exception {
if (chunks == null || chunks.isEmpty()) {
throw new IllegalArgumentException("文档分块列表为空");
}
logger.info("开始索引文档分块,docId: {}, 分块数: {}", docId, chunks.size());
logger.info("开始索引文档分块,docId: {}, 分块数: {}, 类别: {}", docId, chunks.size(), category);
// 1. 删除该文档的旧数据(如果存在)
deleteDocumentChunks(docId);
@@ -192,8 +193,8 @@ public class VectorIndexService {
// 生成向量
List<Float> vector = embeddingService.generateEmbedding(chunk.getContent());
// 构建元数据(使用 docId 作为来源标识)
Map<String, Object> metadata = buildDocumentMetadata(docId, chunk, chunks.size());
// 构建元数据(使用 docId 和 category)
Map<String, Object> metadata = buildDocumentMetadata(docId, chunk, chunks.size(), category);
// 插入到 Milvus
insertToMilvus(chunk.getContent(), vector, metadata, chunk.getChunkIndex());
@@ -206,7 +207,7 @@ public class VectorIndexService {
}
}
logger.info("文档索引完成,docId: {}, 共 {} 个分块", docId, chunks.size());
logger.info("文档索引完成,docId: {}, 共 {} 个分块,类别: {}", docId, chunks.size(), category);
}
/**
@@ -252,7 +253,7 @@ public class VectorIndexService {
/**
* 构建文档元数据(用于上传文档)
*/
private Map<String, Object> buildDocumentMetadata(String docId, DocumentChunk chunk, int totalChunks) {
private Map<String, Object> buildDocumentMetadata(String docId, DocumentChunk chunk, int totalChunks, String category) {
Map<String, Object> metadata = new HashMap<>();
// 文档标识
@@ -268,8 +269,8 @@ public class VectorIndexService {
metadata.put("title", chunk.getTitle());
}
// 默认类别:上传文档
metadata.put("category", "upload");
// 文档类别
metadata.put("category", category != null && !category.isBlank() ? category : "upload");
return metadata;
}