0

There are no results when I apply pagination to the query. But when I comment that code, I get results.

Search log without pagination:

INFO Solr Query - ?q=: AND val:__boost&start=0&rows=1000000&fl=*,score&fq=((_templatename:("Product Details Page") AND _language:("en")) AND is_active_b:("True"))&fq=_indexname:(stratum_products_master_index)&wt=xml

Search log with pagination:

INFO Solr Query - ?q=: AND val:__boost&start=3&rows=3&fl=*,score&fq=((_templatename:("Product Details Page") AND _language:("en")) AND is_active_b:("True"))&fq=_indexname:(stratum_products_master_index)&wt=xml

I observe that for some reason it is start=3 even when I'm passing pageNumber=1 & pageSize=3.
When I comment this line, it works query = query.Page(pageNumber, pageSize);

Where am I going wrong.

private IQueryable<ProductSearchResultItem> GetSearchQuery(string searchTerm, string tagId, int pageNumber, int pageSize)
        {
            var predicate = GetSearchPredicate(searchTerm, tagId);
            IQueryable<ProductSearchResultItem> query = searchService.GetSearchQuery<ProductSearchResultItem>(Constants.SearchIndexes.Products, predicate);

            /// Apply pagination 
            query = query.Page(pageNumber, pageSize);
            return query;
        }

private Expression<Func<ProductSearchResultItem, bool>> GetSearchPredicate(string searchTerm, string tagId, string languageRegionalIsoCode = "en")
        {
            Item productDetailsTemplateItem = SitecoreUtility.GetItem(Templates.ProductDetailsPage.ID);
            string productDetailsTemplateName = productDetailsTemplateItem != null ? productDetailsTemplateItem.Name : string.Empty;

            /// Initialize queries with True for AND queries and False for OR queries
            var andPredicate = PredicateBuilder.True<ProductSearchResultItem>();

            if (!string.IsNullOrWhiteSpace(productDetailsTemplateName))
            {
                /// get only product pages of the specified language
                andPredicate = andPredicate.And(x => x.TemplateName.Equals(productDetailsTemplateName, StringComparison.InvariantCultureIgnoreCase));
                    
                ///get items of specified language
                andPredicate = andPredicate.And(x => x.Language.Equals(languageRegionalIsoCode, StringComparison.InvariantCultureIgnoreCase));

                /// get only active items
                andPredicate = andPredicate.And(x => x.IsActive);

                ///filter by searchTerm
                if (!string.IsNullOrWhiteSpace(searchTerm))
                {
                    andPredicate = andPredicate.And(x => x.Title.Like(searchTerm, 0.75f));
                }

                ///filter by tag
                if (!string.IsNullOrWhiteSpace(tagId))
                {
                    andPredicate = andPredicate.And(x => x.Tags.Contains(new Guid(tagId)));
                }
            }            

            return andPredicate;
        } 
1
  • 1
    Try changing Filter to Where here: query = context.GetQueryable<T>().Filter(predicate);
    – Marek Musielak
    Commented Feb 17, 2023 at 7:12

3 Answers 3

3

You should not use fq parameter in your queries - you should use q parameter instead.

What you send now to Solr is:

INFO Solr Query - ?q=: AND val:__boost&start=3&rows=3&fl=*,score&fq=((_templatename:("Product Details Page") AND _language:("en")) AND is_active_b:("True"))&fq=_indexname:(stratum_products_master_index)&wt=xml

  • q parameter says "anything in _boost order"
  • start from 3rd item
  • return 3 documents
  • and filter results with ((_templatename:("Product Details Page") AND _language:("en")) AND is_active_b:("True"))

The whole filter should be already in q query.

The only thing you have to change is how you pass your predicate to context.GetQueryable. You should not use

query = context.GetQueryable<T>().Filter(predicate);

and instead you should use

query = context.GetQueryable<T>().Where(predicate);

With that, your predicate will be used in query (q) parameter and sorting with pagination will be applied correctly.

