London Dev Meetup Rescheduled! Due to unavoidable reasons, the event has been moved to 21st May. Speakers remain the same—any changes will be communicated. Seats are limited—register here to secure your spot!

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.