fix(service): 优化向量搜索超时与中断处理
新增 ListenableFuture 超时保护(10s),捕获中断与超时异常并恢复中断状态,提升高并发鲁棒性。
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package com.yolo.keyborad.service.impl;
|
package com.yolo.keyborad.service.impl;
|
||||||
|
|
||||||
import com.google.common.primitives.Floats;
|
import com.google.common.primitives.Floats;
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.yolo.keyborad.common.ErrorCode;
|
import com.yolo.keyborad.common.ErrorCode;
|
||||||
import com.yolo.keyborad.exception.BusinessException;
|
import com.yolo.keyborad.exception.BusinessException;
|
||||||
import com.yolo.keyborad.model.vo.QdrantSearchItem;
|
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) {
|
public List<QdrantSearchItem> searchPoint(float[] userVector, int limit) {
|
||||||
try {
|
try {
|
||||||
Points.QueryPoints query = Points.QueryPoints.newBuilder()
|
Points.QueryPoints query = Points.QueryPoints.newBuilder()
|
||||||
.setCollectionName(COLLECTION_NAME) // ★ 必须
|
.setCollectionName(COLLECTION_NAME) // ★ 必须
|
||||||
.setQuery(nearest(userVector)) // ★ 语义向量
|
.setQuery(nearest(userVector)) // ★ 语义向量
|
||||||
.setLimit(limit) // 限制返回数量
|
.setLimit(limit) // 限制返回数量
|
||||||
.setWithPayload(enable(true)) // ★ 带上 payload
|
.setWithPayload(enable(true)) // ★ 带上 payload
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
List<Points.BatchResult> batchResults = qdrantClient.queryBatchAsync(
|
// 使用 ListenableFuture,添加超时保护
|
||||||
|
ListenableFuture<List<Points.BatchResult>> future = qdrantClient.queryBatchAsync(
|
||||||
COLLECTION_NAME,
|
COLLECTION_NAME,
|
||||||
List.of(query)
|
List.of(query)
|
||||||
).get();
|
);
|
||||||
|
|
||||||
|
// 设置超时时间(10秒),避免无限等待
|
||||||
|
List<Points.BatchResult> batchResults = future.get(
|
||||||
|
10, java.util.concurrent.TimeUnit.SECONDS
|
||||||
|
);
|
||||||
Points.BatchResult batchResult = batchResults.get(0);
|
Points.BatchResult batchResult = batchResults.get(0);
|
||||||
|
|
||||||
// 3. 把 Protobuf 的 ScoredPoint 转成你的 DTO
|
// 3. 把 Protobuf 的 ScoredPoint 转成你的 DTO
|
||||||
@@ -129,10 +143,17 @@ public class QdrantVectorService {
|
|||||||
})
|
})
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
|
} catch (InterruptedException e) {
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
// 恢复中断状态,避免吞掉中断信号
|
||||||
log.error("search point 失败", e);
|
Thread.currentThread().interrupt();
|
||||||
throw new BusinessException(ErrorCode.OPERATION_ERROR);
|
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, "向量搜索执行失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user