Sunspot

Sunspot is a Solr client written in Ruby and based on the RSolr project. Sunspot provides an interface between an application(usually Ruby on Rails) and a Solr index. This interface allows the application to send and query data very easily, using Solr as the search engine. A few lines of code are all that are needed to get a basic search function set up.
This document assumes Rails is the underlying framework.
Throughout this guide, you will see some code examples. These code examples are drawn from a very simple Ruby on Rails application, and are designed to offer some real-world, working code that new users will find useful. The complete demo app can be found here.

Note on Sunspot Solr Binary

There is an optional gem, `sunspot_solr`, which offers a pre-packaged Solr distribution for local development. Some online guides recommend installing this and give examples of using it. This information can be very confusing to new users, and we do not recommend it. There are no command line tools or Rake tasks for starting, stopping or restarting a Websolr index. Additionally, the pre-packaged Solr distribution may be a very different version from your Websolr index, which means it will behave differently in a local environment.

Step 1: Set up a Websolr Index

The first step is to make sure that there is a Websolr index ready for your app to interact with. This needs to be set up first so you know which version of the gems you need to install. You will also need to ensure the index has the proper configuration.
All Solr indices need a collection of configuration files that tell Solr what data to expect and how to process it. The Solr configuration files for Sunspot have been compiled into a collection that work on Websolr. You will need to ensure that your index is using the Sunspot configuration in order for it to work correctly.
Websolr indices can be created in a few different ways, and the documentation for each path varies. If you need help creating your index check out the link that pertains to your situation:
  • If you’ve signed up with us at https://websolr.com, you will want to follow the directions here. When it comes to choosing a Solr configuration, make sure to pick the Sunspot option.
  • Heroku users should follow these directions. Websolr will default to creating the new index using Sunspot’s configuration. You can also specify it via the command line, like so: heroku addons:create websolr[:PLAN] [-a APP_NAME] --config=sunspot

Step 2: The Solr Index URL

When you have successfully created your index, it will be given a semi-random URL. You can find this in the Websolr.com Dashboard, in the Overview tab. From this view, you can also verify that the Configuration in use is Sunspot’s:

Heroku users will have an environment variable called WEBSOLR_URL created when Websolr is added to the application. This variable will contain the fully-qualified URL to the cluster.
You can verify that Solr is up and running by appending some endpoint like /select or /admin/ping to your URL and requesting the resource:
Using curl:
curl https://us-east-1.websolr.com/solr/a1b2c3d4e5/select
{"responseHeader":{"status":0,"QTime":59},"response":{"numFound":0,"start":0,"docs":[]}}
Using a browser:

Note on Solr endpoints

A common support subject is“[URGENT] INDEX IS OFFLINE!!”. The root cause ends up simply being a point of confusion. All requests to Solr require an endpoint to be specified, otherwise Solr does not know what to do with the request. Attempting to access a URL without giving an endpoint like /select, /update, /admin/ping, /admin/luke, etc, will result in an HTTP 503 error. This does not mean that the index is offline, just that the user has made an incomplete request. If you absolutely want to verify whether your index is up and running, append /admin/ping to your URL and see what happens.

Step 3: Install the Gem

To install Sunspot, you will need the sunspot_rails gem. Add the following to your Gemfile outside of any blocks:

gem 'sunspot_rails'

Make sure to bundle install. This will install the libraries necessary to use Sunspot.

Step 4: Tell Sunspot where your Solr Index is located

You can optionally also create a sunspot.yml file with this Rake task:

rails generate sunspot_rails:install

The sunspot.yml file looks something like this:

production:
  solr:
    hostname: localhost
    port: 8983
    log_level: WARNING
    path: /solr/production


development:
  solr:
    hostname: localhost
    port: 8982
    log_level: INFO
    path: /solr/development


test:
  solr:
    hostname: localhost
    port: 8981
    log_level: WARNING
    path: /solr/test
This file allows you to designate different Solr indices and instances for different contexts. You may want to use this to set an index for your production app, and a different index for development/staging, and a local index for testing.
Note that the sunspot.yml file will supersede your WEBSOLR_URL variable in the environment running the Rails app! This means that Heroku users who have added Websolr to their app should not create the sunspot.yml file unless they have a good reason. And if you do create it, you’ll need to edit it to point to the right location(s).
If you want to have a sunspot.yml file that points to different indices, you can do something like this:
production:
  solr:
    hostname: us-east-1.websolr.com
    port: 443
    scheme: https
    path: /solr/0a1b2c3d4e5f


development:
  solr:
    hostname: us-east-1.websolr.com
    port: 443
    scheme: https
    path: /solr/blahblahblah


test:
  solr:
    hostname: us-east-1.websolr.com
    port: 443
    scheme: https
    path: /solr/s0m3t35tth1ng

It is also possible to add some additional parameters to the sunspot.yml file, which override the default behaviors. You can find documentation on these different parameters here.

