From 6d6e078f8f8b0c7554d5f73de740b08b870606e6 Mon Sep 17 00:00:00 2001 From: Aayush Kataria Date: Wed, 14 May 2025 09:57:30 -0700 Subject: [PATCH 1/7] Adding weighted RRF changes --- .../cosmos/rx/HybridSearchQueryTest.java | 82 +++++++++++++++++++ .../cosmos/implementation/Constants.java | 3 +- ...idSearchDocumentQueryExecutionContext.java | 60 ++++++++++++-- .../implementation/query/QueryFeature.java | 3 +- .../query/QueryPlanRetriever.java | 3 +- .../hybridsearch/HybridSearchQueryInfo.java | 11 +++ 6 files changed, 150 insertions(+), 12 deletions(-) diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/HybridSearchQueryTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/HybridSearchQueryTest.java index ca0cd1e35864..ad210235b3a3 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/HybridSearchQueryTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/HybridSearchQueryTest.java @@ -149,6 +149,78 @@ public void hybridQueryTest() { validateResults(Arrays.asList("21", "75", "37", "24", "26", "35", "49", "87", "55", "9"), resultDocs); } + @Test(groups = {"query", "split"}, timeOut = TIMEOUT) + public void hybridQueryWeightedRRFTest(){ + // test case 1 + String query = "SELECT TOP 15 c.index AS Index, c.title AS Title, c.text AS Text FROM c " + + "WHERE FullTextContains(c.title, 'John') OR FullTextContains(c.text, 'John') OR FullTextContains(c.text, 'United States')" + + "ORDER BY RANK RRF(FullTextScore(c.title, ['John']), FullTextScore(c.text, ['United States']), [1, 1])"; + List resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() + .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) + .collectList().block(); + assertThat(resultDocs).hasSize(15); + validateResults( + Arrays.asList("61", "51", "49", "54", "75", "24", "77", "76", "80", "25", "22", "2", "66", "57", "85"), + Arrays.asList("61", "51", "49", "54", "75", "24", "77", "76", "80", "25", "22", "2", "66", "85", "57"), + resultDocs + ); + + // test case 2 + query = "SELECT TOP 15 c.index AS Index, c.title AS Title, c.text AS Text FROM c " + + "WHERE FullTextContains(c.title, 'John') OR FullTextContains(c.text, 'John') OR FullTextContains(c.text, 'United States')" + + "ORDER BY RANK RRF(FullTextScore(c.title, ['John']), FullTextScore(c.text, ['United States']), [10, 10])"; + resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() + .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) + .collectList().block(); + assertThat(resultDocs).hasSize(15); + validateResults( + Arrays.asList("61", "51", "49", "54", "75", "24", "77", "76", "80", "25", "22", "2", "66", "57", "85"), + Arrays.asList("61", "51", "49", "54", "75", "24", "77", "76", "80", "25", "22", "2", "66", "85", "57"), + resultDocs + ); + + // test case 3 + query = "SELECT TOP 10 c.index AS Index, c.title AS Title, c.text AS Text FROM c " + + "WHERE FullTextContains(c.title, 'John') OR FullTextContains(c.text, 'John') OR FullTextContains(c.text, 'United States')" + + "ORDER BY RANK RRF(FullTextScore(c.title, ['John']), FullTextScore(c.text, ['United States']), [0.1, 0.1])"; + resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() + .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) + .collectList().block(); + assertThat(resultDocs).hasSize(10); + validateResults( + Arrays.asList("61", "51", "49", "54", "75", "24", "77", "76", "80", "25"), + resultDocs + ); + + // test case 4 + query = "SELECT TOP 10 c.index AS Index, c.title AS Title, c.text AS Text FROM c " + + "WHERE FullTextContains(c.title, 'John') OR FullTextContains(c.text, 'John') OR FullTextContains(c.text, 'United States')" + + "ORDER BY RANK RRF(FullTextScore(c.title, ['John']), FullTextScore(c.text, ['United States']), [-1, -1])"; + resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() + .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) + .collectList().block(); + assertThat(resultDocs).hasSize(15); + validateResults( + Arrays.asList("85", "57", "66", "2", "22", "25", "77", "76", "80", "75", "24", "49", "54", "51", "81"), + Arrays.asList("57", "85", "2", "66", "22", "25", "80", "76", "77", "24", "75", "54", "49", "51", "61"), + resultDocs + ); + + // test case 5 + String vector = getQueryVector(); + query = String.format("SELECT c.index, c.title FROM c " + + "ORDER BY RANK RRF(FullTextScore(c.text, ['United States']), VectorDistance(c.vector, [%s]), [1,1]) " + + "OFFSET 0 LIMIT 10", vector); + resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() + .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) + .collectList().block(); + assertThat(resultDocs).hasSize(10); + validateResults( + Arrays.asList("51", "54", "28", "70", "24", "61", "56", "26", "58", "77"), + resultDocs + ); + } + @Test(groups = {"query", "split"}, timeOut = TIMEOUT) public void wrongHybridQueryTest() { String query = ""; @@ -258,6 +330,16 @@ private void validateResults(List actualIds, List results) { assertThat(resultsIds).isEqualTo(actualIds); } + private void validateResults(List expectedOrder1, List expectedOrder2, List results) { + assertThat(results).isNotNull(); + + List resultsIds = results.stream().map(Document::getId).collect(Collectors.toList()); + assertThat(resultsIds).satisfiesAnyOf( + actual -> assertThat(actual).isEqualTo(expectedOrder1), + actual -> assertThat(actual).isEqualTo(expectedOrder2) + ); + } + public static String getQueryVector() { return "0.02, 0, -0.02, 0, -0.04, -0.01, -0.04, -0.01, 0.06, 0.08, -0.05, -0.04, -0.03, 0.05, -0.03, 0, -0.03, 0, 0.05, 0, 0.03,0.02, 0, 0.04, 0.05, 0.03, 0, 0, 0, -0.03, -0.01, 0.01, 0, -0.01, -0.03, -0.02, -0.05, 0.01, 0, 0.01, 0, 0.01, -0.03, -0.02, 0.02, 0.02, 0.04, 0.01, 0.04, 0.02, -0.01, -0.01, 0.02, 0.01, 0.02, -0.04, -0.01, 0.06, -0.01, -0.03, -0.04, -0.01, -0.01, 0, 0.03, -0.02, 0.03, 0.05, 0.01, 0.04, 0.05, -0.05, -0.01, 0.03, 0.02, -0.02, 0, -0.02, -0.02, -0.04, 0.01, -0.05, 0.01, 0.05, 0, -0.02, 0.03, -0.07, 0.05, 0.02, 0.03, 0.05, 0.05, -0.01, 0.03, -0.08, -0.01, -0.03, 0.04, -0.01, -0.02, -0.01, -0.02, -0.03, 0.03, 0.03,-0.04, 0.04, 0.02, 0, 0.03, -0.02, -0.04, 0.02, 0.01, 0.02, -0.01, 0.03, 0.02, 0.01, -0.02, 0, 0.02, 0, -0.01, 0.02, -0.05, 0.03, 0.03, 0.04, -0.02, 0.04, -0.04, 0.03, 0.03, -0.03, 0, 0.02, 0.06, 0.02, 0.02, -0.01, 0.03, 0, -0.03, -0.06, 0.02, 0, 0.02, -0.04,-0.05, 0.01, 0.02, 0.02, 0.07, 0.05, -0.01, 0.03, -0.03, -0.06, 0.04, 0.01, -0.01, 0.04, 0.02, 0.03, -0.03, 0.03, -0.01, 0.03, -0.04, -0.02, 0.02, -0.02, -0.03, -0.02, 0.02, -0.01, -0.05, -0.07, 0.02, -0.01, 0, -0.01, -0.02, -0.02, -0.03, -0.03, 0, -0.08, -0.01,0, -0.01, -0.03, 0.01, 0, -0.02, -0.03, -0.04, -0.01, 0.02, 0, 0, -0.04, 0.04, -0.01, 0.04, 0, -0.06, 0.02, 0.03, 0.01, 0.06, -0.02, 0, 0.01, 0.01, 0.01, 0, -0.02, 0.03, 0.02, 0.01, -0.01, -0.05, 0.03, -0.04, 0, 0.01, -0.02, -0.04, 0.02, 0, 0.09, -0.04, -0.01,0.02, 0.01, -0.03, 0.04, 0.02, -0.02, -0.02, -0.01, 0.01, -0.04, -0.01, 0.02, 0, 0, 0.07, 0.02, 0, 0, -0.01, 0.01, 0.03, -0.02, 0, 0.03, -0.02, -0.07, -0.04, -0.03, 0, -0.03, -0.02, 0, -0.02, -0.02, -0.05, -0.02, 0, 0.05, 0.01, -0.01, -0.04, 0.02, 0, 0, 0.03,0.02, -0.03, -0.01, -0.02, 0.06, -0.02, 0.01, 0.01, 0.04, -0.04, 0.06, -0.02, 0.01, 0.03, 0.01, 0.02, -0.02, 0.01, -0.04, 0.05, -0.03, 0.01, -0.01, 0, -0.03, -0.03, 0.04, 0.02, -0.03, -0.03, -0.02, 0.06, 0.04, -0.01, 0.01, 0.01, -0.01, -0.02, -0.02, 0.04, 0.01,-0.01, 0.01, -0.01, 0, 0.01, -0.04, 0.01, 0, -0.04, 0.05, 0.01, 0.01, 0.09, -0.04, -0.02, 0.04, 0, 0.04, -0.04, -0.04, 0, 0, -0.01, 0.05, -0.01, 0.02, 0.01, -0.03, 0, -0.06, 0.02, 0.04, 0.01, 0.03, 0.01, -0.04, 0, 0.01, 0.05, 0.02, -0.02, 0.02, 0, -0.02, -0.04,-0.07, -0.02, -0.05, 0.06, 0.01, 0.02, -0.03, 0.06, -0.01, -0.02, -0.02, -0.01, 0, -0.05, 0.06, -0.05, 0, -0.02, -0.02, 0, -0.01, 0.01, 0, -0.01, 0.05, 0.02, 0, 0.02, -0.02, 0.02, 0, 0.08, -0.02, 0.01, -0.03, 0.02, -0.03, 0, -0.01, -0.02, -0.04, 0.06, 0.01,-0.03, -0.03, 0.01, -0.01, 0.01, -0.01, 0.02, -0.03, 0.03, 0.04, 0.02, -0.02, 0.04, 0.01, 0.01, 0.02, 0.01, 0, -0.03, 0.03, -0.02, -0.03, -0.02, 0.02, 0, -0.01, -0.02, -0.02, 0, -0.01, -0.03, 0.02, -0.01, 0.01, -0.08, 0.01, -0.04, -0.05, 0.02, -0.01, -0.03,0.02, 0.01, -0.03, 0.01, 0.02, 0.03, 0.04, -0.04, 0.02, 0, 0.02, 0.02, 0.04, -0.04, -0.1, 0, 0.05, -0.01, 0.03, 0.05, 0.03, -0.02, 0.01, 0.02, -0.05, 0.01, 0, 0.05, -0.01, 0.03, -0.01, 0, 0.04, 0, 0, 0.08, 0.01, 0, -0.04, -0.03, 0, -0.02, -0.01, 0.02, 0.03,0, -0.01, 0, 0, 0, 0.06, 0, 0, 0.01, -0.01, 0.01, 0.04, 0.07, -0.01, 0.01, 0, -0.01, -0.02, 0.01, 0.01, 0, 0.02, 0.01, 0, -0.02, 0.03, 0.02, 0.06, 0.02, -0.01, 0.03, 0.02, -0.02, 0.01, -0.01, 0.03, 0.05, 0.02, 0.01, 0, 0, 0.01, 0.03, -0.03, -0.01, -0.04, 0.03,-0.02, 0.02, -0.02, -0.01, -0.02, 0.01, -0.04, 0.01, -0.04, 0.03, -0.02, -0.02, -0.01, -0.01, 0.07, 0.04, -0.01, 0.08, -0.04, -0.04, 0, 0, -0.01, -0.01, 0.03, -0.04, 0.02, -0.01, -0.04, 0.02, -0.07, -0.02, 0.02, -0.01, 0.02, 0.01, 0, 0.07, -0.01, 0.03, 0.01,-0.05, 0.02, 0.02, -0.01, 0.02, 0.02, -0.03, -0.02, 0.03, -0.01, 0.02, 0, 0, 0.02, -0.01, -0.02, 0.05, 0.02, 0.01, 0.01, -0.03, -0.05, -0.03, 0.01, 0.03, -0.02, -0.01, -0.01, -0.01, 0.03, -0.01, -0.03, 0.02, -0.02, -0.03, -0.02, -0.01, -0.01, -0.01, 0, -0.01,-0.04, -0.02, -0.02, -0.03, 0.04, 0.03, 0, -0.02, -0.01, -0.03, -0.01, -0.04, -0.04, 0.02, 0.01, -0.05, 0.04, -0.03, 0.01, -0.01, -0.03, 0.01, 0.01, 0.01, 0.02, -0.01, -0.02, -0.03, -0.01, -0.01, -0.01, -0.01, -0.03, 0, 0.01, -0.02, -0.01, -0.01, 0.01, 0, -0.04,0.01, -0.01, 0.02, 0, 0, -0.01, 0, 0, 0.03, -0.01, -0.06, -0.04, -0.01, 0, 0.02, -0.05, -0.02, 0.02, -0.01, 0.01, 0.01, -0.01, -0.02, 0, 0.02, -0.01, -0.02, 0.04, -0.01, 0, -0.02, -0.04, -0.03, -0.03, 0, 0.03, -0.01, -0.02, 0, 0.01, -0.01, -0.04, 0.01, -0.03,0.01, 0.03, 0, -0.02, 0, -0.04, -0.02, -0.02, 0.03, -0.02, 0.05, 0.02, 0.03, -0.02, -0.05, -0.01, 0.02, -0.04, 0.02, 0.01, -0.03, 0.01, 0.02, 0, 0.04, 0, -0.01, 0.02, 0.01, 0.02, 0.02, -0.02, 0.04, -0.01, 0, -0.01, 0, 0.01, -0.02, -0.04, 0.06, 0.01, 0, 0.01,-0.02, 0.02, 0.05, 0, 0.03, -0.02, 0.02, -0.03, -0.02, 0.01, 0, 0.06, -0.01, 0, -0.02, -0.02, 0.01, -0.01, 0, -0.03, 0.02, 0, -0.01, -0.02, -0.01, 0.03, -0.03, 0, 0, 0, -0.03, -0.06, 0.04, 0.02, -0.03, -0.06, -0.03, -0.01, -0.03, -0.02, -0.04, 0.01, 0, -0.01,0.02, -0.01, 0.03, 0.02, -0.02, -0.01, -0.02, -0.03, -0.01, 0.01, -0.04, 0.04, 0.03, 0.02, 0, -0.07, -0.02, -0.01, 0, 0.03, -0.01, -0.03, 0, 0.03, 0, -0.01, 0.02, 0.01, 0.02, -0.03, 0, 0.01, -0.02, 0.04, -0.04, 0, -0.05, 0, -0.02, -0.01, 0.03, 0.01, 0, -0.02,0, -0.05, 0.01, -0.01, 0, -0.08, -0.01, -0.02, 0.02, 0.01, -0.01, -0.01, -0.01, 0, 0, -0.01, -0.03, 0, 0, -0.02, 0.05, -0.03, 0.02, 0.01, -0.02, 0.01, 0.01, 0, 0.01, -0.01, 0, -0.04, -0.06, 0.03, -0.02, 0, -0.02, 0.01, 0.03, 0.03, -0.03, -0.01, 0, 0, 0.01,-0.02, -0.01, -0.01, -0.03, -0.02, 0.03, -0.02, 0.03, 0.01, 0.04, -0.04, 0.02, 0.02, 0.02, 0.03, 0, 0.06, -0.01, 0.02, -0.01, 0.01, -0.01, -0.01, -0.03, -0.01, 0.02, 0.01, 0.01, 0, -0.02, 0.03, 0.02, -0.01, -0.02, 0.01, 0.01, 0.04, -0.01, -0.05, 0, -0.01, 0,0.03, -0.01, 0.02, 0.02, -0.04, 0.01, -0.03, -0.02, 0, 0.02, 0, -0.01, 0.02, 0.01, 0.04, -0.04, 0, -0.01, -0.02, 0, -0.02, 0.01, -0.02, 0, 0, 0.03, 0.04, -0.01, 0, 0, 0.03, -0.02, 0.01, -0.02, 0, -0.03, 0.04, 0, 0.01, 0.04, 0, 0.03, -0.02, 0.01, 0.01, -0.02,0.02, -0.05, 0.03, -0.02, -0.01, 0.01, -0.01, 0.02, 0.04, 0.02, 0, -0.02, 0.02, -0.01, -0.03, -0.06, -0.01, -0.01, -0.04, 0.01, -0.01, -0.01, -0.01, -0.02, 0.03, -0.03, 0.05, 0, -0.01, -0.03, 0.03, 0.01, -0.01, -0.01, 0, 0.01, 0.01, 0.02, -0.01, 0.02, -0.02,-0.03, 0.03, -0.02, 0.01, 0, -0.03, 0.02, 0.02, -0.02, 0.01, 0.02, -0.01, 0.02, 0, 0.02, 0.01, 0, 0.05, -0.03, 0.01, 0.03, 0.04, 0.01, 0.01, -0.01, 0.02, -0.03, 0.02, 0.01, 0, -0.01, -0.03, -0.01, 0.02, 0.03, 0, 0.03, 0.02, 0, 0.01, 0.01, 0.02, 0.01, 0.02, 0.03,0.01, -0.03, 0.02, 0.01, 0.02, 0.03, -0.01, 0.01, -0.03, -0.01, -0.02, 0.01, 0, 0, -0.01, -0.02, -0.01, -0.01, 0.01, 0.06, 0.01, 0, -0.01, 0.01, 0, 0, -0.01, -0.01, 0, -0.02, -0.02, -0.01, -0.02, -0.01, -0.05, -0.02, 0.03, 0.02, 0, 0.03, -0.03, -0.03, 0.03, 0,0.02, -0.03, 0.04, -0.04, 0, -0.04, 0.04, 0.01, -0.03, 0.01, -0.02, -0.01, -0.04, 0.02, -0.01, 0.01, 0.01, 0.02, -0.02, 0.03, -0.01, 0, 0.01, 0, 0.02, 0.01, 0.01, 0.03, -0.06, 0.02, 0, -0.02, 0, 0.04, -0.03, 0, 0, -0.02, 0.06, 0.01, -0.03, -0.02, -0.01, -0.03,-0.04, 0.04, 0.03, -0.02, 0, 0.03, -0.04, -0.01, -0.02, -0.02, -0.01, 0.02, 0.02, 0.01, 0.01, 0.01, -0.02, -0.02, -0.03, -0.01, 0.01, 0, 0, 0, 0.02, -0.04, -0.01, -0.01, 0.04, -0.01, 0.01, -0.01, 0.01, -0.03, 0.01, -0.01, 0, -0.01, 0.01, 0, 0.01, -0.04, 0.01, 0,0, 0, 0, 0.02, 0.04, 0.01, 0.01, -0.01, -0.02, 0, 0, 0.01, -0.01, 0.01, -0.01, 0, 0.04, -0.01, -0.02, -0.01, -0.01, -0.01, 0, 0, 0.01, 0.01, 0.04, -0.01, -0.01, 0, -0.03, -0.01, 0.01, -0.01, -0.02, 0.01, -0.02, 0.01, -0.03, 0.02, 0, 0.03, 0.01, -0.03, -0.01,-0.01, 0.02, 0.01, 0, -0.01, 0.03, -0.04, 0.01, -0.01, -0.03, -0.02, 0.02, -0.01, 0, -0.01, 0.02, 0.02, 0.01, 0.03, 0, -0.03, 0, 0.02, -0.03, -0.01, 0.01, 0.06, -0.01, -0.02, 0.01, 0, 0.04, -0.04, 0.01, -0.02, 0, -0.04, 0, 0.02, 0.02, -0.02, 0.04, -0.01, 0.01,0, 0.03, -0.03, 0.04, -0.01, -0.02, -0.02, 0.01, -0.02, -0.01, 0, -0.03, -0.01, 0.02, -0.01, -0.05, 0.02, 0.01, 0, -0.02, -0.03, 0, 0, 0, -0.01, 0.02, 0, 0.02, 0.03, -0.02, 0.02, -0.02, 0.02, -0.01, 0.02, 0, -0.07, -0.01, 0.01, 0.01, -0.01, 0.02, 0, -0.01, 0,0.01, 0.01, -0.06, 0.04, 0, -0.04, -0.01, -0.03, -0.04, -0.01, -0.01, 0.03, -0.02, -0.01, 0.02, 0, -0.04, 0.01, 0.01, -0.01, 0.02, 0.01, 0.03, -0.01, 0, -0.02, -0.02, -0.01, 0.04, -0.02, 0.06, 0, 0, -0.02, 0, 0.01, 0, -0.02, 0.02, 0.02, -0.06, -0.02, 0, 0.02,0.01, -0.01, 0, 0, -0.01, 0.01, -0.04, -0.01, -0.01, 0.01, -0.02, -0.03, 0.01, 0.03, -0.01, -0.01, 0, -0.01, 0, -0.01, 0.05, 0.02, 0, 0, 0.02, -0.01, 0.02, -0.03, -0.01, -0.02, 0.02, 0, 0.01, -0.06, -0.01, 0.01, 0.01, 0.02, 0.02, -0.02, 0.03, 0.01, -0.01, -0.01,0, 0, 0.03, 0.05, 0.05, -0.01, 0.01, -0.03, 0, -0.01, -0.01, 0, -0.02, 0.02, 0, 0.02, -0.01, 0.01, -0.02, 0.01, 0, -0.02, 0.02, 0.01, -0.03, 0.03, -0.04, -0.02, -0.01, 0.01, -0.04, -0.03, -0.02, -0.03, 0.01, 0, 0, -0.02, -0.01, 0.02, 0.01, -0.01, 0.01, 0.03,-0.01, -0.02, -0.01, 0, 0, -0.03, 0, 0.02, 0.03, 0.01, -0.01, 0.02, 0.04, -0.04, 0.02, 0.01, -0.02, -0.01, 0.03, -0.04, -0.01, 0, 0.01, 0.01, 0, 0.03, 0.05, 0, 0, 0.05, 0.01, -0.01, 0, -0.01, 0, -0.01, -0.01, 0.03, -0.01, 0.02, 0, 0, -0.01, 0, -0.02, -0.02,0.05,-0.02, -0.01, -0.01, -0.01, 0.02, 0, -0.01, 0, 0, 0, -0.02, -0.04, 0.01, 0.01, -0.01, 0.01, 0, -0.06, -0.01, -0.04, -0.03, 0.01, 0, -0.01, 0.03, -0.04, -0.01, 0, 0.04, 0.03"; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Constants.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Constants.java index fd28ce67ac11..b431e7c9251b 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Constants.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Constants.java @@ -131,7 +131,8 @@ public static final class Properties { // Hybrid Search Query public static final String GLOBAL_STATISTICS_QUERY = "globalStatisticsQuery"; - public static final String COMPONENT_QUERY_INFOS = "componentQueryInfos"; + public static final String COMPONENT_QUERY_INFOS = "componentWeights"; + public static final String COMPONENT_WEIGHTS = "queryInfo"; public static final String PROJECTION_QUERY_INFO = "projectionQueryInfo"; public static final String SKIP = "skip"; public static final String TAKE = "take"; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/HybridSearchDocumentQueryExecutionContext.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/HybridSearchDocumentQueryExecutionContext.java index 60dc94f25b0f..022e4c53922f 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/HybridSearchDocumentQueryExecutionContext.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/HybridSearchDocumentQueryExecutionContext.java @@ -159,6 +159,9 @@ private Flux> hybridSearch(List rewrittenQueryInfos = retrieveRewrittenQueryInfos(hybridSearchQueryInfo.getComponentQueryInfoList()); + // Retrieve component weights used to sort component queries and compute correct ranks later + List componentWeights = retrieveComponentWeights(hybridSearchQueryInfo.getComponentWeights(), hybridSearchQueryInfo.getComponentQueryInfoList()); + // Run component queries, and retrieve component query results. Flux componentQueryResults = getComponentQueryResults(targetFeedRanges, initialPageSize, collection, rewrittenQueryInfos); @@ -166,13 +169,13 @@ private Flux> hybridSearch(List>> coalescedAndSortedResults = coalesceAndSortResults(componentQueryResults); // Compose component scores matrix, where each tuple is (score, index) - Mono>> componentScoresList = retrieveComponentScores(coalescedAndSortedResults); + Mono>> componentScoresList = retrieveComponentScores(coalescedAndSortedResults, componentWeights); // Compute Ranks Mono>> ranks = computeRanks(componentScoresList); // Compute the RRF scores - return computeRRFScores(ranks, coalescedAndSortedResults); + return computeRRFScores(ranks, coalescedAndSortedResults, componentWeights); } @Override @@ -293,7 +296,9 @@ public Flux> apply(Flux } } - private static Flux> computeRRFScores(Mono>> ranks, Mono>> coalescedAndSortedResults) { + private static Flux> computeRRFScores(Mono>> ranks, + Mono>> coalescedAndSortedResults, + List componentWeights) { return ranks.zipWith(coalescedAndSortedResults) .map(tuple -> { List> ranksInternal = tuple.getT1(); @@ -302,7 +307,7 @@ private static Flux> computeRRFScores(Mono integers : ranksInternal) { - rrfScore += 1.0 / (RRF_CONSTANT + integers.get(index)); + rrfScore += componentWeights.get(index).getWeight() / (RRF_CONSTANT + integers.get(index)); } results.get(index).setScore(rrfScore); @@ -329,7 +334,7 @@ private static Mono>> computeRanks(Mono int rank = 1; // ranks are 1 based for (int index = 0; index < componentScores.get(componentIndex).size(); index++) { // Identical scores should have the same rank - if ((index > 0) && (componentScores.get(componentIndex).get(index).getScore() < componentScores.get(componentIndex).get(index - 1).getScore())) { + if ((index > 0) && (componentScores.get(componentIndex).get(index).getScore() != componentScores.get(componentIndex).get(index - 1).getScore())) { rank += 1; } int rankIndex = componentScores.get(componentIndex).get(index).getIndex(); @@ -340,7 +345,7 @@ private static Mono>> computeRanks(Mono }); } - private static Mono>> retrieveComponentScores(Mono>> coalescedAndSortedResults) { + private static Mono>> retrieveComponentScores(Mono>> coalescedAndSortedResults, List componentWeights) { return coalescedAndSortedResults.map(results -> { List> componentScoresInternal = new ArrayList<>(); for (int i = 0; i < results.get(0).getComponentScores().size(); i++) { @@ -361,9 +366,14 @@ private static Mono>> retrieveComponentScores(Mono scoreTuples : componentScoresInternal) { - scoreTuples.sort(Comparator.comparing(ScoreTuple::getScore, Comparator.reverseOrder())); +// //Sort scores in descending order +// for (List scoreTuples : componentScoresInternal) { +// scoreTuples.sort(Comparator.comparing(ScoreTuple::getScore, Comparator.reverseOrder())); +// } + for (int i = 0; i < componentScoresInternal.size(); i++) { + final int componentIndex = i; + componentScoresInternal.get(i).sort((x,y) -> + componentWeights.get(componentIndex).getComparator().compare(x.getScore(), y.getScore())); } return componentScoresInternal; }); @@ -492,6 +502,38 @@ private GlobalFullTextSearchQueryStatistics aggregateStatistics(List retrieveComponentWeights(List componentWeightList, List componentQueryInfos) { + boolean useDefaultComponentWeight = componentWeightList == null || componentWeightList.isEmpty(); + List componentWeights = new ArrayList<>(); + for (int i=0;i comparator; + + public ComponentWeight(Double weight, SortOrder sortOrder) { + this.weight = weight; + + int comparisonFactor = (sortOrder == SortOrder.Ascending) ? 1 : -1; + this.comparator = (x, y) -> comparisonFactor * Double.compare(x, y); + } + + public Double getWeight() { + return weight; + } + + public Comparator getComparator() { + return comparator; + } + } + public static class ScoreTuple { private final Double score; private final Integer index; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/QueryFeature.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/QueryFeature.java index 9834958a89a8..7808e18782b0 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/QueryFeature.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/QueryFeature.java @@ -17,5 +17,6 @@ public enum QueryFeature { DCount, NonStreamingOrderBy, HybridSearch, - CountIf + CountIf, + WeightedRankFusion } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/QueryPlanRetriever.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/QueryPlanRetriever.java index fdec9762dadf..bb3499548968 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/QueryPlanRetriever.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/QueryPlanRetriever.java @@ -53,7 +53,8 @@ class QueryPlanRetriever { QueryFeature.DCount.name() + ", " + QueryFeature.NonValueAggregate.name() + ", " + QueryFeature.NonStreamingOrderBy.name() + ", " + - QueryFeature.HybridSearch.name(); + QueryFeature.HybridSearch.name() + ", " + + QueryFeature.WeightedRankFusion.name(); private static final String OLD_SUPPORTED_QUERY_FEATURES = QueryFeature.Aggregate.name() + ", " + QueryFeature.CompositeAggregate.name() + ", " + diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/hybridsearch/HybridSearchQueryInfo.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/hybridsearch/HybridSearchQueryInfo.java index ee1d77968540..45b07eb302af 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/hybridsearch/HybridSearchQueryInfo.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/hybridsearch/HybridSearchQueryInfo.java @@ -19,6 +19,8 @@ public class HybridSearchQueryInfo extends JsonSerializable { private String globalStatisticsQuery; @JsonProperty(Constants.Properties.COMPONENT_QUERY_INFOS) private List componentQueryInfoList; + @JsonProperty(Constants.Properties.COMPONENT_WEIGHTS) + private List componentWeights; @JsonProperty(Constants.Properties.PROJECTION_QUERY_INFO) private QueryInfo projectionQueryInfo; @JsonProperty(Constants.Properties.SKIP) @@ -61,6 +63,15 @@ public List getComponentQueryInfoList() { return componentQueryInfoList != null ? this.componentQueryInfoList : (this.componentQueryInfoList = super.getList(Constants.Properties.COMPONENT_QUERY_INFOS, QueryInfo.class)); } + /** + * Gets the list for componentWeights for hybrid search + * + * @return componentWeights + */ + public List getComponentWeights() { + return componentWeights != null ? this.componentWeights : (this.componentWeights = super.getList(Constants.Properties.COMPONENT_WEIGHTS, Double.class)); + } + /** * Gets the projectionQueryInfo for hybrid search * From 76438b480e5016a93e20e7bb589f8e6d75e75d00 Mon Sep 17 00:00:00 2001 From: Aayush Kataria Date: Wed, 14 May 2025 10:02:36 -0700 Subject: [PATCH 2/7] Updating changelog --- sdk/cosmos/azure-cosmos/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/cosmos/azure-cosmos/CHANGELOG.md b/sdk/cosmos/azure-cosmos/CHANGELOG.md index a35849946f94..fb7d87df1ca1 100644 --- a/sdk/cosmos/azure-cosmos/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos/CHANGELOG.md @@ -5,6 +5,7 @@ #### Features Added * Added API to allow customers to wrap/extend `CosmosAsyncContainer` - [PR 43724](https://github.com/Azure/azure-sdk-for-java/pull/43724) and [PR 45087](https://github.com/Azure/azure-sdk-for-java/pull/45087) * Added Per-Partition Automatic Failover which enables failover for writes at per-partition level for Single-Write Multi-Region accounts. - [PR 44099](https://github.com/Azure/azure-sdk-for-java/pull/44099) +* Added Weighted RRF for Hybrid and Full Text Searcg queries - [PR 45328](https://github.com/Azure/azure-sdk-for-java/pull/45328) #### Breaking Changes From 0354ce20e82049929e81726438167a0bd508b575 Mon Sep 17 00:00:00 2001 From: Aayush Kataria Date: Wed, 14 May 2025 10:39:08 -0700 Subject: [PATCH 3/7] Fixing test case --- .../cosmos/rx/HybridSearchQueryTest.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/HybridSearchQueryTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/HybridSearchQueryTest.java index ad210235b3a3..de2cff198ae5 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/HybridSearchQueryTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/HybridSearchQueryTest.java @@ -105,7 +105,7 @@ public void afterClass() { public void hybridQueryTest() { String query = "SELECT TOP 10 c.id, c.text, c.title FROM c WHERE FullTextContains(c.text, 'John') OR " + - "FullTextContains(c.title, 'John') ORDER BY RANK FullTextScore(c.title, ['John'])"; + "FullTextContains(c.title, 'John') ORDER BY RANK FullTextScore(c.title, 'John')"; List resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) .collectList().block(); @@ -113,7 +113,7 @@ public void hybridQueryTest() { validateResults(Arrays.asList("2","57","85"), resultDocs); query = "SELECT c.id, c.title FROM c WHERE FullTextContains(c.title, 'John') " + - "OR FullTextContains(c.text, 'John') ORDER BY RANK FullTextScore(c.title, ['John']) OFFSET 1 LIMIT 5"; + "OR FullTextContains(c.text, 'John') ORDER BY RANK FullTextScore(c.title, 'John') OFFSET 1 LIMIT 5"; resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) .collectList().block(); @@ -122,7 +122,7 @@ public void hybridQueryTest() { query = "SELECT TOP 20 c.id, c.title FROM c WHERE FullTextContains(c.title, 'John') OR " + "FullTextContains(c.text, 'John') OR FullTextContains(c.text, 'United States') " + - "ORDER BY RANK RRF(FullTextScore(c.title, ['John']), FullTextScore(c.text, ['United States']))"; + "ORDER BY RANK RRF(FullTextScore(c.title, 'John'), FullTextScore(c.text, 'United States'))"; resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) .collectList().block(); @@ -131,7 +131,7 @@ public void hybridQueryTest() { query = "SELECT c.id, c.title FROM c WHERE FullTextContains(c.title, 'John') " + "OR FullTextContains(c.text, 'John') OR FullTextContains(c.text, 'United States') ORDER BY " + - "RANK RRF(FullTextScore(c.title, ['John']), FullTextScore(c.text, ['United States'])) OFFSET 5 LIMIT 10"; + "RANK RRF(FullTextScore(c.title, 'John'), FullTextScore(c.text, 'United States')) OFFSET 5 LIMIT 10"; resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) .collectList().block(); @@ -140,7 +140,7 @@ public void hybridQueryTest() { String vector = getQueryVector(); query = String.format("SELECT TOP 10 c.id, c.text, c.title FROM c " + - "ORDER BY RANK RRF(FullTextScore(c.text, ['John']), FullTextScore(c.text, ['United States']), " + + "ORDER BY RANK RRF(FullTextScore(c.text, 'John'), FullTextScore(c.text, 'United States'), " + "VectorDistance(c.vector, [%s]))",vector); resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) @@ -154,7 +154,7 @@ public void hybridQueryWeightedRRFTest(){ // test case 1 String query = "SELECT TOP 15 c.index AS Index, c.title AS Title, c.text AS Text FROM c " + "WHERE FullTextContains(c.title, 'John') OR FullTextContains(c.text, 'John') OR FullTextContains(c.text, 'United States')" + - "ORDER BY RANK RRF(FullTextScore(c.title, ['John']), FullTextScore(c.text, ['United States']), [1, 1])"; + "ORDER BY RANK RRF(FullTextScore(c.title, 'John'), FullTextScore(c.text, 'United States'), [1, 1])"; List resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) .collectList().block(); @@ -168,7 +168,7 @@ public void hybridQueryWeightedRRFTest(){ // test case 2 query = "SELECT TOP 15 c.index AS Index, c.title AS Title, c.text AS Text FROM c " + "WHERE FullTextContains(c.title, 'John') OR FullTextContains(c.text, 'John') OR FullTextContains(c.text, 'United States')" + - "ORDER BY RANK RRF(FullTextScore(c.title, ['John']), FullTextScore(c.text, ['United States']), [10, 10])"; + "ORDER BY RANK RRF(FullTextScore(c.title, 'John'), FullTextScore(c.text, 'United States'), [10, 10])"; resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) .collectList().block(); @@ -195,7 +195,7 @@ public void hybridQueryWeightedRRFTest(){ // test case 4 query = "SELECT TOP 10 c.index AS Index, c.title AS Title, c.text AS Text FROM c " + "WHERE FullTextContains(c.title, 'John') OR FullTextContains(c.text, 'John') OR FullTextContains(c.text, 'United States')" + - "ORDER BY RANK RRF(FullTextScore(c.title, ['John']), FullTextScore(c.text, ['United States']), [-1, -1])"; + "ORDER BY RANK RRF(FullTextScore(c.title, 'John'), FullTextScore(c.text, 'United States'), [-1, -1])"; resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) .collectList().block(); @@ -209,7 +209,7 @@ public void hybridQueryWeightedRRFTest(){ // test case 5 String vector = getQueryVector(); query = String.format("SELECT c.index, c.title FROM c " + - "ORDER BY RANK RRF(FullTextScore(c.text, ['United States']), VectorDistance(c.vector, [%s]), [1,1]) " + + "ORDER BY RANK RRF(FullTextScore(c.text, 'United States'), VectorDistance(c.vector, [%s]), [1,1]) " + "OFFSET 0 LIMIT 10", vector); resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) @@ -236,7 +236,7 @@ public void wrongHybridQueryTest() { } try { - query = "SELECT TOP 10 c.id FROM c WHERE FullTextContains(c.title, 'John') ORDER BY RANK FullTextScore(c.title, ['John']) DESC"; + query = "SELECT TOP 10 c.id FROM c WHERE FullTextContains(c.title, 'John') ORDER BY RANK FullTextScore(c.title, 'John') DESC"; container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) .collectList().block(); @@ -247,7 +247,7 @@ public void wrongHybridQueryTest() { } try { - query = "SELECT TOP 10 c.id FROM c WHERE FullTextContains(c.title, 'John') ORDER BY RANK RRF(FullTextScore(c.title, ['John']), VectorDistance(c.vector, [1,2,3])) DESC"; + query = "SELECT TOP 10 c.id FROM c WHERE FullTextContains(c.title, 'John') ORDER BY RANK RRF(FullTextScore(c.title, 'John'), VectorDistance(c.vector, [1,2,3])) DESC"; container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) .collectList().block(); @@ -258,7 +258,7 @@ public void wrongHybridQueryTest() { } try { - query = "SELECT c.id FROM c WHERE FullTextContains(c.title, 'John') ORDER BY RANK RRF(FullTextScore(c.title, ['John']), VectorDistance(c.vector, [1,2,3]))"; + query = "SELECT c.id FROM c WHERE FullTextContains(c.title, 'John') ORDER BY RANK RRF(FullTextScore(c.title, 'John'), VectorDistance(c.vector, [1,2,3]))"; container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) .collectList().block(); @@ -270,7 +270,7 @@ public void wrongHybridQueryTest() { } try { - query = "SELECT c.id FROM c WHERE FullTextContains(c.title, 'John') ORDER BY RANK RRF(FullTextScore(c.title, ['John']), VectorDistance(c.vector, [1,2,3])) OFFSET 10 LIMIT 5"; + query = "SELECT c.id FROM c WHERE FullTextContains(c.title, 'John') ORDER BY RANK RRF(FullTextScore(c.title, 'John'), VectorDistance(c.vector, [1,2,3])) OFFSET 10 LIMIT 5"; container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) .collectList().block(); @@ -281,7 +281,7 @@ public void wrongHybridQueryTest() { } try { - query = "SELECT c.id FROM c WHERE FullTextContains(c.title, 'John') ORDER BY RANK RRF(FullTextScore(c.title, ['John']), VectorDistance(c.vector, [1,2,3])) OFFSET 10 LIMIT 10"; + query = "SELECT c.id FROM c WHERE FullTextContains(c.title, 'John') ORDER BY RANK RRF(FullTextScore(c.title, 'John'), VectorDistance(c.vector, [1,2,3])) OFFSET 10 LIMIT 10"; container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) .collectList().block(); From dd2095980e6fca651715073e9efa155f0d1059c2 Mon Sep 17 00:00:00 2001 From: Aayush Kataria Date: Wed, 14 May 2025 11:02:00 -0700 Subject: [PATCH 4/7] removing beta tag from full text policy pojos --- .../java/com/azure/cosmos/models/CosmosFullTextIndex.java | 5 ----- .../java/com/azure/cosmos/models/CosmosFullTextPath.java | 7 ------- .../java/com/azure/cosmos/models/CosmosFullTextPolicy.java | 7 ------- 3 files changed, 19 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosFullTextIndex.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosFullTextIndex.java index 5d9851462665..4ea4d8ddbc0a 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosFullTextIndex.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosFullTextIndex.java @@ -5,19 +5,16 @@ import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.JsonSerializable; -import com.azure.cosmos.util.Beta; /** * Represents cosmos full text index of the IndexingPolicy in the Azure Cosmos DB database service. */ -@Beta(value = Beta.SinceVersion.V4_65_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING) public final class CosmosFullTextIndex { private final JsonSerializable jsonSerializable; /** * Constructor */ - @Beta(value = Beta.SinceVersion.V4_65_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING) public CosmosFullTextIndex() { this.jsonSerializable = new JsonSerializable(); } @@ -26,7 +23,6 @@ public CosmosFullTextIndex() { * Gets path. * @return the path. */ - @Beta(value = Beta.SinceVersion.V4_65_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING) public String getPath() { return this.jsonSerializable.getString(Constants.Properties.PATH); } /** @@ -34,7 +30,6 @@ public CosmosFullTextIndex() { * @param path the path. * @return the CosmosFullTextIndex. */ - @Beta(value = Beta.SinceVersion.V4_65_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING) public CosmosFullTextIndex setPath(String path) { this.jsonSerializable.set( Constants.Properties.PATH, diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosFullTextPath.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosFullTextPath.java index 6705235c6820..774bde2cbd5c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosFullTextPath.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosFullTextPath.java @@ -5,13 +5,11 @@ import com.azure.cosmos.implementation.Constants; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; -import com.azure.cosmos.util.Beta; import com.fasterxml.jackson.annotation.JsonProperty; /** * Path settings within {@link CosmosFullTextPolicy} */ -@Beta(value = Beta.SinceVersion.V4_65_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING) public final class CosmosFullTextPath { @JsonProperty(Constants.Properties.PATH) private String path; @@ -21,7 +19,6 @@ public final class CosmosFullTextPath { /** * Constructor */ - @Beta(value = Beta.SinceVersion.V4_65_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING) public CosmosFullTextPath() {} /** @@ -29,7 +26,6 @@ public CosmosFullTextPath() {} * * @return path */ - @Beta(value = Beta.SinceVersion.V4_65_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING) public String getPath() { return path; } @@ -40,7 +36,6 @@ public String getPath() { * @param path the path for the cosmosFullText. * @return CosmosFullTextPath */ - @Beta(value = Beta.SinceVersion.V4_65_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING) public CosmosFullTextPath setPath(String path) { if (StringUtils.isEmpty(path)) { throw new NullPointerException("Full text search path is either null or empty"); @@ -58,7 +53,6 @@ public CosmosFullTextPath setPath(String path) { * Gets the language for the cosmosFullText path. * @return language */ - @Beta(value = Beta.SinceVersion.V4_65_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING) public String getLanguage() { return language; } @@ -68,7 +62,6 @@ public String getLanguage() { * @param language the language for the cosmosFullText path. * @return CosmosFullTextPath */ - @Beta(value = Beta.SinceVersion.V4_65_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING) public CosmosFullTextPath setLanguage(String language) { this.language = language; return this; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosFullTextPolicy.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosFullTextPolicy.java index d337e1f2d826..e997ec85b0b7 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosFullTextPolicy.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosFullTextPolicy.java @@ -4,7 +4,6 @@ package com.azure.cosmos.models; import com.azure.cosmos.implementation.Constants; -import com.azure.cosmos.util.Beta; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; @@ -13,7 +12,6 @@ /** * Full Text Search Policy */ -@Beta(value = Beta.SinceVersion.V4_65_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING) @JsonInclude(JsonInclude.Include.NON_NULL) public final class CosmosFullTextPolicy { @JsonProperty(Constants.Properties.DEFAULT_LANGUAGE) @@ -24,7 +22,6 @@ public final class CosmosFullTextPolicy { /** * Constructor */ - @Beta(value = Beta.SinceVersion.V4_65_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING) public CosmosFullTextPolicy() { } @@ -33,7 +30,6 @@ public CosmosFullTextPolicy() { * * @return the default language for cosmosFullText. */ - @Beta(value = Beta.SinceVersion.V4_65_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING) public String getDefaultLanguage() { return defaultLanguage; } @@ -43,7 +39,6 @@ public String getDefaultLanguage() { * @param defaultLanguage the default language for cosmosFullText. * @return CosmosFullTextPolicy */ - @Beta(value = Beta.SinceVersion.V4_65_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING) public CosmosFullTextPolicy setDefaultLanguage(String defaultLanguage) { this.defaultLanguage = defaultLanguage; return this; @@ -53,7 +48,6 @@ public CosmosFullTextPolicy setDefaultLanguage(String defaultLanguage) { * Gets the paths for cosmosFulltext. * @return the paths for cosmosFulltext. */ - @Beta(value = Beta.SinceVersion.V4_65_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING) public List getPaths() { return paths; } @@ -63,7 +57,6 @@ public List getPaths() { * @param paths the paths for cosmosFulltext. * @return CosmosFullTextPolicy */ - @Beta(value = Beta.SinceVersion.V4_65_0, warningText = Beta.PREVIEW_SUBJECT_TO_CHANGE_WARNING) public CosmosFullTextPolicy setPaths(List paths) { for (CosmosFullTextPath cosmosFullTextPath : paths) { if (cosmosFullTextPath.getLanguage().isEmpty()) { From e796f14617ac4ffa846c6fad04bec0d56ca48f2a Mon Sep 17 00:00:00 2001 From: Aayush Kataria Date: Thu, 15 May 2025 08:24:14 -0700 Subject: [PATCH 5/7] resolving comments --- sdk/cosmos/azure-cosmos/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/cosmos/azure-cosmos/CHANGELOG.md b/sdk/cosmos/azure-cosmos/CHANGELOG.md index 856db72c063c..3e91fb3c4599 100644 --- a/sdk/cosmos/azure-cosmos/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos/CHANGELOG.md @@ -6,7 +6,7 @@ * Added Beta public API to enable http2. - See [PR 43123](https://github.com/Azure/azure-sdk-for-java/pull/43123) * Added API to allow customers to wrap/extend `CosmosAsyncContainer` - [PR 43724](https://github.com/Azure/azure-sdk-for-java/pull/43724) and [PR 45087](https://github.com/Azure/azure-sdk-for-java/pull/45087) * Added Per-Partition Automatic Failover which enables failover for writes at per-partition level for Single-Write Multi-Region accounts. - [PR 44099](https://github.com/Azure/azure-sdk-for-java/pull/44099) -* Added Weighted RRF for Hybrid and Full Text Searcg queries - [PR 45328](https://github.com/Azure/azure-sdk-for-java/pull/45328) +* Added Weighted RRF for Hybrid and Full Text Search queries - [PR 45328](https://github.com/Azure/azure-sdk-for-java/pull/45328) #### Breaking Changes * Added Beta public API to allow defining the consistency behavior for read / query / change feed operations independent of the chosen account-level consistency level. **NOTE: This API is still in preview mode and can only be used when using DIRECT connection mode.** - See [PR 45161](https://github.com/Azure/azure-sdk-for-java/pull/45161) From 98b392c6df73589d0447b187bfc9860e35dc4eb9 Mon Sep 17 00:00:00 2001 From: Aayush Kataria Date: Thu, 15 May 2025 08:31:20 -0700 Subject: [PATCH 6/7] resolving comments --- sdk/cosmos/azure-cosmos/CHANGELOG.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sdk/cosmos/azure-cosmos/CHANGELOG.md b/sdk/cosmos/azure-cosmos/CHANGELOG.md index 834c59426106..b8ec4cdee6d0 100644 --- a/sdk/cosmos/azure-cosmos/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos/CHANGELOG.md @@ -6,10 +6,8 @@ * Added Beta public API to enable http2. - See [PR 43123](https://github.com/Azure/azure-sdk-for-java/pull/43123) * Added API to allow customers to wrap/extend `CosmosAsyncContainer` - [PR 43724](https://github.com/Azure/azure-sdk-for-java/pull/43724) and [PR 45087](https://github.com/Azure/azure-sdk-for-java/pull/45087) * Added Per-Partition Automatic Failover which enables failover for writes at per-partition level for Single-Write Multi-Region accounts. - [PR 44099](https://github.com/Azure/azure-sdk-for-java/pull/44099) -* Added Weighted RRF for Hybrid and Full Text Search queries - [PR 45328](https://github.com/Azure/azure-sdk-for-java/pull/45328) - -#### Breaking Changes * Added Beta public API to allow defining the consistency behavior for read / query / change feed operations independent of the chosen account-level consistency level. **NOTE: This API is still in preview mode and can only be used when using DIRECT connection mode.** - See [PR 45161](https://github.com/Azure/azure-sdk-for-java/pull/45161) +* Added Weighted RRF for Hybrid and Full Text Search queries - [PR 45328](https://github.com/Azure/azure-sdk-for-java/pull/45328) #### Bugs Fixed * Fixed the fail back flow where not all partitions were failing back to original first preferred region for Per-Partition Circuit Breaker. - [PR 44099](https://github.com/Azure/azure-sdk-for-java/pull/44099) From 384319d7681c332fa12177339caafa64db2714ae Mon Sep 17 00:00:00 2001 From: Aayush Kataria Date: Thu, 15 May 2025 20:33:24 -0700 Subject: [PATCH 7/7] Fixing tests --- .../cosmos/rx/HybridSearchQueryTest.java | 102 +++++++++++------- .../cosmos/implementation/Constants.java | 4 +- ...idSearchDocumentQueryExecutionContext.java | 5 +- 3 files changed, 67 insertions(+), 44 deletions(-) diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/HybridSearchQueryTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/HybridSearchQueryTest.java index de2cff198ae5..c12e8e226c8a 100644 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/HybridSearchQueryTest.java +++ b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/HybridSearchQueryTest.java @@ -152,72 +152,76 @@ public void hybridQueryTest() { @Test(groups = {"query", "split"}, timeOut = TIMEOUT) public void hybridQueryWeightedRRFTest(){ // test case 1 - String query = "SELECT TOP 15 c.index AS Index, c.title AS Title, c.text AS Text FROM c " + + String query = "SELECT TOP 15 c.id, c.text, c.title FROM c " + "WHERE FullTextContains(c.title, 'John') OR FullTextContains(c.text, 'John') OR FullTextContains(c.text, 'United States')" + "ORDER BY RANK RRF(FullTextScore(c.title, 'John'), FullTextScore(c.text, 'United States'), [1, 1])"; - List resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() + List results = container.queryItems(query, new CosmosQueryRequestOptions(), HybridSearchQueryTest.Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) .collectList().block(); - assertThat(resultDocs).hasSize(15); + assertThat(results).hasSize(15); + assertThat(results).isNotNull(); + validateResults( - Arrays.asList("61", "51", "49", "54", "75", "24", "77", "76", "80", "25", "22", "2", "66", "57", "85"), - Arrays.asList("61", "51", "49", "54", "75", "24", "77", "76", "80", "25", "22", "2", "66", "85", "57"), - resultDocs + Arrays.asList("60", "53", "50", "48", "23", "1", "56", "21", "74", "24", "76", "75", "65", "79", "84"), + results ); + // test case 2 - query = "SELECT TOP 15 c.index AS Index, c.title AS Title, c.text AS Text FROM c " + + query = "SELECT TOP 15 c.id, c.text, c.title AS Text FROM c " + "WHERE FullTextContains(c.title, 'John') OR FullTextContains(c.text, 'John') OR FullTextContains(c.text, 'United States')" + "ORDER BY RANK RRF(FullTextScore(c.title, 'John'), FullTextScore(c.text, 'United States'), [10, 10])"; - resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() + results = container.queryItems(query, new CosmosQueryRequestOptions(), HybridSearchQueryTest.Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) .collectList().block(); - assertThat(resultDocs).hasSize(15); + assertThat(results).hasSize(15); + assertThat(results).isNotNull(); validateResults( - Arrays.asList("61", "51", "49", "54", "75", "24", "77", "76", "80", "25", "22", "2", "66", "57", "85"), - Arrays.asList("61", "51", "49", "54", "75", "24", "77", "76", "80", "25", "22", "2", "66", "85", "57"), - resultDocs + Arrays.asList("60", "53", "50", "48", "23", "1", "56", "21", "74", "24", "76", "75", "65", "79", "84"), + results ); // test case 3 - query = "SELECT TOP 10 c.index AS Index, c.title AS Title, c.text AS Text FROM c " + + query = "SELECT TOP 10 c.id, c.text, c.title FROM c " + "WHERE FullTextContains(c.title, 'John') OR FullTextContains(c.text, 'John') OR FullTextContains(c.text, 'United States')" + "ORDER BY RANK RRF(FullTextScore(c.title, ['John']), FullTextScore(c.text, ['United States']), [0.1, 0.1])"; - resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() + results = container.queryItems(query, new CosmosQueryRequestOptions(), HybridSearchQueryTest.Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) .collectList().block(); - assertThat(resultDocs).hasSize(10); + assertThat(results).hasSize(10); + assertThat(results).isNotNull(); validateResults( - Arrays.asList("61", "51", "49", "54", "75", "24", "77", "76", "80", "25"), - resultDocs + Arrays.asList("60", "53", "50", "48", "23", "1", "56", "21", "74", "24"), + results ); // test case 4 - query = "SELECT TOP 10 c.index AS Index, c.title AS Title, c.text AS Text FROM c " + + query = "SELECT TOP 10 c.id, c.text, c.title FROM c " + "WHERE FullTextContains(c.title, 'John') OR FullTextContains(c.text, 'John') OR FullTextContains(c.text, 'United States')" + "ORDER BY RANK RRF(FullTextScore(c.title, 'John'), FullTextScore(c.text, 'United States'), [-1, -1])"; - resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() + results = container.queryItems(query, new CosmosQueryRequestOptions(), HybridSearchQueryTest.Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) .collectList().block(); - assertThat(resultDocs).hasSize(15); + assertThat(results).hasSize(10); + assertThat(results).isNotNull(); validateResults( - Arrays.asList("85", "57", "66", "2", "22", "25", "77", "76", "80", "75", "24", "49", "54", "51", "81"), - Arrays.asList("57", "85", "2", "66", "22", "25", "80", "76", "77", "24", "75", "54", "49", "51", "61"), - resultDocs + Arrays.asList("56", "21", "24", "53", "65", "23", "1", "84", "60", "75"), + results ); // test case 5 String vector = getQueryVector(); - query = String.format("SELECT c.index, c.title FROM c " + + query = String.format("SELECT c.id, c.title FROM c " + "ORDER BY RANK RRF(FullTextScore(c.text, 'United States'), VectorDistance(c.vector, [%s]), [1,1]) " + "OFFSET 0 LIMIT 10", vector); - resultDocs = container.queryItems(query, new CosmosQueryRequestOptions(), Document.class).byPage() + results = container.queryItems(query, new CosmosQueryRequestOptions(), HybridSearchQueryTest.Document.class).byPage() .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) .collectList().block(); - assertThat(resultDocs).hasSize(10); + assertThat(results).hasSize(10); + assertThat(results).isNotNull(); validateResults( - Arrays.asList("51", "54", "28", "70", "24", "61", "56", "26", "58", "77"), - resultDocs + Arrays.asList("74", "23", "48", "54", "60", "20", "8", "25", "36", "56"), + results ); } @@ -290,6 +294,37 @@ public void wrongHybridQueryTest() { assertThat(ex.getStatusCode()).isEqualTo(HttpResponseStatus.BAD_REQUEST.code()); assertThat(ex.getMessage()).contains("Executing a hybrid or full-text query with an offset(Skip) greater than or equal to limit(Take)."); } + + try { + query = "SELECT TOP 15 c.id, c.text, c.title FROM c " + + "WHERE FullTextContains(c.title, 'John') OR FullTextContains(c.text, 'John') OR FullTextContains(c.text, 'United States')" + + "ORDER BY RANK RRF(FullTextScore(c.title, 'John'), FullTextScore(c.text, 'United States'), [1, 1, 1])"; + container.queryItems(query, new CosmosQueryRequestOptions(), HybridSearchQueryTest.Document.class).byPage() + .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) + .collectList().block(); + fail("The last parameter of the RRF function is an optional array of weights. When present, " + + "it must be a literal array of numbers, one for each of the component scores used for the RRF function. " + + "The length of this array must be the same as the number of the component scores."); + } catch (CosmosException ex) { + assertThat(ex.getStatusCode()).isEqualTo(HttpResponseStatus.BAD_REQUEST.code()); + assertThat(ex.getMessage()).contains("The length of this array must be the same as the number of the component scores."); + } + + try { + query = "SELECT TOP 15 c.id, c.text, c.title FROM c " + + "WHERE FullTextContains(c.title, 'John') OR FullTextContains(c.text, 'John') OR FullTextContains(c.text, 'United States')" + + "ORDER BY RANK RRF(FullTextScore(c.title, 'John'), FullTextScore(c.text, 'United States'), [1])"; + container.queryItems(query, new CosmosQueryRequestOptions(), HybridSearchQueryTest.Document.class).byPage() + .flatMap(feedResponse -> Flux.fromIterable(feedResponse.getResults())) + .collectList().block(); + fail("The last parameter of the RRF function is an optional array of weights. When present, " + + "it must be a literal array of numbers, one for each of the component scores used for the RRF function. " + + "The length of this array must be the same as the number of the component scores."); + } catch (CosmosException ex) { + assertThat(ex.getStatusCode()).isEqualTo(HttpResponseStatus.BAD_REQUEST.code()); + assertThat(ex.getMessage()).contains("The length of this array must be the same as the number of the component scores."); + } + } private IndexingPolicy populateIndexingPolicy() { @@ -330,17 +365,6 @@ private void validateResults(List actualIds, List results) { assertThat(resultsIds).isEqualTo(actualIds); } - private void validateResults(List expectedOrder1, List expectedOrder2, List results) { - assertThat(results).isNotNull(); - - List resultsIds = results.stream().map(Document::getId).collect(Collectors.toList()); - assertThat(resultsIds).satisfiesAnyOf( - actual -> assertThat(actual).isEqualTo(expectedOrder1), - actual -> assertThat(actual).isEqualTo(expectedOrder2) - ); - } - - public static String getQueryVector() { return "0.02, 0, -0.02, 0, -0.04, -0.01, -0.04, -0.01, 0.06, 0.08, -0.05, -0.04, -0.03, 0.05, -0.03, 0, -0.03, 0, 0.05, 0, 0.03,0.02, 0, 0.04, 0.05, 0.03, 0, 0, 0, -0.03, -0.01, 0.01, 0, -0.01, -0.03, -0.02, -0.05, 0.01, 0, 0.01, 0, 0.01, -0.03, -0.02, 0.02, 0.02, 0.04, 0.01, 0.04, 0.02, -0.01, -0.01, 0.02, 0.01, 0.02, -0.04, -0.01, 0.06, -0.01, -0.03, -0.04, -0.01, -0.01, 0, 0.03, -0.02, 0.03, 0.05, 0.01, 0.04, 0.05, -0.05, -0.01, 0.03, 0.02, -0.02, 0, -0.02, -0.02, -0.04, 0.01, -0.05, 0.01, 0.05, 0, -0.02, 0.03, -0.07, 0.05, 0.02, 0.03, 0.05, 0.05, -0.01, 0.03, -0.08, -0.01, -0.03, 0.04, -0.01, -0.02, -0.01, -0.02, -0.03, 0.03, 0.03,-0.04, 0.04, 0.02, 0, 0.03, -0.02, -0.04, 0.02, 0.01, 0.02, -0.01, 0.03, 0.02, 0.01, -0.02, 0, 0.02, 0, -0.01, 0.02, -0.05, 0.03, 0.03, 0.04, -0.02, 0.04, -0.04, 0.03, 0.03, -0.03, 0, 0.02, 0.06, 0.02, 0.02, -0.01, 0.03, 0, -0.03, -0.06, 0.02, 0, 0.02, -0.04,-0.05, 0.01, 0.02, 0.02, 0.07, 0.05, -0.01, 0.03, -0.03, -0.06, 0.04, 0.01, -0.01, 0.04, 0.02, 0.03, -0.03, 0.03, -0.01, 0.03, -0.04, -0.02, 0.02, -0.02, -0.03, -0.02, 0.02, -0.01, -0.05, -0.07, 0.02, -0.01, 0, -0.01, -0.02, -0.02, -0.03, -0.03, 0, -0.08, -0.01,0, -0.01, -0.03, 0.01, 0, -0.02, -0.03, -0.04, -0.01, 0.02, 0, 0, -0.04, 0.04, -0.01, 0.04, 0, -0.06, 0.02, 0.03, 0.01, 0.06, -0.02, 0, 0.01, 0.01, 0.01, 0, -0.02, 0.03, 0.02, 0.01, -0.01, -0.05, 0.03, -0.04, 0, 0.01, -0.02, -0.04, 0.02, 0, 0.09, -0.04, -0.01,0.02, 0.01, -0.03, 0.04, 0.02, -0.02, -0.02, -0.01, 0.01, -0.04, -0.01, 0.02, 0, 0, 0.07, 0.02, 0, 0, -0.01, 0.01, 0.03, -0.02, 0, 0.03, -0.02, -0.07, -0.04, -0.03, 0, -0.03, -0.02, 0, -0.02, -0.02, -0.05, -0.02, 0, 0.05, 0.01, -0.01, -0.04, 0.02, 0, 0, 0.03,0.02, -0.03, -0.01, -0.02, 0.06, -0.02, 0.01, 0.01, 0.04, -0.04, 0.06, -0.02, 0.01, 0.03, 0.01, 0.02, -0.02, 0.01, -0.04, 0.05, -0.03, 0.01, -0.01, 0, -0.03, -0.03, 0.04, 0.02, -0.03, -0.03, -0.02, 0.06, 0.04, -0.01, 0.01, 0.01, -0.01, -0.02, -0.02, 0.04, 0.01,-0.01, 0.01, -0.01, 0, 0.01, -0.04, 0.01, 0, -0.04, 0.05, 0.01, 0.01, 0.09, -0.04, -0.02, 0.04, 0, 0.04, -0.04, -0.04, 0, 0, -0.01, 0.05, -0.01, 0.02, 0.01, -0.03, 0, -0.06, 0.02, 0.04, 0.01, 0.03, 0.01, -0.04, 0, 0.01, 0.05, 0.02, -0.02, 0.02, 0, -0.02, -0.04,-0.07, -0.02, -0.05, 0.06, 0.01, 0.02, -0.03, 0.06, -0.01, -0.02, -0.02, -0.01, 0, -0.05, 0.06, -0.05, 0, -0.02, -0.02, 0, -0.01, 0.01, 0, -0.01, 0.05, 0.02, 0, 0.02, -0.02, 0.02, 0, 0.08, -0.02, 0.01, -0.03, 0.02, -0.03, 0, -0.01, -0.02, -0.04, 0.06, 0.01,-0.03, -0.03, 0.01, -0.01, 0.01, -0.01, 0.02, -0.03, 0.03, 0.04, 0.02, -0.02, 0.04, 0.01, 0.01, 0.02, 0.01, 0, -0.03, 0.03, -0.02, -0.03, -0.02, 0.02, 0, -0.01, -0.02, -0.02, 0, -0.01, -0.03, 0.02, -0.01, 0.01, -0.08, 0.01, -0.04, -0.05, 0.02, -0.01, -0.03,0.02, 0.01, -0.03, 0.01, 0.02, 0.03, 0.04, -0.04, 0.02, 0, 0.02, 0.02, 0.04, -0.04, -0.1, 0, 0.05, -0.01, 0.03, 0.05, 0.03, -0.02, 0.01, 0.02, -0.05, 0.01, 0, 0.05, -0.01, 0.03, -0.01, 0, 0.04, 0, 0, 0.08, 0.01, 0, -0.04, -0.03, 0, -0.02, -0.01, 0.02, 0.03,0, -0.01, 0, 0, 0, 0.06, 0, 0, 0.01, -0.01, 0.01, 0.04, 0.07, -0.01, 0.01, 0, -0.01, -0.02, 0.01, 0.01, 0, 0.02, 0.01, 0, -0.02, 0.03, 0.02, 0.06, 0.02, -0.01, 0.03, 0.02, -0.02, 0.01, -0.01, 0.03, 0.05, 0.02, 0.01, 0, 0, 0.01, 0.03, -0.03, -0.01, -0.04, 0.03,-0.02, 0.02, -0.02, -0.01, -0.02, 0.01, -0.04, 0.01, -0.04, 0.03, -0.02, -0.02, -0.01, -0.01, 0.07, 0.04, -0.01, 0.08, -0.04, -0.04, 0, 0, -0.01, -0.01, 0.03, -0.04, 0.02, -0.01, -0.04, 0.02, -0.07, -0.02, 0.02, -0.01, 0.02, 0.01, 0, 0.07, -0.01, 0.03, 0.01,-0.05, 0.02, 0.02, -0.01, 0.02, 0.02, -0.03, -0.02, 0.03, -0.01, 0.02, 0, 0, 0.02, -0.01, -0.02, 0.05, 0.02, 0.01, 0.01, -0.03, -0.05, -0.03, 0.01, 0.03, -0.02, -0.01, -0.01, -0.01, 0.03, -0.01, -0.03, 0.02, -0.02, -0.03, -0.02, -0.01, -0.01, -0.01, 0, -0.01,-0.04, -0.02, -0.02, -0.03, 0.04, 0.03, 0, -0.02, -0.01, -0.03, -0.01, -0.04, -0.04, 0.02, 0.01, -0.05, 0.04, -0.03, 0.01, -0.01, -0.03, 0.01, 0.01, 0.01, 0.02, -0.01, -0.02, -0.03, -0.01, -0.01, -0.01, -0.01, -0.03, 0, 0.01, -0.02, -0.01, -0.01, 0.01, 0, -0.04,0.01, -0.01, 0.02, 0, 0, -0.01, 0, 0, 0.03, -0.01, -0.06, -0.04, -0.01, 0, 0.02, -0.05, -0.02, 0.02, -0.01, 0.01, 0.01, -0.01, -0.02, 0, 0.02, -0.01, -0.02, 0.04, -0.01, 0, -0.02, -0.04, -0.03, -0.03, 0, 0.03, -0.01, -0.02, 0, 0.01, -0.01, -0.04, 0.01, -0.03,0.01, 0.03, 0, -0.02, 0, -0.04, -0.02, -0.02, 0.03, -0.02, 0.05, 0.02, 0.03, -0.02, -0.05, -0.01, 0.02, -0.04, 0.02, 0.01, -0.03, 0.01, 0.02, 0, 0.04, 0, -0.01, 0.02, 0.01, 0.02, 0.02, -0.02, 0.04, -0.01, 0, -0.01, 0, 0.01, -0.02, -0.04, 0.06, 0.01, 0, 0.01,-0.02, 0.02, 0.05, 0, 0.03, -0.02, 0.02, -0.03, -0.02, 0.01, 0, 0.06, -0.01, 0, -0.02, -0.02, 0.01, -0.01, 0, -0.03, 0.02, 0, -0.01, -0.02, -0.01, 0.03, -0.03, 0, 0, 0, -0.03, -0.06, 0.04, 0.02, -0.03, -0.06, -0.03, -0.01, -0.03, -0.02, -0.04, 0.01, 0, -0.01,0.02, -0.01, 0.03, 0.02, -0.02, -0.01, -0.02, -0.03, -0.01, 0.01, -0.04, 0.04, 0.03, 0.02, 0, -0.07, -0.02, -0.01, 0, 0.03, -0.01, -0.03, 0, 0.03, 0, -0.01, 0.02, 0.01, 0.02, -0.03, 0, 0.01, -0.02, 0.04, -0.04, 0, -0.05, 0, -0.02, -0.01, 0.03, 0.01, 0, -0.02,0, -0.05, 0.01, -0.01, 0, -0.08, -0.01, -0.02, 0.02, 0.01, -0.01, -0.01, -0.01, 0, 0, -0.01, -0.03, 0, 0, -0.02, 0.05, -0.03, 0.02, 0.01, -0.02, 0.01, 0.01, 0, 0.01, -0.01, 0, -0.04, -0.06, 0.03, -0.02, 0, -0.02, 0.01, 0.03, 0.03, -0.03, -0.01, 0, 0, 0.01,-0.02, -0.01, -0.01, -0.03, -0.02, 0.03, -0.02, 0.03, 0.01, 0.04, -0.04, 0.02, 0.02, 0.02, 0.03, 0, 0.06, -0.01, 0.02, -0.01, 0.01, -0.01, -0.01, -0.03, -0.01, 0.02, 0.01, 0.01, 0, -0.02, 0.03, 0.02, -0.01, -0.02, 0.01, 0.01, 0.04, -0.01, -0.05, 0, -0.01, 0,0.03, -0.01, 0.02, 0.02, -0.04, 0.01, -0.03, -0.02, 0, 0.02, 0, -0.01, 0.02, 0.01, 0.04, -0.04, 0, -0.01, -0.02, 0, -0.02, 0.01, -0.02, 0, 0, 0.03, 0.04, -0.01, 0, 0, 0.03, -0.02, 0.01, -0.02, 0, -0.03, 0.04, 0, 0.01, 0.04, 0, 0.03, -0.02, 0.01, 0.01, -0.02,0.02, -0.05, 0.03, -0.02, -0.01, 0.01, -0.01, 0.02, 0.04, 0.02, 0, -0.02, 0.02, -0.01, -0.03, -0.06, -0.01, -0.01, -0.04, 0.01, -0.01, -0.01, -0.01, -0.02, 0.03, -0.03, 0.05, 0, -0.01, -0.03, 0.03, 0.01, -0.01, -0.01, 0, 0.01, 0.01, 0.02, -0.01, 0.02, -0.02,-0.03, 0.03, -0.02, 0.01, 0, -0.03, 0.02, 0.02, -0.02, 0.01, 0.02, -0.01, 0.02, 0, 0.02, 0.01, 0, 0.05, -0.03, 0.01, 0.03, 0.04, 0.01, 0.01, -0.01, 0.02, -0.03, 0.02, 0.01, 0, -0.01, -0.03, -0.01, 0.02, 0.03, 0, 0.03, 0.02, 0, 0.01, 0.01, 0.02, 0.01, 0.02, 0.03,0.01, -0.03, 0.02, 0.01, 0.02, 0.03, -0.01, 0.01, -0.03, -0.01, -0.02, 0.01, 0, 0, -0.01, -0.02, -0.01, -0.01, 0.01, 0.06, 0.01, 0, -0.01, 0.01, 0, 0, -0.01, -0.01, 0, -0.02, -0.02, -0.01, -0.02, -0.01, -0.05, -0.02, 0.03, 0.02, 0, 0.03, -0.03, -0.03, 0.03, 0,0.02, -0.03, 0.04, -0.04, 0, -0.04, 0.04, 0.01, -0.03, 0.01, -0.02, -0.01, -0.04, 0.02, -0.01, 0.01, 0.01, 0.02, -0.02, 0.03, -0.01, 0, 0.01, 0, 0.02, 0.01, 0.01, 0.03, -0.06, 0.02, 0, -0.02, 0, 0.04, -0.03, 0, 0, -0.02, 0.06, 0.01, -0.03, -0.02, -0.01, -0.03,-0.04, 0.04, 0.03, -0.02, 0, 0.03, -0.04, -0.01, -0.02, -0.02, -0.01, 0.02, 0.02, 0.01, 0.01, 0.01, -0.02, -0.02, -0.03, -0.01, 0.01, 0, 0, 0, 0.02, -0.04, -0.01, -0.01, 0.04, -0.01, 0.01, -0.01, 0.01, -0.03, 0.01, -0.01, 0, -0.01, 0.01, 0, 0.01, -0.04, 0.01, 0,0, 0, 0, 0.02, 0.04, 0.01, 0.01, -0.01, -0.02, 0, 0, 0.01, -0.01, 0.01, -0.01, 0, 0.04, -0.01, -0.02, -0.01, -0.01, -0.01, 0, 0, 0.01, 0.01, 0.04, -0.01, -0.01, 0, -0.03, -0.01, 0.01, -0.01, -0.02, 0.01, -0.02, 0.01, -0.03, 0.02, 0, 0.03, 0.01, -0.03, -0.01,-0.01, 0.02, 0.01, 0, -0.01, 0.03, -0.04, 0.01, -0.01, -0.03, -0.02, 0.02, -0.01, 0, -0.01, 0.02, 0.02, 0.01, 0.03, 0, -0.03, 0, 0.02, -0.03, -0.01, 0.01, 0.06, -0.01, -0.02, 0.01, 0, 0.04, -0.04, 0.01, -0.02, 0, -0.04, 0, 0.02, 0.02, -0.02, 0.04, -0.01, 0.01,0, 0.03, -0.03, 0.04, -0.01, -0.02, -0.02, 0.01, -0.02, -0.01, 0, -0.03, -0.01, 0.02, -0.01, -0.05, 0.02, 0.01, 0, -0.02, -0.03, 0, 0, 0, -0.01, 0.02, 0, 0.02, 0.03, -0.02, 0.02, -0.02, 0.02, -0.01, 0.02, 0, -0.07, -0.01, 0.01, 0.01, -0.01, 0.02, 0, -0.01, 0,0.01, 0.01, -0.06, 0.04, 0, -0.04, -0.01, -0.03, -0.04, -0.01, -0.01, 0.03, -0.02, -0.01, 0.02, 0, -0.04, 0.01, 0.01, -0.01, 0.02, 0.01, 0.03, -0.01, 0, -0.02, -0.02, -0.01, 0.04, -0.02, 0.06, 0, 0, -0.02, 0, 0.01, 0, -0.02, 0.02, 0.02, -0.06, -0.02, 0, 0.02,0.01, -0.01, 0, 0, -0.01, 0.01, -0.04, -0.01, -0.01, 0.01, -0.02, -0.03, 0.01, 0.03, -0.01, -0.01, 0, -0.01, 0, -0.01, 0.05, 0.02, 0, 0, 0.02, -0.01, 0.02, -0.03, -0.01, -0.02, 0.02, 0, 0.01, -0.06, -0.01, 0.01, 0.01, 0.02, 0.02, -0.02, 0.03, 0.01, -0.01, -0.01,0, 0, 0.03, 0.05, 0.05, -0.01, 0.01, -0.03, 0, -0.01, -0.01, 0, -0.02, 0.02, 0, 0.02, -0.01, 0.01, -0.02, 0.01, 0, -0.02, 0.02, 0.01, -0.03, 0.03, -0.04, -0.02, -0.01, 0.01, -0.04, -0.03, -0.02, -0.03, 0.01, 0, 0, -0.02, -0.01, 0.02, 0.01, -0.01, 0.01, 0.03,-0.01, -0.02, -0.01, 0, 0, -0.03, 0, 0.02, 0.03, 0.01, -0.01, 0.02, 0.04, -0.04, 0.02, 0.01, -0.02, -0.01, 0.03, -0.04, -0.01, 0, 0.01, 0.01, 0, 0.03, 0.05, 0, 0, 0.05, 0.01, -0.01, 0, -0.01, 0, -0.01, -0.01, 0.03, -0.01, 0.02, 0, 0, -0.01, 0, -0.02, -0.02,0.05,-0.02, -0.01, -0.01, -0.01, 0.02, 0, -0.01, 0, 0, 0, -0.02, -0.04, 0.01, 0.01, -0.01, 0.01, 0, -0.06, -0.01, -0.04, -0.03, 0.01, 0, -0.01, 0.03, -0.04, -0.01, 0, 0.04, 0.03"; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Constants.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Constants.java index b431e7c9251b..a58173cf1fc8 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Constants.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Constants.java @@ -131,8 +131,8 @@ public static final class Properties { // Hybrid Search Query public static final String GLOBAL_STATISTICS_QUERY = "globalStatisticsQuery"; - public static final String COMPONENT_QUERY_INFOS = "componentWeights"; - public static final String COMPONENT_WEIGHTS = "queryInfo"; + public static final String COMPONENT_QUERY_INFOS = "componentQueryInfos"; + public static final String COMPONENT_WEIGHTS = "componentWeights"; public static final String PROJECTION_QUERY_INFO = "projectionQueryInfo"; public static final String SKIP = "skip"; public static final String TAKE = "take"; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/HybridSearchDocumentQueryExecutionContext.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/HybridSearchDocumentQueryExecutionContext.java index 022e4c53922f..9b4c1658dd83 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/HybridSearchDocumentQueryExecutionContext.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/HybridSearchDocumentQueryExecutionContext.java @@ -306,10 +306,9 @@ private static Flux> computeRRFScores(Mono integers : ranksInternal) { - rrfScore += componentWeights.get(index).getWeight() / (RRF_CONSTANT + integers.get(index)); + for (int componentIndex = 0; componentIndex < ranksInternal.size(); ++componentIndex) { + rrfScore += componentWeights.get(componentIndex).getWeight() / (RRF_CONSTANT + ranksInternal.get(componentIndex).get(index)); } - results.get(index).setScore(rrfScore); } // Sort on the RRF scores to build the final result