Also when you use query.Page(pageNumber, pageSize); with 1 for pageNumber, you in fact request for second page of the search results. pageNumber is 0-based. If you want first page and you got 1 from the calling method, you need to use

query.Page(pageNumber - 1, pageSize);
3
  • I changed Filter to Where. Still no results. I had to change query.Page to query.Skip().Take() as suggested by @Filip. The Search log with Where is now Solr Query - ?q=((_templatename:("Product Details Page") AND _language:("en")) AND is_active_b:("True")) AND _val_:__boost&start=0&rows=3&fl=*,score&fq=_indexname:(stratum_products_master_index)&wt=xml
    – sukesh
    Commented Feb 17, 2023 at 8:18
  • Also, it says user Filter Query wherever possible. sitecore.stackexchange.com/questions/16127/…
    – sukesh
    Commented Feb 17, 2023 at 8:19
  • 2
    when you use query.Page(pageNumber, pageSize); with 1 for pageNumber, you in fact request for second page of the search results. pageNumber is 0-based. If you want first page and you got 1 from the calling method, you need to use query.Page(pageNumber - 1, pageSize);
    – Marek Musielak
    Commented Feb 17, 2023 at 8:31
1

Try using this

query.Skip(pageSize * (pageNumber - 1)).Take(pageSize);
1

Pagination is simply a way to restrict the number of search results we want to view, by saying that we want to get a specific segment of search results. An example could be to retrieve all search results from the first result to and including the next 20 subsequent results. The way this is achieved in the ContentSearch API is by using the LINQ extension methods Skip() and Take():

using (var context = ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())  
{
  // Grab the first 20 search results
  var results = context.GetQueryable<SearchResultItem>()
                       .Where(...)
                       .Skip(0).Take(20); 
}

Note: Instead of using the Skip() and Take() methods directly, you can leverage the Page() extension method, which does the exact same thing, even more elegantly.

public class ProductSearcher  
{
  public ProductSearchResult Search(SearchCriteria criteria)  
  {
    using (var context = ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())  
    {
      var filterPredicate = PredicateBuilder.True<SearchResultItem>();
  
      // Only take products created over the past year
      filterPredicate = filterPredicate
                       .And(x => x.CreatedDate.Between(DateTime.Now.Date.AddYears(-1), DateTime.Now.Date, Inclusion.Both));
  
      // Query by the search term
      var searchTermPredicate = PredicateBuilder.False<SearchResultItem>();
      searchTermPredicate = searchTermPredicate
                           .Or(x => x.Name.Like(criteria.SearchTerm, 0.75f)))
                           .Or(x => x.Content.Contains(criteria.SearchTerm));
  
      // Construct final filter predicate, and apply filter 
      var predicate = filterPredicate.And(searchTermPredicate);
      var query = context.GetQueryable<SearchResultItem>().Filter(predicate);
  
      // Apply sorting
      query = query.OrderBy(x => x.CreatedDate).ThenBy(x => x.Name);
  
      // Apply pagination 
      query = query.Page(criteria.PageNumber, criteria.PageSize)
  
      // Fetch the results
      var results = query.GetResults();
      var totalResults = results.TotalSearchResults;
      var productResults = results.Hits.Select(MapSearchResultItemToProduct).ToArray();
  
      return new ProductSearchResult 
      {
        NumberOfResults = totalResults,
        Results = productResults           
      };
    }
  }
  
  public Product MapSearchResultItemToProduct(SearchResultItem item)  
  {
    // Map to a Product domain object...
  }
}

public class SearchCriteria  
{
  public string SearchTerm { get; set; }
  public int PageNumber { get; set; }
  public int PageSize { get; set; }
}

public class ProductSearchResult  
{
  public int NumberOfResults { get; set; }
  public IEnumerable<Product> Results { get; set; }
}

More details and Credit: https://soen.ghost.io/a-re-introduction-to-the-contentsearch-api-in-sitecore-part-2/

Hope it helps!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.