websolr-rails 1.4.4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. data/.gitignore +1 -10
  2. data/LICENSE +17 -16
  3. data/README.rdoc +16 -62
  4. data/Rakefile +2 -60
  5. data/VERSION +1 -1
  6. data/lib/websolr-rails.rb +54 -1
  7. data/lib/websolr.rb +2 -1
  8. metadata +12 -215
  9. data/CHANGELOG +0 -8
  10. data/TESTING_THE_PLUGIN +0 -25
  11. data/bin/websolr +0 -10
  12. data/config/solr.yml +0 -15
  13. data/config/solr_environment.rb +0 -22
  14. data/generate_rdoc.sh +0 -13
  15. data/lib/acts_as_solr.rb +0 -65
  16. data/lib/acts_methods.rb +0 -281
  17. data/lib/class_methods.rb +0 -243
  18. data/lib/common_methods.rb +0 -89
  19. data/lib/deprecation.rb +0 -61
  20. data/lib/instance_methods.rb +0 -181
  21. data/lib/lazy_document.rb +0 -18
  22. data/lib/parser_methods.rb +0 -230
  23. data/lib/search_results.rb +0 -72
  24. data/lib/solr.rb +0 -21
  25. data/lib/solr/connection.rb +0 -190
  26. data/lib/solr/document.rb +0 -78
  27. data/lib/solr/exception.rb +0 -13
  28. data/lib/solr/field.rb +0 -39
  29. data/lib/solr/importer.rb +0 -19
  30. data/lib/solr/importer/array_mapper.rb +0 -26
  31. data/lib/solr/importer/delimited_file_source.rb +0 -38
  32. data/lib/solr/importer/hpricot_mapper.rb +0 -27
  33. data/lib/solr/importer/mapper.rb +0 -51
  34. data/lib/solr/importer/solr_source.rb +0 -43
  35. data/lib/solr/importer/xpath_mapper.rb +0 -35
  36. data/lib/solr/indexer.rb +0 -52
  37. data/lib/solr/request.rb +0 -26
  38. data/lib/solr/request/add_document.rb +0 -63
  39. data/lib/solr/request/base.rb +0 -36
  40. data/lib/solr/request/commit.rb +0 -31
  41. data/lib/solr/request/delete.rb +0 -50
  42. data/lib/solr/request/dismax.rb +0 -46
  43. data/lib/solr/request/index_info.rb +0 -22
  44. data/lib/solr/request/modify_document.rb +0 -51
  45. data/lib/solr/request/optimize.rb +0 -21
  46. data/lib/solr/request/ping.rb +0 -36
  47. data/lib/solr/request/select.rb +0 -56
  48. data/lib/solr/request/spellcheck.rb +0 -30
  49. data/lib/solr/request/standard.rb +0 -402
  50. data/lib/solr/request/update.rb +0 -23
  51. data/lib/solr/response.rb +0 -27
  52. data/lib/solr/response/add_document.rb +0 -17
  53. data/lib/solr/response/base.rb +0 -42
  54. data/lib/solr/response/commit.rb +0 -17
  55. data/lib/solr/response/delete.rb +0 -13
  56. data/lib/solr/response/dismax.rb +0 -8
  57. data/lib/solr/response/index_info.rb +0 -26
  58. data/lib/solr/response/modify_document.rb +0 -17
  59. data/lib/solr/response/optimize.rb +0 -14
  60. data/lib/solr/response/ping.rb +0 -28
  61. data/lib/solr/response/ruby.rb +0 -42
  62. data/lib/solr/response/select.rb +0 -17
  63. data/lib/solr/response/spellcheck.rb +0 -20
  64. data/lib/solr/response/standard.rb +0 -64
  65. data/lib/solr/response/xml.rb +0 -42
  66. data/lib/solr/solrtasks.rb +0 -27
  67. data/lib/solr/util.rb +0 -32
  68. data/lib/solr/xml.rb +0 -44
  69. data/lib/solr_fixtures.rb +0 -13
  70. data/lib/tasks/database.rake +0 -18
  71. data/lib/tasks/solr.rake +0 -94
  72. data/lib/tasks/test.rake +0 -7
  73. data/lib/websolr_controller.rb +0 -233
  74. data/lib/websolr_option_parser.rb +0 -61
  75. data/lib/websolr_rails.rb +0 -1
  76. data/lib/websolr_rails/tasks.rb +0 -4
  77. data/lib/will_paginate_support.rb +0 -12
  78. data/solr/CHANGES.txt +0 -1207
  79. data/solr/LICENSE.txt +0 -712
  80. data/solr/NOTICE.txt +0 -90
  81. data/solr/etc/jetty.xml +0 -205
  82. data/solr/etc/webdefault.xml +0 -379
  83. data/solr/lib/easymock.jar +0 -0
  84. data/solr/lib/jetty-6.1.3.jar +0 -0
  85. data/solr/lib/jetty-util-6.1.3.jar +0 -0
  86. data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
  87. data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
  88. data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
  89. data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
  90. data/solr/lib/servlet-api-2.4.jar +0 -0
  91. data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
  92. data/solr/lib/xpp3-1.1.3.4.O.jar +0 -0
  93. data/solr/logs/.empty-dir-for-git +0 -0
  94. data/solr/solr/README.txt +0 -52
  95. data/solr/solr/bin/abc +0 -176
  96. data/solr/solr/bin/abo +0 -176
  97. data/solr/solr/bin/backup +0 -108
  98. data/solr/solr/bin/backupcleaner +0 -142
  99. data/solr/solr/bin/commit +0 -128
  100. data/solr/solr/bin/optimize +0 -129
  101. data/solr/solr/bin/readercycle +0 -129
  102. data/solr/solr/bin/rsyncd-disable +0 -77
  103. data/solr/solr/bin/rsyncd-enable +0 -76
  104. data/solr/solr/bin/rsyncd-start +0 -145
  105. data/solr/solr/bin/rsyncd-stop +0 -105
  106. data/solr/solr/bin/scripts-util +0 -83
  107. data/solr/solr/bin/snapcleaner +0 -148
  108. data/solr/solr/bin/snapinstaller +0 -168
  109. data/solr/solr/bin/snappuller +0 -248
  110. data/solr/solr/bin/snappuller-disable +0 -77
  111. data/solr/solr/bin/snappuller-enable +0 -77
  112. data/solr/solr/bin/snapshooter +0 -109
  113. data/solr/solr/conf/admin-extra.html +0 -31
  114. data/solr/solr/conf/protwords.txt +0 -21
  115. data/solr/solr/conf/schema.xml +0 -126
  116. data/solr/solr/conf/scripts.conf +0 -24
  117. data/solr/solr/conf/solrconfig.xml +0 -458
  118. data/solr/solr/conf/stopwords.txt +0 -57
  119. data/solr/solr/conf/synonyms.txt +0 -31
  120. data/solr/solr/conf/xslt/example.xsl +0 -132
  121. data/solr/solr/conf/xslt/example_atom.xsl +0 -63
  122. data/solr/solr/conf/xslt/example_rss.xsl +0 -62
  123. data/solr/start.jar +0 -0
  124. data/solr/tmp/.empty-dir-for-git +0 -0
  125. data/solr/webapps/solr.war +0 -0
  126. data/test/config/solr.yml +0 -2
  127. data/test/db/connections/mysql/connection.rb +0 -10
  128. data/test/db/connections/sqlite/connection.rb +0 -8
  129. data/test/db/migrate/001_create_books.rb +0 -15
  130. data/test/db/migrate/002_create_movies.rb +0 -12
  131. data/test/db/migrate/003_create_categories.rb +0 -11
  132. data/test/db/migrate/004_create_electronics.rb +0 -16
  133. data/test/db/migrate/005_create_authors.rb +0 -12
  134. data/test/db/migrate/006_create_postings.rb +0 -9
  135. data/test/db/migrate/007_create_posts.rb +0 -13
  136. data/test/db/migrate/008_create_gadgets.rb +0 -11
  137. data/test/fixtures/authors.yml +0 -9
  138. data/test/fixtures/books.yml +0 -13
  139. data/test/fixtures/categories.yml +0 -7
  140. data/test/fixtures/db_definitions/mysql.sql +0 -41
  141. data/test/fixtures/electronics.yml +0 -49
  142. data/test/fixtures/movies.yml +0 -9
  143. data/test/fixtures/postings.yml +0 -10
  144. data/test/functional/acts_as_solr_test.rb +0 -413
  145. data/test/functional/association_indexing_test.rb +0 -37
  146. data/test/functional/faceted_search_test.rb +0 -163
  147. data/test/functional/multi_solr_search_test.rb +0 -51
  148. data/test/models/author.rb +0 -10
  149. data/test/models/book.rb +0 -10
  150. data/test/models/category.rb +0 -8
  151. data/test/models/electronic.rb +0 -21
  152. data/test/models/gadget.rb +0 -9
  153. data/test/models/movie.rb +0 -17
  154. data/test/models/novel.rb +0 -2
  155. data/test/models/post.rb +0 -3
  156. data/test/models/posting.rb +0 -11
  157. data/test/test_helper.rb +0 -51
  158. data/test/unit/acts_methods_shoulda.rb +0 -70
  159. data/test/unit/class_methods_shoulda.rb +0 -88
  160. data/test/unit/common_methods_shoulda.rb +0 -112
  161. data/test/unit/instance_methods_shoulda.rb +0 -326
  162. data/test/unit/lazy_document_shoulda.rb +0 -35
  163. data/test/unit/parser_instance.rb +0 -19
  164. data/test/unit/parser_methods_shoulda.rb +0 -278
  165. data/test/unit/solr_instance.rb +0 -46
  166. data/test/unit/test_helper.rb +0 -14
  167. data/websolr-rails.gemspec +0 -243
