Azure Search .Net SDK potentially does not return all requested results to a request. In this case it will return a ContinuationToken as part of the result (DocumentSearchResult).
If Azure Search can't include all results in a single response, the response returned will include a continuation token that can be passed to ContinueSearch to retrieve more results. See DocumentSearchResultBase.ContinuationToken for more information. Note that this method is not meant to help you implement paging of search results. You can implement paging using the Top and Skip parameters to the Search method.
As such, it is recommended that when a ContinuationToken is returned, a call is made to ContinueSearch to get the rest of the results.
What is the best/recommended way to combine two objects of Type DocumentSearchResult<T>
(one having come from the original Search and the other from ContinueSearch) so that I can return all results together to the consumer?
Here's my first stab at it ("PerformSearch" is the method to be called that should return all results):
private DocumentSearchResult<T> PerformSearch<T>(string searchText, SearchParameters searchParameters) where T : class
{
var searchIndexClient = GetSearchIndexClient<T>();
var searchResults = searchIndexClient.Documents.Search<T>(searchText, searchParameters);
if (searchResults.ContinuationToken != null)
{
ContinueSearch(searchResults, searchIndexClient, searchResults.ContinuationToken);
}
return searchResults;
}
private void ContinueSearch<T>(DocumentSearchResult<T> previousResults, SearchIndexClient searchIndexClient, SearchContinuationToken continuationToken) where T : class
{
var results = searchIndexClient.Documents.ContinueSearch<T>(continuationToken);
previousResults.AddResults(results);
if (results.ContinuationToken != null)
{
ContinueSearch(previousResults, searchIndexClient, results.ContinuationToken);
}
}
public static void AddResults<T>(this DocumentSearchResult<T> first, DocumentSearchResult<T> second) where T : class
{
foreach (var searchResult in second.Results)
{
first.Results.Add(searchResult);
}
foreach (var facet in second.Facets)
{
first.Facets.Add(facet.Key, facet.Value);
}
}
You can combine the results as you have in your example, but there is no point in combining the facets. This is because facets are computed across the entire results of the query on each request, not just over the slice of results that you get back. If you make a series of ContinueSearch
requests and the index isn't modified during that time, you should get back exactly the same facets each time. If your index is changing and you want the most up-to-date facet results, return the final one to your client.
In terms of what's the recommended way of doing this, I actually don't recommend it unless you use $top
to limit the overall size of the results, or you're prepared to deal with very large result sets. Azure Search limits the size of a response for good reasons, and those reasons probably apply to you too, assuming you're also writing a service.
If you're writing a client, maybe you should try implementing an iterator over the results (IEnumerable<SearchResult<T>>
), although you'd have to return the extra information (facets, document count) out-of-band somehow.