The project is in a healthy, maintained state
Do basic administrative operations on a solr cloud instance and collections within
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 0
>= 0
>= 0

Runtime

~> 2.0
~> 1.0
~> 2.0
 Project Readme

SolrCloud::Connection

Common usage

# Connect to the server, upload a config set, make a collection based on it,
# and make an alias pointing to that collection

server = SolrCloud::Connection.new(url: url, user: user, password: pass) 
cfg = server.create_configset(name: "my_cfg", confdir: "/path/to/my/conf")
cars_v1 = server.create_collection(name: "cars_v1", configset: "my_cfg")
cars = cars_v1.alias_as("cars")

Basic functionality / Roadmap

Do basic administrative tasks on a running Solr cloud instance

  • create (i.e., upload) a configSet when given a conf directory
  • list, create, and delete configsets, collections, and aliases
  • get basic version information for the running solr
  • check on the health of individual collections
  • treat an alias (mostly) as a collection
  • automatically generate methods to talk to defined requestHandlers and updateHandlers
  • provide a way to talk to the analyzer for testing of fieldTypes
  • hook into the schema API
  • allow it to work with cores, and not just solrcloud collections (which, you know bad naming then)
  • figure out how to deal with managed resources
  • get info from updateHandler metrics, esp. pending documents and cumulative errors
  • hook into performance metrics for easy reporting and checks
  • support more of the v2 API

In almost all cases, you can treat an alias to a collection like the underlying collection.

A note about deleting things

Collections, aliases, and configsets all have a #delete! method. Keep in mind that solr enforces a rule that nothing in-use can be deleted. This gem will throw appropriate errors if you try to delete a configset that's being used by a collection, or try to delete a collections that's pointed to by an alias.

Caveats

  • At this point the API is unstable
  • Solr has no sense of an atomic action and plenty of other ways (e.g, the admin interface) to mess with things, so nothing is cached. This means that individual actions can involve several round-trips to solr. If you're doing so much admin that this becomes a bottleneck, you're well outside this gem's target case.
  • While solr aliases can point to more than one collection at a time, this gem enforces one collection per alias (although many aliases can point to the same collection)

Usage

The code below covers all the basics. See the docs for full sets of parameters, which errors are thrown, etc.

Create a connection to the server

url = "http://localhost:9090/"
user = "solr"
password = "SolrRocks"
config_directory = "/path/to/myconfig/conf" # Directory 'conf' contains solrconfig.xml

require "solr_cloud/connection"

server = SolrCloud::Connection.new(url: url, user: user, password: pass) 
  #=> <SolrCloud::Connection http://localhost:9090>

  # or bring your own Faraday object
  # server2 = SolrCloud::Connection.new_with_faraday(faraday_connection)

  ### Get some basic info

server.version_string #=> "8.11.2"
server.cloud? #=> true
server.mode #=> "solrcloud"

Configsets

# List the configsets
server.configsets #=> [<SolrCloud::Configset '_default' at http://localhost:9090>]

# Sometimes you just want the names.
server.configset_names #=> ["_default"]

# Create a new configset by taking a conf directory, zipping it up,
# and sending it to solr
cset = server.create_configset(name: "horseless", confdir: config_directory)
  #=> <SolrCloud::Configset 'horseless' at http://localhost:9090>
server.configset_names #=> ["_default", "horseless"]

# That's a dumb name for a config set. Delete it and try again.
cset.delete! #=> <SolrCloud::Connection http://localhost:9090>
cset = server.create_configset(name: "cars_cfg", confdir: config_directory)
  #=> <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>
server.configsets
  #=> [<SolrCloud::Configset '_default' at http://localhost:9090>,
  #    <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>]

# Can't be overwritten by accident
server.create_configset(name: "cars_cfg", confdir: config_directory)
  #=> raised #<SolrCloud::WontOverwriteError: Won't replace configset cars_cfg unless 'force: true' passed >

# But you can force it
server.create_configset(name: "cars_cfg", confdir: config_directory, force: true)
  #=> <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>

cfg = server.get_configset("cars_cfg") #=> <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>
cfg.in_use? #=> false

Collections

# Now create a collection based on an already-existing configset
cars_v1 = server.create_collection(name: "cars_v1", configset: "cars_cfg") 
  #=> <SolrCloud::Collection 'cars_v1'>
server.collections #=> [<SolrCloud::Collection 'cars_v1'>]
server.collection_names #=> ["cars_v1"]

# Check it out quick
cars_v1.alive? #=> "OK"
cars_v1.healthy? #=> true
cars_v1.count #=> 0

# Any aliases
cars_v1.aliased? #=> false
cars_v1.aliases #=> []

