<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Slash Dot Dash: Quick Ferret primer with examples</title>
    <link>http://www.slashdotdash.net/articles/2007/01/09/quick-ferret-primer-with-examples</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Rolling on Rails</description>
    <item>
      <title>Quick Ferret primer with examples</title>
      <description>&lt;p&gt;Need a fast, full-text search capability for your Rails app? Step forward &lt;a href="http://ferret.davebalmain.com/trac/"&gt;Ferret&lt;/a&gt; and the &lt;a href="http://projects.jkraemer.net/acts_as_ferret/"&gt;acts_as_ferret plugin&lt;/a&gt;.&lt;/p&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Ferret is a high-performance, full-featured text search engine library written for Ruby. It is inspired by Apache Lucene Java project.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Acts_as_ferret is a plugin for Ruby on Rails which makes it simple to implement full text search for Rails. It builds on Ferret which is a ruby port of Apache Lucene. It is a technology suitable for nearly any application that requires full-text search.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;p&gt;&lt;strong&gt;1. Install ferret&lt;/strong&gt;&lt;/p&gt;


&lt;pre&gt;
sudo gem install ferret
&lt;/pre&gt;

	&lt;p&gt;&lt;strong&gt;2. Install acts_as_ferret plugin&lt;/strong&gt;&lt;/p&gt;


&lt;pre&gt;
ruby script/plugin install -x svn://projects.jkraemer.net/acts_as_ferret/tags/stable/acts_as_ferret
&lt;/pre&gt;

	&lt;p&gt;&lt;strong&gt;3. Add acts_as_ferret to ActiveRecord model&lt;/strong&gt;&lt;/p&gt;


&lt;pre&gt;
class Item &amp;lt; ActiveRecord::Base
  acts_as_ferret
end
&lt;/pre&gt;

	&lt;p&gt;&lt;strong&gt;4. Search&lt;/strong&gt;&lt;/p&gt;


&lt;pre&gt;
Item.find_by_contents(query) # Query is a string representing your query
&lt;/pre&gt;

	&lt;p&gt;Very simple implementation for great search performance.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Advanced Usage&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;For some slightly advanced usage I needed to search text across a one-to-one relationship, plus page and sort the results. The following class declaration shows the Item has a related ItemDescription (containing a description field) that is included in the search index (via the description method in Item). The title is also given a boost so that matches in the title field have more importance than the description. I also needed to be able to sort the results by published date (pub_date). This required a conversion of the datetime field to integer for correct sorting.&lt;/p&gt;


item.rb
&lt;pre&gt;
class Item &amp;lt; ActiveRecord::Base
  has_one :item_description

  acts_as_ferret :fields =&amp;gt; {:title =&amp;gt; {:boost =&amp;gt; 2, :index =&amp;gt; :untokenized}, 
                             :description =&amp;gt; {},
                             :pub_date_sort =&amp;gt; {:index =&amp;gt; :untokenized_omit_norms, :term_vector =&amp;gt; :no}}

  def description
    @description ||= item_description.description
  end

  # To enable sorting by date it must be converted to an integer
  def pub_date_sort
    pub_date.to_i
  end
end
&lt;/pre&gt;

	&lt;p&gt;It is also a good idea to add a convenience method to the Item model to use the search:&lt;/p&gt;


item.rb
&lt;pre&gt;
def self.full_text_search(q, options = {})
  return nil if q.nil? || q.empty?
  default_options = {:limit =&amp;gt; 50, :page =&amp;gt; 1}
  options = default_options.merge options
  options[:offset] = options[:limit] * (options.delete(:page).to_i-1)  
  results = Item.find_by_contents(q, options)
  return [results.total_hits, results]
end
&lt;/pre&gt;

	&lt;p&gt;Add a method that creates a paginator in application.rb:&lt;/p&gt;


application.rb
&lt;pre&gt;
def pages_for(size, options = {})
  default_options = {:per_page =&amp;gt; 50}
  options = default_options.merge options
  pages = Paginator.new self, size, options[:per_page], (params[:page]||1)
  pages
end
&lt;/pre&gt;

	&lt;p&gt;Add a search method to the controller, note the use of a reverse sort so that the &lt;strong&gt;newest&lt;/strong&gt; items (by published date) are returned first.&lt;/p&gt;


