sunspot 2.0.0.pre.111215 → 2.0.0.pre.120415
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.
- data/History.txt +7 -0
- data/lib/sunspot/batcher.rb +62 -0
- data/lib/sunspot/configuration.rb +2 -0
- data/lib/sunspot/dsl/field_group.rb +20 -0
- data/lib/sunspot/dsl/field_query.rb +24 -0
- data/lib/sunspot/dsl/restriction_with_near.rb +24 -2
- data/lib/sunspot/indexer.rb +11 -6
- data/lib/sunspot/query.rb +3 -3
- data/lib/sunspot/query/abstract_field_facet.rb +3 -0
- data/lib/sunspot/query/bbox.rb +15 -0
- data/lib/sunspot/query/field_group.rb +5 -3
- data/lib/sunspot/query/geofilt.rb +4 -3
- data/lib/sunspot/query/range_facet.rb +14 -0
- data/lib/sunspot/search.rb +1 -1
- data/lib/sunspot/search/abstract_search.rb +5 -0
- data/lib/sunspot/search/field_group.rb +6 -0
- data/lib/sunspot/search/group.rb +19 -0
- data/lib/sunspot/search/range_facet.rb +37 -0
- data/lib/sunspot/session.rb +3 -1
- data/lib/sunspot/session_proxy.rb +8 -0
- data/lib/sunspot/session_proxy/retry_5xx_session_proxy.rb +67 -0
- data/lib/sunspot/version.rb +1 -1
- data/spec/api/batcher_spec.rb +112 -0
- data/spec/api/indexer/batch_spec.rb +29 -3
- data/spec/api/query/faceting_examples.rb +59 -0
- data/spec/api/query/spatial_examples.rb +16 -0
- data/spec/api/session_proxy/retry_5xx_session_proxy_spec.rb +73 -0
- data/spec/api/session_spec.rb +12 -0
- data/spec/integration/faceting_spec.rb +20 -0
- data/spec/integration/field_grouping_spec.rb +9 -0
- data/spec/integration/geospatial_spec.rb +27 -1
- data/spec/integration/indexing_spec.rb +22 -0
- data/sunspot.gemspec +1 -2
- metadata +35 -29
data/History.txt
CHANGED
|
@@ -5,6 +5,13 @@
|
|
|
5
5
|
* Adds #query_time method to retrieve the Solr query time in
|
|
6
6
|
milliseconds (Jason Weathered)
|
|
7
7
|
* Fixes syntax of highlighting when used with nested dismax queries (Marco Crepaldi)
|
|
8
|
+
* Adds ability to nest `Sunspot.batch` calls (Thorbjørn Hermansen)
|
|
9
|
+
* Adds `open_timeout` and `read_timeout` configuration options (Rob Di
|
|
10
|
+
Marco)
|
|
11
|
+
* Adds `offset` options to facets (Federico Gonzalez)
|
|
12
|
+
* Adds `Retry5xxSessionProxy` to retry requests when an internal server error
|
|
13
|
+
occurs (Nick Zadrozny)
|
|
14
|
+
* Adds support for range queries (Jan Ulrich)
|
|
8
15
|
|
|
9
16
|
== 1.3.0 2011-11-26
|
|
10
17
|
* Requests to Solr use HTTP POST verb by default to avoid issues when the query string grows too large for GET (Johan Van Ryseghem)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module Sunspot
|
|
2
|
+
#
|
|
3
|
+
# Keeps a stack of batches and helps out when Indexer is asked to batch documents.
|
|
4
|
+
#
|
|
5
|
+
# If the client does something like
|
|
6
|
+
#
|
|
7
|
+
# Sunspot.batch do
|
|
8
|
+
# some_code_here
|
|
9
|
+
# which_triggers_some_other_code
|
|
10
|
+
# which_again_calls
|
|
11
|
+
# Sunspot.batch { ... }
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# it is the Batcher's job to keep track of these nestings. The inner will
|
|
15
|
+
# be sent of to be indexed first.
|
|
16
|
+
#
|
|
17
|
+
class Batcher
|
|
18
|
+
include Enumerable
|
|
19
|
+
|
|
20
|
+
# Raised if you ask to end current, but no current exists
|
|
21
|
+
class NoCurrentBatchError < StandardError; end
|
|
22
|
+
|
|
23
|
+
def initialize
|
|
24
|
+
@stack = []
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def current
|
|
28
|
+
@stack.last or start_new
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def start_new
|
|
32
|
+
(@stack << []).last
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def end_current
|
|
36
|
+
fail NoCurrentBatchError if @stack.empty?
|
|
37
|
+
|
|
38
|
+
@stack.pop
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def depth
|
|
42
|
+
@stack.length
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def batching?
|
|
46
|
+
depth > 0
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def each(&block)
|
|
50
|
+
current.each(&block)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def push(value)
|
|
54
|
+
current << value
|
|
55
|
+
end
|
|
56
|
+
alias << push
|
|
57
|
+
|
|
58
|
+
def concat(values)
|
|
59
|
+
current.concat values
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -13,6 +13,26 @@ module Sunspot
|
|
|
13
13
|
@group.limit = num
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
#
|
|
17
|
+
# If set, facet counts are based on the most relevant document of
|
|
18
|
+
# each group matching the query.
|
|
19
|
+
#
|
|
20
|
+
# Supported in Solr 3.4 and above.
|
|
21
|
+
#
|
|
22
|
+
# ==== Example
|
|
23
|
+
#
|
|
24
|
+
# Sunspot.search(Post) do
|
|
25
|
+
# group :title do
|
|
26
|
+
# truncate
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# facet :title, :extra => :any
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
def truncate
|
|
33
|
+
@group.truncate = true
|
|
34
|
+
end
|
|
35
|
+
|
|
16
36
|
# Specify the order that results should be returned in. This method can
|
|
17
37
|
# be called multiple times; precedence will be in the order given.
|
|
18
38
|
#
|
|
@@ -185,6 +185,19 @@ module Sunspot
|
|
|
185
185
|
# semantic meaning is attached to them. The label for +facet+ should be
|
|
186
186
|
# a symbol; the label for +row+ can be whatever you'd like.
|
|
187
187
|
#
|
|
188
|
+
# ==== Range Facets
|
|
189
|
+
#
|
|
190
|
+
# One can use the Range Faceting feature on any date field or any numeric
|
|
191
|
+
# field that supports range queries. This is particularly useful for the
|
|
192
|
+
# cases in the past where one might stitch together a series of range
|
|
193
|
+
# queries (as facet by query) for things like prices, etc.
|
|
194
|
+
#
|
|
195
|
+
# For example faceting over average ratings can be done as follows:
|
|
196
|
+
#
|
|
197
|
+
# Sunspot.search(Post) do
|
|
198
|
+
# facet :average_rating, :range => 1..5, :range_interval => 1
|
|
199
|
+
# end
|
|
200
|
+
#
|
|
188
201
|
# ==== Parameters
|
|
189
202
|
#
|
|
190
203
|
# field_names...<Symbol>:: fields for which to return field facets
|
|
@@ -195,6 +208,8 @@ module Sunspot
|
|
|
195
208
|
# Either :count (values matching the most terms first) or :index (lexical)
|
|
196
209
|
# :limit<Integer>::
|
|
197
210
|
# The maximum number of facet rows to return
|
|
211
|
+
# :offset<Integer>::
|
|
212
|
+
# The offset from which to start returning facet rows
|
|
198
213
|
# :minimum_count<Integer>::
|
|
199
214
|
# The minimum count a facet row must have to be returned
|
|
200
215
|
# :zeros<Boolean>::
|
|
@@ -276,6 +291,15 @@ module Sunspot
|
|
|
276
291
|
end
|
|
277
292
|
search_facet = @search.add_date_facet(field, options)
|
|
278
293
|
Sunspot::Query::DateFieldFacet.new(field, options)
|
|
294
|
+
elsif options[:range]
|
|
295
|
+
unless [Sunspot::Type::TimeType, Sunspot::Type::FloatType, Sunspot::Type::IntegerType ].inject(false){|res,type| res || field.type.is_a?(type)}
|
|
296
|
+
raise(
|
|
297
|
+
ArgumentError,
|
|
298
|
+
':range can only be specified for date or numeric fields'
|
|
299
|
+
)
|
|
300
|
+
end
|
|
301
|
+
search_facet = @search.add_range_facet(field, options)
|
|
302
|
+
Sunspot::Query::RangeFacet.new(field, options)
|
|
279
303
|
else
|
|
280
304
|
search_facet = @search.add_field_facet(field, options)
|
|
281
305
|
Sunspot::Query::FieldFacet.new(field, options)
|
|
@@ -130,8 +130,30 @@ module Sunspot
|
|
|
130
130
|
# :radius<Numeric>::
|
|
131
131
|
# Radius (in kilometers)
|
|
132
132
|
#
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
# ==== Options
|
|
134
|
+
#
|
|
135
|
+
# <dt><code>:bbox</code></dt>
|
|
136
|
+
# <dd>If `true`, performs the search using `bbox`. `bbox` is
|
|
137
|
+
# more performant, but also more inexact (guaranteed to encompass
|
|
138
|
+
# all of the points of interest, but may also include other points
|
|
139
|
+
# that are slightly outside of the required distance).</dd>
|
|
140
|
+
#
|
|
141
|
+
def in_radius(lat, lon, radius, options = {})
|
|
142
|
+
@query.add_geo(Sunspot::Query::Geofilt.new(@field, lat, lon, radius, options))
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
#
|
|
146
|
+
# Performs a query that is filtered by a bounding box
|
|
147
|
+
#
|
|
148
|
+
# ==== Parameters
|
|
149
|
+
#
|
|
150
|
+
# :first_corner<Array>::
|
|
151
|
+
# First corner (expressed as an array `[latitude, longitude]`)
|
|
152
|
+
# :second_corner<Array>::
|
|
153
|
+
# Second corner (expressed as an array `[latitude, longitude]`)
|
|
154
|
+
#
|
|
155
|
+
def in_bounding_box(first_corner, second_corner)
|
|
156
|
+
@query.add_geo(Sunspot::Query::Bbox.new(@field, first_corner, second_corner))
|
|
135
157
|
end
|
|
136
158
|
end
|
|
137
159
|
end
|
data/lib/sunspot/indexer.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'sunspot/batcher'
|
|
2
|
+
|
|
1
3
|
module Sunspot
|
|
2
4
|
#
|
|
3
5
|
# This class presents a service for adding, updating, and removing data
|
|
@@ -22,10 +24,10 @@ module Sunspot
|
|
|
22
24
|
#
|
|
23
25
|
def add(model)
|
|
24
26
|
documents = Util.Array(model).map { |m| prepare(m) }
|
|
25
|
-
if
|
|
26
|
-
|
|
27
|
+
if batcher.batching?
|
|
28
|
+
batcher.concat(documents)
|
|
27
29
|
else
|
|
28
|
-
|
|
30
|
+
add_documents(documents)
|
|
29
31
|
end
|
|
30
32
|
end
|
|
31
33
|
|
|
@@ -69,19 +71,22 @@ module Sunspot
|
|
|
69
71
|
# Start batch processing
|
|
70
72
|
#
|
|
71
73
|
def start_batch
|
|
72
|
-
|
|
74
|
+
batcher.start_new
|
|
73
75
|
end
|
|
74
76
|
|
|
75
77
|
#
|
|
76
78
|
# Write batch out to Solr and clear it
|
|
77
79
|
#
|
|
78
80
|
def flush_batch
|
|
79
|
-
add_documents(
|
|
80
|
-
@batch = nil
|
|
81
|
+
add_documents(batcher.end_current)
|
|
81
82
|
end
|
|
82
83
|
|
|
83
84
|
private
|
|
84
85
|
|
|
86
|
+
def batcher
|
|
87
|
+
@batcher ||= Batcher.new
|
|
88
|
+
end
|
|
89
|
+
|
|
85
90
|
#
|
|
86
91
|
# Convert documents into hash of indexed properties
|
|
87
92
|
#
|
data/lib/sunspot/query.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
%w(filter abstract_field_facet connective boost_query date_field_facet dismax
|
|
1
|
+
%w(filter abstract_field_facet connective boost_query date_field_facet range_facet dismax
|
|
2
2
|
field_facet highlighting pagination restriction common_query
|
|
3
|
-
standard_query more_like_this more_like_this_query geo geofilt query_facet
|
|
4
|
-
sort sort_composite text_field_boost function_query
|
|
3
|
+
standard_query more_like_this more_like_this_query geo geofilt bbox query_facet
|
|
4
|
+
scope sort sort_composite text_field_boost function_query
|
|
5
5
|
composite_fulltext field_group).each do |file|
|
|
6
6
|
require(File.join(File.dirname(__FILE__), 'query', file))
|
|
7
7
|
end
|
|
@@ -26,6 +26,9 @@ module Sunspot
|
|
|
26
26
|
if @options[:limit]
|
|
27
27
|
params[qualified_param('limit')] = @options[:limit].to_i
|
|
28
28
|
end
|
|
29
|
+
if @options[:offset]
|
|
30
|
+
params[qualified_param('offset')] = @options[:offset].to_i
|
|
31
|
+
end
|
|
29
32
|
if @options[:prefix]
|
|
30
33
|
params[qualified_param('prefix')] = escape(@options[:prefix].to_s)
|
|
31
34
|
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Sunspot
|
|
2
|
+
module Query
|
|
3
|
+
class Bbox
|
|
4
|
+
def initialize(field, first_corner, second_corner)
|
|
5
|
+
@field, @first_corner, @second_corner = field, first_corner, second_corner
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def to_params
|
|
9
|
+
filter = "#{@field.indexed_name}:[#{@first_corner.join(",")} TO #{@second_corner.join(",")}]"
|
|
10
|
+
|
|
11
|
+
{:fq => filter}
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -4,7 +4,7 @@ module Sunspot
|
|
|
4
4
|
# A FieldGroup groups by the unique values of a given field.
|
|
5
5
|
#
|
|
6
6
|
class FieldGroup
|
|
7
|
-
attr_accessor :limit
|
|
7
|
+
attr_accessor :limit, :truncate
|
|
8
8
|
|
|
9
9
|
def initialize(field)
|
|
10
10
|
if field.multiple?
|
|
@@ -21,12 +21,14 @@ module Sunspot
|
|
|
21
21
|
|
|
22
22
|
def to_params
|
|
23
23
|
params = {
|
|
24
|
-
:group
|
|
25
|
-
:"group.
|
|
24
|
+
:group => "true",
|
|
25
|
+
:"group.ngroups" => "true",
|
|
26
|
+
:"group.field" => @field.indexed_name
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
params.merge!(@sort.to_params("group."))
|
|
29
30
|
params[:"group.limit"] = @limit if @limit
|
|
31
|
+
params[:"group.truncate"] = @truncate if @truncate
|
|
30
32
|
|
|
31
33
|
params
|
|
32
34
|
end
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
module Sunspot
|
|
2
2
|
module Query
|
|
3
3
|
class Geofilt
|
|
4
|
-
def initialize(field, lat, lon, radius)
|
|
5
|
-
@field, @lat, @lon, @radius = field, lat, lon, radius
|
|
4
|
+
def initialize(field, lat, lon, radius, options = {})
|
|
5
|
+
@field, @lat, @lon, @radius, @options = field, lat, lon, radius, options
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
def to_params
|
|
9
|
-
|
|
9
|
+
func = @options[:bbox] ? "bbox" : "geofilt"
|
|
10
10
|
|
|
11
|
+
filter = "{!#{func} sfield=#{@field.indexed_name} pt=#{@lat},#{@lon} d=#{@radius}}"
|
|
11
12
|
{:fq => filter}
|
|
12
13
|
end
|
|
13
14
|
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Sunspot
|
|
2
|
+
module Query
|
|
3
|
+
class RangeFacet < AbstractFieldFacet
|
|
4
|
+
def to_params
|
|
5
|
+
params = super
|
|
6
|
+
params[:"facet.range"] = [@field.indexed_name]
|
|
7
|
+
params[qualified_param('range.start')] = @field.to_indexed(@options[:range].first)
|
|
8
|
+
params[qualified_param('range.end')] = @field.to_indexed(@options[:range].last)
|
|
9
|
+
params[qualified_param('range.gap')] = "#{@options[:range_interval] || 10}"
|
|
10
|
+
params
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
data/lib/sunspot/search.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
%w(abstract_search standard_search more_like_this_search query_facet field_facet
|
|
2
|
-
date_facet facet_row hit highlight field_group group hit_enumerable).each do |file|
|
|
2
|
+
date_facet range_facet facet_row hit highlight field_group group hit_enumerable).each do |file|
|
|
3
3
|
require File.join(File.dirname(__FILE__), 'search', file)
|
|
4
4
|
end
|
|
5
5
|
|
|
@@ -226,6 +226,11 @@ module Sunspot
|
|
|
226
226
|
add_facet(name, DateFacet.new(field, self, options))
|
|
227
227
|
end
|
|
228
228
|
|
|
229
|
+
def add_range_facet(field, options) #:nodoc:
|
|
230
|
+
name = (options[:name] || field.name)
|
|
231
|
+
add_facet(name, RangeFacet.new(field, self, options))
|
|
232
|
+
end
|
|
233
|
+
|
|
229
234
|
def highlights_for(doc) #:nodoc:
|
|
230
235
|
if @solr_result['highlighting']
|
|
231
236
|
@solr_result['highlighting'][doc['id']]
|
data/lib/sunspot/search/group.rb
CHANGED
|
@@ -23,6 +23,10 @@ module Sunspot
|
|
|
23
23
|
@verified_hits ||= super
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
def results
|
|
27
|
+
@results ||= verified_hits.map { |hit| hit.instance }
|
|
28
|
+
end
|
|
29
|
+
|
|
26
30
|
def highlights_for(doc)
|
|
27
31
|
@search.highlights_for(doc)
|
|
28
32
|
end
|
|
@@ -30,6 +34,21 @@ module Sunspot
|
|
|
30
34
|
def solr_docs
|
|
31
35
|
@doclist['docs']
|
|
32
36
|
end
|
|
37
|
+
|
|
38
|
+
def data_accessor_for(clazz)
|
|
39
|
+
@search.data_accessor_for(clazz)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
#
|
|
43
|
+
# The total number of documents matching the query for this group
|
|
44
|
+
#
|
|
45
|
+
# ==== Returns
|
|
46
|
+
#
|
|
47
|
+
# Integer:: Total matching documents
|
|
48
|
+
#
|
|
49
|
+
def total
|
|
50
|
+
@doclist['numFound']
|
|
51
|
+
end
|
|
33
52
|
end
|
|
34
53
|
end
|
|
35
54
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Sunspot
|
|
2
|
+
module Search
|
|
3
|
+
class RangeFacet
|
|
4
|
+
def initialize(field, search, options)
|
|
5
|
+
@field, @search, @options = field, search, options
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def field_name
|
|
9
|
+
@field.name
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def rows
|
|
13
|
+
@rows ||=
|
|
14
|
+
begin
|
|
15
|
+
data = @search.facet_response['facet_ranges'][@field.indexed_name]
|
|
16
|
+
gap = (@options[:range_interval] || 10).to_i
|
|
17
|
+
rows = []
|
|
18
|
+
|
|
19
|
+
if data['counts']
|
|
20
|
+
Hash[*data['counts']].each_pair do |start_str, count|
|
|
21
|
+
start = start_str.to_f
|
|
22
|
+
finish = start + gap
|
|
23
|
+
rows << FacetRow.new(start..finish, count, self)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
if @options[:sort] == :count
|
|
28
|
+
rows.sort! { |lrow, rrow| rrow.count <=> lrow.count }
|
|
29
|
+
else
|
|
30
|
+
rows.sort! { |lrow, rrow| lrow.value.first <=> rrow.value.first }
|
|
31
|
+
end
|
|
32
|
+
rows
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/sunspot/session.rb
CHANGED
|
@@ -239,7 +239,9 @@ module Sunspot
|
|
|
239
239
|
#
|
|
240
240
|
def connection
|
|
241
241
|
@connection ||=
|
|
242
|
-
self.class.connection_class.connect(:url
|
|
242
|
+
self.class.connection_class.connect(:url => config.solr.url,
|
|
243
|
+
:read_timeout => config.solr.read_timeout,
|
|
244
|
+
:open_timeout => config.solr.open_timeout)
|
|
243
245
|
end
|
|
244
246
|
|
|
245
247
|
def indexer
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'abstract_session_proxy')
|
|
2
|
+
|
|
3
|
+
module Sunspot
|
|
4
|
+
module SessionProxy
|
|
5
|
+
class Retry5xxSessionProxy < AbstractSessionProxy
|
|
6
|
+
|
|
7
|
+
class RetryHandler
|
|
8
|
+
attr_reader :search_session
|
|
9
|
+
|
|
10
|
+
def initialize(search_session)
|
|
11
|
+
@search_session = search_session
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def method_missing(m, *args, &block)
|
|
15
|
+
retry_count = 1
|
|
16
|
+
begin
|
|
17
|
+
search_session.send(m, *args, &block)
|
|
18
|
+
rescue Errno::ECONNRESET => e
|
|
19
|
+
if retry_count > 0
|
|
20
|
+
$stderr.puts "Error - #{e.message[/^.*$/]} - retrying..."
|
|
21
|
+
retry_count -= 1
|
|
22
|
+
retry
|
|
23
|
+
else
|
|
24
|
+
$stderr.puts "Error - #{e.message[/^.*$/]} - ignoring..."
|
|
25
|
+
end
|
|
26
|
+
rescue RSolr::Error::Http => e
|
|
27
|
+
if (500..599).include?(e.response[:status].to_i)
|
|
28
|
+
if retry_count > 0
|
|
29
|
+
$stderr.puts "Error - #{e.message[/^.*$/]} - retrying..."
|
|
30
|
+
retry_count -= 1
|
|
31
|
+
retry
|
|
32
|
+
else
|
|
33
|
+
$stderr.puts "Error - #{e.message[/^.*$/]} - ignoring..."
|
|
34
|
+
e.response
|
|
35
|
+
end
|
|
36
|
+
else
|
|
37
|
+
raise e
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
attr_reader :search_session
|
|
44
|
+
attr_reader :retry_handler
|
|
45
|
+
|
|
46
|
+
delegate :new_search, :search, :config,
|
|
47
|
+
:new_more_like_this, :more_like_this,
|
|
48
|
+
:delete_dirty, :delete_dirty?,
|
|
49
|
+
:to => :search_session
|
|
50
|
+
|
|
51
|
+
def initialize(search_session = Sunspot.session)
|
|
52
|
+
@search_session = search_session
|
|
53
|
+
@retry_handler = RetryHandler.new(search_session)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def rescued_exception(method, e)
|
|
57
|
+
$stderr.puts("Exception in #{method}: #{e.message}")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
delegate :batch, :commit, :commit_if_dirty, :commit_if_delete_dirty,
|
|
61
|
+
:dirty?, :index!, :index, :optimize, :remove!, :remove, :remove_all!,
|
|
62
|
+
:remove_all, :remove_by_id!, :remove_by_id,
|
|
63
|
+
:to => :retry_handler
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
data/lib/sunspot/version.rb
CHANGED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
|
2
|
+
|
|
3
|
+
describe Sunspot::Batcher do
|
|
4
|
+
it "includes Enumerable" do
|
|
5
|
+
described_class.should include Enumerable
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
describe "#each" do
|
|
9
|
+
let(:current) { [:foo, :bar] }
|
|
10
|
+
before { subject.stub(:current).and_return current }
|
|
11
|
+
|
|
12
|
+
it "iterates over current" do
|
|
13
|
+
yielded_values = []
|
|
14
|
+
|
|
15
|
+
subject.each do |value|
|
|
16
|
+
yielded_values << value
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
yielded_values.should eq current
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe "adding to current batch" do
|
|
24
|
+
it "#push pushes to current" do
|
|
25
|
+
subject.push :foo
|
|
26
|
+
subject.current.should include :foo
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "#<< pushes to current" do
|
|
30
|
+
subject.push :foo
|
|
31
|
+
subject.current.should include :foo
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "#concat concatinates on current batch" do
|
|
35
|
+
subject << :foo
|
|
36
|
+
subject.concat [:bar, :mix]
|
|
37
|
+
should include :foo, :bar, :mix
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
describe "#current" do
|
|
43
|
+
context "no current" do
|
|
44
|
+
it "starts a new" do
|
|
45
|
+
expect { subject.current }.to change(subject, :depth).by 1
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "is empty by default" do
|
|
49
|
+
subject.current.should be_empty
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
context "with a current" do
|
|
54
|
+
before { subject.start_new }
|
|
55
|
+
|
|
56
|
+
it "does not start a new" do
|
|
57
|
+
expect { subject.current }.to_not change(subject, :depth)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "returns the same as last time" do
|
|
61
|
+
subject.current.should eq subject.current
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe "#start_new" do
|
|
67
|
+
it "creates a new batches" do
|
|
68
|
+
expect { 2.times { subject.start_new } }.to change(subject, :depth).by 2
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "changes current" do
|
|
72
|
+
subject << :foo
|
|
73
|
+
subject.start_new
|
|
74
|
+
should_not include :foo
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
describe "#end_current" do
|
|
79
|
+
context "no current batch" do
|
|
80
|
+
it "fails" do
|
|
81
|
+
expect { subject.end_current }.to raise_error Sunspot::Batcher::NoCurrentBatchError
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
context "with current batch" do
|
|
86
|
+
before { subject.start_new }
|
|
87
|
+
|
|
88
|
+
it "changes current" do
|
|
89
|
+
subject << :foo
|
|
90
|
+
subject.end_current
|
|
91
|
+
should_not include :foo
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "returns current" do
|
|
95
|
+
subject << :foo
|
|
96
|
+
subject.end_current.should include :foo
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
describe "#batching?" do
|
|
102
|
+
it "is false when depth is 0" do
|
|
103
|
+
subject.should_receive(:depth).and_return 0
|
|
104
|
+
should_not be_batching
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it "is true when depth is more than 0" do
|
|
108
|
+
subject.should_receive(:depth).and_return 1
|
|
109
|
+
should be_batching
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
|
2
2
|
|
|
3
3
|
describe 'batch indexing', :type => :indexer do
|
|
4
|
+
let(:posts) { Array.new(2) { |index| Post.new :title => "Post number #{index}!" } }
|
|
5
|
+
|
|
4
6
|
it 'should send all batched adds in a single request' do
|
|
5
|
-
posts = Array.new(2) { Post.new }
|
|
6
7
|
session.batch do
|
|
7
8
|
for post in posts
|
|
8
9
|
session.index(post)
|
|
@@ -12,7 +13,6 @@ describe 'batch indexing', :type => :indexer do
|
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
it 'should add all batched adds' do
|
|
15
|
-
posts = Array.new(2) { Post.new }
|
|
16
16
|
session.batch do
|
|
17
17
|
for post in posts
|
|
18
18
|
session.index(post)
|
|
@@ -36,11 +36,37 @@ describe 'batch indexing', :type => :indexer do
|
|
|
36
36
|
pending 'batching all operations'
|
|
37
37
|
connection.should_not_receive(:add)
|
|
38
38
|
connection.should_not_receive(:remove)
|
|
39
|
-
posts = Array.new(2) { Post.new }
|
|
40
39
|
session.batch do
|
|
41
40
|
session.index(posts[0])
|
|
42
41
|
session.remove(posts[1])
|
|
43
42
|
end
|
|
44
43
|
connection.adds
|
|
45
44
|
end
|
|
45
|
+
|
|
46
|
+
describe "nesting of batches" do
|
|
47
|
+
let(:a_nested_batch) do
|
|
48
|
+
session.batch do
|
|
49
|
+
session.index posts[0]
|
|
50
|
+
|
|
51
|
+
session.batch do
|
|
52
|
+
session.index posts[1]
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "behaves like two sets of batches, does the inner first, then outer" do
|
|
58
|
+
session.batch { session.index posts[1] }
|
|
59
|
+
session.batch { session.index posts[0] }
|
|
60
|
+
|
|
61
|
+
two_sets_of_batches_adds = connection.adds.dup
|
|
62
|
+
connection.adds.clear
|
|
63
|
+
|
|
64
|
+
a_nested_batch
|
|
65
|
+
nested_batches_adds = connection.adds
|
|
66
|
+
|
|
67
|
+
nested_batches_adds.first.first.field_by_name(:title_ss).value.should eq(
|
|
68
|
+
two_sets_of_batches_adds.first.first.field_by_name(:title_ss).value
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
46
72
|
end
|
|
@@ -54,6 +54,13 @@ shared_examples_for "facetable query" do
|
|
|
54
54
|
end
|
|
55
55
|
connection.should have_last_search_with(:"f.category_ids_im.facet.limit" => 10)
|
|
56
56
|
end
|
|
57
|
+
|
|
58
|
+
it 'sets the facet offset' do
|
|
59
|
+
search do
|
|
60
|
+
facet :category_ids, :offset => 10
|
|
61
|
+
end
|
|
62
|
+
connection.should have_last_search_with(:"f.category_ids_im.facet.offset" => 10)
|
|
63
|
+
end
|
|
57
64
|
|
|
58
65
|
it 'sets the facet minimum count' do
|
|
59
66
|
search do
|
|
@@ -255,6 +262,58 @@ shared_examples_for "facetable query" do
|
|
|
255
262
|
end
|
|
256
263
|
end
|
|
257
264
|
|
|
265
|
+
describe 'on range facets' do
|
|
266
|
+
before :each do
|
|
267
|
+
@range = 2..4
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
it 'does not send range facet parameters if integer range is not specified' do
|
|
271
|
+
search do |query|
|
|
272
|
+
query.facet :average_rating
|
|
273
|
+
end
|
|
274
|
+
connection.should_not have_last_search_with(:"facet.range")
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
it 'sets the facet to a range facet if the range is specified' do
|
|
278
|
+
search do |query|
|
|
279
|
+
query.facet :average_rating, :range => @range
|
|
280
|
+
end
|
|
281
|
+
connection.should have_last_search_with(:"facet.range" => ['average_rating_ft'])
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
it 'sets the facet start and end' do
|
|
285
|
+
search do |query|
|
|
286
|
+
query.facet :average_rating, :range => @range
|
|
287
|
+
end
|
|
288
|
+
connection.should have_last_search_with(
|
|
289
|
+
:"f.average_rating_ft.facet.range.start" => '2.0',
|
|
290
|
+
:"f.average_rating_ft.facet.range.end" => '4.0'
|
|
291
|
+
)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
it 'defaults the range interval to 10' do
|
|
295
|
+
search do |query|
|
|
296
|
+
query.facet :average_rating, :range => @range
|
|
297
|
+
end
|
|
298
|
+
connection.should have_last_search_with(:"f.average_rating_ft.facet.range.gap" => "10")
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
it 'uses custom range interval' do
|
|
302
|
+
search do |query|
|
|
303
|
+
query.facet :average_rating, :range => @range, :range_interval => 1
|
|
304
|
+
end
|
|
305
|
+
connection.should have_last_search_with(:"f.average_rating_ft.facet.range.gap" => "1")
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
it 'does not allow date faceting on a non-continuous field' do
|
|
309
|
+
lambda do
|
|
310
|
+
search do |query|
|
|
311
|
+
query.facet :title, :range => @range
|
|
312
|
+
end
|
|
313
|
+
end.should raise_error(ArgumentError)
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
258
317
|
describe 'using queries' do
|
|
259
318
|
it 'turns faceting on' do
|
|
260
319
|
search do
|
|
@@ -8,4 +8,20 @@ shared_examples_for "spatial query" do
|
|
|
8
8
|
|
|
9
9
|
connection.should have_last_search_including(:fq, "{!geofilt sfield=coordinates_new_ll pt=23,-46 d=100}")
|
|
10
10
|
end
|
|
11
|
+
|
|
12
|
+
it 'filters by radius via bbox (inexact)' do
|
|
13
|
+
search do
|
|
14
|
+
with(:coordinates_new).in_radius(23, -46, 100, :bbox => true)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
connection.should have_last_search_including(:fq, "{!bbox sfield=coordinates_new_ll pt=23,-46 d=100}")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'filters by bounding box' do
|
|
21
|
+
search do
|
|
22
|
+
with(:coordinates_new).in_bounding_box([45, -94], [46, -93])
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
connection.should have_last_search_including(:fq, "coordinates_new_ll:[45,-94 TO 46,-93]")
|
|
26
|
+
end
|
|
11
27
|
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__))
|
|
2
|
+
|
|
3
|
+
describe Sunspot::SessionProxy::Retry5xxSessionProxy do
|
|
4
|
+
|
|
5
|
+
before :each do
|
|
6
|
+
Sunspot::Session.connection_class = Mock::ConnectionFactory.new
|
|
7
|
+
@sunspot_session = Sunspot.session
|
|
8
|
+
@proxy = Sunspot::SessionProxy::Retry5xxSessionProxy.new(@sunspot_session)
|
|
9
|
+
Sunspot.session = @proxy
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class FakeRSolrErrorHttp < RSolr::Error::Http
|
|
13
|
+
def backtrace
|
|
14
|
+
[]
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
let :fake_rsolr_request do
|
|
19
|
+
{:uri => 'http://solr.test/uri'}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def fake_rsolr_response(status)
|
|
23
|
+
{:status => status.to_s}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
let :post do
|
|
27
|
+
Post.new(:title => 'test')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "should behave normally without a stubbed exception" do
|
|
31
|
+
@sunspot_session.should_receive(:index).and_return(mock)
|
|
32
|
+
Sunspot.index(post)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "should be successful with a single exception followed by a sucess" do
|
|
36
|
+
e = FakeRSolrErrorHttp.new(fake_rsolr_request, fake_rsolr_response(503))
|
|
37
|
+
@sunspot_session.should_receive(:index).and_return do
|
|
38
|
+
@sunspot_session.should_receive(:index).and_return(mock)
|
|
39
|
+
raise e
|
|
40
|
+
end
|
|
41
|
+
Sunspot.index(post)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "should return the error response after two exceptions" do
|
|
45
|
+
fake_response = fake_rsolr_response(503)
|
|
46
|
+
e = FakeRSolrErrorHttp.new(fake_rsolr_request, fake_response)
|
|
47
|
+
fake_success = mock('success')
|
|
48
|
+
|
|
49
|
+
@sunspot_session.should_receive(:index).and_return do
|
|
50
|
+
@sunspot_session.should_receive(:index).and_return do
|
|
51
|
+
@sunspot_session.stub!(:index).and_return(fake_success)
|
|
52
|
+
raise e
|
|
53
|
+
end
|
|
54
|
+
raise e
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
response = Sunspot.index(post)
|
|
58
|
+
response.should_not == fake_success
|
|
59
|
+
response.should == fake_response
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "should not retry a 4xx" do
|
|
63
|
+
e = FakeRSolrErrorHttp.new(fake_rsolr_request, fake_rsolr_response(400))
|
|
64
|
+
@sunspot_session.should_receive(:index).and_raise(e)
|
|
65
|
+
lambda { Sunspot.index(post) }.should raise_error
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# TODO: try against more than just Sunspot.index? but that's just testing the
|
|
69
|
+
# invocation of delegate, so probably not important. -nz 11Apr12
|
|
70
|
+
|
|
71
|
+
it_should_behave_like 'session proxy'
|
|
72
|
+
|
|
73
|
+
end
|
data/spec/api/session_spec.rb
CHANGED
|
@@ -85,6 +85,18 @@ describe 'Session' do
|
|
|
85
85
|
Sunspot.commit
|
|
86
86
|
connection.opts[:url].should == 'http://127.0.0.1:8981/solr'
|
|
87
87
|
end
|
|
88
|
+
|
|
89
|
+
it 'should open a connection with custom read timeout' do
|
|
90
|
+
Sunspot.config.solr.read_timeout = 0.5
|
|
91
|
+
Sunspot.commit
|
|
92
|
+
connection.opts[:read_timeout].should == 0.5
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it 'should open a connection with custom open timeout' do
|
|
96
|
+
Sunspot.config.solr.open_timeout = 0.5
|
|
97
|
+
Sunspot.commit
|
|
98
|
+
connection.opts[:open_timeout].should == 0.5
|
|
99
|
+
end
|
|
88
100
|
end
|
|
89
101
|
|
|
90
102
|
context 'custom session' do
|
|
@@ -84,6 +84,13 @@ describe 'search faceting' do
|
|
|
84
84
|
end
|
|
85
85
|
search.facet(:title).rows.map { |row| row.value }.should include('zero')
|
|
86
86
|
end
|
|
87
|
+
|
|
88
|
+
it 'should return facet rows from an offset' do
|
|
89
|
+
search = Sunspot.search(Post) do
|
|
90
|
+
facet :title, :offset => 3
|
|
91
|
+
end
|
|
92
|
+
search.facet(:title).rows.map { |row| row.value }.should == %w(one zero)
|
|
93
|
+
end
|
|
87
94
|
|
|
88
95
|
it 'should return a specified minimum count' do
|
|
89
96
|
search = Sunspot.search(Post) do
|
|
@@ -134,6 +141,19 @@ describe 'search faceting' do
|
|
|
134
141
|
search.facet(:title).rows.first.value.should == :none
|
|
135
142
|
search.facet(:title).rows.first.count.should == 1
|
|
136
143
|
end
|
|
144
|
+
|
|
145
|
+
it 'gives correct facet count when group == true and truncate == true' do
|
|
146
|
+
search = Sunspot.search(Post) do
|
|
147
|
+
group :title do
|
|
148
|
+
truncate
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
facet :title, :extra => :any
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Should be 5 instead of 11
|
|
155
|
+
search.facet(:title).rows.first.count.should == 5
|
|
156
|
+
end
|
|
137
157
|
end
|
|
138
158
|
|
|
139
159
|
context 'multiselect faceting' do
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require File.expand_path("../spec_helper", File.dirname(__FILE__))
|
|
2
|
+
require File.expand_path("../helpers/search_helper", File.dirname(__FILE__))
|
|
2
3
|
|
|
3
4
|
describe "field grouping" do
|
|
4
5
|
before :each do
|
|
@@ -22,6 +23,14 @@ describe "field grouping" do
|
|
|
22
23
|
search.group(:title).groups.should include { |g| g.value == "Title2" }
|
|
23
24
|
end
|
|
24
25
|
|
|
26
|
+
it "returns the number of matches unique groups" do
|
|
27
|
+
search = Sunspot.search(Post) do
|
|
28
|
+
group :title
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
search.group(:title).total.should == 2
|
|
32
|
+
end
|
|
33
|
+
|
|
25
34
|
it "provides access to the number of matches before grouping" do
|
|
26
35
|
search = Sunspot.search(Post) do
|
|
27
36
|
group :title
|
|
@@ -10,7 +10,7 @@ describe "geospatial search" do
|
|
|
10
10
|
Sunspot.index!(@post)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
it "matches posts
|
|
13
|
+
it "matches posts within the radius" do
|
|
14
14
|
results = Sunspot.search(Post) {
|
|
15
15
|
with(:coordinates_new).in_radius(32, -68, 1)
|
|
16
16
|
}.results
|
|
@@ -27,6 +27,32 @@ describe "geospatial search" do
|
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
describe "filtering by bounding box" do
|
|
31
|
+
before :all do
|
|
32
|
+
Sunspot.remove_all
|
|
33
|
+
|
|
34
|
+
@post = Post.new(:title => "Howdy",
|
|
35
|
+
:coordinates => Sunspot::Util::Coordinates.new(32, -68))
|
|
36
|
+
Sunspot.index!(@post)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "matches post within the bounding box" do
|
|
40
|
+
results = Sunspot.search(Post) {
|
|
41
|
+
with(:coordinates_new).in_bounding_box [31, -69], [33, -67]
|
|
42
|
+
}.results
|
|
43
|
+
|
|
44
|
+
results.should include(@post)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "filters out posts not in the bounding box" do
|
|
48
|
+
results = Sunspot.search(Post) {
|
|
49
|
+
with(:coordinates_new).in_bounding_box [20, -70], [21, -69]
|
|
50
|
+
}.results
|
|
51
|
+
|
|
52
|
+
results.should_not include(@post)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
30
56
|
describe "ordering by geodist" do
|
|
31
57
|
before :all do
|
|
32
58
|
Sunspot.remove_all
|
|
@@ -30,4 +30,26 @@ describe 'indexing' do
|
|
|
30
30
|
end
|
|
31
31
|
Sunspot.search(Post).should have(2).results
|
|
32
32
|
end
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
describe "in batches" do
|
|
36
|
+
let(:post_1) { Post.new :title => 'A tittle' }
|
|
37
|
+
let(:post_2) { Post.new :title => 'Another title' }
|
|
38
|
+
|
|
39
|
+
describe "nested" do
|
|
40
|
+
let(:a_nested_batch) do
|
|
41
|
+
Sunspot.batch do
|
|
42
|
+
Sunspot.index post_1
|
|
43
|
+
|
|
44
|
+
Sunspot.batch do
|
|
45
|
+
Sunspot.index post_2
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "does not fail" do
|
|
51
|
+
expect { a_nested_batch }.to_not raise_error
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
33
55
|
end
|
data/sunspot.gemspec
CHANGED
|
@@ -25,8 +25,7 @@ Gem::Specification.new do |s|
|
|
|
25
25
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
26
26
|
s.require_paths = ["lib"]
|
|
27
27
|
|
|
28
|
-
s.add_dependency 'rsolr', '~>1.0.
|
|
29
|
-
s.add_dependency 'escape', '~>0.0.4'
|
|
28
|
+
s.add_dependency 'rsolr', '~>1.0.7'
|
|
30
29
|
s.add_dependency 'pr_geohash', '~>1.0'
|
|
31
30
|
|
|
32
31
|
s.add_development_dependency 'rspec', '~>2.6.0'
|
metadata
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sunspot
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
|
|
4
|
+
hash: -2204637468
|
|
5
|
+
prerelease: 6
|
|
5
6
|
segments:
|
|
6
7
|
- 2
|
|
7
8
|
- 0
|
|
8
9
|
- 0
|
|
9
10
|
- pre
|
|
10
|
-
-
|
|
11
|
-
version: 2.0.0.pre.
|
|
11
|
+
- 120415
|
|
12
|
+
version: 2.0.0.pre.120415
|
|
12
13
|
platform: ruby
|
|
13
14
|
authors:
|
|
14
15
|
- Mat Brown
|
|
@@ -34,76 +35,69 @@ autorequire:
|
|
|
34
35
|
bindir: bin
|
|
35
36
|
cert_chain: []
|
|
36
37
|
|
|
37
|
-
date:
|
|
38
|
-
default_executable:
|
|
38
|
+
date: 2012-04-15 00:00:00 Z
|
|
39
39
|
dependencies:
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: rsolr
|
|
42
42
|
prerelease: false
|
|
43
43
|
requirement: &id001 !ruby/object:Gem::Requirement
|
|
44
|
+
none: false
|
|
44
45
|
requirements:
|
|
45
46
|
- - ~>
|
|
46
47
|
- !ruby/object:Gem::Version
|
|
48
|
+
hash: 25
|
|
47
49
|
segments:
|
|
48
50
|
- 1
|
|
49
51
|
- 0
|
|
50
|
-
-
|
|
51
|
-
version: 1.0.
|
|
52
|
+
- 7
|
|
53
|
+
version: 1.0.7
|
|
52
54
|
type: :runtime
|
|
53
55
|
version_requirements: *id001
|
|
54
|
-
- !ruby/object:Gem::Dependency
|
|
55
|
-
name: escape
|
|
56
|
-
prerelease: false
|
|
57
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - ~>
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
segments:
|
|
62
|
-
- 0
|
|
63
|
-
- 0
|
|
64
|
-
- 4
|
|
65
|
-
version: 0.0.4
|
|
66
|
-
type: :runtime
|
|
67
|
-
version_requirements: *id002
|
|
68
56
|
- !ruby/object:Gem::Dependency
|
|
69
57
|
name: pr_geohash
|
|
70
58
|
prerelease: false
|
|
71
|
-
requirement: &
|
|
59
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
|
60
|
+
none: false
|
|
72
61
|
requirements:
|
|
73
62
|
- - ~>
|
|
74
63
|
- !ruby/object:Gem::Version
|
|
64
|
+
hash: 15
|
|
75
65
|
segments:
|
|
76
66
|
- 1
|
|
77
67
|
- 0
|
|
78
68
|
version: "1.0"
|
|
79
69
|
type: :runtime
|
|
80
|
-
version_requirements: *
|
|
70
|
+
version_requirements: *id002
|
|
81
71
|
- !ruby/object:Gem::Dependency
|
|
82
72
|
name: rspec
|
|
83
73
|
prerelease: false
|
|
84
|
-
requirement: &
|
|
74
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
|
75
|
+
none: false
|
|
85
76
|
requirements:
|
|
86
77
|
- - ~>
|
|
87
78
|
- !ruby/object:Gem::Version
|
|
79
|
+
hash: 23
|
|
88
80
|
segments:
|
|
89
81
|
- 2
|
|
90
82
|
- 6
|
|
91
83
|
- 0
|
|
92
84
|
version: 2.6.0
|
|
93
85
|
type: :development
|
|
94
|
-
version_requirements: *
|
|
86
|
+
version_requirements: *id003
|
|
95
87
|
- !ruby/object:Gem::Dependency
|
|
96
88
|
name: hanna
|
|
97
89
|
prerelease: false
|
|
98
|
-
requirement: &
|
|
90
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
|
91
|
+
none: false
|
|
99
92
|
requirements:
|
|
100
93
|
- - ">="
|
|
101
94
|
- !ruby/object:Gem::Version
|
|
95
|
+
hash: 3
|
|
102
96
|
segments:
|
|
103
97
|
- 0
|
|
104
98
|
version: "0"
|
|
105
99
|
type: :development
|
|
106
|
-
version_requirements: *
|
|
100
|
+
version_requirements: *id004
|
|
107
101
|
description: " Sunspot is a library providing a powerful, all-ruby API for the Solr search engine. Sunspot manages the configuration of persistent\n Ruby classes for search and indexing and exposes Solr's most powerful features through a collection of DSLs. Complex search operations\n can be performed without hand-writing any boolean queries or building Solr parameters by hand.\n"
|
|
108
102
|
email:
|
|
109
103
|
- mat@patch.com
|
|
@@ -123,6 +117,7 @@ files:
|
|
|
123
117
|
- lib/light_config.rb
|
|
124
118
|
- lib/sunspot.rb
|
|
125
119
|
- lib/sunspot/adapters.rb
|
|
120
|
+
- lib/sunspot/batcher.rb
|
|
126
121
|
- lib/sunspot/class_set.rb
|
|
127
122
|
- lib/sunspot/composite_setup.rb
|
|
128
123
|
- lib/sunspot/configuration.rb
|
|
@@ -148,6 +143,7 @@ files:
|
|
|
148
143
|
- lib/sunspot/indexer.rb
|
|
149
144
|
- lib/sunspot/query.rb
|
|
150
145
|
- lib/sunspot/query/abstract_field_facet.rb
|
|
146
|
+
- lib/sunspot/query/bbox.rb
|
|
151
147
|
- lib/sunspot/query/boost_query.rb
|
|
152
148
|
- lib/sunspot/query/common_query.rb
|
|
153
149
|
- lib/sunspot/query/composite_fulltext.rb
|
|
@@ -165,6 +161,7 @@ files:
|
|
|
165
161
|
- lib/sunspot/query/more_like_this_query.rb
|
|
166
162
|
- lib/sunspot/query/pagination.rb
|
|
167
163
|
- lib/sunspot/query/query_facet.rb
|
|
164
|
+
- lib/sunspot/query/range_facet.rb
|
|
168
165
|
- lib/sunspot/query/restriction.rb
|
|
169
166
|
- lib/sunspot/query/scope.rb
|
|
170
167
|
- lib/sunspot/query/sort.rb
|
|
@@ -185,6 +182,7 @@ files:
|
|
|
185
182
|
- lib/sunspot/search/more_like_this_search.rb
|
|
186
183
|
- lib/sunspot/search/paginated_collection.rb
|
|
187
184
|
- lib/sunspot/search/query_facet.rb
|
|
185
|
+
- lib/sunspot/search/range_facet.rb
|
|
188
186
|
- lib/sunspot/search/standard_search.rb
|
|
189
187
|
- lib/sunspot/session.rb
|
|
190
188
|
- lib/sunspot/session_proxy.rb
|
|
@@ -192,6 +190,7 @@ files:
|
|
|
192
190
|
- lib/sunspot/session_proxy/class_sharding_session_proxy.rb
|
|
193
191
|
- lib/sunspot/session_proxy/id_sharding_session_proxy.rb
|
|
194
192
|
- lib/sunspot/session_proxy/master_slave_session_proxy.rb
|
|
193
|
+
- lib/sunspot/session_proxy/retry_5xx_session_proxy.rb
|
|
195
194
|
- lib/sunspot/session_proxy/sharding_session_proxy.rb
|
|
196
195
|
- lib/sunspot/session_proxy/silent_fail_session_proxy.rb
|
|
197
196
|
- lib/sunspot/session_proxy/thread_local_session_proxy.rb
|
|
@@ -204,6 +203,7 @@ files:
|
|
|
204
203
|
- pkg/.gitignore
|
|
205
204
|
- script/console
|
|
206
205
|
- spec/api/adapters_spec.rb
|
|
206
|
+
- spec/api/batcher_spec.rb
|
|
207
207
|
- spec/api/binding_spec.rb
|
|
208
208
|
- spec/api/class_set_spec.rb
|
|
209
209
|
- spec/api/hit_enumerable_spec.rb
|
|
@@ -244,6 +244,7 @@ files:
|
|
|
244
244
|
- spec/api/session_proxy/class_sharding_session_proxy_spec.rb
|
|
245
245
|
- spec/api/session_proxy/id_sharding_session_proxy_spec.rb
|
|
246
246
|
- spec/api/session_proxy/master_slave_session_proxy_spec.rb
|
|
247
|
+
- spec/api/session_proxy/retry_5xx_session_proxy_spec.rb
|
|
247
248
|
- spec/api/session_proxy/sharding_session_proxy_spec.rb
|
|
248
249
|
- spec/api/session_proxy/silent_fail_session_proxy_spec.rb
|
|
249
250
|
- spec/api/session_proxy/spec_helper.rb
|
|
@@ -287,7 +288,6 @@ files:
|
|
|
287
288
|
- tasks/rdoc.rake
|
|
288
289
|
- tasks/schema.rake
|
|
289
290
|
- tasks/todo.rake
|
|
290
|
-
has_rdoc: true
|
|
291
291
|
homepage: http://outoftime.github.com/sunspot
|
|
292
292
|
licenses: []
|
|
293
293
|
|
|
@@ -301,16 +301,20 @@ rdoc_options:
|
|
|
301
301
|
require_paths:
|
|
302
302
|
- lib
|
|
303
303
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
304
|
+
none: false
|
|
304
305
|
requirements:
|
|
305
306
|
- - ">="
|
|
306
307
|
- !ruby/object:Gem::Version
|
|
308
|
+
hash: 3
|
|
307
309
|
segments:
|
|
308
310
|
- 0
|
|
309
311
|
version: "0"
|
|
310
312
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
313
|
+
none: false
|
|
311
314
|
requirements:
|
|
312
315
|
- - ">"
|
|
313
316
|
- !ruby/object:Gem::Version
|
|
317
|
+
hash: 25
|
|
314
318
|
segments:
|
|
315
319
|
- 1
|
|
316
320
|
- 3
|
|
@@ -319,12 +323,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
319
323
|
requirements: []
|
|
320
324
|
|
|
321
325
|
rubyforge_project: sunspot
|
|
322
|
-
rubygems_version: 1.
|
|
326
|
+
rubygems_version: 1.8.15
|
|
323
327
|
signing_key:
|
|
324
328
|
specification_version: 3
|
|
325
329
|
summary: Library for expressive, powerful interaction with the Solr search engine
|
|
326
330
|
test_files:
|
|
327
331
|
- spec/api/adapters_spec.rb
|
|
332
|
+
- spec/api/batcher_spec.rb
|
|
328
333
|
- spec/api/binding_spec.rb
|
|
329
334
|
- spec/api/class_set_spec.rb
|
|
330
335
|
- spec/api/hit_enumerable_spec.rb
|
|
@@ -365,6 +370,7 @@ test_files:
|
|
|
365
370
|
- spec/api/session_proxy/class_sharding_session_proxy_spec.rb
|
|
366
371
|
- spec/api/session_proxy/id_sharding_session_proxy_spec.rb
|
|
367
372
|
- spec/api/session_proxy/master_slave_session_proxy_spec.rb
|
|
373
|
+
- spec/api/session_proxy/retry_5xx_session_proxy_spec.rb
|
|
368
374
|
- spec/api/session_proxy/sharding_session_proxy_spec.rb
|
|
369
375
|
- spec/api/session_proxy/silent_fail_session_proxy_spec.rb
|
|
370
376
|
- spec/api/session_proxy/spec_helper.rb
|