# Its configset
cars_v1.configset #=> <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>

# Commit anything that's been added
cars_v1.commit #=> <SolrCloud::Collection 'cars_v1'>

# Solr knows when a configset is in use, and won't delete it

cfg.delete! 
    #=> raised #<SolrCloud::ConfigSetInUseError: Can not delete ConfigSet 
    # as it is currently being used by collection [cars_v1]>

Aliases

# We'll want to alias it so we can just use 'cars'
cars = cars_v1.alias_as("cars") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>
cars_v1.alias? #=> false
cars_v1.aliased? #=> true

cars_v1.has_alias?("cars") #=> true
cars_v1.alias_as("autos") #=> <SolrCloud::Alias 'autos' (alias of 'cars_v1')>
cars_v1.aliases
  #=> [<SolrCloud::Alias 'cars' (alias of 'cars_v1')>, <SolrCloud::Alias 'autos' (alias of 'cars_v1')>]

cars_v1.get_alias("autos").delete! #=> <SolrCloud::Connection http://localhost:9090>
cars_v1.aliases #=> [<SolrCloud::Alias 'cars' (alias of 'cars_v1')>]

# There's syntactic sugar for switching out aliases
cars_v2 = server.create_collection(name: "cars_v2", configset: "cars_cfg") #=> <SolrCloud::Collection 'cars_v2'>
cars = server.get_alias("cars") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>

cars.collection #=> <SolrCloud::Collection 'cars_v1' (aliased by 'cars')>
cars.switch_collection_to("cars_v2") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v2')>
cars.collection #=> <SolrCloud::Collection 'cars_v2' (aliased by 'cars')>
cars_v1.aliases #=> []
cars_v2.aliases #=> [<SolrCloud::Alias 'cars' (alias of 'cars_v2')>]

# Aliases will swap from collection to collection without warning
cars_v1.alias_as("cars") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>

# ...unless you use the bang(!) version
cars_v2.alias_as!("cars") #=> raised #<SolrCloud::AliasAlreadyDefinedError: Alias cars already points to cars_v1>

# You can also just switch it from the alias itself.
cars.switch_collection_to("cars_v1") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>

# Aliases show up as "collections" so you can just use them interchangeably
server.collection_names #=> ["cars_v1", "cars_v2", "cars"]

# They even == to each other
cars #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>
cars == cars_v1 #=> true
cars == cars_v2 #=> false

# But sometimes you want to differentiate them from each other
server.only_collection_names #=> ["cars_v1", "cars_v2"]
cars.alias? #=> true
cars_v1.alias? #=> false

cars.collection #=> <SolrCloud::Collection 'cars_v1' (aliased by 'cars')>

Accessing objects from other objects

# You can grab existing collections/aliases/configsets from the server
# as well as when they're returned by a create_* statement
cv1 = server.get_collection("cars_v1") #=> <SolrCloud::Collection 'cars_v1' (aliased by 'cars')>
cars = server.get_collection("cars") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>

# get_* methods might return nil
typo = "cars_V1" #=> "cars_V1"
server.has_collection?(typo) #=> false
dne = server.get_collection(typo) #=> nil

# get_*! methods will throw an error
dne = server.get_collection!(typo) #=> raised #<SolrCloud::NoSuchCollectionError: Collection 'cars_V1' not found>

# alias#collection returns the underlying collection.
# collection#collection returns itself. This makes it easier to
# write code without differentiating between them.

cars.collection #=> <SolrCloud::Collection 'cars_v1' (aliased by 'cars')>
cars_v1.collection #=> <SolrCloud::Collection 'cars_v1' (aliased by 'cars')>

# Configsets, Aliases, and Collections know how they're related

cars_v1.aliases #=> [<SolrCloud::Alias 'cars' (alias of 'cars_v1')>]
cars = cars_v1.get_alias("cars") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>
cfg = cars.configset #=> <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>
cfg.collections #=> [<SolrCloud::Collection 'cars_v1' (aliased by 'cars')>, <SolrCloud::Collection 'cars_v2'>]

Documentation

Run bundle exec rake docs to generate the documentation in docs/

Installation

Install the gem and add to the application's Gemfile by executing:

$ bundle add solr_cloud-connection

If bundler is not being used to manage dependencies, install the gem by executing:

$ gem install solr_cloud-connection

Testing

This repository is set up to run tests under docker.

  1. docker compose build
  2. docker compose run app bundle install
  3. docker compose up
  4. docker compose run app bundle exec rspec

Contributing

Bugs, functionality suggestions, API suggestions, feature requests, etc. all welcome on GitHub at https://github.com/mlibrary/solr_cloud-connection.