simple_solr_client 0.2.0 → 0.2.1
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 +5 -5
- data/CHANGES.md +3 -0
- data/README.md +0 -3
- data/lib/simple_solr_client.rb +12 -7
- data/lib/simple_solr_client/client.rb +1 -1
- data/lib/simple_solr_client/core.rb +2 -8
- data/lib/simple_solr_client/core/admin.rb +0 -1
- data/lib/simple_solr_client/core/core_data.rb +0 -4
- data/lib/simple_solr_client/version.rb +1 -1
- data/simple_solr_client.gemspec +6 -8
- data/solr_sample_core/conf/schema.xml +3 -1
- data/solr_sample_core/conf/solrconfig.xml +1163 -1493
- data/spec/client_basics_spec.rb +5 -5
- data/spec/core_basics_spec.rb +21 -0
- data/spec/minitest_helper.rb +6 -3
- metadata +11 -36
- data/lib/simple_solr_client/schema.rb +0 -217
- data/lib/simple_solr_client/schema/analysis.rb +0 -79
- data/lib/simple_solr_client/schema/copyfield.rb +0 -42
- data/lib/simple_solr_client/schema/dynamic_field.rb +0 -23
- data/lib/simple_solr_client/schema/field.rb +0 -46
- data/lib/simple_solr_client/schema/field_or_type.rb +0 -112
- data/lib/simple_solr_client/schema/field_type.rb +0 -47
- data/lib/simple_solr_client/schema/matcher.rb +0 -16
- data/spec/core_basics.rb +0 -21
- data/spec/schema_spec.rb +0 -113
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'simple_solr_client/schema/matcher'
|
2
|
-
|
3
|
-
class SimpleSolrClient::Schema::CopyField
|
4
|
-
include SimpleSolrClient::Schema::Matcher
|
5
|
-
|
6
|
-
attr_accessor :source, :dest
|
7
|
-
|
8
|
-
def initialize(source, dest)
|
9
|
-
self.source = source
|
10
|
-
@dest = dest
|
11
|
-
@matcher = derive_matcher(source)
|
12
|
-
@dest_matcher = derive_matcher(dest)
|
13
|
-
end
|
14
|
-
|
15
|
-
# What name will we get from a matching thing?
|
16
|
-
def dynamic_name(s)
|
17
|
-
return @dest unless @dest =~ /\*/
|
18
|
-
|
19
|
-
m = @matcher.match(s)
|
20
|
-
if m
|
21
|
-
prefix = m[1]
|
22
|
-
return @dest.sub(/\*/, prefix)
|
23
|
-
end
|
24
|
-
nil
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
def source=(s)
|
29
|
-
@matcher = derive_matcher(s)
|
30
|
-
@source = s
|
31
|
-
end
|
32
|
-
|
33
|
-
def to_xml_node(doc = nil)
|
34
|
-
doc ||= Nokogiri::XML::Document.new
|
35
|
-
cf = Nokogiri::XML::Element.new('copyField', doc)
|
36
|
-
cf['source'] = source
|
37
|
-
cf['dest'] = dest
|
38
|
-
cf
|
39
|
-
end
|
40
|
-
|
41
|
-
|
42
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'simple_solr_client/schema/field'
|
2
|
-
class SimpleSolrClient::Schema
|
3
|
-
class DynamicField < Field
|
4
|
-
|
5
|
-
def initialize(*args)
|
6
|
-
super
|
7
|
-
@dynamic = true
|
8
|
-
end
|
9
|
-
|
10
|
-
def xml_node(doc)
|
11
|
-
Nokogiri::XML::Element.new('dynamicField', doc)
|
12
|
-
end
|
13
|
-
|
14
|
-
# What name will we get from a matching thing?
|
15
|
-
def dynamic_name(s)
|
16
|
-
m = @matcher.match(s)
|
17
|
-
if m
|
18
|
-
m[1] << m[2]
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'simple_solr_client/schema/field_or_type'
|
2
|
-
class SimpleSolrClient::Schema
|
3
|
-
class Field < Field_or_Type
|
4
|
-
include Matcher
|
5
|
-
|
6
|
-
attr_accessor :type_name, :type
|
7
|
-
attr_reader :matcher
|
8
|
-
|
9
|
-
|
10
|
-
def initialize(*args)
|
11
|
-
super
|
12
|
-
@dynamic = false
|
13
|
-
end
|
14
|
-
|
15
|
-
# We'll defer to the field type when calling any of the attribute
|
16
|
-
# methods
|
17
|
-
([TEXT_ATTR_MAP.keys, BOOL_ATTR_MAP.keys].flatten - [:type_name]).each do |x|
|
18
|
-
define_method(x) do
|
19
|
-
rv = super()
|
20
|
-
if rv.nil?
|
21
|
-
self.type[x]
|
22
|
-
else
|
23
|
-
rv
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
# We can only resolve the actual type in the presence of a
|
31
|
-
# particular schema
|
32
|
-
def resolve_type(schema)
|
33
|
-
self.type = schema.field_type(self.type_name)
|
34
|
-
self
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
# When we reset the name, make sure to re-derive the matcher
|
39
|
-
# object
|
40
|
-
def name=(n)
|
41
|
-
@name = n
|
42
|
-
@matcher = derive_matcher(n)
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
end
|
@@ -1,112 +0,0 @@
|
|
1
|
-
# Base class for Field/DynamicField/FieldType
|
2
|
-
module SimpleSolrClient
|
3
|
-
class Schema
|
4
|
-
class Field_or_Type
|
5
|
-
|
6
|
-
include Comparable
|
7
|
-
attr_accessor :name,
|
8
|
-
:type_name
|
9
|
-
|
10
|
-
|
11
|
-
# Take in a hash, and set anything in it that we recognize.
|
12
|
-
# Sloppy from a data point of view, but make for easy
|
13
|
-
# duplication and creation from xml/json
|
14
|
-
|
15
|
-
def initialize(h = {})
|
16
|
-
@attributes = {}
|
17
|
-
h.each_pair do |k, v|
|
18
|
-
begin
|
19
|
-
self[k] = v
|
20
|
-
rescue
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
TEXT_ATTR_MAP = {
|
26
|
-
:name => 'name',
|
27
|
-
:type_name => 'type',
|
28
|
-
:precision_step => 'precisionStep',
|
29
|
-
:position_increment_gap => 'positionIncrementGap'
|
30
|
-
}
|
31
|
-
|
32
|
-
BOOL_ATTR_MAP = {
|
33
|
-
:stored => 'stored',
|
34
|
-
:indexed => 'indexed',
|
35
|
-
:multi => 'multiValued',
|
36
|
-
:multivalued => 'multiValued',
|
37
|
-
:multiValued => 'multiValued',
|
38
|
-
:multi_valued => 'multiValued',
|
39
|
-
:sort_missing_last => 'sortMissingLast',
|
40
|
-
:docvalues => 'docValues',
|
41
|
-
:docValues => 'docvalues',
|
42
|
-
:doc_values => 'docvalues',
|
43
|
-
}
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
def ==(other)
|
49
|
-
if other.respond_to? :name
|
50
|
-
name == other.name and type_name == other.type_name
|
51
|
-
else
|
52
|
-
name == other
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
|
57
|
-
def self.new_from_solr_hash(h)
|
58
|
-
f = self.new
|
59
|
-
|
60
|
-
TEXT_ATTR_MAP.merge(BOOL_ATTR_MAP).each_pair do |field, xmlattr|
|
61
|
-
define_method(field.to_sym) do
|
62
|
-
self[field.to_sym]
|
63
|
-
end
|
64
|
-
f[field] = h[xmlattr]
|
65
|
-
end
|
66
|
-
|
67
|
-
# Make some "method?" for the boolean attributes
|
68
|
-
BOOL_ATTR_MAP.keys.each do |methname|
|
69
|
-
q_methname = ((methname.to_s) + '?').to_sym
|
70
|
-
alias_method q_methname, methname
|
71
|
-
end
|
72
|
-
|
73
|
-
# Set the name "manually" to force the
|
74
|
-
# matcher
|
75
|
-
f.name = h['name']
|
76
|
-
f
|
77
|
-
end
|
78
|
-
|
79
|
-
|
80
|
-
# Reverse the process to get XML
|
81
|
-
def to_xml_node
|
82
|
-
doc ||= Nokogiri::XML::Document.new
|
83
|
-
xml = xml_node(doc)
|
84
|
-
TEXT_ATTR_MAP.merge(BOOL_ATTR_MAP).each_pair do |field, xmlattr|
|
85
|
-
iv = instance_variable_get("@#{field}".to_sym)
|
86
|
-
xml[xmlattr] = iv unless iv.nil?
|
87
|
-
end
|
88
|
-
xml
|
89
|
-
end
|
90
|
-
|
91
|
-
def to_xml
|
92
|
-
to_xml_node.to_xml
|
93
|
-
end
|
94
|
-
|
95
|
-
# Allow access to methods via [], for easy looping
|
96
|
-
def [](k)
|
97
|
-
@attributes[k.to_sym]
|
98
|
-
end
|
99
|
-
|
100
|
-
def []=(k, v)
|
101
|
-
@attributes[k.to_sym] = v
|
102
|
-
end
|
103
|
-
|
104
|
-
|
105
|
-
# Make a hash out of it, for easy feeding back into another call to #new
|
106
|
-
def to_h
|
107
|
-
@attributes
|
108
|
-
end
|
109
|
-
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
require 'simple_solr_client/schema/analysis'
|
2
|
-
|
3
|
-
# A basic field type
|
4
|
-
#
|
5
|
-
# We don't even try to represent the analysis chain; just store the raw
|
6
|
-
# xml
|
7
|
-
#
|
8
|
-
# We also, in blatent disregard for separation of concerns and encapsulation,
|
9
|
-
# put in a place to store a core. This is filled when the fieldtype is added
|
10
|
-
# to the schema via add_field_type, so we can have access to the
|
11
|
-
# analysis chain.
|
12
|
-
|
13
|
-
class SimpleSolrClient::Schema
|
14
|
-
class FieldType < Field_or_Type
|
15
|
-
include SimpleSolrClient::Schema::Analysis
|
16
|
-
|
17
|
-
attr_accessor :xml, :solr_class, :core
|
18
|
-
|
19
|
-
def initialize(*args)
|
20
|
-
super
|
21
|
-
@xml = nil
|
22
|
-
end
|
23
|
-
|
24
|
-
# Make sure the type is never set, so we don't get stuck
|
25
|
-
# trying to find a type's "type"
|
26
|
-
def type
|
27
|
-
nil
|
28
|
-
end
|
29
|
-
|
30
|
-
|
31
|
-
def self.new_from_solr_hash(h)
|
32
|
-
ft = super
|
33
|
-
ft.solr_class = h['class']
|
34
|
-
ft
|
35
|
-
end
|
36
|
-
|
37
|
-
# Luckily, a nokogiri node can act like a hash, so we can
|
38
|
-
# just re-use #new_from_solr_hash
|
39
|
-
def self.new_from_xml(xml)
|
40
|
-
ft = new_from_solr_hash(Nokogiri.XML(xml).children.first)
|
41
|
-
ft.xml = xml
|
42
|
-
ft
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# Figure out how to match a field name to a copyfield/dynamicfield
|
2
|
-
class SimpleSolrClient::Schema
|
3
|
-
module Matcher
|
4
|
-
def derive_matcher(src)
|
5
|
-
if src =~ /\A\*(.*)/
|
6
|
-
Regexp.new("\\A(.*)(#{Regexp.escape($1)})\\Z")
|
7
|
-
else
|
8
|
-
src
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def matches(s)
|
13
|
-
@matcher === s
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
data/spec/core_basics.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
require 'minitest_helper'
|
2
|
-
|
3
|
-
describe SimpleSolrClient::Client do
|
4
|
-
|
5
|
-
before do
|
6
|
-
@core = TempCore.instance.core('core_basics')
|
7
|
-
end
|
8
|
-
it "creates a new object" do
|
9
|
-
@core.base_url.must_equal "http://localhost:8983/solr"
|
10
|
-
end
|
11
|
-
|
12
|
-
it "constructs a url with no args" do
|
13
|
-
@core.url.must_equal "http://localhost:8983/solr/#{@core.name}"
|
14
|
-
end
|
15
|
-
|
16
|
-
it "constructs a URL with args" do
|
17
|
-
@core.url('admin', 'ping').must_equal "http://localhost:8983/solr/#{@core.name}/admin/ping"
|
18
|
-
end
|
19
|
-
|
20
|
-
|
21
|
-
end
|
data/spec/schema_spec.rb
DELETED
@@ -1,113 +0,0 @@
|
|
1
|
-
require 'minitest_helper'
|
2
|
-
|
3
|
-
describe "Schema" do
|
4
|
-
|
5
|
-
SS = SimpleSolrClient::Schema # convenience
|
6
|
-
|
7
|
-
before do
|
8
|
-
@core = TempCore.instance.core('schema_spec')
|
9
|
-
@schema = @core.schema
|
10
|
-
end
|
11
|
-
|
12
|
-
describe "the id field" do
|
13
|
-
it "finds it" do
|
14
|
-
@schema.field('id').name.must_equal 'id'
|
15
|
-
end
|
16
|
-
|
17
|
-
it "has a type name of string" do
|
18
|
-
@schema.field('id').type_name.must_equal 'string'
|
19
|
-
end
|
20
|
-
|
21
|
-
it "has the string type" do
|
22
|
-
@schema.field('id').type.must_equal @schema.field_type('string')
|
23
|
-
end
|
24
|
-
|
25
|
-
it "matches on exact match" do
|
26
|
-
@schema.field('id').matches('id').must_equal true
|
27
|
-
end
|
28
|
-
|
29
|
-
it "doesn't match on inexact match" do
|
30
|
-
@schema.field('id').matches('testid').must_equal false
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
describe "the _i dynamic field" do
|
36
|
-
it "finds it" do
|
37
|
-
@schema.dynamic_field('*_i').wont_be_nil
|
38
|
-
end
|
39
|
-
|
40
|
-
it "has type int" do
|
41
|
-
@schema.dynamic_field("*_i").type.must_equal @schema.field_type('int')
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'matches appropriates' do
|
45
|
-
dfield = @schema.dynamic_field('*_i')
|
46
|
-
dfield.matches('test_i').must_equal true
|
47
|
-
dfield.matches('test_s_i').must_equal true
|
48
|
-
dfield.matches('test_i_s').must_equal false
|
49
|
-
end
|
50
|
-
|
51
|
-
it "is found when looking for a match" do
|
52
|
-
dfield = @schema.dynamic_field('*_i')
|
53
|
-
results = @schema.resulting_fields("year_i")
|
54
|
-
results.size.must_equal 1
|
55
|
-
results.first.type.must_equal dfield.type
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
describe "add/delete field" do
|
61
|
-
it "allows us to add a field" do
|
62
|
-
@schema.add_field SS::Field.new(:name => 'new_field', :type_name => 'string')
|
63
|
-
@schema.write
|
64
|
-
@core.reload
|
65
|
-
@schema.field('new_field').wont_be_nil
|
66
|
-
end
|
67
|
-
|
68
|
-
it "allows us to drop a field" do
|
69
|
-
@schema.add_field SS::Field.new(:name => 'new_field', :type_name => 'string')
|
70
|
-
@schema.write
|
71
|
-
@core.reload
|
72
|
-
@schema.field('new_field').wont_be_nil
|
73
|
-
@schema.drop_field('new_field')
|
74
|
-
@schema.write
|
75
|
-
@schema = @core.reload.schema
|
76
|
-
@schema.fields.map(&:name).wont_include 'new_field'
|
77
|
-
end
|
78
|
-
|
79
|
-
|
80
|
-
end
|
81
|
-
|
82
|
-
describe 'Dynamic Fields' do
|
83
|
-
it "adds a dfield" do
|
84
|
-
@schema.add_dynamic_field SS::DynamicField.new(:name => '*_test_i', :type_name => 'string', :stored => true)
|
85
|
-
@schema.write
|
86
|
-
@schema = @core.reload.schema
|
87
|
-
@schema.dynamic_field('*_test_i').wont_be_nil
|
88
|
-
end
|
89
|
-
|
90
|
-
it "prefers longer dfield names when determining resulting_fields" do
|
91
|
-
@schema.add_dynamic_field SS::DynamicField.new(:name => '*_test_i', :type_name => 'string', :stored => true)
|
92
|
-
@schema.write
|
93
|
-
@schema = @core.reload.schema
|
94
|
-
rf = @schema.resulting_fields('bill_test_i')
|
95
|
-
rf.size.must_equal 1
|
96
|
-
rf.first.type.name.must_equal 'string'
|
97
|
-
end
|
98
|
-
|
99
|
-
it "prefers explicity-defined fields to dynamic fields" do
|
100
|
-
@schema.add_field SS::Field.new(:name=>'explicit_i', :type_name=>'string')
|
101
|
-
@schema.write
|
102
|
-
@schema = @core.reload.schema
|
103
|
-
rf = @schema.resulting_fields('explicit_i')
|
104
|
-
rf.size.must_equal 1
|
105
|
-
rf.first.type.name.must_equal 'string'
|
106
|
-
end
|
107
|
-
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
|
-
|
112
|
-
end
|
113
|
-
|