solr-ruby 0.0.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.
Files changed (45) hide show
  1. data/lib/solr.rb +18 -0
  2. data/lib/solr/connection.rb +158 -0
  3. data/lib/solr/document.rb +71 -0
  4. data/lib/solr/exception.rb +13 -0
  5. data/lib/solr/field.rb +35 -0
  6. data/lib/solr/request.rb +24 -0
  7. data/lib/solr/request/add_document.rb +63 -0
  8. data/lib/solr/request/base.rb +29 -0
  9. data/lib/solr/request/commit.rb +21 -0
  10. data/lib/solr/request/delete.rb +50 -0
  11. data/lib/solr/request/dismax.rb +43 -0
  12. data/lib/solr/request/index_info.rb +17 -0
  13. data/lib/solr/request/optimize.rb +21 -0
  14. data/lib/solr/request/ping.rb +36 -0
  15. data/lib/solr/request/select.rb +54 -0
  16. data/lib/solr/request/standard.rb +105 -0
  17. data/lib/solr/request/update.rb +22 -0
  18. data/lib/solr/response.rb +24 -0
  19. data/lib/solr/response/add_document.rb +17 -0
  20. data/lib/solr/response/base.rb +42 -0
  21. data/lib/solr/response/commit.rb +32 -0
  22. data/lib/solr/response/delete.rb +13 -0
  23. data/lib/solr/response/dismax.rb +8 -0
  24. data/lib/solr/response/index_info.rb +26 -0
  25. data/lib/solr/response/optimize.rb +14 -0
  26. data/lib/solr/response/ping.rb +28 -0
  27. data/lib/solr/response/ruby.rb +42 -0
  28. data/lib/solr/response/standard.rb +60 -0
  29. data/lib/solr/response/xml.rb +37 -0
  30. data/lib/solr/xml.rb +47 -0
  31. data/test/unit/add_document_test.rb +40 -0
  32. data/test/unit/commit_test.rb +41 -0
  33. data/test/unit/connection_test.rb +55 -0
  34. data/test/unit/delete_test.rb +56 -0
  35. data/test/unit/dismax_request_test.rb +26 -0
  36. data/test/unit/document_test.rb +59 -0
  37. data/test/unit/field_test.rb +42 -0
  38. data/test/unit/ping_test.rb +51 -0
  39. data/test/unit/request_test.rb +61 -0
  40. data/test/unit/response_test.rb +42 -0
  41. data/test/unit/solr_mock_base.rb +40 -0
  42. data/test/unit/standard_request_test.rb +108 -0
  43. data/test/unit/standard_response_test.rb +174 -0
  44. data/test/unit/suite.rb +25 -0
  45. metadata +92 -0
