4
votes

I want ElasticSearch (Tire gem to be specific) to return the result based on the number of times a keyword appears in the fields. For example, I index the field title in a model called Article. I have two objects, the first object has the title value 'Funny Funny subject' while the second object has the title value 'Funny subject'. I want to index in such a way that if I search for the keyword 'Funny', the first object will return first since it has two 'Funny' words appearing in the title. Is it possible to do this via Tire? What is the indexing method called as well?

1

1 Answers

2
votes

Here a working sample, the key factor here is the boostvalue that has to be high enough and you can't use wildcharts in the query.

require 'tire'
require 'yajl/json_gem'

articles = [
  { :id => '0', :type => 'article', :title => 'nothing funny'},
  { :id => '1', :type => 'article', :title => 'funny'},
  { :id => '2', :type => 'article', :title => 'funny funny funny'}
]

Tire.index 'articles' do
  import articles
end

Tire.index 'articles' do
  delete

  create :mappings => {
    :article => {
      :properties => {
        :id       => { :type => 'string', :index => 'not_analyzed', :include_in_all => false },
        :title    => { :type => 'string', :boost => 50.0,            :analyzer => 'snowball'  },
        :tags     => { :type => 'string', :analyzer => 'keyword'                             },
        :content  => { :type => 'string', :analyzer => 'snowball'                            }
      }
    }
  }

  import articles do |documents|
    documents.map { |document| document.update(:title => document[:title].downcase) }
  end

  refresh
end

s = Tire.search('articles') do
  query do
    string "title:funny"
  end
end

s.results.each do |document|
  puts "* id:#{ document.id } #{ document.title } score: #{document._score}"
end

gives

* id:2 funny funny funny score: 14.881571
* id:1 funny score: 14.728935
* id:0 nothing funny score: 9.81929