pduey-sunspot 1.2.1.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 (166) hide show
  1. data/.gitignore +12 -0
  2. data/Gemfile +5 -0
  3. data/History.txt +225 -0
  4. data/LICENSE +18 -0
  5. data/Rakefile +15 -0
  6. data/TODO +13 -0
  7. data/VERSION.yml +4 -0
  8. data/bin/sunspot-installer +19 -0
  9. data/installer/config/schema.yml +95 -0
  10. data/lib/light_config.rb +40 -0
  11. data/lib/sunspot.rb +568 -0
  12. data/lib/sunspot/adapters.rb +265 -0
  13. data/lib/sunspot/composite_setup.rb +202 -0
  14. data/lib/sunspot/configuration.rb +46 -0
  15. data/lib/sunspot/data_extractor.rb +50 -0
  16. data/lib/sunspot/dsl.rb +5 -0
  17. data/lib/sunspot/dsl/adjustable.rb +47 -0
  18. data/lib/sunspot/dsl/field_query.rb +279 -0
  19. data/lib/sunspot/dsl/fields.rb +103 -0
  20. data/lib/sunspot/dsl/fulltext.rb +243 -0
  21. data/lib/sunspot/dsl/function.rb +14 -0
  22. data/lib/sunspot/dsl/functional.rb +44 -0
  23. data/lib/sunspot/dsl/more_like_this_query.rb +56 -0
  24. data/lib/sunspot/dsl/paginatable.rb +28 -0
  25. data/lib/sunspot/dsl/query_facet.rb +36 -0
  26. data/lib/sunspot/dsl/restriction.rb +25 -0
  27. data/lib/sunspot/dsl/restriction_with_near.rb +121 -0
  28. data/lib/sunspot/dsl/scope.rb +217 -0
  29. data/lib/sunspot/dsl/search.rb +30 -0
  30. data/lib/sunspot/dsl/standard_query.rb +121 -0
  31. data/lib/sunspot/field.rb +193 -0
  32. data/lib/sunspot/field_factory.rb +129 -0
  33. data/lib/sunspot/indexer.rb +131 -0
  34. data/lib/sunspot/installer.rb +31 -0
  35. data/lib/sunspot/installer/library_installer.rb +45 -0
  36. data/lib/sunspot/installer/schema_builder.rb +219 -0
  37. data/lib/sunspot/installer/solrconfig_updater.rb +76 -0
  38. data/lib/sunspot/installer/task_helper.rb +18 -0
  39. data/lib/sunspot/java.rb +8 -0
  40. data/lib/sunspot/query.rb +11 -0
  41. data/lib/sunspot/query/abstract_field_facet.rb +52 -0
  42. data/lib/sunspot/query/boost_query.rb +24 -0
  43. data/lib/sunspot/query/common_query.rb +85 -0
  44. data/lib/sunspot/query/composite_fulltext.rb +36 -0
  45. data/lib/sunspot/query/connective.rb +206 -0
  46. data/lib/sunspot/query/date_field_facet.rb +14 -0
  47. data/lib/sunspot/query/dismax.rb +128 -0
  48. data/lib/sunspot/query/field_facet.rb +41 -0
  49. data/lib/sunspot/query/filter.rb +38 -0
  50. data/lib/sunspot/query/function_query.rb +52 -0
  51. data/lib/sunspot/query/geo.rb +53 -0
  52. data/lib/sunspot/query/highlighting.rb +55 -0
  53. data/lib/sunspot/query/more_like_this.rb +61 -0
  54. data/lib/sunspot/query/more_like_this_query.rb +12 -0
  55. data/lib/sunspot/query/pagination.rb +38 -0
  56. data/lib/sunspot/query/query_facet.rb +16 -0
  57. data/lib/sunspot/query/restriction.rb +262 -0
  58. data/lib/sunspot/query/scope.rb +9 -0
  59. data/lib/sunspot/query/sort.rb +95 -0
  60. data/lib/sunspot/query/sort_composite.rb +33 -0
  61. data/lib/sunspot/query/standard_query.rb +16 -0
  62. data/lib/sunspot/query/text_field_boost.rb +17 -0
  63. data/lib/sunspot/schema.rb +151 -0
  64. data/lib/sunspot/search.rb +9 -0
  65. data/lib/sunspot/search/abstract_search.rb +335 -0
  66. data/lib/sunspot/search/date_facet.rb +35 -0
  67. data/lib/sunspot/search/facet_row.rb +27 -0
  68. data/lib/sunspot/search/field_facet.rb +88 -0
  69. data/lib/sunspot/search/highlight.rb +38 -0
  70. data/lib/sunspot/search/hit.rb +150 -0
  71. data/lib/sunspot/search/more_like_this_search.rb +31 -0
  72. data/lib/sunspot/search/paginated_collection.rb +55 -0
  73. data/lib/sunspot/search/query_facet.rb +67 -0
  74. data/lib/sunspot/search/standard_search.rb +21 -0
  75. data/lib/sunspot/session.rb +260 -0
  76. data/lib/sunspot/session_proxy.rb +87 -0
  77. data/lib/sunspot/session_proxy/abstract_session_proxy.rb +29 -0
  78. data/lib/sunspot/session_proxy/class_sharding_session_proxy.rb +66 -0
  79. data/lib/sunspot/session_proxy/id_sharding_session_proxy.rb +89 -0
  80. data/lib/sunspot/session_proxy/master_slave_session_proxy.rb +43 -0
  81. data/lib/sunspot/session_proxy/sharding_session_proxy.rb +222 -0
  82. data/lib/sunspot/session_proxy/silent_fail_session_proxy.rb +42 -0
  83. data/lib/sunspot/session_proxy/thread_local_session_proxy.rb +37 -0
  84. data/lib/sunspot/setup.rb +350 -0
  85. data/lib/sunspot/text_field_setup.rb +29 -0
  86. data/lib/sunspot/type.rb +372 -0
  87. data/lib/sunspot/util.rb +243 -0
  88. data/lib/sunspot/version.rb +3 -0
  89. data/pduey-sunspot.gemspec +38 -0
  90. data/script/console +10 -0
  91. data/spec/api/adapters_spec.rb +33 -0
  92. data/spec/api/binding_spec.rb +50 -0
  93. data/spec/api/indexer/attributes_spec.rb +149 -0
  94. data/spec/api/indexer/batch_spec.rb +46 -0
  95. data/spec/api/indexer/dynamic_fields_spec.rb +42 -0
  96. data/spec/api/indexer/fixed_fields_spec.rb +57 -0
  97. data/spec/api/indexer/fulltext_spec.rb +43 -0
  98. data/spec/api/indexer/removal_spec.rb +53 -0
  99. data/spec/api/indexer/spec_helper.rb +1 -0
  100. data/spec/api/indexer_spec.rb +14 -0
  101. data/spec/api/query/advanced_manipulation_examples.rb +35 -0
  102. data/spec/api/query/connectives_examples.rb +189 -0
  103. data/spec/api/query/dsl_spec.rb +18 -0
  104. data/spec/api/query/dynamic_fields_examples.rb +165 -0
  105. data/spec/api/query/faceting_examples.rb +397 -0
  106. data/spec/api/query/fulltext_examples.rb +313 -0
  107. data/spec/api/query/function_spec.rb +70 -0
  108. data/spec/api/query/geo_examples.rb +68 -0
  109. data/spec/api/query/highlighting_examples.rb +223 -0
  110. data/spec/api/query/more_like_this_spec.rb +140 -0
  111. data/spec/api/query/ordering_pagination_examples.rb +95 -0
  112. data/spec/api/query/scope_examples.rb +275 -0
  113. data/spec/api/query/spec_helper.rb +1 -0
  114. data/spec/api/query/standard_spec.rb +28 -0
  115. data/spec/api/query/text_field_scoping_examples.rb +30 -0
  116. data/spec/api/query/types_spec.rb +20 -0
  117. data/spec/api/search/dynamic_fields_spec.rb +33 -0
  118. data/spec/api/search/faceting_spec.rb +360 -0
  119. data/spec/api/search/highlighting_spec.rb +69 -0
  120. data/spec/api/search/hits_spec.rb +131 -0
  121. data/spec/api/search/paginated_collection_spec.rb +26 -0
  122. data/spec/api/search/results_spec.rb +66 -0
  123. data/spec/api/search/search_spec.rb +23 -0
  124. data/spec/api/search/spec_helper.rb +1 -0
  125. data/spec/api/session_proxy/class_sharding_session_proxy_spec.rb +85 -0
  126. data/spec/api/session_proxy/id_sharding_session_proxy_spec.rb +30 -0
  127. data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +41 -0
  128. data/spec/api/session_proxy/sharding_session_proxy_spec.rb +77 -0
  129. data/spec/api/session_proxy/silent_fail_session_proxy_spec.rb +24 -0
  130. data/spec/api/session_proxy/spec_helper.rb +9 -0
  131. data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +39 -0
  132. data/spec/api/session_spec.rb +220 -0
  133. data/spec/api/spec_helper.rb +3 -0
  134. data/spec/api/sunspot_spec.rb +18 -0
  135. data/spec/ext.rb +11 -0
  136. data/spec/helpers/indexer_helper.rb +29 -0
  137. data/spec/helpers/query_helper.rb +38 -0
  138. data/spec/helpers/search_helper.rb +80 -0
  139. data/spec/integration/dynamic_fields_spec.rb +57 -0
  140. data/spec/integration/faceting_spec.rb +238 -0
  141. data/spec/integration/highlighting_spec.rb +24 -0
  142. data/spec/integration/indexing_spec.rb +33 -0
  143. data/spec/integration/keyword_search_spec.rb +317 -0
  144. data/spec/integration/local_search_spec.rb +64 -0
  145. data/spec/integration/more_like_this_spec.rb +43 -0
  146. data/spec/integration/scoped_search_spec.rb +354 -0
  147. data/spec/integration/spec_helper.rb +7 -0
  148. data/spec/integration/stored_fields_spec.rb +12 -0
  149. data/spec/integration/test_pagination.rb +32 -0
  150. data/spec/mocks/adapters.rb +32 -0
  151. data/spec/mocks/blog.rb +3 -0
  152. data/spec/mocks/comment.rb +21 -0
  153. data/spec/mocks/connection.rb +126 -0
  154. data/spec/mocks/mock_adapter.rb +30 -0
  155. data/spec/mocks/mock_class_sharding_session_proxy.rb +24 -0
  156. data/spec/mocks/mock_record.rb +52 -0
  157. data/spec/mocks/mock_sharding_session_proxy.rb +15 -0
  158. data/spec/mocks/photo.rb +11 -0
  159. data/spec/mocks/post.rb +85 -0
  160. data/spec/mocks/super_class.rb +2 -0
  161. data/spec/mocks/user.rb +13 -0
  162. data/spec/spec_helper.rb +28 -0
  163. data/tasks/rdoc.rake +27 -0
  164. data/tasks/schema.rake +19 -0
  165. data/tasks/todo.rake +4 -0
  166. metadata +369 -0
