Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Cosmos] Hybrid Search query pipeline #38275

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
f0b9f26
Create hybrid_search_aggregator.py
simorenoh Nov 1, 2024
2829bc1
others
simorenoh Nov 1, 2024
daf04e8
Update execution_dispatcher.py
simorenoh Nov 1, 2024
da4c295
Update execution_dispatcher.py
simorenoh Nov 1, 2024
13482e3
sync changes, need to look at vector + FTS/ skip + take
simorenoh Nov 5, 2024
2570238
async pipeline
simorenoh Nov 5, 2024
20a5a8d
Merge branch 'main' into fts-query
simorenoh Nov 6, 2024
d900083
account for skip/take and simplify logics
simorenoh Nov 11, 2024
7dce7c1
small hack for now
simorenoh Nov 12, 2024
c266c6a
fixing top/limit logic
simorenoh Nov 12, 2024
2ecfbf8
return only payload
simorenoh Nov 13, 2024
13a21c1
fix hack
simorenoh Nov 13, 2024
1b89369
pylint
simorenoh Nov 14, 2024
66b1163
simplifying further
simorenoh Nov 14, 2024
d6e199a
small changes
simorenoh Nov 14, 2024
729c64f
adds readme, buffer limit, simplifies
simorenoh Nov 14, 2024
93eba14
simplify async, CI green
simorenoh Nov 14, 2024
188e12f
Merge branch 'main' into fts-query
simorenoh Nov 14, 2024
835a72b
Update hybrid_search_aggregator.py
simorenoh Nov 14, 2024
2dc6077
Update sdk/cosmos/azure-cosmos/README.md
simorenoh Nov 14, 2024
77ea6dd
update variable name
simorenoh Nov 14, 2024
3cdcc7f
Merge branch 'fts-query' of https://github.com/simorenoh/azure-sdk-fo…
simorenoh Nov 14, 2024
705a14b
add sync and async tests
simorenoh Nov 15, 2024
8052a14
Update README.md
simorenoh Nov 15, 2024
a86cbf8
simplifications, test fixes
simorenoh Nov 15, 2024
0c4d9a4
add wrong query tests
simorenoh Nov 15, 2024
c2242eb
pylint/cspell
simorenoh Nov 15, 2024
efce422
Merge branch 'main' into fts-query
simorenoh Nov 15, 2024
1fb4dfb
Update CHANGELOG.md
simorenoh Nov 15, 2024
b10c580
small changes
simorenoh Nov 15, 2024
84753dc
test updates
simorenoh Nov 15, 2024
70581ac
Update hybrid_search_data.py
simorenoh Nov 15, 2024
f90914a
cspell, samples
simorenoh Nov 15, 2024
ff66988
change tops
simorenoh Nov 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions sdk/cosmos/azure-cosmos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,40 @@ not being able to recognize the new NonStreamingOrderBy capability that makes ve
If this happens, you can set the `AZURE_COSMOS_DISABLE_NON_STREAMING_ORDER_BY` environment variable to `"True"` to opt out of this
functionality and continue operating as usual.*

### Public Preview - Full Text Search

With the addition of the full text indexing and full text policies, the SDK can now perform full text search and hybrid search queries.
These queries can utilize the new query functions `FullTextContains()`, `FullTextContainsAll`, and `FullTextContainsAny` to efficiently
search for the given terms within your item fields.

Beyond these, you can also utilize the new `Order By RANK` and `Order By RANK RRF` along with `FullTextScore` to execute the [BM25][BM25] scoring algorithm
or [Reciprocal Rank Fusion][RRF] (RRF) on your query, finding the items with the highest relevance to the terms you are looking for.
All of these mentioned queries would look something like this:

- `SELECT TOP 10 c.id, c.text FROM c WHERE FullTextContains(c.text, 'quantum')`


- `SELECT TOP 10 c.id, c.text FROM c WHERE FullTextContainsAll(c.text, 'quantum', 'theory')`


- `SELECT TOP 10 c.id, c.text FROM c WHERE FullTextContainsAny(c.text, 'quantum', 'theory')`


- `SELECT TOP 10 c.id, c.text FROM c ORDER BY RANK FullTextScore(c.text, ['quantum', 'theory'])`


- `SELECT TOP 10 c.id, c.text FROM c ORDER BY RANK RRF(FullTextScore(c.text, ['quantum', 'theory']), FullTextScore(c.text, ['model']))`


- `SELECT TOP 10 c.id, c.text FROM c ORDER BY RANK RRF(FullTextScore(c.text, ['quantum', 'theory']), FullTextScore(c.text, ['model']), VectorDistance(c.embedding, {item_embedding}))"`

