Customizing Solr Highlighting with Sunspot

Posted on · 1 minute read

Need full-text text search in your web app? You don’t have to use Elasticsearch. There are alternatives. Even in 2025, some will refuse to switch to Elasticsearch, preferring to use venerable tools such as Solr instead.

The Gallian village from Asterix & Obelix

Recently, I worked on a Ruby on Rails project that used Solr and Sunspot to interface with Solr. I was given a particular task to customize how much text is shown around a word the user was searching for - in other words, to change the size of the highlight fragment. But only for one field for one particular model - and that made things tricky!

Let’s see how I managed.

Changing the Highlight Fragment Size

Ad-hoc changes to the fragment size can be made using solr_params.

search = Sunspot.new_search(@all_entities) do
  # Adjust the fragment size from its default of 100
  adjust_solr_params do |solr_params|
    solr_params['hl.fragsize'] = 300
  end
end
search = search.execute
@results = search.hits

However, this would change the fragment size for all searches. Let’s say we have a particular model and want to adjust the fragment size only for searches concerning that model.

class Post < ApplicationRecord
  searchable do
    integer(:id)

    text(:title, stored: true)
    text(:content, stored: true)

    string(:class_name) do
      self.class.name
    end
  end
end

To change the highlight fragment size for content, but not for the title, we can adjust solr_params to include the field size. Note that fields are generally postfixed with texts.

search = Sunspot.new_search(@all_entities) do
  adjust_solr_params do |solr_params|
    solr_params['hl.content_texts.fragsize'] = 300
  end
end

That works - but only if there are no other models with a content field. If you have multiple models with the same field names, all of those would be affected. We need to make one last change: change the name with which the content field is indexed.

class Post < ApplicationRecord
  searchable do
    # Content will now be indexed as post_content_texts
    text(:content, stored: true, as: :post_content_texts)
  end
end
search = Sunspot.new_search(@all_entities) do
  adjust_solr_params do |solr_params|
    solr_params['hl.post_content_texts.fragsize'] = 300
  end
end

And there you have it. Easy enough in hindsight 🙂