solr_cloud-connection 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +184 -52
- data/Rakefile +1 -1
- data/lib/solr_cloud/alias.rb +7 -7
- data/lib/solr_cloud/collection.rb +31 -10
- data/lib/solr_cloud/configset.rb +2 -1
- data/lib/solr_cloud/connection/alias_admin.rb +1 -4
- data/lib/solr_cloud/connection/collection_admin.rb +5 -6
- data/lib/solr_cloud/connection/configset_admin.rb +0 -1
- data/lib/solr_cloud/connection/version.rb +1 -1
- data/lib/solr_cloud/connection.rb +14 -13
- data/lib/solr_cloud/errors.rb +2 -0
- data/readme.rb +162 -0
- metadata +58 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da67e9a6312ae058259368a9933abe711d1c0554337c59c5f688cf2f17cee606
|
4
|
+
data.tar.gz: 36b815217b2f3e806d9b639d4839f093d61327ee496fee1c3d4774039c688e48
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c828e6c7f7976cee46ac7b81c8955d2253253e3084e3841e26a502bf2d03808327578e69e63a47c0907dd7d38df3db27747a2383a6e8a6f9f4b1a73c69832340
|
7
|
+
data.tar.gz: 25548a6825b308a62ec376bf1b59d596a557c8508f9feeb56cabd5bc402907ecf4f7602658c5087483424844d1fffddf2c7673ecc2f16cefb3ad79f03696aba5
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [0.5.0] - 2025-03-24
|
4
|
+
- Added some sugar for unifying aliases and collections
|
5
|
+
- Update tests
|
6
|
+
- Better errors
|
7
|
+
- Flesh out README.md to be a useful document
|
8
|
+
|
9
|
+
|
3
10
|
## [0.4.0] - 2023-12-07
|
4
11
|
- Fixed rules about what names are legal collections/configsets/aliases
|
5
12
|
- Update version and changelog
|
data/README.md
CHANGED
@@ -1,14 +1,36 @@
|
|
1
1
|
# SolrCloud::Connection
|
2
2
|
|
3
|
-
|
3
|
+
## Common usage
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
```ruby
|
6
|
+
|
7
|
+
# Connect to the server, upload a config set, make a collection based on it,
|
8
|
+
# and make an alias pointing to that collection
|
9
|
+
|
10
|
+
server = SolrCloud::Connection.new(url: url, user: user, password: pass)
|
11
|
+
cfg = server.create_configset(name: "my_cfg", confdir: "/path/to/my/conf")
|
12
|
+
cars_v1 = server.create_collection(name: "cars_v1", configset: "my_cfg")
|
13
|
+
cars = cars_v1.alias_as("cars")
|
14
|
+
|
15
|
+
```
|
16
|
+
|
17
|
+
## Basic functionality / Roadmap
|
18
|
+
|
19
|
+
Do basic administrative tasks on a running Solr cloud instance
|
20
|
+
|
21
|
+
* [x] create (i.e., upload) a configSet when given a `conf` directory
|
22
|
+
* [x] list, create, and delete configsets, collections, and aliases
|
23
|
+
* [x] get basic version information for the running solr
|
24
|
+
* [x] check on the health of individual collections
|
25
|
+
* [x] treat an alias (mostly) as a collection
|
26
|
+
* [ ] automatically generate methods to talk to defined requestHandlers and updateHandlers
|
27
|
+
* [ ] provide a way to talk to the analyzer for testing of fieldTypes
|
28
|
+
* [ ] hook into the schema API
|
29
|
+
* [ ] allow it to work with cores, and not just solrcloud collections (which, you know bad naming then)
|
30
|
+
* [ ] figure out how to deal with managed resources
|
31
|
+
* [ ] get info from updateHandler metrics, esp. pending documents and cumulative errors
|
32
|
+
* [ ] hook into performance metrics for easy reporting and checks
|
33
|
+
* [ ] support more of the v2 API
|
12
34
|
|
13
35
|
In almost all cases, you can treat an alias to a collection like the underlying collection.
|
14
36
|
|
@@ -22,7 +44,7 @@ a collections that's pointed to by an alias.
|
|
22
44
|
## Caveats
|
23
45
|
|
24
46
|
* At this point the API is unstable
|
25
|
-
*
|
47
|
+
* Solr has no sense of an atomic action and plenty of other ways
|
26
48
|
(e.g, the admin interface) to mess with things, so nothing is cached.
|
27
49
|
This means that individual actions can involve several round-trips to solr. If you're doing so much admin
|
28
50
|
that this becomes a bottleneck, you're well outside this gem's target case.
|
@@ -34,70 +56,179 @@ a collections that's pointed to by an alias.
|
|
34
56
|
The code below covers all the basics. See the docs for full sets of parameters, which errors are
|
35
57
|
thrown, etc.
|
36
58
|
|
59
|
+
|
60
|
+
### Create a connection to the server
|
61
|
+
|
37
62
|
```ruby
|
63
|
+
url = "http://localhost:9090/"
|
64
|
+
user = "solr"
|
65
|
+
password = "SolrRocks"
|
66
|
+
config_directory = "/path/to/myconfig/conf" # Directory 'conf' contains solrconfig.xml
|
38
67
|
|
39
68
|
require "solr_cloud/connection"
|
40
69
|
|
41
|
-
server = SolrCloud::
|
42
|
-
|
70
|
+
server = SolrCloud::Connection.new(url: url, user: user, password: pass)
|
71
|
+
#=> <SolrCloud::Connection http://localhost:9090>
|
43
72
|
|
44
|
-
# or bring your own Faraday object
|
45
|
-
#
|
73
|
+
# or bring your own Faraday object
|
74
|
+
# server2 = SolrCloud::Connection.new_with_faraday(faraday_connection)
|
75
|
+
|
76
|
+
### Get some basic info
|
77
|
+
|
78
|
+
server.version_string #=> "8.11.2"
|
79
|
+
server.cloud? #=> true
|
80
|
+
server.mode #=> "solrcloud"
|
81
|
+
```
|
46
82
|
|
83
|
+
### Configsets
|
84
|
+
```ruby
|
85
|
+
# List the configsets
|
86
|
+
server.configsets #=> [<SolrCloud::Configset '_default' at http://localhost:9090>]
|
87
|
+
|
88
|
+
# Sometimes you just want the names.
|
47
89
|
server.configset_names #=> ["_default"]
|
48
|
-
default = server.get_configset("_default") #=> <SolrCloud::Configset '_default' at http://localhost:8983>
|
49
90
|
|
50
|
-
# Create a new
|
51
|
-
|
52
|
-
server.
|
91
|
+
# Create a new configset by taking a conf directory, zipping it up,
|
92
|
+
# and sending it to solr
|
93
|
+
cset = server.create_configset(name: "horseless", confdir: config_directory)
|
94
|
+
#=> <SolrCloud::Configset 'horseless' at http://localhost:9090>
|
95
|
+
server.configset_names #=> ["_default", "horseless"]
|
53
96
|
|
54
|
-
# That's a dumb name.
|
55
|
-
cset.delete!
|
56
|
-
cset = server.create_configset(name: "
|
97
|
+
# That's a dumb name for a config set. Delete it and try again.
|
98
|
+
cset.delete! #=> <SolrCloud::Connection http://localhost:9090>
|
99
|
+
cset = server.create_configset(name: "cars_cfg", confdir: config_directory)
|
100
|
+
#=> <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>
|
101
|
+
server.configsets
|
102
|
+
#=> [<SolrCloud::Configset '_default' at http://localhost:9090>,
|
103
|
+
# <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>]
|
57
104
|
|
58
|
-
#
|
59
|
-
server.
|
60
|
-
|
61
|
-
server.alias_names #=> ["cars"]
|
105
|
+
# Can't be overwritten by accident
|
106
|
+
server.create_configset(name: "cars_cfg", confdir: config_directory)
|
107
|
+
#=> raised #<SolrCloud::WontOverwriteError: Won't replace configset cars_cfg unless 'force: true' passed >
|
62
108
|
|
63
|
-
|
64
|
-
|
109
|
+
# But you can force it
|
110
|
+
server.create_configset(name: "cars_cfg", confdir: config_directory, force: true)
|
111
|
+
#=> <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>
|
65
112
|
|
66
|
-
|
67
|
-
|
113
|
+
cfg = server.get_configset("cars_cfg") #=> <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>
|
114
|
+
cfg.in_use? #=> false
|
68
115
|
|
116
|
+
```
|
69
117
|
|
70
|
-
|
71
|
-
cars_v2.alias? #=> false. It's a true collection
|
72
|
-
cars_v2.aliased? #=> true
|
73
|
-
cars_v2.aliases #=> [<SolrCloud::Alias "cars" (alias of "cars_v2")> ]
|
74
|
-
cars_v2.has_alias?("cars") #=> true
|
118
|
+
### Collections
|
75
119
|
|
76
|
-
|
120
|
+
```ruby
|
121
|
+
# Now create a collection based on an already-existing configset
|
122
|
+
cars_v1 = server.create_collection(name: "cars_v1", configset: "cars_cfg")
|
123
|
+
#=> <SolrCloud::Collection 'cars_v1'>
|
124
|
+
server.collections #=> [<SolrCloud::Collection 'cars_v1'>]
|
125
|
+
server.collection_names #=> ["cars_v1"]
|
77
126
|
|
78
|
-
#
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
cars_v3.configset #=> <SolrCloud::Configset 'cars_config' at http://localhost:8023>
|
127
|
+
# Check it out quick
|
128
|
+
cars_v1.alive? #=> "OK"
|
129
|
+
cars_v1.healthy? #=> true
|
130
|
+
cars_v1.count #=> 0
|
83
131
|
|
84
|
-
#
|
85
|
-
|
86
|
-
|
132
|
+
# Any aliases
|
133
|
+
cars_v1.aliased? #=> false
|
134
|
+
cars_v1.aliases #=> []
|
135
|
+
|
136
|
+
# Its configset
|
137
|
+
cars_v1.configset #=> <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>
|
138
|
+
|
139
|
+
# Commit anything that's been added
|
140
|
+
cars_v1.commit #=> <SolrCloud::Collection 'cars_v1'>
|
141
|
+
|
142
|
+
# Solr knows when a configset is in use, and won't delete it
|
143
|
+
|
144
|
+
cfg.delete!
|
145
|
+
#=> raised #<SolrCloud::ConfigSetInUseError: Can not delete ConfigSet
|
146
|
+
# as it is currently being used by collection [cars_v1]>
|
147
|
+
|
148
|
+
```
|
149
|
+
|
150
|
+
### Aliases
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
# We'll want to alias it so we can just use 'cars'
|
154
|
+
cars = cars_v1.alias_as("cars") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>
|
155
|
+
cars_v1.alias? #=> false
|
156
|
+
cars_v1.aliased? #=> true
|
157
|
+
|
158
|
+
cars_v1.has_alias?("cars") #=> true
|
159
|
+
cars_v1.alias_as("autos") #=> <SolrCloud::Alias 'autos' (alias of 'cars_v1')>
|
160
|
+
cars_v1.aliases
|
161
|
+
#=> [<SolrCloud::Alias 'cars' (alias of 'cars_v1')>, <SolrCloud::Alias 'autos' (alias of 'cars_v1')>]
|
162
|
+
|
163
|
+
cars_v1.get_alias("autos").delete! #=> <SolrCloud::Connection http://localhost:9090>
|
164
|
+
cars_v1.aliases #=> [<SolrCloud::Alias 'cars' (alias of 'cars_v1')>]
|
165
|
+
|
166
|
+
# There's syntactic sugar for switching out aliases
|
167
|
+
cars_v2 = server.create_collection(name: "cars_v2", configset: "cars_cfg") #=> <SolrCloud::Collection 'cars_v2'>
|
168
|
+
cars = server.get_alias("cars") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>
|
169
|
+
|
170
|
+
cars.collection #=> <SolrCloud::Collection 'cars_v1' (aliased by 'cars')>
|
171
|
+
cars.switch_collection_to("cars_v2") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v2')>
|
87
172
|
cars.collection #=> <SolrCloud::Collection 'cars_v2' (aliased by 'cars')>
|
173
|
+
cars_v1.aliases #=> []
|
174
|
+
cars_v2.aliases #=> [<SolrCloud::Alias 'cars' (alias of 'cars_v2')>]
|
175
|
+
|
176
|
+
# Aliases will swap from collection to collection without warning
|
177
|
+
cars_v1.alias_as("cars") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>
|
178
|
+
|
179
|
+
# ...unless you use the bang(!) version
|
180
|
+
cars_v2.alias_as!("cars") #=> raised #<SolrCloud::AliasAlreadyDefinedError: Alias cars already points to cars_v1>
|
181
|
+
|
182
|
+
# You can also just switch it from the alias itself.
|
183
|
+
cars.switch_collection_to("cars_v1") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>
|
184
|
+
|
185
|
+
# Aliases show up as "collections" so you can just use them interchangeably
|
186
|
+
server.collection_names #=> ["cars_v1", "cars_v2", "cars"]
|
187
|
+
|
188
|
+
# They even == to each other
|
189
|
+
cars #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>
|
190
|
+
cars == cars_v1 #=> true
|
191
|
+
cars == cars_v2 #=> false
|
192
|
+
|
193
|
+
# But sometimes you want to differentiate them from each other
|
194
|
+
server.only_collection_names #=> ["cars_v1", "cars_v2"]
|
195
|
+
cars.alias? #=> true
|
196
|
+
cars_v1.alias? #=> false
|
197
|
+
|
198
|
+
cars.collection #=> <SolrCloud::Collection 'cars_v1' (aliased by 'cars')>
|
199
|
+
|
200
|
+
```
|
201
|
+
|
202
|
+
### Accessing objects from other objects
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
# You can grab existing collections/aliases/configsets from the server
|
206
|
+
# as well as when they're returned by a create_* statement
|
207
|
+
cv1 = server.get_collection("cars_v1") #=> <SolrCloud::Collection 'cars_v1' (aliased by 'cars')>
|
208
|
+
cars = server.get_collection("cars") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>
|
209
|
+
|
210
|
+
# get_* methods might return nil
|
211
|
+
typo = "cars_V1" #=> "cars_V1"
|
212
|
+
server.has_collection?(typo) #=> false
|
213
|
+
dne = server.get_collection(typo) #=> nil
|
214
|
+
|
215
|
+
# get_*! methods will throw an error
|
216
|
+
dne = server.get_collection!(typo) #=> raised #<SolrCloud::NoSuchCollectionError: Collection 'cars_V1' not found>
|
217
|
+
|
218
|
+
# alias#collection returns the underlying collection.
|
219
|
+
# collection#collection returns itself. This makes it easier to
|
220
|
+
# write code without differentiating between them.
|
88
221
|
|
89
|
-
|
90
|
-
|
91
|
-
cars_v2.aliases #=> [<SolrCloud::Alias "cars" (alias of "cars_v2")>, <SolrCloud::Alias "old_cars" (alias of "cars_v2")>]
|
222
|
+
cars.collection #=> <SolrCloud::Collection 'cars_v1' (aliased by 'cars')>
|
223
|
+
cars_v1.collection #=> <SolrCloud::Collection 'cars_v1' (aliased by 'cars')>
|
92
224
|
|
93
|
-
#
|
94
|
-
cars.switch_collection_to cars_v3
|
225
|
+
# Configsets, Aliases, and Collections know how they're related
|
95
226
|
|
96
|
-
|
97
|
-
|
227
|
+
cars_v1.aliases #=> [<SolrCloud::Alias 'cars' (alias of 'cars_v1')>]
|
228
|
+
cars = cars_v1.get_alias("cars") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>
|
229
|
+
cfg = cars.configset #=> <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>
|
230
|
+
cfg.collections #=> [<SolrCloud::Collection 'cars_v1' (aliased by 'cars')>, <SolrCloud::Collection 'cars_v2'>]
|
98
231
|
|
99
|
-
# cars_v1 isn't doing anything for us anymore. Ditch it.
|
100
|
-
cars_v1.delete!
|
101
232
|
|
102
233
|
```
|
103
234
|
|
@@ -126,4 +257,5 @@ This repository is set up to run tests under docker.
|
|
126
257
|
|
127
258
|
## Contributing
|
128
259
|
|
129
|
-
|
260
|
+
Bugs, functionality suggestions, API suggestions, feature requests, etc. all welcome
|
261
|
+
on GitHub at https://github.com/mlibrary/solr_cloud-connection.
|
data/Rakefile
CHANGED
data/lib/solr_cloud/alias.rb
CHANGED
@@ -41,13 +41,13 @@ module SolrCloud
|
|
41
41
|
# @return [Collection] the now-current collection
|
42
42
|
def switch_collection_to(coll)
|
43
43
|
collect_name = case coll
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
44
|
+
when String
|
45
|
+
coll
|
46
|
+
when Collection
|
47
|
+
coll.name
|
48
|
+
else
|
49
|
+
raise "Alias#switch_collection_to only takes a name(string) or a collection, not '#{coll}'"
|
50
|
+
end
|
51
51
|
raise NoSuchCollectionError unless connection.has_collection?(collect_name)
|
52
52
|
connection.create_alias(name: name, collection_name: collect_name, force: true)
|
53
53
|
end
|
@@ -7,7 +7,6 @@ module SolrCloud
|
|
7
7
|
# A Collection provides basic services on the collection -- checking its health,
|
8
8
|
# creating or reporting aliases, and deleting itself.
|
9
9
|
class Collection
|
10
|
-
|
11
10
|
extend Forwardable
|
12
11
|
|
13
12
|
# Forward the HTTP verbs to the underlying connection
|
@@ -50,13 +49,26 @@ module SolrCloud
|
|
50
49
|
@sp = "/solr/#{name}"
|
51
50
|
end
|
52
51
|
|
52
|
+
def collection
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
def ==(other)
|
57
|
+
case other
|
58
|
+
when SolrCloud::Collection
|
59
|
+
collection.name == other.collection.name
|
60
|
+
else
|
61
|
+
false
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
53
65
|
# Delete this collection. Will no-op if the collection somehow doesn't still exist (because it was
|
54
66
|
# deleted via a different method, such as through the API)
|
55
67
|
# @return [Connection] The connection object used to create this collection object
|
56
68
|
def delete!
|
57
69
|
return connection unless exist?
|
58
70
|
raise CollectionAliasedError.new("Cannot delete collection #{name}; it has alias(s) #{alias_names.join(", ")}") if aliased?
|
59
|
-
connection.get("solr/admin/collections", {
|
71
|
+
connection.get("solr/admin/collections", {action: "DELETE", name: name})
|
60
72
|
connection
|
61
73
|
end
|
62
74
|
|
@@ -74,6 +86,8 @@ module SolrCloud
|
|
74
86
|
false
|
75
87
|
end
|
76
88
|
|
89
|
+
alias_method :ping, :alive?
|
90
|
+
|
77
91
|
# Is this an alias?
|
78
92
|
# Putting this in here breaks all sorts of isolation principles,
|
79
93
|
# but being able to call #get_alias? on anything collection-like is
|
@@ -136,6 +150,13 @@ module SolrCloud
|
|
136
150
|
connection.create_alias(name: alias_name, collection_name: name, force: true)
|
137
151
|
end
|
138
152
|
|
153
|
+
def alias_as!(alias_name)
|
154
|
+
if connection.has_alias?(alias_name)
|
155
|
+
raise AliasAlreadyDefinedError.new("Alias #{alias_name} already points to #{connection.get_alias(alias_name).collection.name}")
|
156
|
+
end
|
157
|
+
alias_as(alias_name, force: false)
|
158
|
+
end
|
159
|
+
|
139
160
|
# Send a commit (soft if unspecified)
|
140
161
|
# @return self
|
141
162
|
def commit(hard: false)
|
@@ -160,10 +181,10 @@ module SolrCloud
|
|
160
181
|
|
161
182
|
def add(docs)
|
162
183
|
docarray = if docs === Array
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
184
|
+
docs
|
185
|
+
else
|
186
|
+
[docs]
|
187
|
+
end
|
167
188
|
post("solr/#{name}/update/") do |r|
|
168
189
|
r.body = docarray
|
169
190
|
end
|
@@ -179,10 +200,10 @@ module SolrCloud
|
|
179
200
|
def inspect
|
180
201
|
anames = alias_names
|
181
202
|
astring = if anames.empty?
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
203
|
+
""
|
204
|
+
else
|
205
|
+
" (aliased by #{anames.map { |x| "'#{x}'" }.join(", ")})"
|
206
|
+
end
|
186
207
|
"<#{self.class} '#{name}'#{astring}>"
|
187
208
|
end
|
188
209
|
|
data/lib/solr_cloud/configset.rb
CHANGED
@@ -7,7 +7,6 @@ module SolrCloud
|
|
7
7
|
# throw an error if that's an illegal operation (because a collection is
|
8
8
|
# using it)
|
9
9
|
class Configset
|
10
|
-
|
11
10
|
# @return [String] the name of this configset
|
12
11
|
attr_reader :name
|
13
12
|
|
@@ -33,6 +32,8 @@ module SolrCloud
|
|
33
32
|
connection.only_collections.select { |coll| coll.configset.name == name }
|
34
33
|
end
|
35
34
|
|
35
|
+
alias_method :collections, :used_by
|
36
|
+
|
36
37
|
# Are there any collections currently using this configset?
|
37
38
|
# @return [Boolean]
|
38
39
|
def in_use?
|
@@ -5,7 +5,6 @@ module SolrCloud
|
|
5
5
|
# methods having to do with aliases, to be included by the connection object.
|
6
6
|
# These are split out only to make it easier to deal with them.
|
7
7
|
module AliasAdmin
|
8
|
-
|
9
8
|
# A simple data-class to pair an alias with its collection
|
10
9
|
AliasCollectionPair = Struct.new(:alias, :collection)
|
11
10
|
|
@@ -24,7 +23,7 @@ module SolrCloud
|
|
24
23
|
end
|
25
24
|
raise NoSuchCollectionError.new("Can't find collection #{collection_name}") unless has_collection?(collection_name)
|
26
25
|
if has_alias?(name) && !force
|
27
|
-
raise WontOverwriteError.new("Alias '#{name}' already points to collection '#{
|
26
|
+
raise WontOverwriteError.new("Alias '#{name}' already points to collection '#{get_alias(name).collection.name}'; won't overwrite without force: true")
|
28
27
|
end
|
29
28
|
connection.get("solr/admin/collections", action: "CREATEALIAS", name: name, collections: collection_name)
|
30
29
|
get_alias(name)
|
@@ -83,5 +82,3 @@ module SolrCloud
|
|
83
82
|
end
|
84
83
|
end
|
85
84
|
end
|
86
|
-
|
87
|
-
|
@@ -20,17 +20,16 @@ module SolrCloud
|
|
20
20
|
# @raise [WontOverwriteError] if the collection already exists
|
21
21
|
# @return [Collection] the collection created
|
22
22
|
def create_collection(name:, configset:, shards: 1, replication_factor: 1)
|
23
|
-
|
24
23
|
unless legal_solr_name?(name)
|
25
24
|
raise IllegalNameError.new("'#{name}' is not a valid solr name. Use only ASCII letters/numbers, dash, and underscore")
|
26
25
|
end
|
27
26
|
|
28
27
|
configset_name = case configset
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
28
|
+
when Configset
|
29
|
+
configset.name
|
30
|
+
else
|
31
|
+
configset.to_s
|
32
|
+
end
|
34
33
|
raise WontOverwriteError.new("Collection #{name} already exists") if has_collection?(name)
|
35
34
|
raise NoSuchConfigSetError.new("Configset '#{configset_name}' doesn't exist") unless has_configset?(configset_name)
|
36
35
|
|
@@ -7,7 +7,6 @@ module SolrCloud
|
|
7
7
|
# methods having to do with configsets, to be included by the connection object.
|
8
8
|
# These are split out only to make it easier to deal with them.
|
9
9
|
module ConfigsetAdmin
|
10
|
-
|
11
10
|
# Given the path to a solr configuration "conf" directory (i.e., the one with
|
12
11
|
# solrconfig.xml in it), zip it up and send it to solr as a new configset.
|
13
12
|
# @param name [String] Name to give the new configset
|
@@ -31,12 +31,20 @@ module SolrCloud
|
|
31
31
|
# @return [String] String representation of the URL to solr
|
32
32
|
attr_reader :url
|
33
33
|
|
34
|
+
# @return [String] solr user
|
35
|
+
attr_reader :user
|
36
|
+
alias_method :username, :user
|
37
|
+
|
38
|
+
# @return [String] Solr password
|
39
|
+
attr_reader :password
|
40
|
+
|
34
41
|
# @return [#info] The logger
|
35
42
|
attr_reader :logger
|
36
43
|
|
37
44
|
# @return [Faraday::Connection] the underlying Faraday connection
|
38
45
|
attr_reader :connection
|
39
46
|
|
47
|
+
|
40
48
|
# let the underlying connection handle HTTP verbs
|
41
49
|
|
42
50
|
# @!method get
|
@@ -72,12 +80,12 @@ module SolrCloud
|
|
72
80
|
@user = user
|
73
81
|
@password = password
|
74
82
|
@logger = case logger
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
83
|
+
when :off, :none
|
84
|
+
Logger.new(File::NULL, level: Logger::FATAL)
|
85
|
+
when nil
|
86
|
+
Logger.new($stderr, level: Logger::WARN)
|
87
|
+
else
|
88
|
+
logger
|
81
89
|
end
|
82
90
|
@connection = create_raw_connection(url: url, adapter: adapter, user: user, password: password, logger: @logger)
|
83
91
|
bail_if_incompatible!
|
@@ -112,10 +120,6 @@ module SolrCloud
|
|
112
120
|
end
|
113
121
|
end
|
114
122
|
|
115
|
-
# Allow accessing the raw_connection via "connection". Yes, connection.connection
|
116
|
-
# can be confusing, but it makes the *_admin stuff easier to read.
|
117
|
-
alias_method :connection, :connection
|
118
|
-
|
119
123
|
# Check to see if we can actually talk to the solr in question
|
120
124
|
# raise [UnsupportedSolr] if the solr version isn't at least 8
|
121
125
|
# raise [ConnectionFailed] if we can't connect for some reason
|
@@ -192,6 +196,3 @@ module SolrCloud
|
|
192
196
|
end
|
193
197
|
end
|
194
198
|
end
|
195
|
-
|
196
|
-
|
197
|
-
|
data/lib/solr_cloud/errors.rb
CHANGED
data/readme.rb
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pathname"
|
4
|
+
$LOAD_PATH.unshift Pathname.new(__dir__) + "lib"
|
5
|
+
require_relative "lib/solr_cloud/connection"
|
6
|
+
config_directory = "/Users/dueberb/devel/mlibrary/solr_cloud-connection/spec/data/simple_configuration/conf"
|
7
|
+
url = "http://localhost:9090"
|
8
|
+
user = "solr"
|
9
|
+
pass = "SolrRocks"
|
10
|
+
|
11
|
+
server = SolrCloud::Connection.new(url: url, user: user, password: pass) #=>
|
12
|
+
|
13
|
+
server.aliases.each { |a| a.delete! }
|
14
|
+
server.collections.each { |c| c.delete! }
|
15
|
+
server.configsets.reject { |c| c.name == "_default" }.each { |c| c.delete! }
|
16
|
+
|
17
|
+
# or bring your own Faraday object
|
18
|
+
# server2 = SolrCloud::Connection.new_with_faraday(faraday_connection)
|
19
|
+
|
20
|
+
### Get some basic info
|
21
|
+
|
22
|
+
server.version_string
|
23
|
+
server.cloud?
|
24
|
+
server.mode
|
25
|
+
|
26
|
+
### Configsets
|
27
|
+
|
28
|
+
# List the configsets
|
29
|
+
server.configsets
|
30
|
+
|
31
|
+
# Sometimes you just want the names.
|
32
|
+
server.configset_names
|
33
|
+
|
34
|
+
# Create a new configset by taking a conf directory, zipping it up,
|
35
|
+
# and sending it to solr
|
36
|
+
cset = server.create_configset(name: "horseless", confdir: config_directory)
|
37
|
+
server.configset_names
|
38
|
+
|
39
|
+
# That's a dumb name for a config set. Delete it and try again.
|
40
|
+
cset.delete!
|
41
|
+
cset = server.create_configset(name: "cars_cfg", confdir: config_directory)
|
42
|
+
server.configsets
|
43
|
+
|
44
|
+
# Can't be overwritten by accident
|
45
|
+
begin
|
46
|
+
server.create_configset(name: "cars_cfg", confdir: config_directory)
|
47
|
+
rescue => e
|
48
|
+
end
|
49
|
+
|
50
|
+
# But you can force it
|
51
|
+
server.create_configset(name: "cars_cfg", confdir: config_directory, force: true)
|
52
|
+
|
53
|
+
cfg = server.get_configset("cars_cfg")
|
54
|
+
cfg.in_use?
|
55
|
+
|
56
|
+
#### Collections
|
57
|
+
|
58
|
+
# Now create a collection based on an already-existing configset
|
59
|
+
cars_v1 = server.create_collection(name: "cars_v1", configset: "cars_cfg")
|
60
|
+
server.collections
|
61
|
+
server.collection_names
|
62
|
+
|
63
|
+
# Check it out quick
|
64
|
+
cars_v1.alive?
|
65
|
+
cars_v1.healthy?
|
66
|
+
cars_v1.count
|
67
|
+
|
68
|
+
# Any aliases
|
69
|
+
cars_v1.aliased?
|
70
|
+
cars_v1.aliases
|
71
|
+
|
72
|
+
# Its configset
|
73
|
+
cars_v1.configset
|
74
|
+
|
75
|
+
# Commit anything that's been added
|
76
|
+
cars_v1.commit
|
77
|
+
|
78
|
+
# Solr knows its configset is in use, and won't delete it
|
79
|
+
|
80
|
+
begin
|
81
|
+
cfg.delete!
|
82
|
+
rescue
|
83
|
+
end
|
84
|
+
|
85
|
+
##### Aliases
|
86
|
+
|
87
|
+
# We'll want to alias it so we can just use 'cars'
|
88
|
+
cars = cars_v1.alias_as("cars")
|
89
|
+
cars_v1.alias?
|
90
|
+
cars_v1.aliased?
|
91
|
+
|
92
|
+
cars_v1.has_alias?("cars")
|
93
|
+
cars_v1.alias_as("autos")
|
94
|
+
cars_v1.aliases
|
95
|
+
|
96
|
+
cars_v1.get_alias("autos").delete!
|
97
|
+
cars_v1.aliases
|
98
|
+
|
99
|
+
# There's syntactic sugar for switching out aliases
|
100
|
+
cars_v2 = server.create_collection(name: "cars_v2", configset: "cars_cfg")
|
101
|
+
cars = server.get_alias("cars")
|
102
|
+
|
103
|
+
cars.collection
|
104
|
+
cars.switch_collection_to("cars_v2")
|
105
|
+
cars.collection
|
106
|
+
cars_v1.aliases
|
107
|
+
cars_v2.aliases
|
108
|
+
|
109
|
+
# Aliases will swap from collection to collection without warning
|
110
|
+
cars_v1.alias_as("cars")
|
111
|
+
|
112
|
+
# ...unless you use the bang(!) version
|
113
|
+
begin
|
114
|
+
cars_v2.alias_as!("cars")
|
115
|
+
rescue
|
116
|
+
end
|
117
|
+
|
118
|
+
# You can also just switch it from the alias itself.
|
119
|
+
cars.switch_collection_to("cars_v1")
|
120
|
+
|
121
|
+
# Aliases show up as "collections" so you can just use them interchangeably
|
122
|
+
server.collection_names
|
123
|
+
|
124
|
+
# They even == to each other
|
125
|
+
|
126
|
+
# But sometimes you want to differentiate them from each other
|
127
|
+
server.only_collection_names
|
128
|
+
cars.alias?
|
129
|
+
cars_v1.alias?
|
130
|
+
|
131
|
+
cars.collection
|
132
|
+
|
133
|
+
### Ways to get access to aliases/collections/configsets
|
134
|
+
|
135
|
+
# You can grab existing collections/aliases/configsets from the server
|
136
|
+
# as well as when they're returned by a create_* statement
|
137
|
+
cv1 = server.get_collection("cars_v1")
|
138
|
+
cars = server.get_collection("cars")
|
139
|
+
|
140
|
+
# get_*! methods raise an error
|
141
|
+
typo = "cars_V1"
|
142
|
+
server.has_collection?(typo)
|
143
|
+
dne = server.get_collection(typo)
|
144
|
+
|
145
|
+
begin
|
146
|
+
dne = server.get_collection!(typo)
|
147
|
+
rescue
|
148
|
+
end
|
149
|
+
|
150
|
+
# alias#collection returns the underlying collection.
|
151
|
+
# collection#collection returns itself. This makes it easier to
|
152
|
+
# write code without differentiating between them.
|
153
|
+
|
154
|
+
cars.collection
|
155
|
+
cars_v1.collection
|
156
|
+
|
157
|
+
# Configsets, Aliases, and Collections know how they're related
|
158
|
+
|
159
|
+
cars_v1.aliases
|
160
|
+
cars = cars_v1.get_alias("cars")
|
161
|
+
cfg = cars.configset
|
162
|
+
cfg.collections
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solr_cloud-connection
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bill Dueber
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-09-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -16,112 +16,144 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.
|
19
|
+
version: '2.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 2.
|
26
|
+
version: '2.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: httpx
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 1.
|
33
|
+
version: '1.0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 1.
|
40
|
+
version: '1.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rubyzip
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 2.
|
47
|
+
version: '2.0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 2.
|
54
|
+
version: '2.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
61
|
+
version: '13.0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
68
|
+
version: '13.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: rspec
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
75
|
+
version: '3.0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
82
|
+
version: '3.0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: standard
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
89
|
+
version: 1.35.0
|
90
|
+
- - "~>"
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '1.0'
|
90
93
|
type: :development
|
91
94
|
prerelease: false
|
92
95
|
version_requirements: !ruby/object:Gem::Requirement
|
93
96
|
requirements:
|
94
97
|
- - ">="
|
95
98
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
99
|
+
version: 1.35.0
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '1.0'
|
97
103
|
- !ruby/object:Gem::Dependency
|
98
104
|
name: simplecov
|
99
105
|
requirement: !ruby/object:Gem::Requirement
|
100
106
|
requirements:
|
101
107
|
- - ">="
|
102
108
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
109
|
+
version: 0.22.0
|
110
|
+
- - "~>"
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0.0'
|
104
113
|
type: :development
|
105
114
|
prerelease: false
|
106
115
|
version_requirements: !ruby/object:Gem::Requirement
|
107
116
|
requirements:
|
108
117
|
- - ">="
|
109
118
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
119
|
+
version: 0.22.0
|
120
|
+
- - "~>"
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0.0'
|
111
123
|
- !ruby/object:Gem::Dependency
|
112
124
|
name: yard
|
113
125
|
requirement: !ruby/object:Gem::Requirement
|
114
126
|
requirements:
|
115
127
|
- - ">="
|
116
128
|
- !ruby/object:Gem::Version
|
117
|
-
version:
|
129
|
+
version: 0.9.0
|
130
|
+
- - "~>"
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: 0.9.0
|
118
133
|
type: :development
|
119
134
|
prerelease: false
|
120
135
|
version_requirements: !ruby/object:Gem::Requirement
|
121
136
|
requirements:
|
122
137
|
- - ">="
|
123
138
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
139
|
+
version: 0.9.0
|
140
|
+
- - "~>"
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: 0.9.0
|
143
|
+
- !ruby/object:Gem::Dependency
|
144
|
+
name: dotenv
|
145
|
+
requirement: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - "~>"
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '3.0'
|
150
|
+
type: :development
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - "~>"
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '3.0'
|
125
157
|
description:
|
126
158
|
email:
|
127
159
|
- bill@dueber.com
|
@@ -148,6 +180,7 @@ files:
|
|
148
180
|
- lib/solr_cloud/connection/configset_admin.rb
|
149
181
|
- lib/solr_cloud/connection/version.rb
|
150
182
|
- lib/solr_cloud/errors.rb
|
183
|
+
- readme.rb
|
151
184
|
homepage: https://github.com/mlibrary/solr_cloud-connection
|
152
185
|
licenses: []
|
153
186
|
metadata:
|
@@ -169,7 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
169
202
|
- !ruby/object:Gem::Version
|
170
203
|
version: '0'
|
171
204
|
requirements: []
|
172
|
-
rubygems_version: 3.
|
205
|
+
rubygems_version: 3.5.11
|
173
206
|
signing_key:
|
174
207
|
specification_version: 4
|
175
208
|
summary: Do basic administrative operations on a solr cloud instance and collections
|