Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

CircleCI Maintainability Gem Version


Object-Oriented approach to Solr in Ruby.

Table of contents


Add solrb to your Gemfile:

gem 'solrb'

If you are going to use solrb with solr cloud:

gem 'zk' # required for solrb solr-cloud integration
gem 'solrb'


Setting Solr URL via environment variable

The simplest way to use Solrb is SORL_URL environment variable (that has a core name in it):

  ENV['SOLR_URL'] = 'http://localhost:8983/solr/demo'

You can also use Solr.configure to specify the solr URL explicitly:

Solr.configure do |config|
  config.url = 'http://localhost:8983/solr/demo'

It's important to note that those fields that are not configured, will be passed as-is to solr. So you only need to specify fields in configuration if you want Solrb to modify them at runtime.

Single core configuration

Use Solr.configure for an additional configuration:

Solr.configure do |config|
  config.url = 'http://localhost:8983/solr/demo'

  # This gem uses faraday to make requests to Solr. You can specify additional faraday
  # options here.
  config.faraday_options = {}

  # Core's URL is 'http://localhost:8983/solr/demo'
  # Adding fields to work with
  config.define_core do |f|
    f.field :title, dynamic_field: :text
    f.dynamic_field :text, solr_name: '*_text'

Multiple core configuration

Solr.configure do |config|
  config.url = 'http://localhost:8983/solr'

  # Define a core with fields that will be used with Solr.
  # Core URL is 'http://localhost:8983/solr/listings'
  config.define_core(name: :listings) do |f|
    # When a dynamic_field is present, the field name will be mapped to match the dynamic field.
    # Here, "title" will be mapped to "title_text"
    # You must define a dynamic field to be able to use the dynamic_field option
    f.field :title, dynamic_field: :text

    # When solr_name is present, the field name will be mapped to the solr_name at runtime
    f.field :tags, solr_name: :tags_array

    # define a dynamic field
    f.dynamic_field :text, solr_name: '*_text'

  # Pass `default: true` to use one core as a default.
  # Core's URL is 'http://localhost:8983/solr/cars'
  config.define_core(name: :cars, default: true) do |f|
    f.field :manufacturer, solr_name: :manuf_s
    f.field :model, solr_name: :model_s

Warning: Solrb doesn't support fields with the same name. If you have two fields with the same name mapping to a single solr field, you'll have to rename one of the fields.

config.define_core do |f|
  # Not allowed: Two fields with same name 'title'
  f.field :title, solr_name: :article_title
  f.field :title, solr_name: :page_title

Solr Cloud

To enable solr cloud mode you must define a zookeeper url on solr config block. In solr cloud mode you don't need to provide a solr url (config.url or ENV['SOLR_URL']). Solrb will watch the zookeeper state to receive up-to-date information about active solr nodes including the solr urls.

You can also specify the ACL credentials for Zookeeper. More Information

Solr.configure do |config|
  config.zookeeper_urls = ['localhost:2181', 'localhost:2182', 'localhost:2183']
  config.zookeeper_auth_user = 'zk_acl_user'
  config.zookeeper_auth_password = 'zk_acl_password'

If you are using puma web server in clustered mode you must call enable_solr_cloud! on on_worker_boot callback to make each puma worker connect with zookeeper.

on_worker_boot do


To enable master-slave mode you must define a master url and slave url on solr config block. In solr master-slave mode you don't need to provide a solr url (config.url or ENV['SOLR_URL']).

Solr.configure do |config|
  config.master_url = 'localhost:8983'
  config.slave_url = 'localhost:8984'
  # Disable select queries from master:
  config.disable_read_from_master = true
  # Specify Gray-list service
  config.nodes_gray_list =

If you are using puma web server in clustered mode you must call enable_master_slave! on on_worker_boot callback to make each puma worker connect with zookeeper.

on_worker_boot do

Gray list

Solrb provides two built-in services:

  • Solr::MasterSlave::NodesGrayList::Disabled — Disabled service (default). Just does nothing.
  • Solr::MasterSlave::NodesGrayList::InMemory — In memory service. It stores failed URLs in an instance variable, so it's not shared across threads/servers. URLs will be marked as "gray" for 5 minutes, but if all URLs are gray, the policy will try to send requests to these URLs earlier.

You are able to implement your own services with corresponding API.

Force node URL

You can force solrb to use a specific node URL with the with_node_url method:

Solr.with_node_url('http://localhost:9000') do 'example', query_fields: query_fields).run

Basic Authentication

Basic authentication is supported by solrb. You can enable it by providing auth_user and auth_password on the config block.

Solr.configure do |config|
  config.auth_user = 'user'
  config.auth_password = 'password'


# creates a single document and commits it to index
doc =
doc.add_field(:id, 1)
doc.add_field(:name, 'Solrb!!!')

commit =

request =[doc, commit])

You can also create indexing document directly from attributes:

doc = { id: 5, name: 'John' })