items_controller.rb
&lt;pre&gt;
def search
    s = Ferret::Search::SortField.new(:pub_date_sort, :reverse =&amp;gt; true)

    @query = params[:query]
    @item_count, @latest_items = Item.full_text_search(@query, {:page =&amp;gt; (params[:page]||1), :sort =&amp;gt; s})
    @item_pages = pages_for(@item_count)
end
&lt;/pre&gt;

	&lt;p&gt;The @item_pages can then be used by the standard Rails paginator in the view to provide paged search results.&lt;/p&gt;


	&lt;h4&gt;References&lt;/h4&gt;


	&lt;p&gt;&lt;a href="http://blog.zmok.net/articles/2006/10/18/full-text-search-in-ruby-on-rails-3-ferret"&gt;Full text search in Ruby on Rails 3 &amp;#8211; ferret&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Tue, 09 Jan 2007 22:44:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:dabeb2e4-10c5-4de4-bc2e-374a7dfda52a</guid>
      <author>ben@slashdotdash.net (Ben)</author>
      <link>http://www.slashdotdash.net/articles/2007/01/09/quick-ferret-primer-with-examples</link>
      <category>Ruby on Rails</category>
    </item>
    <item>
      <title>"Quick Ferret primer with examples" by Bill</title>
      <description>&lt;p&gt;I&amp;#8217;m using ferret for my application now, but I&amp;#8217;m finding that I&amp;#8217;ve hit the wall with its capabilities when it comes to sorting by something like the distance between two zip codes.  The issue being is that the user posts a search form with a zip code and the index doesn&amp;#8217;t know about anything other than the values on the indexed model, nothing external to it.&lt;/p&gt;


	&lt;p&gt;Someone told me Sphinx (UltraSphinx specifically) would suit my needs, but I tried it out and had even more issues with it.  I guess UltraSphinx has geo calculations or something built into it.&lt;/p&gt;


	&lt;p&gt;Have you ever attempted something like this or maybe know what I might try to get this to work?&lt;/p&gt;</description>
      <pubDate>Fri, 14 Mar 2008 21:25:15 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:f0c57cb0-9894-46d8-878c-c2e75115fe87</guid>
      <link>http://www.slashdotdash.net/articles/2007/01/09/quick-ferret-primer-with-examples#comment-402</link>
    </item>
    <item>
      <title>"Quick Ferret primer with examples" by Ben</title>
      <description>&lt;p&gt;Something like the following search form would do the trick.&lt;/p&gt;


&lt;pre&gt;&amp;lt;% form_tag search_items_path, :method =&amp;gt; :get do %&amp;gt;
  &amp;lt;%= text_field_tag 'query', '' %&amp;gt;
  &amp;lt;%= submit_tag 'Search'  %&amp;gt;
&amp;lt;% end %&amp;gt;&lt;/pre&gt;</description>
      <pubDate>Thu, 17 Jan 2008 11:48:28 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:a9dfbae2-2f4e-48e0-a6e8-f2f12285149a</guid>
      <link>http://www.slashdotdash.net/articles/2007/01/09/quick-ferret-primer-with-examples#comment-351</link>
    </item>
    <item>
      <title>"Quick Ferret primer with examples" by Robert</title>
      <description>&lt;p&gt;How do I actually add a search bar on a given page for people to enter search items? Thanks for any help you can offer, I appreciate it.&lt;/p&gt;


	&lt;p&gt;Robert&lt;/p&gt;</description>
      <pubDate>Thu, 17 Jan 2008 07:38:03 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:b86f85a1-25c2-44f1-90da-9d0cb9ae50dc</guid>
      <link>http://www.slashdotdash.net/articles/2007/01/09/quick-ferret-primer-with-examples#comment-350</link>
    </item>
    <item>
      <title>"Quick Ferret primer with examples" by Ben</title>
      <description>&lt;p&gt;Just a quick note to say that I am now using &lt;a href="http://www.slashdotdash.net/articles/2007/08/06/rails-searching-with-sphinx" rel="nofollow"&gt;Sphinx&lt;/a&gt; instead of Ferret for all my Rails searching needs!&lt;/p&gt;</description>
      <pubDate>Sun, 12 Aug 2007 20:47:29 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:a95d5ff6-9bf9-4871-acdc-f531d65e19c4</guid>
      <link>http://www.slashdotdash.net/articles/2007/01/09/quick-ferret-primer-with-examples#comment-130</link>
    </item>
  </channel>
</rss>
