Paging with Examine
Paging with Lucene and Examine requires some specific API usage. It's very easy to get wrong by using Linq's Skip/Take methods and when doing this you'll inadvertently end up loading in all search results from Lucene and then filtering in memory when what you really want to do is have Lucene only create the minimal search result objects that you are interested in.
There are 2 important parts to this:
- The Skip method on the ISearchResults object
- The Search overload on the BaseSearchProvider where you can specify maxResults
ISearchResults.Skip
This is very different from the Linq Skip method so you need to be sure you are using the Skip method on the ISearchResults object. This tells Lucene to skip over a specific number of results without allocating the result objects. If you use Linq’s Skip method on the underlying IEnumerable<SearchResult> of ISearchResults, this will allocate all of the result objects and then filter them in memory which is what you don’t want to do.
Search with maxResults
Lucene isn’t perfect for paging because it doesn’t natively support the Linq equivalent to “Skip/Take”. It understands Skip (as above) but doesn’t understand Take, instead it only knows how to limit the max results so that it doesn’t allocate every result, most of which you would probably not need when paging.
With the combination of ISearchResult.Skip and maxResults, we can tell Lucene to:
- Skip over a certain number of results without allocating them and tell Lucene
- only allocate a certain number of results after skipping
Show me the code
//for example purposes, we want to show page #4 (which is pageIndex of 3)
var pageIndex = 3;
//for this example, the page size is 10 items
var pageSize = 10;
var searchResult = searchProvider.Search(criteria,
//don't return more results than we need for the paging
//this is the 'trick' - we need to load enough search results to fill
//all pages from 1 to the current page of 4
maxResults: pageSize*(pageIndex + 1));
//then we use the Skip method to tell Lucene to not allocate search results
//for the first 3 pages
var pagedResults = searchResult.Skip(pageIndex*pageSize);
var totalResults = searchResult.TotalItemCount;
So that is the correct way to do paging with Examine and Lucene which ensures max performance and minimal object allocations.