acquia drupal planet

Sneaky Drupal Pagers

See the update at the bottom!

Drupal’s pagers are neat, and when they were first developed, were way ahead of their time. They also have a couple problems. One of them is scalability. When you’ve got 10,000,000 somethings, calculating how many pages there are so that you can skip to the last one is time consuming.

Another limitation is that the pager is designed to page over a database query. The Apache Solr Search module uses Drupal pagers to move through pages of search results that come from Solr. The pseudo code for getting this to work looks like this:

<?php
// What result do we want to start on?
$offset = $page * $number_per_page;

// How many search results are there in total?
$total = $result->get_total();

// Send a very simple database query to the pager system to trick it.
pager_query("SELECT %d", $offset, 0, NULL, $total);

// Magic happens here. A pager appears.
$output .= theme('pager');
?>

That’s great! But I recently had a case where it was impossible to tell how many results there are in the total set. What is really needed is the ability to advance the pager until there aren’t any more pages, but Drupal doesn’t support anything like this by default. Twitter does it, but Drupal… meh. It’s sneaky time!

<?php
// Remember: http://is.gd/3Sf9Z
$total = 0;

// Note that $page is zero based (page zero is the first page).
// Note also that count($results) is just one page's worth of results,
// not the entire possible set (which is impossible to calculate).

// If there are fewer results than what we want to show per page,
// we know we've come to the end of the result set, and don't need
// to show any more pages.
if (count($results) < $number_per_page) {
 
$total = $number_per_page * ($page + 1);
}
// Otherwise, we want to tell the pager to give us yet another
// page to go to.
else {
 
$total = $number_per_page * ($page + 2);
}
// Now the pager will either end where we are, or add one
// more page to the end. This way you can keep advancing one
// more page until there are no more results left.
pager_query("SELECT %d", $number_per_page, 0, NULL, $total);
$output .= theme('pager');
?>

This strategy could be applied to both of the problem cases I mentioned above. If you have a HUGE result set and need a pager, and don’t want to destroy your database, this is a viable technique. It also works if you’re getting your results from a source that can’t tell you how many results there are in total. And it’s sneaky. Enjoy.

Update:

Instead of using a database query to manipulate the page you can manipulate the globals instead:
$GLOBALS[‘pager_page_array’][] = 1; //what page you are on
$GLOBALS[‘pager_total’][] = 3; // total number of pages
$items_per_page = 50;
print theme(‘pager’, NULL, $items_per_page);

Thanks Chx for the tip!

Views 3 + Apache Solr + Acquia Drupal = The Future of Search

For the last six months, Scott Reynolds has been keeping a big juicy secret. As the maintainer of the Apache Solr Views module, he knows just how cool the future of Drupal Search is going to be. His module, based on an idea and code from Thomas Seidl, lets you make custom searches against the Solr index the same way you currently make views against the MySQL database. Want to build a search that just includes videos and MP3s, and renders the results as a playlist? Or how about a search that is limited to the current user's images, displayed in a slideshow? How about a block that shows the latest results that contain the phrase "badgers are the new pony"? Well, even if you didn't want a block like that, with Views 3 and Apache Solr Views, you can have it.

Thomas Siedl's brilliant idea was that Views should be able to build "queries" against any data source, not just databases. Earl Miles agreed, and inagurated the Views 3 branch by commiting the patch by Thomas (with great help from Jeff Miccolis and others). With Views 3 I predict you'll be able to build Views using data from Flickr, or from RDF databases using SPARQL, or from the local file system, or from any other data source that has an API.

To test it all out I used the Acquia Drupal Stack to create a new site (I just love the stack's multisite functionality!). I then signed up for a trial Acquia Network subscription because I wanted to get my hands on 30 days of free Acquia Search (it's easier than setting up Solr myself). I then downloaded Views 3 and Apache Solr (DRUPAL-6--2, just for fun. DRUPAL-6--1 works, too). I had to get the Apache Solr Views module from CVS (Scott, make a devel release!). I put these in sites/all/modules so that they'd override the versions in the Acquia Drupal Stack.

The CVS command for getting Apache Solr Views

$ cvs -d:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal-contrib \
co -d apachesolr_views contributions/modules/apachesolr_views

I installed Apache Solr manually which means I also needed to get the SolrPhpClient library. Since I have Drush, and since Apache Solr DRUPAL-6--2 has Drush integration, I did it like this:

$ drush solr phpclient

I <3 Drush!

I then used FeedAPI to grab all sorts of content from Planet Drupal. I could have just as well used Drush and the Devel module to generate some content, but lorem ipsum gets mighty boring. Finally I used Drush to run cron and even did a search (from the command line!) to check that the content was in the index.

$ drush cron
$ # wait a few minutes for the search index to commit the changes...
$ drush solr search drupal
node/175 by admin (user/1)
title: Agile and Scrum Videos
 This is likely to become a pretty big collection of videos about Scrum and
other other Agile based managements processes. (Drupal 5, Drupal 6, Drupal 7,
Drupal Planet, Drupal Video) ...

node/1 by admin (user/1)
title: Welcome to your new Acquia Drupal website!
 If you are new to Drupal, follow these steps to set up your web site in
minutes: Step 1 ... , forums, polls, tags, comments, ratings, and more. Acquia
Drupal comes with many modules to power social publishing capabilities on your
site. Hundreds of additional Drupal 6.x compatible modules ...    

The good stuff

Now for the good stuff. When you make a new view in Views 3 you get asked what data source to use. Here you can see that I use the Apache Solr search index as a data source.

Views 3 asks for data source

Then I added some fields. These are not the same fields that are available to node based views. They are specific to the underlying data source.

Apache Solr fields in Views 3

I also added a sort so that the results would be displayed according to the search score (keyword relevance).

Adding a sort on score

In order to make this view seem like a "search" screen, it needs a search box, right? You get that by adding a search filter and exposing it. I could add more filters, too, like a filter to limit it to just one content type.

Exposing the search filter

This shouldn't just be a copy of the normal search screen. The results should look different. To that end I told Views to render the results in a table.

Tell views to theme the results as a table

Since we want this to be a page view it needs a path, and I went ahead and stuck it in the menu as well.

Finally, I want to be able to use Apache Solr's facet blocks along with the view. This is a three-step process.

  1. First I have to enable the facet filters (I enabled the block for Tags - a taxonomy vocabulary I have) at q=admin/settings/apachesolr/enabled-filters
  2. Then I have to actually place the blocks at q=admin/build/block
  3. Finall, and this is important, I have to pass in an argument to the view to filter by the same "things" that I'm filtering for with the facets. In my example I have the taxonomy facet block enabled, and therefore need to pass in an argument for taxonomy term.

Add an argument for every facet filter you use

How does it taste?

It tastes great! Feast your eyes on this marvelous search screen.

Search results with Views 3 and Apache Solr

The keyword search and the facet block interact seamlessly.

Search term modules and facet filter Drupal 6

An interesting point to note is that there are no database queries used in retrieving the data or displaying it. No complex views query with lots of joins, and no node_load() calls for displaying the results. This method of querying Solr is just as efficient as using the normal Apache Solr search module.

To my mind, Views 3 and Apache Solr Views are the future of Solr search for Drupal. Even though they are both in heavy development, you can try them out and enjoy the great control you have over your search experience. There are many more handlers that need writing, too, so jump into the Apache Solr Views issue queue and help out. Since it all works with Acquia Drupal and Acquia Search, you can easily get up and running using an Acquia subscription. Enjoy!

Syndicate content