Rails Full Text Search with Ferret

by Jens Kramer

Ferret Library
http://ferret.davebalmain.com
. gem install ferret

the problem?
    collected information, and suddenly someone needs to search it!

Ferret structure:
    index
        documents
            fields

Indexing
    index = Ferret::Index.new :path => '/tmp/index'

    book.each do | book|
        index < < {
                    :content => book.content,
                    :title => book.title,
                    :author => book.author
                }   
    end

    index.optimize
    index.close

Searching

    index.search_each('ruby') do |doc_id, score|
        doc = index[doc_id]
        puts … 
    end
    index.close

    note: doc_id changes whenever you change your index, so not a good using it

Query Language
    text based, very expressive, very powerful meta language        basic queries
        - fox
        - w?ldcar*
        - quick~0.5
        - [20050725 20050905]
        - “quick|speedy|fast <> fox”
        - “quick|fast fox”~2
    combined queries
        - (quick fast) and fox
        - +(qui* fast) -brown +fox
        - description:(quick fast) and name:fox
        - content:rails title:rails^5 +date: >= 20070101

Ferret Query API
    sp_term_q = SpanTermQuery.new(:content, ‘rails’)
    sp_first_q ) SpanFirstQuery.new(sp_term_q, 100)

    result = index.search(sp_first_q)

Sorting
    result = index.search(’ruby’, :sort => ‘date DESC, title’)

    sort = Ferret::Search::Sort.new(
        Ferret::Search::SortField(:date, :reverse = true, type => :byte)
    )

Ferret Browser
    - interesting tool… :)     - comes with the gem
    - lets you browse your index


Basic Usage in Rails

    class Book < ActiveRecord::Base
        acts_as_ferret
    end

    Book.rebuild.index
    results = Book.find_with_ferret …

Field Options
    acts_as_ferret(
        :fields => {
            :title => {:store => :yes, :books => 10}
            …
            }
        :ferret = {
            :analyser => GermanSteammingAnalyser.new # custom analyser 
            }
    )

Custom fields 
    that won’t go into the DB.  
                acts_as_ferret(
        :fields => {
            :title => {:store => :yes, :books => 10}
            :booktitle => {}   # custom!
            }

    ? carefull this fields might be lost when you rebuild index 

ActiveRecord Options
    allow to modify default active record options

Lazy Options
    store only partials not entire results

Multi_Search
    you have multiple models, but you’ll need a single search method for an entire app
    the only requirement, STORE THE CLASSNAME on the index:
        acts_as_ferret(:fields = {…}, :store_classname => true)

(EXAMPLE)

Ferret out there in the wild:
    omdb.org
    xing.com
    blogblogs.com.br
    lingr.com
    altlaw.org
    pertior.com 
    sachsen-gesetze.de

Further Reading

    Ferret Shorcut 
    Lucene in Action

    ferret-talk@rubyforge.org
    ferret.davebalmain.com
    projects.jkraemer.net/act_as_ferret