data/lib/lazy_document.rb DELETED
@@ -1,18 +0,0 @@
1
- module ActsAsSolr
2
- class LazyDocument
3
- attr_reader :id, :clazz
4
-
5
- def initialize(id, clazz)
6
- @id = id
7
- @clazz = clazz
8
- end
9
-
10
- def method_missing(name, *args)
11
- unless @__instance
12
- @__instance = @clazz.find(@id)
13
- end
14
-
15
- @__instance.send(name, *args)
16
- end
17
- end
18
- end
@@ -1,230 +0,0 @@
1
- module ActsAsSolr #:nodoc:
2
- module ParserMethods
3
- protected
4
-
5
- # Method used by mostly all the ClassMethods when doing a search
6
- def parse_query(query=nil, options={}, models=nil)
7
- valid_options = [:offset, :limit, :facets, :models, :results_format, :order, :scores, :operator, :include, :lazy, :highlight]
8
- query_options = {}
9
-
10
- return nil if (query.nil? || query.strip == '')
11
-
12
- raise "Invalid parameters: #{(options.keys - valid_options).join(',')}" unless (options.keys - valid_options).empty?
13
- begin
14
- Deprecation.validate_query(options)
15
- query_options[:start] = options[:offset]
16
- query_options[:rows] = options[:limit]
17
- query_options[:operator] = options[:operator]
18
-
19
- if options[:highlight] == true
20
- options[:highlight] = {:fields => "*"}
21
- end
22
-
23
- if options[:highlight]
24
- query_options[:highlighting] = {}
25
- query_options[:highlighting][:field_list] = []
26
- query_options[:highlighting][:field_list] << options[:highlight][:fields].collect {|k| "#{k}_t"} if options[:highlight][:fields]
27
- query_options[:highlighting][:require_field_match] = options[:highlight][:require_field_match] if options[:highlight][:require_field_match]
28
- query_options[:highlighting][:max_snippets] = options[:highlight][:max_snippets] if options[:highlight][:max_snippets]
29
- query_options[:highlighting][:prefix] = options[:highlight][:prefix] if options[:highlight][:prefix]
30
- query_options[:highlighting][:suffix] = options[:highlight][:suffix] if options[:highlight][:suffix]
31
- end
32
-
33
- # first steps on the facet parameter processing
34
- if options[:facets]
35
- query_options[:facets] = {}
36
- query_options[:facets][:limit] = -1 # TODO: make this configurable
37
- query_options[:facets][:sort] = :count if options[:facets][:sort]
38
- query_options[:facets][:mincount] = 0
39
- query_options[:facets][:mincount] = 1 if options[:facets][:zeros] == false
40
- # override the :zeros (it's deprecated anyway) if :mincount exists
41
- query_options[:facets][:mincount] = options[:facets][:mincount] if options[:facets][:mincount]
42
- query_options[:facets][:fields] = options[:facets][:fields].collect{|k| "#{k}_facet"} if options[:facets][:fields]
43
- query_options[:filter_queries] = replace_types([*options[:facets][:browse]].collect{|k| "#{k.sub!(/ *: */,"_facet:")}"}) if options[:facets][:browse]
44
- query_options[:facets][:queries] = replace_types(options[:facets][:query].collect{|k| "#{k.sub!(/ *: */,"_t:")}"}) if options[:facets][:query]
45
-
46
- if options[:facets][:dates]
47
- query_options[:date_facets] = {}
48
- # if options[:facets][:dates][:fields] exists then :start, :end, and :gap must be there
49
- if options[:facets][:dates][:fields]
50
- [:start, :end, :gap].each { |k| raise "#{k} must be present in faceted date query" unless options[:facets][:dates].include?(k) }
51
- query_options[:date_facets][:fields] = []
52
- options[:facets][:dates][:fields].each { |f|
53
- if f.kind_of? Hash
54
- key = f.keys[0]
55
- query_options[:date_facets][:fields] << {"#{key}_d" => f[key]}
56
- validate_date_facet_other_options(f[key][:other]) if f[key][:other]
57
- else
58
- query_options[:date_facets][:fields] << "#{f}_d"
59
- end
60
- }
61
- end
62
-
63
- query_options[:date_facets][:start] = options[:facets][:dates][:start] if options[:facets][:dates][:start]
64
- query_options[:date_facets][:end] = options[:facets][:dates][:end] if options[:facets][:dates][:end]
65
- query_options[:date_facets][:gap] = options[:facets][:dates][:gap] if options[:facets][:dates][:gap]
66
- query_options[:date_facets][:hardend] = options[:facets][:dates][:hardend] if options[:facets][:dates][:hardend]
67
- query_options[:date_facets][:filter] = replace_types([*options[:facets][:dates][:filter]].collect{|k| "#{k.sub!(/ *:(?!\d) */,"_d:")}"}) if options[:facets][:dates][:filter]
68
-
69
- if options[:facets][:dates][:other]
70
- validate_date_facet_other_options(options[:facets][:dates][:other])
71
- query_options[:date_facets][:other] = options[:facets][:dates][:other]
72
- end
73
-
74
- end
75
- end
76
-
77
- if models.nil?
78
- # TODO: use a filter query for type, allowing Solr to cache it individually
79
- models = "AND #{solr_type_condition}"
80
- field_list = solr_configuration[:primary_key_field]
81
- else
82
- field_list = "id"
83
- end
84
-
85
- query_options[:field_list] = [field_list, 'score']
86
- query = "(#{query.gsub(/ *: */,"_t:")}) #{models}"
87
- order = options[:order].split(/\s*,\s*/).collect{|e| e.gsub(/\s+/,'_t ').gsub(/\bscore_t\b/, 'score') }.join(',') if options[:order]
88
- query_options[:query] = replace_types([query])[0] # TODO adjust replace_types to work with String or Array
89
-
90
- if options[:order]
91
- # TODO: set the sort parameter instead of the old ;order. style.
92
- query_options[:query] << ';' << replace_types([order], false)[0]
93
- end
94
-
95
- ActsAsSolr::Post.execute(Solr::Request::Standard.new(query_options))
96
- rescue
97
- raise "There was a problem executing your search: #{$!} in #{$!.backtrace.first}"
98
- end
99
- end
100
-
101
- def solr_type_condition
102
- subclasses.inject("(#{solr_configuration[:type_field]}:#{self.name}") do |condition, subclass|
103
- condition << " OR #{solr_configuration[:type_field]}:#{subclass.name}"
104
- end << ')'
105
- end
106
-
107
- # Parses the data returned from Solr
108
- def parse_results(solr_data, options = {})
109
- results = {
110
- :docs => [],
111
- :total => 0
112
- }
113
-
114
- configuration = {
115
- :format => :objects
116
- }
117
- results.update(:facets => {'facet_fields' => []}) if options[:facets]
118
- return SearchResults.new(results) if (solr_data.nil? || solr_data.total_hits == 0)
119
-
120
- configuration.update(options) if options.is_a?(Hash)
121
-
122
- ids = solr_data.hits.collect {|doc| doc["#{solr_configuration[:primary_key_field]}"]}.flatten
123
-
124
- result = find_objects(ids, options, configuration)
125
-
126
- add_scores(result, solr_data) if configuration[:format] == :objects && options[:scores]
127
-
128
- highlighted = {}
129
- solr_data.highlighting.map do |x,y|
130
- e={}
131
- y1=y.map{|x1,y1| e[x1.gsub(/_[^_]*/,"")]=y1} unless y.nil?
132
- highlighted[x.gsub(/[^:]*:/,"").to_i]=e
133
- end unless solr_data.highlighting.nil?
134
-
135
- results.update(:facets => solr_data.data['facet_counts']) if options[:facets]
136
- results.update({:docs => result, :total => solr_data.total_hits, :max_score => solr_data.max_score, :query_time => solr_data.data['responseHeader']['QTime']})
137
- results.update({:highlights=>highlighted})
138
-
139
-
140
- sr = SearchResults.new(results)
141
-
142
- sr.records.each do |model|
143
- model.init_solr(results)
144
- end
145
-
146
- sr
147
- end
148
-
149
-
150
- def find_objects(ids, options, configuration)
151
- result = if configuration[:lazy] && configuration[:format] != :ids
152
- ids.collect {|id| ActsAsSolr::LazyDocument.new(id, self)}
153
- elsif configuration[:format] == :objects
154
- conditions = [ "#{self.table_name}.#{primary_key} in (?)", ids ]
155
- find_options = {:conditions => conditions}
156
- find_options[:include] = options[:include] if options[:include]
157
- result = reorder(self.find(:all, find_options), ids)
158
- else
159
- ids
160
- end
161
-
162
- result
163
- end
164
-
165
- # Reorders the instances keeping the order returned from Solr
166
- def reorder(things, ids)
167
- ordered_things = Array.new(things.size)
168
- raise "Out of sync! Found #{ids.size} items in index, but only #{things.size} were found in database!" unless things.size == ids.size
169
- things.each do |thing|
170
- position = ids.index(thing.id)
171
- ordered_things[position] = thing
172
- end
173
- ordered_things
174
- end
175
-
176
- # Replaces the field types based on the types (if any) specified
177
- # on the acts_as_solr call
178
- def replace_types(strings, include_colon=true)
179
- suffix = include_colon ? ":" : ""
180
- if configuration[:solr_fields]
181
- configuration[:solr_fields].each do |name, options|
182
- solr_name = options[:as] || name.to_s
183
- solr_type = get_solr_field_type(options[:type])
184
- field = "#{solr_name}_#{solr_type}#{suffix}"
185
- strings.each_with_index {|s,i| strings[i] = s.gsub(/#{solr_name.to_s}_t#{suffix}/,field) }
186
- end
187
- end
188
- if configuration[:solr_includes]
189
- configuration[:solr_includes].each do |association, options|
190
- solr_name = options[:as] || association.to_s.singularize
191
- solr_type = get_solr_field_type(options[:type])
192
- field = "#{solr_name}_#{solr_type}#{suffix}"
193
- strings.each_with_index {|s,i| strings[i] = s.gsub(/#{solr_name.to_s}_t#{suffix}/,field) }
194
- end
195
- end
196
- strings
197
- end
198
-
199
- # Adds the score to each one of the instances found
200
- def add_scores(results, solr_data)
201
- with_score = []
202
- solr_data.hits.each do |doc|
203
- with_score.push([doc["score"],
204
- results.find {|record| scorable_record?(record, doc) }])
205
- end
206
- with_score.each do |score, object|
207
- class << object; attr_accessor :solr_score; end
208
- object.solr_score = score
209
- end
210
- end
211
-
212
- def scorable_record?(record, doc)
213
- doc_id = doc["#{solr_configuration[:primary_key_field]}"]
214
- if doc_id.nil?
215
- doc_id = doc["id"]
216
- "#{record.class.name}:#{record_id(record)}" == doc_id.first.to_s
217
- else
218
- record_id(record).to_s == doc_id.to_s
219
- end
220
- end
221
-
222
- def validate_date_facet_other_options(options)
223
- valid_other_options = [:after, :all, :before, :between, :none]
224
- options = [options] unless options.kind_of? Array
225
- bad_options = options.map {|x| x.to_sym} - valid_other_options
226
- raise "Invalid option#{'s' if bad_options.size > 1} for faceted date's other param: #{bad_options.join(', ')}. May only be one of :after, :all, :before, :between, :none" if bad_options.size > 0
227
- end
228
-
229
- end
230
- end
@@ -1,72 +0,0 @@
1
- module ActsAsSolr #:nodoc:
2
-
3
- # TODO: Possibly looking into hooking it up with Solr::Response::Standard
4
- #
5
- # Class that returns the search results with four methods.
6
- #
7
- # books = Book.find_by_solr 'ruby'
8
- #
9
- # the above will return a SearchResults class with 4 methods:
10
- #
11
- # docs|results|records: will return an array of records found
12
- #
13
- # books.records.empty?
14
- # => false
15
- #
16
- # total|num_found|total_hits: will return the total number of records found
17
- #
18
- # books.total
19
- # => 2
20
- #
21
- # facets: will return the facets when doing a faceted search
22
- #
23
- # max_score|highest_score: returns the highest score found
24
- #
25
- # books.max_score
26
- # => 1.3213213
27
- #
28
- #
29
- class SearchResults
30
- def initialize(solr_data={})
31
- @solr_data = solr_data
32
- end
33
-
34
- # Returns an array with the instances. This method
35
- # is also aliased as docs and records
36
- def results
37
- @solr_data[:docs]
38
- end
39
-
40
- # Returns the total records found. This method is
41
- # also aliased as num_found and total_hits
42
- def total
43
- @solr_data[:total]
44
- end
45
-
46
- # Returns the facets when doing a faceted search
47
- def facets
48
- @solr_data[:facets]
49
- end
50
-
51
- # Returns the highest score found. This method is
52
- # also aliased as highest_score
53
- def max_score
54
- @solr_data[:max_score]
55
- end
56
-
57
- def query_time
58
- @solr_data[:query_time]
59
- end
60
-
61
- def highlights
62
- @solr_data[:highlights]
63
- end
64
-
65
- alias docs results
66
- alias records results
67
- alias num_found total
68
- alias total_hits total
69
- alias highest_score max_score
70
- end
71
-
72
- end
data/lib/solr.rb DELETED
@@ -1,21 +0,0 @@
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/util'
19
- require 'solr/xml'
20
- require 'solr/importer'
21
- require 'solr/indexer'
@@ -1,190 +0,0 @@
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
- # TODO: add a convenience method to POST a Solr .xml file, like Solr's example post.sh
16
-
17
- class Solr::Connection
18
- attr_reader :url, :autocommit, :connection
19
-
20
- ILLEGAL_XML_CHARS = /[\x00-\x1F]/
21
-
22
- # create a connection to a solr instance using the url for the solr
23
- # application context:
24
- #
25
- # conn = Solr::Connection.new("http://example.com:8080/solr")
26
- #
27
- # if you would prefer to have all adds/updates autocommitted,
28
- # use :autocommit => :on
29
- #
30
- # conn = Solr::Connection.new('http://example.com:8080/solr',
31
- # :autocommit => :on)
32
-
33
- def initialize(url="http://localhost:8983/solr", opts={})
34
- @url = URI.parse(url)
35
- unless @url.kind_of? URI::HTTP
36
- raise "invalid http url: #{url}"
37
- end
38
-
39
- # TODO: Autocommit seems nice at one level, but it currently is confusing because
40
- # only calls to Connection#add/#update/#delete, though a Connection#send(AddDocument.new(...))
41
- # does not autocommit. Maybe #send should check for the request types that require a commit and
42
- # commit in #send instead of the individual methods?
43
- @autocommit = opts[:autocommit] == :on
44
-
45
- # Not actually opening the connection yet, just setting up the persistent connection.
46
- @connection = Net::HTTP.new(@url.host, @url.port)
47
-
48
- @connection.read_timeout = opts[:timeout] if opts[:timeout]
49
- end
50
-
51
- # add a document to the index. you can pass in either a hash
52
- #
53
- # conn.add(:id => 123, :title => 'Tlon, Uqbar, Orbis Tertius')
54
- #
55
- # or a Solr::Document
56
- #
57
- # conn.add(Solr::Document.new(:id => 123, :title = 'On Writing')
58
- #
59
- # true/false will be returned to designate success/failure
60
-
61
- def add(doc)
62
- request = Solr::Request::AddDocument.new(doc)
63
- response = send(request)
64
- commit if @autocommit
65
- return response.ok?
66
- end
67
-
68
- # update a document in the index (really just an alias to add)
69
-
70
- def update(doc)
71
- return add(doc)
72
- end
73
-
74
- # performs a standard query and returns a Solr::Response::Standard
75
- #
76
- # response = conn.query('borges')
77
- #
78
- # alternative you can pass in a block and iterate over hits
79
- #
80
- # conn.query('borges') do |hit|
81
- # puts hit
82
- # end
83
- #
84
- # options include:
85
- #
86
- # :sort, :default_field, :rows, :filter_queries, :debug_query,
87
- # :explain_other, :facets, :highlighting, :mlt,
88
- # :operator => :or / :and
89
- # :start => defaults to 0
90
- # :field_list => array, defaults to ["*", "score"]
91
-
92
- def query(query, options={}, &action)
93
- # TODO: Shouldn't this return an exception if the Solr status is not ok? (rather than true/false).
94
- create_and_send_query(Solr::Request::Standard, options.update(:query => query), &action)
95
- end
96
-
97
- # performs a dismax search and returns a Solr::Response::Standard
98
- #
99
- # response = conn.search('borges')
100
- #
101
- # options are same as query, but also include:
102
- #
103
- # :tie_breaker, :query_fields, :minimum_match, :phrase_fields,
104
- # :phrase_slop, :boost_query, :boost_functions
105
-
106
- def search(query, options={}, &action)
107
- create_and_send_query(Solr::Request::Dismax, options.update(:query => query), &action)
108
- end
109
-
110
- # sends a commit message to the server
111
- def commit(options={})
112
- response = send(Solr::Request::Commit.new(options))
113
- return response.ok?
114
- end
115
-
116
- # sends an optimize message to the server
117
- def optimize
118
- response = send(Solr::Request::Optimize.new)
119
- return response.ok?
120
- end
121
-
122
- # pings the connection and returns true/false if it is alive or not
123
- def ping
124
- begin
125
- response = send(Solr::Request::Ping.new)
126
- return response.ok?
127
- rescue
128
- return false
129
- end
130
- end
131
-
132
- # delete a document from the index using the document id
133
- def delete(document_id)
134
- response = send(Solr::Request::Delete.new(:id => document_id))
135
- commit if @autocommit
136
- response.ok?
137
- end
138
-
139
- # delete using a query
140
- def delete_by_query(query)
141
- response = send(Solr::Request::Delete.new(:query => query))
142
- commit if @autocommit
143
- response.ok?
144
- end
145
-
146
- def info
147
- send(Solr::Request::IndexInfo.new)
148
- end
149
-
150
- # send a given Solr::Request and return a RubyResponse or XmlResponse
151
- # depending on the type of request
152
- def send(request)
153
- data = post(request)
154
- Solr::Response::Base.make_response(request, data)
155
- end
156
-
157
- # send the http post request to solr; for convenience there are shortcuts
158
- # to some requests: add(), query(), commit(), delete() or send()
159
- def post(request)
160
- if ENV["DEBUG"]
161
- puts "POST #{@url.path + "/" + request.handler}"
162
- puts "-- DATA -------------------"
163
- puts request.to_s
164
- puts "-- END DATA ---------------"
165
- end
166
-
167
- request = request.to_s.gsub(ILLEGAL_XML_CHARS, '')
168
-
169
- response = @connection.post(@url.path + "/" + request.handler,
170
- request.to_s,
171
- { "Content-Type" => request.content_type })
172
-
173
- case response
174
- when Net::HTTPSuccess then response.body
175
- else
176
- response.error!
177
- end
178
-
179
- end
180
-
181
- private
182
-
183
- def create_and_send_query(klass, options = {}, &action)
184
- request = klass.new(options)
185
- response = send(request)
186
- return response unless action
187
- response.each {|hit| action.call(hit)}
188
- end
189
-
190
- end