fix: align vectorstore live retrieval
This commit is contained in:
@@ -106,7 +106,7 @@ public class VectorSearchService {
|
|||||||
result.setMetadata(toJson(document.getMetadata()));
|
result.setMetadata(toJson(document.getMetadata()));
|
||||||
result.setRawScore(document.getScore());
|
result.setRawScore(document.getScore());
|
||||||
result.setScoreLabel("similarity");
|
result.setScoreLabel("similarity");
|
||||||
result.setScore(toCompatibleL2Distance(document.getScore()));
|
result.setScore(toCompatibleL2Distance(document));
|
||||||
results.add(result);
|
results.add(result);
|
||||||
}
|
}
|
||||||
logger.info("Spring AI VectorStore search complete, candidates={}", results.size());
|
logger.info("Spring AI VectorStore search complete, candidates={}", results.size());
|
||||||
@@ -166,6 +166,14 @@ public class VectorSearchService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private float toCompatibleL2Distance(Document document) {
|
||||||
|
Double distance = extractDistance(document.getMetadata());
|
||||||
|
if (distance != null) {
|
||||||
|
return distance.floatValue();
|
||||||
|
}
|
||||||
|
return toCompatibleL2Distance(document.getScore());
|
||||||
|
}
|
||||||
|
|
||||||
private float toCompatibleL2Distance(Double similarity) {
|
private float toCompatibleL2Distance(Double similarity) {
|
||||||
if (similarity == null) {
|
if (similarity == null) {
|
||||||
return (float) maxL2Distance;
|
return (float) maxL2Distance;
|
||||||
@@ -174,6 +182,24 @@ public class VectorSearchService {
|
|||||||
return (float) ((1.0 - bounded) * maxL2Distance);
|
return (float) ((1.0 - bounded) * maxL2Distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Double extractDistance(Map<String, Object> metadata) {
|
||||||
|
if (metadata == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Object value = metadata.get("distance");
|
||||||
|
if (value instanceof Number number) {
|
||||||
|
return number.doubleValue();
|
||||||
|
}
|
||||||
|
if (value instanceof String text) {
|
||||||
|
try {
|
||||||
|
return Double.parseDouble(text);
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private String toJson(Map<String, Object> metadata) {
|
private String toJson(Map<String, Object> metadata) {
|
||||||
if (metadata == null || metadata.isEmpty()) {
|
if (metadata == null || metadata.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
@@ -196,8 +222,8 @@ public class VectorSearchService {
|
|||||||
private String content;
|
private String content;
|
||||||
/**
|
/**
|
||||||
* Compatibility score used by existing lookup relevance normalization.
|
* Compatibility score used by existing lookup relevance normalization.
|
||||||
* SDK mode keeps L2 distance; VectorStore mode maps similarity into a
|
* SDK mode keeps L2 distance; VectorStore mode prefers the Milvus
|
||||||
* L2-like distance using retrieval.normalization.max-l2-distance.
|
* distance metadata and falls back to similarity mapping.
|
||||||
*/
|
*/
|
||||||
private float score;
|
private float score;
|
||||||
private Double rawScore;
|
private Double rawScore;
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ spring:
|
|||||||
milvus:
|
milvus:
|
||||||
initialize-schema: false
|
initialize-schema: false
|
||||||
database-name: ${milvus.database}
|
database-name: ${milvus.database}
|
||||||
collection-name: business_knowledge
|
collection-name: biz
|
||||||
embedding-dimension: ${milvus.vector-dim}
|
embedding-dimension: ${milvus.vector-dim}
|
||||||
index-type: IVF_FLAT
|
index-type: IVF_FLAT
|
||||||
metric-type: L2
|
metric-type: L2
|
||||||
|
|||||||
@@ -67,6 +67,32 @@ class VectorSearchServiceTest {
|
|||||||
assertTrue(results.get(0).getMetadata().contains("spring.md"));
|
assertTrue(results.get(0).getMetadata().contains("spring.md"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void vectorStoreSearchUsesDistanceMetadataAsCompatibleScore() {
|
||||||
|
VectorStore vectorStore = mock(VectorStore.class);
|
||||||
|
ObjectProvider<VectorStore> provider = mock(ObjectProvider.class);
|
||||||
|
when(provider.getIfAvailable()).thenReturn(vectorStore);
|
||||||
|
when(vectorStore.similaritySearch(any(SearchRequest.class))).thenReturn(List.of(
|
||||||
|
Document.builder()
|
||||||
|
.id("spring-doc")
|
||||||
|
.text("spring content")
|
||||||
|
.metadata(Map.of("distance", 0.5659486, "category", "api"))
|
||||||
|
.score(0.4340514)
|
||||||
|
.build()
|
||||||
|
));
|
||||||
|
|
||||||
|
VectorSearchService service = new VectorSearchService();
|
||||||
|
setMode(service, "auto");
|
||||||
|
setVectorStore(service, provider);
|
||||||
|
|
||||||
|
List<VectorSearchService.SearchResult> results = service.searchSimilarDocuments("query", 3, null);
|
||||||
|
|
||||||
|
assertEquals(1, results.size());
|
||||||
|
assertEquals("similarity", results.get(0).getScoreLabel());
|
||||||
|
assertEquals(0.4340514, results.get(0).getRawScore(), 0.0001);
|
||||||
|
assertEquals(0.5659486f, results.get(0).getScore(), 0.0001);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void autoModeFallsBackToSdkWhenVectorStoreFails() {
|
void autoModeFallsBackToSdkWhenVectorStoreFails() {
|
||||||
VectorStore vectorStore = mock(VectorStore.class);
|
VectorStore vectorStore = mock(VectorStore.class);
|
||||||
|
|||||||
Reference in New Issue
Block a user