In this article I show you how to use views and views_fastsearch to make customized search forms that fit your exact needs. Have you ever wanted to restrict search to just one or two content types? Or search on only an exact set of nodes, say all articles written by a given author? Views and views_fastsearch are the right tools for the job.This article applies to Drupal 5.x, plus the views 1.6 and the views fastsearch 5.x-1.x-dev modules.
UPDATE: As of August 21, 2007, there is no 5.x-1.2 release of views_fastsearch. Until that release is completed, use the 5.x-1.x-dev version of the module to see the features described in this article.
Drupal's search module contains a powerful indexer which makes keyword searching efficient and accurate. On its own, the search module provides either a plain vanilla search field, or the advanced search form, but doesn't provide a mechanism for customizing the offerings. It is an either/or proposition. The views module is well loved for its ability to let you define a custom set of content on your site, and through the use of exposed filters, allow the site visitor to narrow the selection even further. These two modules can be glued together and made to cooperate using the views fastsearch module. In this article I show how to build a search form that has filters for taxonomy terms and content types.
For all the talk about the views module, it is often not fully understood what a view actually is. In its most basic form a view is a set of content (nodes). In fact, when you create a new view, it is, in its initial state, the set of all of the nodes on your site. All of the other stuff that you may do that view will either narrow the set of nodes to be smaller and more focused, or define how those nodes should be displayed.
One of the best features of views is its filters. Once you've defined the initial set of content that the view is dealing with, filters can be used to narrow the set. By exposing the filter to the end user as a form element you empower your visitors to slice and dice the view to taste, and find exactly the content that they are looking for.
The views fastsearch is one such filter. It allows you to start with a view and narrow the set of content based on keywords. It utilizes the very search index that the search module has built, but it restricts its search to the content set defined by the view. It also uses clever SQL to do the actual searching quicker than the search module, thus the "fast" aspect.
The definition of a view as a set of content is a practical definition to work with. It makes it clear that if our goal is to replace Drupal's standard search (which searches all of the published content on your site), the default view (all content) is a good starting place. Once we create a new view, the steps that remain are to narrow the set (limit it to published content), tell it how to present the results (as search results), and to expose the views fastsearch keyword filter so that users can enter their search keywords. We will then have a near identical replacement for Drupal's standard search.
To get set up I installed the search, views and views_fastsearch modules. I created a small amount of content by hand. There are five nodes in total, and they all contain the word Drupal. I kept the two default content types, Story and Page, that are present in a fresh Drupal 5.2 install. I created a taxonomy vocabulary called Drupal topic with the terms core, modules, and themes. I ran cron.php once to make sure that the search index has been built.
First I will show you how to search this content with views fastsearch, after which I will show how a customized form can be built to filter by taxonomy and content type.
Once the modules are installed and some content has been created, it's time to create a view. This is done by navigating to Administer->Site building->Views->Add.
Fill out the following fields:
- Name: This is the machine name of the view. I used content_search
- Access: You have the chance to limit access to this view by role. Leaving all roles unchecked is equivalent to allowing access to everyone, which is the typical configuration for site search.
- Description: A brief description of the view that will be useful to you as an administrator later. It appears on the views administration page and is never seen by your end users.
Provide a page view
- Provide Page View: This must be checked in order for views to provide a page view.
- URL: This is actually the Drupal path (the 'q' parameter), not a full URL. It should not conflict with existing Drupal paths, so using search here will cause problems. I chose fastsearch, but you can use any path you choose. This path can be aliased using the path module.
- View Type: This should be Search Results to emulate traditional Drupal search. Feel free to try the other options, though. For Table View or List View you will need to also add the fields which you wish to be displayed.
- Title: This will be the page title for the search page. This can be whatever you want. I chose "Search by keyword, type and taxonomy".
- Use Pager: This is important if you want your end user to be able to see more than the first page of search results.
- Nodes per Page: Unlike the core search module, views allows you to define how many results per page are displayed. If you are the type who likes Google to show 50 results per page, you can set this number to 50 and enjoy.
For the Search Results view type the only field that is needed is the Search Score field. No configuration is need on the field. If you wish to experiment with other view types (Table, for example), you need to explicitly add each field that should be displayed.
Filters and exposed filters
Nearly every view that you ever create should be filtered to only include published material. The views fastsearch is also a filter (Search: Fast Index). Both of these are added in the filters section. The fastsearch filter should also be exposed to the end user (otherwise they can't enter their search keywords!)
In the Filters fieldset:
- Node: Published: This limits the set of searchable nodes to those that are published. Yes means that the set should be filtered to only include those nodes that are published. If you wanted to build an interface for searching through the unpublished nodes on your site, you could set this to No.
- Search: Fast Index: This is the filter that says "take the set of nodes in this view and reduce it to only those which have a certain search term in the search index."
- After adding the Search: Fast Index to the filters, it will have an Expose button. Use that button to add the filter to the the Exposed Filters fieldset:
- Label: This is text that will appear as a label on the form element that instructs the end user what the field should be used for. I chose "Keyword search".
- Optional: This determines whether a value has to be given for this filter to get any results at all. When unchecked, as in Figure IV, it is not optional, and no nodes will be returned by the view if the Keyword search field is left empty. This is the same behavior that the Drupal core search module has, as well as Google and other search engines. First you are presented with a search screen and no results. Only after you type some keywords and submit the form are search results shown. If the Optional box were checked, it would instruct the view to ignore this filter if no value is present. The view would then show its default set of content (which is all content on the site in this case), and someone coming to the search screen would be confronted with a full array of search results even though they have not yet searched for anything. As you'll see later in this article, this creates a point of conflict when we add and expose further filters.
- Filter settings Default: When checked, this tells the filter to inherit default settings from the Value field for this filter in the Filters fieldset.
- Force Single: Some filters can have multiple values (eg. the taxonomy filter could have core and modules selected). Checking the Force Single checkbox limits the end user to only one choice. Practically, this changes the form element from a multiple select to a single select.
- Lock Operator: Some filters have multiple possible operators (eg. AND/OR). When this is the case, the default behavior is to show an extra form element which specifies the operator. This is usually too much for the normal end user (but can be pure candy for power users), and you can hide that extra form element by checking Lock Operator
Last but not least, it is important to tell views how to sort the results. If you think about this in terms of Google or Yahoo!, you'll realize that search is not just a matter of identifying the right results, but also making sure that the right ones appear at the top of the list for the convenience of the person searching. This task falls to the scores that have been created by the search index. Adding a Search Score sort to our view will guarantee that the most relevant results are displayed first. Make sure that the sort is set to Descending, or you'll end up presenting the least relevant items first!
Now if you visit example.com/fastsearch you should see a nice search form waiting for you. Since the core search module is also active, we can compare the search results produced by the two. In my tests, the scoring factors affect the ordering of the results differently for fastsearch and core search. Overall, the core search handles scoring in a more sophisticated manner than the fast search filter. Fast search makes up for this, though, by allowing more control over the set of content being searched, and also by defining a hook that lets modules add their own scoring factors to search results.
Now it's time to add two more filters to the view so that we can narrow the results based on content type and taxonomy term. Go back to the view and open up its edit tab.
In the Filters fieldset, add two more filters:
- Taxonomy: Terms for Drupal topic: Drupal topic is the name of the taxonomy vocabulary in my test data. Different Terms for ... filters will appear for your specific vocabularies
- Node: Type: This filters on the node type, and you must select all of the options in Value that you want to be available to the end user. In my test data there are only two content types, Story and Page, and I want the end user to be able to search in both. One common feature request on Drupal.org is to limit search to one or more content types, or to exclude a content type altogether. With this filter you can achieve just that.
Now click Expose on both of the new filters to make form elements available to the end user.
- Search: Fast Index - Optional: I mentioned in the discussion of the Optional checkbox in the Exposed Filters fieldset, there is some conflict between the Search: Fast Index field and the other filters. You'll notice in Figure VIII that Optional has now been checked - the search term is now indeed optional. This is done because it is a nice feature to be able to use the other two filters, Drupal term and Type, on their own. You can select all of the Story type content that is categorized as core, for example. If the Search: Fast Index filter is required, then this is impossible because you always have to enter a search term (thus narrowing the results to only that term). The drawback of making the filter optional is that the initial search page will show a set of results even before the user has entered any criteria. If this is disturbing to you, you'll need to make the field not optional and do without the functionality of filtering based on type and taxonomy alone.
- Taxonomy: Terms for Drupal topic:
- Node: Type: For both the taxonomy and the node type filters, the same applies. We want them to be optional so that the user can search with keyword alone. I chose the Force Single option because I like the cleanlier feel of a single select more than the multiple select. I chose Lock Operator because I don't think my site users necessarily want to think about AND/OR operators when searching.
Now with two more exposed filters, we can do some very precise searching.
If you visit Administer->Site configuration->Search settings you will notice that the Views Fastsearch module has extended the options found on this page. There is now a views_fastsearch fieldset at the bottom of the page with a field labeled search_index. The issue here is the nature of the SQL query that gets built and an older bug with the search index building that leads to extra rows in the search_index table. For a full discussion of the issue, see the Drupal.org issue queue. For those sites that started off life as Drupal 5.x sites, it is fairly safe to choose the No duplicates (Unique Index Exists) option and save the configuration. This will lead in the best performance for your fast searches.
The Views Fastsearch filter is an exciting module that opens up many possibilities for custom searches in Drupal. One very neat feature is its exposing of a
hook_search_ranking function. Modules can implement this function to add scoring factors to fast searches. For example, the Voting API could add a scoring factor that gave a higher score (and thus a higher ranking in search results) to content based on the average voting result. Since scoring factors can be weighed relative to each other, this gives administrators an amazing amount of control over the fine-tuning of search results.
Another neat trick that can be done with the fastsearch filter is to implement
theme_search_form in such a way that the default search form is replaced with the filters from the fastsearch view. This effectively replaces core Drupal search with your fastsearch search.