Step 5: Add Sunspot to your Models

Any model that you will want to be searchable with Sunspot will need to be configured to do so by adding the searchable block with its attributes. Our demo app has a User model that looks something like this:

class User < ActiveRecord::Base
  searchable do
    text :first_name
    text :last_name
    text :email
    text :address
    text :city
    integer :zip_code
    text :company
    text :company_description
  end
end

This makes the model searchable with Sunspot. 

Step 6: Create a Search Route

You will need to set up a route to handle searching. The easiest way to do this is to have a search route per model. This involves updating your models’ corresponding controller, and defining a route in config/routes.rb. You’ll also need to have some views that handle rendering the results, and a form that posts data to the controller(s). Take a look at how we implemented this in our demo app for some examples of how this is done.

Our Example

In our example Rails app, we have one model, User, with a handful of attributes. It looks something like this:

class User < ActiveRecord::Base
  searchable do
    text :first_name
    text :last_name
    text :email
    text :address
    text :city
    integer :zip_code
    text :company
    text :company_description
  end
end

To implement search, we used the file called app/controllers/users_controller.rb and added this code:

def search
   @results = User.search { fulltext "#{params[:q]}"}.results 
end

Note on Hits vs. Results

The User#search method above returns a Sunspot data structure of the matching object IDs. Calling .hits on this data structure will return the IDs, while calling .results will return the actual ActiveRecord objects. See the Readme file for more information.

We then created a route in the config/routes.rb file:

resources :users do
    collection do
      post :search  # creates a route called users_search
    end
  end

Next, we need to have some views to render the data we get back from Solr. The search controller action will be rendered by creating a file called app/views/users/search.html.erb and adding:

<div class="container">
  <h3>Search Results</h3>
  <% if @results.present? %>
    <%= render partial: 'search_result' %>
  <% else %>
    <h4>Nothing here, chief!</h4>
  <% end %>
</div>

This way if there are no results to show, we simply put a banner indicating as such. If there are results to display, we will iterate over the collection(assigning each one to a local variable called result), and passing it off to a partial. Create a file for a partial called app/views/users/_search_result.html.erb and add:

<div class="row">
  <div class="col">
    <%= link_to "#{result.first_name} #{result.last_name} <#{result.email}>", user_path(result) %><br />
    <strong><%= result.company %></strong><br />
    <em><%= result.company_description %></em><br />
    <br />
  </div>
</div>
This partial simply renders a search result using some of the data of the matching ActiveRecord objects.
At this point, the User model is configured for searching in Solr, and has routes for sending a query to Solr. The next step is to render a form so that a user can actually use this feature. This is possible with a basic form_with helper.
In the demo app, we added this to the navigation bar:
<%= form_with(url: search_users_path, method: "post", class: 'form-inline my-2 my-lg-0', local: true) do %>
     <%= text_field_tag(:q, nil, class: "form-control mr-sm-2", placeholder: "Search") %>
     <%= button_tag("Search", class: "btn btn-outline-info my-2 my-sm-0", name: nil) %>
  <% end %>

This code renders a form that looks like this:

Please note that these classes use Bootstrap, which may not be in use with your application. The ERB scaffold should be easily adapted to your purposes.
We’re close to finishing up! We just need to tell the app where the Websolr index is located, then push our data into it.

Step 7: Push data into Solr

Now that the app has everything it needs to query the index and render the results, we need to push data into Solr. There are a few ways to do this.
One method is to open up a Rails console and run <Model>.reindex. So if you want to reindex a model called User, you would run User.reindex.
Another method is to use Rake tasks from the command line. If you wanted to reindex that same User model, you could run: bundle exec rake sunspot:reindex.

Step 8: Put it all together

At this point you should have all of the pieces you need to search your data using Sunspot. In our demo app, we have this simple list of users:

This search box is rendered by a form that will pass the query to the UsersController#search action, via the route set up in config/routes.rb :

This query will reach the UsersController#search action, where it will be passed to Sunspot, which queries Solr. Solr will search the users index, and return any results to a class variable called @results.
The UsersController will then ensure the appropriate views are rendered. Each result will be rendered by the partial app/views/users/_search_result.html.erb. It looks something like this:

Congratulations! You have implemented Sunspot in Rails!

Final Thoughts

This documentation demonstrated how to quickly get Solr added to a basic Rails application. We installed the Sunspot gem, added it to a model, set up the search route, and created the views and partials needed to render the results. Then we set up the connection to Solr and pushed the data into the slice. Finally, we were able to search that data through our app.
Hopefully this was enough to get you up and running with Sunspot. This documentation is not exhaustive, and there are a lot of really cool features that Sunspot offers. There are other additional changes and customizations that can be implemented to make search more accurate and resilient. 

You can find information on these additional subjects in the Cookbook section below. And if you have any ideas or requests for additional content, please don’t hesitate to let us know!