How to boost Solr search results by document type?

203 Views Asked by At

Note: I'm using Sunspot with Rails, but a generic Solr response could still guide me in the right direction if you're not familiar with Sunspot's DSL.

I have a few models similar to these:

class Book < ActiveRecord::Base
  searchable do
    text :title, boost: 2.0
    text :content
  end
end

class Article < ActiveRecord::Base
  searchable do
    text :title, boost: 2.0
    text :content
  end
end

I'm needing to do a fulltext search in all models at the same time for a mixed result, but articles should be considered a bit more relevant than books in the search results.

My current code to perform the search is as follows.

search = Sunspot.search do
  fulltext search_terms, minimum_match: 1
end

This correctly returns mixed results, but I'd need Article results to be boosted in comparison to Book results. I want to be clear that this is NOT the same as listing all Article results first and then listing all Book results. There could still be some mix depending on how Solr ranks the results based on their overall content.

I'm guessing I'll need to use some boost function but can't figure out exactly how.

Any pointers?

1

There are 1 best solutions below

0
Nick Zadrozny On

Sunspot generally tries to expose these kinds of things as functions within the "search" block. ​Checking the Sunspot docs shows this…

# Posts with pizza, scored higher if featured
Post.search do
  fulltext 'pizza' do
    boost(2.0) { with(:featured, true) }
  end
end

​​ That's from https://sunspot.github.io/docs/#Search_In_Depth

​Because Sunspot indexes the model name into the "type" field, I think you could adapt that thusly:

boost(10.0) { with(:type, "Article") }

Alas. If you do try this, you'll get an error like this:

Sunspot::UnrecognizedFieldError: No field configured for Article, Book with name 'type'

That's because current versions of Sunspot's DSL in this case reference the fields are defined in the searchable block, whereas the type field is kind of a special case. Perhaps a good opportunity for a contribution to Sunspot there?

Knowing that, we have a possible workaround, and that is to define our own custom type-related field on your documents. Perhaps call it source to avoid clobbering the special cased defaults, though testing may show that not to be a big deal.

Leading me to this final code example (untested, ymmv, etc!)

class Article < ActiveRecord::Base
  searchable do
    text :title, boost: 2.0
    text :content
    string :source do
      class.name
    end
  end
end

Sunspot.search(Article, Book) do
  fulltext(search_terms) do
    minimum_match 1
    boost(ARTICLE_BOOST) { where(source, "Article") }
  end
end