Simple Query

  query_field = :name)

  request = 'term', query_fields: [query_field]) 1, page_size: 10)

Querying multiple cores

For multi-core configuration use Solr.with_core block:

Solr.with_core(:models) do
  Solr.delete_by_id(3242343) 'term', query_fields: query_fields)[doc])

Query with field boost

  query_fields = [
    # Use boost_magnitude argument to apply boost to a specific field that you query :name, boost_magnitude: 16), :title)
  request = 'term', query_fields: query_fields) 1, page_size: 10)

Query with filtering

  query_fields = [ :name), :title)
  filters = [ :equal, field: :title, value: 'A title')]
  request = 'term', query_fields: query_fields, filters: filters) 1, page_size: 10)

AND and OR filters

  usa_filter = :equal, field: :contry, value: 'USA'), :equal, field: :region, value: 'Idaho')
  canada_filter = :equal, field: :contry, value: 'Canada'), :equal, field: :region, value: 'Alberta')

  location_filters =, canada_filter)
  request = 'term', filters: location_filters) 1, page_size: 10)

Query with sorting

  query_fields = [ :name), :title)
  sort_fields = [ :name, direction: :asc)]
  request = 'term', query_fields: query_fields)
  request.sorting = sort_fields) 1, page_size: 10)

Default sorting logic is following: nulls last, not-nulls first.

  query_fields = [ :name)
  sort_fields = [ :is_featured, direction: :desc), "score desc")
  request = 'term', query_fields: query_fields)
  request.sorting = sort_fields) 1, page_size: 10)

Query with grouping

  query_fields = [ :name), :category)
  request = 'term', query_fields: query_fields)
  request.grouping = :category, limit: 10) 1, page_size: 10)

Query with facets

  query_fields = [ :name), :category)
  request = 'term', query_fields: query_fields)
  request.facets = [ :terms, field: :category, options: { limit: 10 })] 1, page_size: 10)

Query with boosting functions

  query_fields = [ :name), :category)
  request = 'term', query_fields: query_fields)
  request.boosting =
    multiplicative_boost_functions: [ :name)],
    phrase_boosts: [ :category, boost_magnitude: 4)]
  ) 1, page_size: 10)

Dictionary boosting function

Sometimes you want to do a dictionary-style boosting example: given a hash (dictionary)

{3025 => 2.0, 3024 => 1.5, 3023 => 1.2}

and a field of category_id the resulting boosting function will be:

if(eq(category_id_it, 3025), 2.0, if(eq(category_id_it, 3024), 1.5, if(eq(category_id_it, 3023), 1.2, 1)))

note that I added spaces for readability, real Solr query functions must always be w/out spaces

Example of usage:

  category_id_boosts = {3025 => 2.0, 3024 => 1.5, 3023 => 1.2}
  request.boosting =
    multiplicative_boost_functions: [ :category_id,
        dictionary: category_id_boosts)

Query with shards.preference

  shards_preference =
    properties: [ 'replica.type', value: 'PULL')
  request = 'term', shards_preference: shards_preference) 1, page_size: 10)

Field list

  query_fields = [ :name), :category)
  request = 'term', query_fields: query_fields)
  # Solr::Query::Request will return only :id field by default.
  # Specify additional return fields (fl param) by setting the request field_list
  request.field_list = [:name, :category] 1, page_size: 10)

Deleting documents

Solr.delete_by_id(3242343, commit: true)
Solr.delete_by_query('*:*', commit: true)

Active Support instrumentation

This gem publishes events via Active Support Instrumentation

To subscribe to solrb events, you can add this code to initializer:

ActiveSupport::Notifications.subscribe('request.solrb')  do |*args|
  event =*args)
  if Logger::INFO == Rails.logger.level"Solrb #{event.duration.round(1)}ms")
  elsif Logger::DEBUG == Rails.logger.level && Rails.env.development?


It's possible to inspect the parameters for each solr query request done using Solrb by requiring solr/testing file in your test suite. The query parameters will be accessible by reading Solr::Testing.last_solr_request after each request.

require 'solr/testing'

RSpec.describe MyTest do
  let(:query) { 'Solrb') }
  it 'returns the last solr request params' do 1, page_size: 10)
    expect(Solr::Testing.last_solr_request.body[:params]).to eq({ ... })

Running specs

This project is setup to use CI to run all specs agains a real solr.

If you want to run it locally, you can either use CircleCI CLI or do a completely manual setup (for up-to-date steps see circleci config)

docker pull solr:7.7.1
docker run -it --name test-solr -p 8983:8983/tcp -t solr:7.7.1
# create a core
curl 'http://localhost:8983/solr/admin/cores?action=CREATE&name=test-core&configSet=_default'
# disable field guessing
curl http://localhost:8983/solr/test-core/config -d '{"set-user-property": {"update.autoCreateFields":"false"}}'
SOLR_URL=http://localhost:8983/solr/test-core rspec