These queries must always use a TOP or LIMIT clause within the query since hybrid search queries have to look through a lot of data otherwise and may become too expensive or long-running.
Since these queries are relatively expensive, the SDK sets a default limit of 1000 max items per query - if you'd like to raise that further, you
can use the `AZURE_COSMOS_MAX_ITEM_BUFFER_HYBRID_SEARCH` environment variable to do so. However, be advised that queries with too many vector results
simorenoh marked this conversation as resolved.
Show resolved Hide resolved
may have additional latencies associated with searching in the service.

You can find our sync samples [here][cosmos_index_sample] and our async samples [here][cosmos_index_sample_async] as well to help yourself out.
simorenoh marked this conversation as resolved.
Show resolved Hide resolved

## Troubleshooting

### General
Expand Down Expand Up @@ -904,6 +938,8 @@ For more extensive documentation on the Cosmos DB service, see the [Azure Cosmos
[cosmos_concurrency_sample]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/cosmos/azure-cosmos/samples/concurrency_sample.py
[cosmos_index_sample]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/cosmos/azure-cosmos/samples/index_management.py
[cosmos_index_sample_async]: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/cosmos/azure-cosmos/samples/index_management_async.py
[RRF]: https://learn.microsoft.com/azure/search/hybrid-search-ranking
[BM25]: https://en.wikipedia.org/wiki/Okapi_BM25

## Contributing

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3141,7 +3141,8 @@ def _GetQueryPlanThroughGateway(self, query: str, resource_link: str, **kwargs:
documents._QueryFeature.OffsetAndLimit + "," +
documents._QueryFeature.OrderBy + "," +
documents._QueryFeature.Top + "," +
documents._QueryFeature.NonStreamingOrderBy)
documents._QueryFeature.NonStreamingOrderBy + "," +
documents._QueryFeature.HybridSearch)
if os.environ.get('AZURE_COSMOS_DISABLE_NON_STREAMING_ORDER_BY', False):
supported_query_features = (documents._QueryFeature.Aggregate + "," +
documents._QueryFeature.CompositeAggregate + "," +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ def __init__(self, partition_key_target_range, client, collection_link, query, d
self._is_finished = False
self._has_started = False
self._cur_item = None
self._query = query
# initiate execution context

path = _base.GetPathFromLink(collection_link, "docs")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@

import os
from azure.cosmos._execution_context.aio import endpoint_component, multi_execution_aggregator
from azure.cosmos._execution_context.aio import non_streaming_order_by_aggregator
from azure.cosmos._execution_context.aio import non_streaming_order_by_aggregator, hybrid_search_aggregator
from azure.cosmos._execution_context.aio.base_execution_context import _QueryExecutionContextBase
from azure.cosmos._execution_context.aio.base_execution_context import _DefaultQueryExecutionContext
from azure.cosmos._execution_context.execution_dispatcher import _is_partitioned_execution_info
from azure.cosmos._execution_context.execution_dispatcher import _is_partitioned_execution_info, _is_hybrid_search_query
from azure.cosmos._execution_context.query_execution_info import _PartitionedQueryExecutionInfo
from azure.cosmos.documents import _DistinctType
from azure.cosmos.exceptions import CosmosHttpResponseError
Expand Down Expand Up @@ -89,7 +89,7 @@ async def fetch_next_block(self):
try:
return await self._execution_context.fetch_next_block()
except CosmosHttpResponseError as e:
if _is_partitioned_execution_info(e): #cross partition query not servable
if _is_partitioned_execution_info(e) or _is_hybrid_search_query(self._query, e):
query_to_use = self._query if self._query is not None else "Select * from root r"
query_execution_info = _PartitionedQueryExecutionInfo(await self._client._GetQueryPlanThroughGateway
(query_to_use, self._resource_link))
Expand Down Expand Up @@ -126,6 +126,22 @@ async def _create_pipelined_execution_context(self, query_execution_info):
self._options,
query_execution_info)
await execution_context_aggregator._configure_partition_ranges()
elif query_execution_info.has_hybrid_search_query_info():
hybrid_search_query_info = query_execution_info._query_execution_info['hybridSearchQueryInfo']
if not hybrid_search_query_info['take']:
raise ValueError("Executing a hybrid search query without TOP or LIMIT can consume many" +
" RUs very fast and have long runtimes. Please ensure you are using one" +
" of the two filters with your hybrid search query.")
if hybrid_search_query_info['take'] > os.environ.get('AZURE_COSMOS_MAX_ITEM_BUFFER_HYBRID_SEARCH', 1000):
raise ValueError("Executing a hybrid search query with more items than the max is not allowed." +
"Please ensure you are using a limit smaller than the max, or change the max.")
execution_context_aggregator = \
hybrid_search_aggregator._HybridSearchContextAggregator(self._client,
self._resource_link,
self._options,
query_execution_info,
hybrid_search_query_info)
await execution_context_aggregator._run_hybrid_search()
else:
execution_context_aggregator = multi_execution_aggregator._MultiExecutionContextAggregator(self._client,
self._resource_link,
Expand Down
Loading