Try our conversational search powered by Generative AI!

Paging Search Results

Vote:
 

Hi everyone!

I'm trying to sort the search results of the Alloy example MVC in pages but I don't know how to start doing it and I need someone who guides me a little bit in my way to do it.

I'm not using EPiServer Find, is essential to use it to make this work?

Thanks =)

#123227
Jun 29, 2015 13:08
Vote:
 

Hi,

I have created a Gist with the code I have written and using for paging (works for any IEnumerable<T>) that you can take a look at. You can find it here. To use this code you can modify your search page view model by changing the type of the Hits property to IPagedEnumerable<SearchHit>:

public IPagedEnumerable<SearchHit> Hits { get; set; }

Next, modify your action so it handles a page querystring parameter:

public ViewResult Index(SearchPage currentPage, string q, int page = 1)

And in your action where you create an instance of the view model you set the Hits property like this:

int pageSize = 10;

var hits = Search(q.Trim(), ContentReference.StartPage, ControllerContext.HttpContext, currentPage.LanguageID).ToList();

model.Hits = new PagedList<SearchPageModel.SearchHit>(HttpContext, hits, page, pageSize)
{
   QueryParamName = "page"
};

Finally in the view, somewhere below or above the search results, you render the paging partial that you can find in the Gist:

@{ Html.RenderPartial("_Paging", Model.Hits); }
#123265
Edited, Jun 30, 2015 13:15
Vote:
 

I would also modify the SearchService class in Alloy so it handles paging, so you only get back the results for the current page. In the implementation I have (maybe it's an old version of Alloy) it just gets the 40 first hits. This Search method should be changed from:

public virtual SearchResults Search(string searchText, PageReference rootPage, HttpContextBase context, string languageBranch,
                             string[] fileDirectories, int maxResults)
{
    var query = CreateQuery(searchText, rootPage, context, languageBranch, fileDirectories);
    return _searchHandler.GetSearchResults(query, 1, maxResults);
}

To:

public virtual SearchResults Search(string searchText, PageReference rootPage, HttpContextBase context, string languageBranch,
                             string[] fileDirectories, int page, int pageSize)
{
    var query = CreateQuery(searchText, rootPage, context, languageBranch, fileDirectories);
    return _searchHandler.GetSearchResults(query, page, pageSize);
}

Next you should modify the Search method in the SearchPage controller:

private IEnumerable<SearchPageModel.SearchHit> Search(string searchText, PageReference rootPage, HttpContextBase context, string languageBranch, int page, int pageSize, out int numberOfHits)
{
    var searchResults = _searchService.Search(searchText, rootPage, context, languageBranch, _fileDirectories, page, pageSize);

    numberOfHits = searchResults.TotalHits;
    return searchResults.IndexResponseItems.SelectMany(CreateHitModel);
}

And finally, use this code in the Index action:

int numberOfHits;
int pageSize = 10;
 
var hits = Search(q.Trim(), ContentReference.StartPage, ControllerContext.HttpContext, currentPage.LanguageID, page, pageSize, out numberOfHits).ToList();
 
model.Hits = new PagedList<SearchPageModel.SearchHit>(HttpContext, hits, numberOfHits, page, pageSize)
{
   QueryParamName = "page"
};
model.NumberOfHits = numberOfHits;
#123279
Jun 30, 2015 15:18
Vote:
 

When modifying the Search Service I have a different version (IEnumerable<ContentReference> searchRoots instead of PageReference rootPage).

If I modifiy it I will also need to modify the CreateQuery method.

These are my versions.

Search

public virtual SearchResults Search(string searchText, IEnumerable<ContentReference> searchRoots, HttpContextBase context, string languageBranch, int maxResults)
        {
            var query = CreateQuery(searchText, searchRoots, context, languageBranch);
            return _searchHandler.GetSearchResults(query, 1, maxResults);
        }

CreateQuery

private IQueryExpression CreateQuery(string searchText, IEnumerable<ContentReference> searchRoots, HttpContextBase context, string languageBranch)
        {
            //Main query which groups other queries. Each query added
            //must match in order for a page or file to be returned.
            var query = new GroupQuery(LuceneOperator.AND);

            //Add free text query to the main query
            query.QueryExpressions.Add(new FieldQuery(searchText));

            //Search for pages using the provided language
            var pageTypeQuery = new GroupQuery(LuceneOperator.AND);
            pageTypeQuery.QueryExpressions.Add(new ContentQuery<PageData>());
            pageTypeQuery.QueryExpressions.Add(new FieldQuery(languageBranch, Field.Culture));

            //Search for media without languages
            var contentTypeQuery = new GroupQuery(LuceneOperator.OR);
            contentTypeQuery.QueryExpressions.Add(new ContentQuery<MediaData>());
            contentTypeQuery.QueryExpressions.Add(pageTypeQuery);

            query.QueryExpressions.Add(contentTypeQuery);

            //Create and add query which groups type conditions using OR
            var typeQueries = new GroupQuery(LuceneOperator.OR);
            query.QueryExpressions.Add(typeQueries);
            
            foreach (var root in searchRoots)
            {
                var contentRootQuery = new VirtualPathQuery();
                contentRootQuery.AddContentNodes(root, _contentLoader);
                typeQueries.QueryExpressions.Add(contentRootQuery);
            }

            var accessRightsQuery = new AccessControlListQuery();
            accessRightsQuery.AddAclForUser(PrincipalInfo.Current, context);
            query.QueryExpressions.Add(accessRightsQuery);

            return query;
        }

It also says that _fileDirectories doesn't exist in the SearchPageController.

#123299
Edited, Jul 01, 2015 10:21
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.