@@ -0,0 +1,568 @@
1
+ require 'set'
2
+ require 'time'
3
+ require 'date'
4
+ require 'enumerator'
5
+ require 'cgi'
6
+ begin
7
+ require 'rsolr'
8
+ rescue LoadError
9
+ require 'rubygems'
10
+ require 'rsolr'
11
+ end
12
+
13
+ require File.join(File.dirname(__FILE__), 'light_config')
14
+
15
+ %w(util adapters configuration setup composite_setup text_field_setup field
16
+ field_factory data_extractor indexer query search session session_proxy
17
+ type dsl).each do |filename|
18
+ require File.join(File.dirname(__FILE__), 'sunspot', filename)
19
+ end
20
+
21
+ #
22
+ # The Sunspot module provides class-method entry points to most of the
23
+ # functionality provided by the Sunspot library. Internally, the Sunspot
24
+ # singleton class contains a (non-thread-safe!) instance of Sunspot::Session,
25
+ # to which it delegates most of the class methods it exposes. In the method
26
+ # documentation below, this instance is referred to as the "singleton session".
27
+ #
28
+ # Though the singleton session provides a convenient entry point to Sunspot,
29
+ # it is by no means required to use the Sunspot class methods. Multiple sessions
30
+ # may be instantiated and used (if you need to connect to multiple Solr
31
+ # instances, for example.)
32
+ #
33
+ # Note that the configuration of classes for index/search (the +setup+
34
+ # method) is _not_ session-specific, but rather global.
35
+ #
36
+ module Sunspot
37
+ UnrecognizedFieldError = Class.new(StandardError)
38
+ UnrecognizedRestrictionError = Class.new(StandardError)
39
+ NoAdapterError = Class.new(StandardError)
40
+ NoSetupError = Class.new(StandardError)
41
+ IllegalSearchError = Class.new(StandardError)
42
+ NotImplementedError = Class.new(StandardError)
43
+
44
+ autoload :Installer, File.join(File.dirname(__FILE__), 'sunspot', 'installer')
45
+
46
+ class <<self
47
+ #
48
+ # Clients can inject a session proxy, allowing them to implement custom
49
+ # session-management logic while retaining the Sunspot singleton API as
50
+ # an available interface. The object assigned to this attribute must
51
+ # respond to all of the public methods of the Sunspot::Session class.
52
+ #
53
+ attr_writer :session
54
+
55
+ # Configures indexing and search for a given class.
56
+ #
57
+ # ==== Parameters
58
+ #
59
+ # clazz<Class>:: class to configure
60
+ #
61
+ # ==== Example
62
+ #
63
+ # Sunspot.setup(Post) do
64
+ # text :title, :body
65
+ # string :author_name
66
+ # integer :blog_id
67
+ # integer :category_ids
68
+ # float :average_rating, :using => :ratings_average
69
+ # time :published_at
70
+ # string :sort_title do
71
+ # title.downcase.sub(/^(an?|the)\W+/, ''/) if title = self.title
72
+ # end
73
+ # end
74
+ #
75
+ # ====== Attribute Fields vs. Virtual Fields
76
+ #
77
+ # Attribute fields call a method on the indexed object and index the
78
+ # return value. All of the fields defined above except for the last one are
79
+ # attribute fields. By default, the field name will also be the attribute
80
+ # used; this can be overriden with the +:using+ option, as in
81
+ # +:average_rating+ above. In that case, the attribute +:ratings_average+
82
+ # will be indexed with the field name +:average_rating+.
83
+ #
84
+ # +:sort_title+ is a virtual field, which evaluates the block inside the
85
+ # context of the instance being indexed, and indexes the value returned
86
+ # by the block. If the block you pass takes an argument, it will be passed
87
+ # the instance rather than being evaluated inside of it; so, the following
88
+ # example is equivalent to the one above (assuming #title is public):
89
+ #
90
+ # Sunspot.setup(Post) do
91
+ # string :sort_title do |post|
92
+ # post.title.downcase.sub(/^(an?|the)\W+/, ''/) if title = self.title
93
+ # end
94
+ # end
95
+ #
96
+ # ===== Field Types
97
+ #
98
+ # The available types are:
99
+ #
100
+ # * +text+
101
+ # * +string+
102
+ # * +integer+
103
+ # * +float+
104
+ # * +time+
105
+ # * +boolean+
106
+ #
107
+ # Note that the +text+ type behaves quite differently from the others -
108
+ # this is the type that is indexed as fulltext, and is searched using the
109
+ # +keywords+ method inside the search DSL. Text fields cannot have
110
+ # restrictions set on them, nor can they be used in order statements or
111
+ # for facets. All other types are indexed literally, and thus can be used
112
+ # for all of those operations. They will not, however, be searched in
113
+ # fulltext. In this way, Sunspot provides a complete barrier between
114
+ # fulltext fields and value fields.
115
+ #
116
+ # It is fine to specify a field both as a text field and a string field;
117
+ # internally, the fields will have different names so there is no danger
118
+ # of conflict.
119
+ #
120
+ # ===== Dynamic Fields
121
+ #
122
+ # For use cases which have highly dynamic data models (for instance, an
123
+ # open set of key-value pairs attached to a model), it may be useful to
124
+ # defer definition of fields until indexing time. Sunspot exposes dynamic
125
+ # fields, which define a data accessor (either attribute or virtual, see
126
+ # above), which accepts a hash of field names to values. Note that the field
127
+ # names in the hash are internally scoped to the base name of the dynamic
128
+ # field, so any time they are referred to, they are referred to using both
129
+ # the base name and the dynamic (runtime-specified) name.
130
+ #
131
+ # Dynamic fields are speficied in the setup block using the type name
132
+ # prefixed by +dynamic_+. For example:
133
+ #
134
+ # Sunspot.setup(Post) do
135
+ # dynamic_string :custom_values do
136
+ # key_value_pairs.inject({}) do |hash, key_value_pair|
137
+ # hash[key_value_pair.key.to_sym] = key_value_pair.value
138
+ # end
139
+ # end
140
+ # end
141
+ #
142
+ # If you later wanted to facet all of the values for the key "cuisine",
143
+ # you could issue:
144
+ #
145
+ # Sunspot.search(Post) do
146
+ # dynamic :custom_values do
147
+ # facet :cuisine
148
+ # end
149
+ # end
150
+ #
151
+ # In the documentation, +:custom_values+ is referred to as the "base name" -
152
+ # that is, the one specified statically - and +:cuisine+ is referred to as
153
+ # the dynamic name, which is the part that is specified at indexing time.
154
+ #
155
+ def setup(clazz, &block)
156
+ Setup.setup(clazz, &block)
157
+ end
158
+
159
+ # Indexes objects on the singleton session.
160
+ #
161
+ # ==== Parameters
162
+ #
163
+ # objects...<Object>:: objects to index (may pass an array or varargs)
164
+ #
165
+ # ==== Example
166
+ #
167
+ # post1, post2 = new Array(2) { Post.create }
168
+ # Sunspot.index(post1, post2)
169
+ #
170
+ # Note that indexed objects won't be reflected in search until a commit is
171
+ # sent - see Sunspot.index! and Sunspot.commit
172
+ #
173
+ def index(*objects)
174
+ session.index(*objects)
175
+ end
176
+
177
+ # Indexes objects on the singleton session and commits immediately.
178
+ #
179
+ # See: Sunspot.index and Sunspot.commit
180
+ #
181
+ # ==== Parameters
182
+ #
183
+ # objects...<Object>:: objects to index (may pass an array or varargs)
184
+ #
185
+ def index!(*objects)
186
+ session.index!(*objects)
187
+ end
188
+
189
+ # Commits the singleton session
190
+ #
191
+ # When documents are added to or removed from Solr, the changes are
192
+ # initially stored in memory, and are not reflected in Solr's existing
193
+ # searcher instance. When a commit message is sent, the changes are written
194
+ # to disk, and a new searcher is spawned. Commits are thus fairly
195
+ # expensive, so if your application needs to index several documents as part
196
+ # of a single operation, it is advisable to index them all and then call
197
+ # commit at the end of the operation.
198
+ #
199
+ # Note that Solr can also be configured to automatically perform a commit
200
+ # after either a specified interval after the last change, or after a
201
+ # specified number of documents are added. See
202
+ # http://wiki.apache.org/solr/SolrConfigXml
203
+ #
204
+ def commit
205
+ session.commit
206
+ end
207
+
208
+ # Optimizes the index on the singletion session.
209
+ #
210
+ # Frequently adding and deleting documents to Solr, leaves the index in a
211
+ # fragmented state. The optimize command merges all index segments into
212
+ # a single segment and removes any deleted documents, making it faster to
213
+ # search. Since optimize rebuilds the index from scratch, it takes some
214
+ # time and requires double the space on the hard disk while it's rebuilding.
215
+ # Note that optimize also commits.
216
+ def optimize
217
+ session.optimize
218
+ end
219
+
220
+ #
221
+ # Create a new Search instance, but do not execute it immediately. Generally
222
+ # you will want to use the #search method to build and execute searches in
223
+ # one step, but if you are building searches piecemeal you may call
224
+ # #new_search and then call #build one or more times to add components to
225
+ # the query.
226
+ #
227
+ # ==== Example
228
+ #
229
+ # search = Sunspot.new_search do
230
+ # with(:blog_id, 1)
231
+ # end
232
+ # search.build do
233
+ # keywords('some keywords')
234
+ # end
235
+ # search.build do
236
+ # order_by(:published_at, :desc)
237
+ # end
238
+ # search.execute
239
+ #
240
+ # # This is equivalent to:
241
+ # Sunspot.search do
242
+ # with(:blog_id, 1)
243
+ # keywords('some keywords')
244
+ # order_by(:published_at, :desc)
245
+ # end
246
+ #
247
+ # ==== Parameters
248
+ #
249
+ # types<Class>...::
250
+ # One or more types to search for. If no types are passed, all
251
+ # configured types will be searched for.
252
+ #
253
+ # ==== Returns
254
+ #
255
+ # Sunspot::Search::
256
+ # Search object, not yet executed. Query parameters can be added manually;
257
+ # then #execute should be called.
258
+ #
259
+ def new_search(*types, &block)
260
+ session.new_search(*types, &block)
261
+ end
262
+
263
+
264
+ # Search for objects in the index.
265
+ #
266
+ # ==== Parameters
267
+ #
268
+ # types<Class>...::
269
+ # One or more types to search for. If no types are passed, all
270
+ # configured types will be searched.
271
+ #
272
+ # ==== Returns
273
+ #
274
+ # Sunspot::Search:: Object containing results, facets, count, etc.
275
+ #
276
+ # The fields available for restriction, ordering, etc. are those that meet
277
+ # the following criteria:
278
+ #
279
+ # * They are not of type +text+.
280
+ # * They are defined for at least one of the classes being searched
281
+ # * They have the same data type for all of the classes being searched.
282
+ # * They have the same multiple flag for all of the classes being searched.
283
+ # * They have the same stored flag for all of the classes being searched.
284
+ #
285
+ # The restrictions available are the constants defined in the
286
+ # Sunspot::Restriction class. The standard restrictions are:
287
+ #
288
+ # with(:field_name).equal_to(value)
289
+ # with(:field_name, value) # shorthand for above
290
+ # with(:field_name).less_than(value)
291
+ # with(:field_name).greater_than(value)
292
+ # with(:field_name).between(value1..value2)
293
+ # with(:field_name).any_of([value1, value2, value3])
294
+ # with(:field_name).all_of([value1, value2, value3])
295
+ # without(some_instance) # exclude that particular instance
296
+ #
297
+ # +without+ can be substituted for +with+, causing the restriction to be
298
+ # negated. In the last example above, only +without+ works, as it does not
299
+ # make sense to search only for an instance you already have.
300
+ #
301
+ # Equality restrictions can take +nil+ as a value, which restricts the
302
+ # results to documents that have no value for the given field. Passing +nil+
303
+ # as a value to other restriction types is illegal. Thus:
304
+ #
305
+ # with(:field_name, nil) # ok
306
+ # with(:field_name).equal_to(nil) # ok
307
+ # with(:field_name).less_than(nil) # bad
308
+ #
309
+ # ==== Example
310
+ #
311
+ # Sunspot.search(Post) do
312
+ # keywords 'great pizza'
313
+ # with(:published_at).less_than Time.now
314
+ # with :blog_id, 1
315
+ # without current_post
316
+ # facet :category_ids
317
+ # order_by :published_at, :desc
318
+ # paginate 2, 15
319
+ # end
320
+ #
321
+ # If the block passed to #search takes an argument, that argument will
322
+ # present the DSL, and the block will be evaluated in the calling context.
323
+ # This will come in handy for building searches using instance data or
324
+ # methods, e.g.:
325
+ #
326
+ # Sunspot.search(Post) do |query|
327
+ # query.with(:blog_id, @current_blog.id)
328
+ # end
329
+ #
330
+ # See Sunspot::DSL::Search, Sunspot::DSL::Scope, Sunspot::DSL::FieldQuery
331
+ # and Sunspot::DSL::Query for the full API presented inside the block.
332
+ #
333
+ def search(*types, &block)
334
+ session.search(*types, &block)
335
+ end
336
+
337
+ def new_more_like_this(object, *types, &block)
338
+ session.new_more_like_this(object, *types, &block)
339
+ end
340
+
341
+ #
342
+ # Initiate a MoreLikeThis search. MoreLikeThis is a special type of search
343
+ # that finds similar documents using fulltext comparison. The fields to be
344
+ # compared are `text` fields set up with the `:more_like_this` option set to
345
+ # `true`. By default, more like this returns objects of the same type as the
346
+ # object used for comparison, but a list of types can optionally be passed
347
+ # to this method to return similar documents of other types. This will only
348
+ # work for types that have common fields.
349
+ #
350
+ # The DSL for MoreLikeThis search exposes several methods for setting
351
+ # options specific to this type of search. See the
352
+ # Sunspot::DSL::MoreLikeThis class and the MoreLikeThis documentation on
353
+ # the Solr wiki: http://wiki.apache.org/solr/MoreLikeThis
354
+ #
355
+ # MoreLikeThis searches have all of the same scoping, ordering, and faceting
356
+ # functionality as standard searches; the only thing you can't do in a MLT
357
+ # search is fulltext matching (since the MLT itself is a fulltext query).
358
+ #
359
+ # ==== Example
360
+ #
361
+ # post = Post.first
362
+ # Sunspot.more_like_this(post, Post, Page) do
363
+ # fields :title, :body
364
+ # with(:updated_at).greater_than(1.month.ago)
365
+ # facet(:category_ids)
366
+ # end
367
+ #
368
+ #
369
+ def more_like_this(object, *types, &block)
370
+ session.more_like_this(object, *types, &block)
371
+ end
372
+
373
+ # Remove objects from the index. Any time an object is destroyed, it must
374
+ # be removed from the index; otherwise, the index will contain broken
375
+ # references to objects that do not exist, which will cause errors when
376
+ # those objects are matched in search results.
377
+ #
378
+ # If a block is passed, it is evaluated as a search scope; in this way,
379
+ # documents can be removed by an arbitrary query. In this case, the
380
+ # arguments to the method should be the classes to run the query on.
381
+ #
382
+ # ==== Parameters
383
+ #
384
+ # objects...<Object>::
385
+ # Objects to remove from the index (may pass an array or varargs)
386
+ #
387
+ # ==== Example (remove a document)
388
+ #
389
+ # post.destroy
390
+ # Sunspot.remove(post)
391
+ #
392
+ # ==== Example (remove by query)
393
+ #
394
+ # Sunspot.remove(Post) do
395
+ # with(:created_at).less_than(Time.now - 14.days)
396
+ # end
397
+ #
398
+ def remove(*objects, &block)
399
+ session.remove(*objects, &block)
400
+ end
401
+
402
+ #
403
+ # Remove objects from the index and immediately commit. See Sunspot.remove
404
+ #
405
+ # ==== Parameters
406
+ #
407
+ # objects...<Object>:: Objects to remove from the index
408
+ #
409
+ def remove!(*objects)
410
+ session.remove!(*objects)
411
+ end
412
+
413
+ #
414
+ # Remove an object from the index using its class name and primary key.
415
+ # Useful if you know this information and want to remove an object without
416
+ # instantiating it from persistent storage
417
+ #
418
+ # ==== Parameters
419
+ #
420
+ # clazz<Class>:: Class of the object, or class name as a string or symbol
421
+ # id::
422
+ # Primary key of the object. This should be the same id that would be
423
+ # returned by the class's instance adapter.
424
+ #
425
+ def remove_by_id(clazz, id)
426
+ session.remove_by_id(clazz, id)
427
+ end
428
+
429
+ #
430
+ # Remove an object by class name and primary key, and immediately commit.
431
+ # See #remove_by_id and #commit
432
+ #
433
+ def remove_by_id!(clazz, id)
434
+ session.remove_by_id!(clazz, id)
435
+ end
436
+
437
+ # Remove all objects of the given classes from the index. There isn't much
438
+ # use for this in general operations but it can be useful for maintenance,
439
+ # testing, etc. If no arguments are passed, remove everything from the
440
+ # index.
441
+ #
442
+ # ==== Parameters
443
+ #
444
+ # classes...<Class>::
445
+ # classes for which to remove all instances from the index (may pass an
446
+ # array or varargs)
447
+ #
448
+ # ==== Example
449
+ #
450
+ # Sunspot.remove_all(Post, Blog)
451
+ #
452
+ def remove_all(*classes)
453
+ session.remove_all(*classes)
454
+ end
455
+
456
+ #
457
+ # Remove all objects of the given classes from the index and immediately
458
+ # commit. See Sunspot.remove_all
459
+ #
460
+ # ==== Parameters
461
+ #
462
+ # classes...<Class>::
463
+ # classes for which to remove all instances from the index
464
+ def remove_all!(*classes)
465
+ session.remove_all!(*classes)
466
+ end
467
+
468
+ #
469
+ # Process all adds in a batch. Any Sunspot adds initiated inside the block
470
+ # will be sent in bulk when the block finishes. Useful if your application
471
+ # initiates index adds from various places in code as part of a single
472
+ # operation; doing a batch add will give better performance.
473
+ #
474
+ # ==== Example
475
+ #
476
+ # Sunspot.batch do
477
+ # post = Post.new
478
+ # Sunspot.add(post)
479
+ # comment = Comment.new
480
+ # Sunspot.add(comment)
481
+ # end
482
+ #
483
+ # Sunspot will send both the post and the comment in a single request.
484
+ #
485
+ def batch(&block)
486
+ session.batch(&block)
487
+ end
488
+
489
+ #
490
+ # True if documents have been added, updated, or removed since the last
491
+ # commit.
492
+ #
493
+ # ==== Returns
494
+ #
495
+ # Boolean:: Whether there have been any updates since the last commit
496
+ #
497
+ def dirty?
498
+ session.dirty?
499
+ end
500
+
501
+ #
502
+ # Sends a commit if the session is dirty (see #dirty?).
503
+ #
504
+ def commit_if_dirty
505
+ session.commit_if_dirty
506
+ end
507
+
508
+ #
509
+ # True if documents have been removed since the last commit.
510
+ #
511
+ # ==== Returns
512
+ #
513
+ # Boolean:: Whether there have been any deletes since the last commit
514
+ #
515
+ def delete_dirty?
516
+ session.delete_dirty?
517
+ end
518
+
519
+ #
520
+ # Sends a commit if the session has deletes since the last commit (see #delete_dirty?).
521
+ #
522
+ def commit_if_delete_dirty
523
+ session.commit_if_delete_dirty
524
+ end
525
+
526
+ # Returns the configuration associated with the singleton session. See
527
+ # Sunspot::Configuration for details.
528
+ #
529
+ # ==== Returns
530
+ #
531
+ # LightConfig::Configuration:: configuration for singleton session
532
+ #
533
+ def config
534
+ session.config
535
+ end
536
+
537
+ #
538
+ # Resets the singleton session. This is useful for clearing out all
539
+ # static data between tests, but probably nowhere else.
540
+ #
541
+ # ==== Parameters
542
+ #
543
+ # keep_config<Boolean>::
544
+ # Whether to retain the configuration used by the current singleton
545
+ # session. Default false.
546
+ #
547
+ def reset!(keep_config = false)
548
+ config =
549
+ if keep_config
550
+ session.config
551
+ else
552
+ Configuration.build
553
+ end
554
+ @session = Session.new(config)
555
+ end
556
+
557
+ #
558
+ # Get the singleton session, creating it if none yet exists.
559
+ #
560
+ # ==== Returns
561
+ #
562
+ # Sunspot::Session:: the singleton session
563
+ #
564
+ def session #:nodoc:
565
+ @session ||= Session.new
566
+ end
567
+ end
568
+ end