views:

633

answers:

3

I have a search page that I'm implementing as part of an ASP.NET + MVC + jquery site. The search query scores each result that is returned as part of the results set. i.e. Higher score for closer match.

Because the results set can change, and because the algorithm that scores the matches is somewhat intensive, I only want to load the results once and to find a way to click through the pages of results.

I figured that I would make a page that contained all of the search results (each result has its own ) and just show/hide a subset by clicking on buttons associated with jquery code. I think I can see how to do this before I start trying to make it work (I'm still fairly new to jquery), but thought I'd first see if anyone has any better ideas.

Thanks in advance for any suggestions.

Edit: Francisco's suggestion was just what I needed. I implemented it with some minor changes and created some jquery buttons to navigate to first/prev/next/last page along with a 'Viewing results n-m out of N' label. Thanks for all the suggestions.

+1  A: 

Cache the results and page through the cached resultset. Maybe using a combination of jqGrid and json.

However you do not really include enough information for us to give the best approach.

You need to do some analysis first.

Factors to consider :

  • How many results is a user likely to look through?

  • Can a user deal with so much information on one page?

  • Is the page going to be slow if you render the whole result set?

UPDATE

Another option could be to use Infinite Scroll. Basically as the user scrolls the results and is towards the end of the screen you auto load in x more results. More here and here

redsquare
Thanks for taking a look. I considering caching but I don't know how to do that.Users will typically see 50-100 results, and I planned to make pages with 5 results per page. The total results are too large to put on one page - each 'result' is actually a few lines and there's just too much. Even 10 results on a page means a user will have to do a lot of scrolling.While the results are long, there's not actually that much data (~200 bytes per result). There's just something about the content (that I won't go into) that mean it has to occupy a fair bit of screen area.
Another idea, added to the answer
redsquare
+1  A: 

Have you considered using something like Lucene.NET for your indexing? Lucene.NET does a very good job in dealing with offsets for paging. The Document instances that you return from your search could contain the key values for the individual records or you could store enough information to represent the visual aspects for each search result for each item, as well.

When the user pages, you just adjust your offset. Things like query caching and optimization are built-in. I pulled down and compiled a few weeks ago and had a POC to build the index, add and remove items from the index, and return results in just a few minutes by cobbling the samples together. I much prefer using a dedicate index for indexing, leaving the database to work more as a dedicated storage medium - but that is my personal preference.

If you decide to check it out, pull and compile the source from their SVN. The "stable" version is a bit outdated.

Edit:

Here is a brief example on paging with Lucene.NET: Paging using Lucene.net

joseph.ferris
Hadn't heard of that but will check it out. I would generally like to do this without adding additional technology though, and I figure this should already be possible using ASP.NET, MVC, LINQ to SQL and jquery - all of which I'm already using.
Understood. It is definitely possible, it just comes down to a matter of determining what the expected load is going to be on the system and recognizing that this could become a point to be revisited at a later time. Depending on the number of records and the number of concurrent users, something like Lucene.NET might be overkill.
joseph.ferris
+1  A: 

I think your idea is good enough.

Just put all the elements you want from each page into differents divs. Then give the div a class or id attribute that is easily identifiable, such as:

<div id="page1" class="divpage">
page 1 html here
</div>
<div id="page2" class="divpage">
page 2 html here
</div>

etc

The jQuery code would look like this:

$("#page1").show();
$(".divpage").hide(); //this hides all other divs

Edit:

To do this dynamically, creat a strongly-typed view associated to your list of results. The header of the view should be something like:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<Result>>" %>

With "result" being your class:

public class Result
{
    int score {get;set;}
    string data {get;set;}
}

Then in your view, you put this:

<%int resultsPerPage = 10;
int currentResults = 0;
int numPage=0;

foreach(var item in Model) 
{   
    if (currentResults==0) Response.Write("<div id=\"page"+numPage+"\" class=\"divpage\">");
    %>

    <%=item.score.ToString()%>
    <%=item.data%>

    <%currentResults++;
    if (currentResults>resultsPerPage)
    {
        numPage++;
        currentResults=0;
        Response.Write("</div>");
    }
}%>

<%if (currentResults!=0) Response.Write("</div>");%>

Then for your buttons:

<%for (int i=0;i<numPage;i++)
{
%>
<a href="" onclick="showPage('<%=i%>');return false;">Page <%=i%></a>

<%}%>

<script type="text/javascript">

function showPage(num)
{
    $("#page"+num).show();
    $(".divpage").hide();
}

</script>

Finally, in your controller:

public ActionResult ShowResults()
{
    List<Result> results = getResultsOrdererdByScoreFunction();
    return View(results);
}
Francisco
I considered that, but how would I do that dynamically? I don't know in advance how many pages there'll be. I can easily generate the div ids to contain sequential numbers, but how does one access those elements using a variable for the page number in javascript?
added some code for that
Francisco
Thanks @Francisco! I think this is what I want to do. Let me try it out and get back to you.