fix(service): 优化向量搜索超时与中断处理

新增 ListenableFuture 超时保护(10s),捕获中断与超时异常并恢复中断状态,提升高并发鲁棒性。
This commit is contained in:
2025-12-12 13:24:03 +08:00
parent f391f9dfe1
commit b4c35b0df3

View File

@@ -1,6 +1,7 @@
package com.yolo.keyborad.service.impl;
import com.google.common.primitives.Floats;
import com.google.common.util.concurrent.ListenableFuture;
import com.yolo.keyborad.common.ErrorCode;
import com.yolo.keyborad.exception.BusinessException;
import com.yolo.keyborad.model.vo.QdrantSearchItem;
@@ -88,19 +89,32 @@ public class QdrantVectorService {
// }
// }
/**
* 搜索向量(高并发优化版本,避免阻塞线程池)
*
* @param userVector 用户输入的向量
* @param limit 返回结果数量限制
* @return 搜索结果列表
*/
public List<QdrantSearchItem> searchPoint(float[] userVector, int limit) {
try {
Points.QueryPoints query = Points.QueryPoints.newBuilder()
.setCollectionName(COLLECTION_NAME) // ★ 必须
.setQuery(nearest(userVector)) // ★ 语义向量
.setLimit(limit) // 限制返回数量
.setWithPayload(enable(true)) // ★ 带上 payload
.setWithPayload(enable(true)) // ★ 带上 payload
.build();
List<Points.BatchResult> batchResults = qdrantClient.queryBatchAsync(
// 使用 ListenableFuture添加超时保护
ListenableFuture<List<Points.BatchResult>> future = qdrantClient.queryBatchAsync(
COLLECTION_NAME,
List.of(query)
).get();
);
// 设置超时时间10秒避免无限等待
List<Points.BatchResult> batchResults = future.get(
10, java.util.concurrent.TimeUnit.SECONDS
);
Points.BatchResult batchResult = batchResults.get(0);
// 3. 把 Protobuf 的 ScoredPoint 转成你的 DTO
@@ -129,10 +143,17 @@ public class QdrantVectorService {
})
.toList();
} catch (InterruptedException | ExecutionException e) {
log.error("search point 失败", e);
throw new BusinessException(ErrorCode.OPERATION_ERROR);
} catch (InterruptedException e) {
// 恢复中断状态,避免吞掉中断信号
Thread.currentThread().interrupt();
log.error("search point 被中断", e);
throw new BusinessException(ErrorCode.OPERATION_ERROR, "向量搜索被中断");
} catch (java.util.concurrent.TimeoutException e) {
log.error("search point 超时", e);
throw new BusinessException(ErrorCode.OPERATION_ERROR, "向量搜索超时,请稍后重试");
} catch (ExecutionException e) {
log.error("search point 执行失败", e);
throw new BusinessException(ErrorCode.OPERATION_ERROR, "向量搜索执行失败");
}
}