@@ -0,0 +1,18 @@
1
+ # The ASF licenses this file to You under the Apache License, Version 2.0
2
+ # (the "License"); you may not use this file except in compliance with
3
+ # the License. You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ module Solr; end
14
+ require 'solr/exception'
15
+ require 'solr/request'
16
+ require 'solr/connection'
17
+ require 'solr/response'
18
+ require 'solr/xml'
@@ -0,0 +1,158 @@
1
+ # The ASF licenses this file to You under the Apache License, Version 2.0
2
+ # (the "License"); you may not use this file except in compliance with
3
+ # the License. You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ require 'net/http'
14
+
15
+ class Solr::Connection
16
+ attr_reader :url, :autocommit, :connection
17
+
18
+ # create a connection to a solr instance using the url for the solr
19
+ # application context:
20
+ #
21
+ # conn = Solr::Connection.new("http://example.com:8080/solr")
22
+ #
23
+ # if you would prefer to have all adds/updates autocommitted,
24
+ # use :autocommit => :on
25
+ #
26
+ # conn = Solr::Connection.new('http://example.com:8080/solr',
27
+ # :autocommit => :on)
28
+
29
+ def initialize(url, opts={})
30
+ @url = URI.parse(url)
31
+ unless @url.kind_of? URI::HTTP
32
+ raise "invalid http url: #{url}"
33
+ end
34
+
35
+ # TODO: Autocommit seems nice at one level, but it currently is confusing because
36
+ # only calls to Connection#add/#update/#delete, though a Connection#send(AddDocument.new(...))
37
+ # does not autocommit. Maybe #send should check for the request types that require a commit and
38
+ # commit in #send instead of the individual methods?
39
+ @autocommit = opts[:autocommit] == :on
40
+
41
+ # Not actually opening the connection yet, just setting up the persistent connection.
42
+ @connection = Net::HTTP.new(@url.host, @url.port)
43
+ end
44
+
45
+ # add a document to the index. you can pass in either a hash
46
+ #
47
+ # conn.add(:id => 123, :title => 'Tlon, Uqbar, Orbis Tertius')
48
+ #
49
+ # or a Solr::Document
50
+ #
51
+ # conn.add(Solr::Document.new(:id => 123, :title = 'On Writing')
52
+ #
53
+ # true/false will be returned to designate success/failure
54
+
55
+ def add(doc)
56
+ request = Solr::Request::AddDocument.new(doc)
57
+ response = send(request)
58
+ commit if @autocommit
59
+ return response.ok?
60
+ end
61
+
62
+ # update a document in the index (really just an alias to add)
63
+
64
+ def update(doc)
65
+ return add(doc)
66
+ end
67
+
68
+ # performs a standard query and returns a Solr::Response::Standard
69
+ #
70
+ # response = conn.query('borges')
71
+ #
72
+ # alternative you can pass in a block and iterate over hits
73
+ #
74
+ # conn.query('borges') do |hit|
75
+ # puts hit
76
+ # end
77
+
78
+ def query(query, options={}, &action)
79
+ # TODO: Shouldn't this return an exception if the Solr status is not ok? (rather than true/false).
80
+ create_and_send_query(Solr::Request::Standard, options.update(:query => query), &action)
81
+ end
82
+
83
+ def search(query, options={}, &action)
84
+ create_and_send_query(Solr::Request::Dismax, options.update(:query => query), &action)
85
+ end
86
+
87
+ # sends a commit message to the server
88
+ def commit
89
+ response = send(Solr::Request::Commit.new)
90
+ return response.ok?
91
+ end
92
+
93
+ # sends an optimize message to the server
94
+ def optimize
95
+ response = send(Solr::Request::Optimize.new)
96
+ return response.ok?
97
+ end
98
+
99
+ # pings the connection and returns true/false if it is alive or not
100
+ def ping
101
+ begin
102
+ response = send(Solr::Request::Ping.new)
103
+ return response.ok?
104
+ rescue
105
+ return false
106
+ end
107
+ end
108
+
109
+ # delete a document from the index using the document id
110
+ def delete(document_id)
111
+ response = send(Solr::Request::Delete.new(:id => document_id))
112
+ commit if @autocommit
113
+ response.ok?
114
+ end
115
+
116
+ # delete using a query
117
+ def delete_by_query(query)
118
+ response = send(Solr::Request::Delete.new(:query => query))
119
+ commit if @autocommit
120
+ response.ok?
121
+ end
122
+
123
+ def info
124
+ send(Solr::Request::IndexInfo.new)
125
+ end
126
+
127
+ # send a given Solr::Request and return a RubyResponse or XmlResponse
128
+ # depending on the type of request
129
+ def send(request)
130
+ data = post(request)
131
+ Solr::Response::Base.make_response(request, data)
132
+ end
133
+
134
+ # send the http post request to solr; for convenience there are shortcuts
135
+ # to some requests: add(), query(), commit(), delete() or send()
136
+ def post(request)
137
+ response = @connection.post(@url.path + "/" + request.handler,
138
+ request.to_s,
139
+ { "Content-Type" => "application/x-www-form-urlencoded; charset=utf-8" })
140
+
141
+ case response
142
+ when Net::HTTPSuccess then response.body
143
+ else
144
+ response.error!
145
+ end
146
+
147
+ end
148
+
149
+ private
150
+
151
+ def create_and_send_query(klass, options = {}, &action)
152
+ request = klass.new(options)
153
+ response = send(request)
154
+ return response unless action
155
+ response.each {|hit| action.call(hit)}
156
+ end
157
+
158
+ end
@@ -0,0 +1,71 @@
1
+ # The ASF licenses this file to You under the Apache License, Version 2.0
2
+ # (the "License"); you may not use this file except in compliance with
3
+ # the License. You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ require 'solr/xml'
14
+ require 'solr/field'
15
+
16
+ class Solr::Document
17
+ include Enumerable
18
+
19
+ # Create a new Solr::Document, optionally passing in a hash of
20
+ # key/value pairs for the fields
21
+ #
22
+ # doc = Solr::Document.new(:creator => 'Jorge Luis Borges')
23
+ def initialize(hash={})
24
+ @fields = []
25
+ self << hash
26
+ end
27
+
28
+ # Append a Solr::Field
29
+ #
30
+ # doc << Solr::Field.new(:creator => 'Jorge Luis Borges')
31
+ #
32
+ # If you are truly lazy you can simply pass in a hash:
33
+ #
34
+ # doc << {:creator => 'Jorge Luis Borges'}
35
+ def <<(fields)
36
+ case fields
37
+ when Hash
38
+ fields.each_pair do |name,value|
39
+ if value.respond_to?(:each)
40
+ value.each {|v| @fields << Solr::Field.new(name => v)}
41
+ else
42
+ @fields << Solr::Field.new(name => value)
43
+ end
44
+ end
45
+ when Solr::Field
46
+ @fields << fields
47
+ else
48
+ raise "must pass in Solr::Field or Hash"
49
+ end
50
+ end
51
+
52
+ # shorthand to allow hash lookups
53
+ # doc['name']
54
+ def [](name)
55
+ field = @fields.find {|f| f.name == name.to_s}
56
+ return field.value if field
57
+ return nil
58
+ end
59
+
60
+ # shorthand to assign as a hash
61
+ def []=(name,value)
62
+ @fields << Solr::Field.new(name => value)
63
+ end
64
+
65
+ # convert the Document to a REXML::Element
66
+ def to_xml
67
+ e = Solr::XML::Element.new 'doc'
68
+ @fields.each {|f| e.add_element(f.to_xml)}
69
+ return e
70
+ end
71
+ end
@@ -0,0 +1,13 @@
1
+ # The ASF licenses this file to You under the Apache License, Version 2.0
2
+ # (the "License"); you may not use this file except in compliance with
3
+ # the License. You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ class Solr::Exception < Exception; end
@@ -0,0 +1,35 @@
1
+ # The ASF licenses this file to You under the Apache License, Version 2.0
2
+ # (the "License"); you may not use this file except in compliance with
3
+ # the License. You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ require 'solr/xml'
14
+ require 'time'
15
+
16
+ class Solr::Field
17
+ attr_accessor :name
18
+ attr_accessor :value
19
+
20
+ def initialize(key_val, opts={})
21
+ raise "first argument must be a hash" unless key_val.kind_of? Hash
22
+ @name = key_val.keys[0].to_s
23
+ @value = key_val.values[0]
24
+ # Convert any Time values into UTC/XML schema format (which Solr requires).
25
+ @value = @value.respond_to?(:utc) ? @value.utc.xmlschema : @value.to_s
26
+ end
27
+
28
+ def to_xml
29
+ e = Solr::XML::Element.new 'field'
30
+ e.attributes['name'] = @name
31
+ e.text = @value
32
+ return e
33
+ end
34
+
35
+ end
@@ -0,0 +1,24 @@
1
+ # The ASF licenses this file to You under the Apache License, Version 2.0
2
+ # (the "License"); you may not use this file except in compliance with
3
+ # the License. You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ module Solr; module Request; end; end
14
+ require 'solr/request/add_document'
15
+ require 'solr/request/base'
16
+ require 'solr/request/commit'
17
+ require 'solr/request/delete'
18
+ require 'solr/request/ping'
19
+ require 'solr/request/select'
20
+ require 'solr/request/standard'
21
+ require 'solr/request/dismax'
22
+ require 'solr/request/update'
23
+ require 'solr/request/index_info'
24
+ require 'solr/request/optimize'
@@ -0,0 +1,63 @@
1
+ # The ASF licenses this file to You under the Apache License, Version 2.0
2
+ # (the "License"); you may not use this file except in compliance with
3
+ # the License. You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ require 'solr/xml'
14
+ require 'solr/request/base'
15
+ require 'solr/document'
16
+ require 'solr/request/update'
17
+
18
+ class Solr::Request::AddDocument < Solr::Request::Update
19
+
20
+ # create the request, optionally passing in a Solr::Document
21
+ #
22
+ # request = Solr::Request::AddDocument.new doc
23
+ #
24
+ # as a short cut you can pass in a Hash instead:
25
+ #
26
+ # request = Solr::Request.new :creator => 'Jorge Luis Borges'
27
+ #
28
+ # or an array, to add multiple documents at the same time:
29
+ #
30
+ # request = Solr::Request::AddDocument.new([doc1, doc2, doc3])
31
+
32
+ def initialize(doc={})
33
+ @docs = []
34
+ if doc.is_a?(Array)
35
+ doc.each { |d| add_doc(d) }
36
+ else
37
+ add_doc(doc)
38
+ end
39
+ end
40
+
41
+ # returns the request as a string suitable for posting
42
+
43
+ def to_s
44
+ e = Solr::XML::Element.new 'add'
45
+ for doc in @docs
46
+ e.add_element doc.to_xml
47
+ end
48
+ return e.to_s
49
+ end
50
+
51
+ private
52
+ def add_doc(doc)
53
+ case doc
54
+ when Hash
55
+ @docs << Solr::Document.new(doc)
56
+ when Solr::Document
57
+ @docs << doc
58
+ else
59
+ raise "must pass in Solr::Document or Hash"
60
+ end
61
+ end
62
+
63
+ end
@@ -0,0 +1,29 @@
1
+ # The ASF licenses this file to You under the Apache License, Version 2.0
2
+ # (the "License"); you may not use this file except in compliance with
3
+ # the License. You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ class Solr::Request::Base
14
+
15
+ # returns either :xml or :ruby depending on what the
16
+ # response type is for a given request
17
+
18
+ def response_format
19
+ raise "unknown request type: #{self.class}"
20
+ end
21
+
22
+ # returns the solr handler or url fragment that can
23
+ # respond to this type of request
24
+
25
+ def handler
26
+ raise "unkown request type: #{self.class}"
27
+ end
28
+
29
+ end
@@ -0,0 +1,21 @@
1
+ # The ASF licenses this file to You under the Apache License, Version 2.0
2
+ # (the "License"); you may not use this file except in compliance with
3
+ # the License. You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ require 'solr/xml'
14
+
15
+ class Solr::Request::Commit < Solr::Request::Update
16
+
17
+ def to_s
18
+ Solr::XML::Element.new('commit').to_s
19
+ end
20
+
21
+ end
@@ -0,0 +1,50 @@
1
+ # The ASF licenses this file to You under the Apache License, Version 2.0
2
+ # (the "License"); you may not use this file except in compliance with
3
+ # the License. You may obtain a copy of the License at
4
+ #
5
+ # http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # Unless required by applicable law or agreed to in writing, software
8
+ # distributed under the License is distributed on an "AS IS" BASIS,
9
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and
11
+ # limitations under the License.
12
+
13
+ require 'solr/xml'
14
+
15
+ class Solr::Request::Delete < Solr::Request::Update
16
+
17
+ # A delete request can be for a specific document id
18
+ #
19
+ # request = Solr::Request::Delete.new(:id => 1234)
20
+ #
21
+ # or by query:
22
+ #
23
+ # request = Solr::Request::Delete.new(:query =>
24
+ #
25
+ def initialize(options)
26
+ unless options.kind_of?(Hash) and (options[:id] or options[:query])
27
+ raise Solr::Exception.new("must pass in :id or :query")
28
+ end
29
+ if options[:id] and options[:query]
30
+ raise Solr::Exception.new("can't pass in both :id and :query")
31
+ end
32
+ @document_id = options[:id]
33
+ @query = options[:query]
34
+ end
35
+
36
+ def to_s
37
+ delete_element = Solr::XML::Element.new('delete')
38
+ if @document_id
39
+ id_element = Solr::XML::Element.new('id')
40
+ id_element.text = @document_id
41
+ delete_element.add_element(id_element)
42
+ elsif @query
43
+ query = Solr::XML::Element.new('query')
44
+ query.text = @query
45
+ delete_element.add_element(query)
46
+ end
47
+ delete_element.to_s
48
+ end
49
+ end
50
+