multiLibraryVectorSearch 多知识库向量搜索
(eid int64, req *SearchRequest, configService *ChunkConfigService)
| 3331 | |
| 3332 | // multiLibraryVectorSearch 多知识库向量搜索 |
| 3333 | func (s *SearchService) multiLibraryVectorSearch(eid int64, req *SearchRequest, configService *ChunkConfigService) ([]SearchResultItem, error) { |
| 3334 | multiSearchStart := time.Now() |
| 3335 | logger.SysLogf("🔍 开始多知识库向量搜索 (eid=%d, libraries=%v)", eid, req.LibraryIDs) |
| 3336 | logger.SysDebugf("【向量检索】多库并发参数: eid=%d, query=%q, top_k=%d, libraries=%v, files=%v, chunk_types=%v", |
| 3337 | eid, truncateForDebug(req.Query, 256), req.TopK, |
| 3338 | previewInt64IDsForDebug(req.LibraryIDs, 50), previewInt64IDsForDebug(req.FileIDs, 50), req.ChunkTypes) |
| 3339 | |
| 3340 | // 检查 singleVectorSearchFn 是否被 mock(测试场景) |
| 3341 | // 如果被 mock,则走原来的流程(不预获取 embedding) |
| 3342 | if !isDefaultSingleVectorSearchFn() { |
| 3343 | // 测试场景:singleVectorSearchFn 被 mock,走原来的流程 |
| 3344 | return s.multiLibraryVectorSearchLegacy(eid, req, configService) |
| 3345 | } |
| 3346 | |
| 3347 | if configService == nil { |
| 3348 | configService = NewChunkConfigService(s.db) |
| 3349 | } |
| 3350 | |
| 3351 | // 预先获取企业全局配置和 embedding(只调用一次,避免多次调用 embedding API) |
| 3352 | configStart := time.Now() |
| 3353 | config, configErr := configService.GetConfig(eid, nil, model.ChunkTypeDefault) |
| 3354 | if configErr != nil { |
| 3355 | logger.SysLogf("❌ 获取企业全局配置失败: eid=%d, err=%v", eid, configErr) |
| 3356 | return nil, fmt.Errorf("获取企业全局配置失败: %v", configErr) |
| 3357 | } |
| 3358 | logger.SysDebugf("【向量检索】获取配置耗时: eid=%d, elapsed_ms=%d", eid, time.Since(configStart).Milliseconds()) |
| 3359 | |
| 3360 | if config.EmbeddingChannelID == nil { |
| 3361 | return nil, fmt.Errorf("未配置向量化渠道") |
| 3362 | } |
| 3363 | |
| 3364 | // 预先获取 embedding(多库并发搜索时,所有库共用同一个 embedding) |
| 3365 | embeddingStart := time.Now() |
| 3366 | queryVector64, embeddingErr := s.embedding.GetQueryEmbedding(eid, req.Query, *config.EmbeddingChannelID, config) |
| 3367 | if embeddingErr != nil { |
| 3368 | return nil, fmt.Errorf("生成查询向量失败: %v", embeddingErr) |
| 3369 | } |
| 3370 | logger.SysDebugf("【向量检索】获取Embedding耗时: eid=%d, channel_id=%d, elapsed_ms=%d, vector_dim=%d", |
| 3371 | eid, *config.EmbeddingChannelID, time.Since(embeddingStart).Milliseconds(), len(queryVector64)) |
| 3372 | |
| 3373 | // 转换向量格式 (float64 -> float32) |
| 3374 | queryVector := make([]float32, len(queryVector64)) |
| 3375 | for i, v := range queryVector64 { |
| 3376 | queryVector[i] = float32(v) |
| 3377 | } |
| 3378 | |
| 3379 | libraryMap, err := s.batchGetLibrariesByIDs(eid, req.LibraryIDs) |
| 3380 | if err != nil { |
| 3381 | logger.SysLogf("批量获取库信息失败: %v", err) |
| 3382 | } |
| 3383 | |
| 3384 | // 并发搜索各个知识库,先保留原始向量结果,随后统一富化,避免每个库重复查一轮 DB。 |
| 3385 | type libraryResult struct { |
| 3386 | libraryID int64 |
| 3387 | collection string |
| 3388 | vectorResults []vectorstore.SearchResult |
| 3389 | err error |
| 3390 | elapsedMs int64 |
no test coverage detected