sunspot 2.2.8 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/sunspot/configuration.rb +1 -0
- data/lib/sunspot/dsl/field_query.rb +11 -0
- data/lib/sunspot/dsl/field_stats.rb +7 -0
- data/lib/sunspot/query.rb +3 -3
- data/lib/sunspot/query/abstract_json_field_facet.rb +70 -0
- data/lib/sunspot/query/date_field_json_facet.rb +25 -0
- data/lib/sunspot/query/field_json_facet.rb +19 -0
- data/lib/sunspot/query/field_stats.rb +35 -2
- data/lib/sunspot/query/range_json_facet.rb +28 -0
- data/lib/sunspot/schema.rb +10 -2
- data/lib/sunspot/search.rb +4 -3
- data/lib/sunspot/search/abstract_search.rb +13 -0
- data/lib/sunspot/search/field_json_facet.rb +33 -0
- data/lib/sunspot/search/json_facet_row.rb +40 -0
- data/lib/sunspot/search/json_facet_stats.rb +23 -0
- data/lib/sunspot/search/stats_json_row.rb +82 -0
- data/lib/sunspot/search/stats_row.rb +3 -1
- data/lib/sunspot/session.rb +7 -5
- data/lib/sunspot/util.rb +23 -0
- data/lib/sunspot/version.rb +1 -1
- data/spec/api/query/fulltext_examples.rb +16 -6
- data/spec/helpers/integration_helper.rb +1 -0
- data/spec/integration/faceting_spec.rb +213 -0
- data/spec/integration/scoped_search_spec.rb +1 -1
- data/spec/integration/stats_spec.rb +44 -3
- data/spec/mocks/post.rb +4 -0
- data/spec/spec_helper.rb +2 -6
- data/sunspot.gemspec +1 -1
- metadata +15 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 698b438f344a3e391c87d9f755dc227869fefad88555b261ef4dcd9cc9d9c1d1
|
4
|
+
data.tar.gz: 2ba1b782a43a5eafd6f1bc6397ef221fe94bbbb92f1036505530719a50f07882
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8f89e196fd125f6c0b2bd8eda2aecf7c288860ff14ab128d695f61252344fc07b0011ed8c10d8c5578227eae814df368fecf3332d306ae2a79e9b5da593dfc97
|
7
|
+
data.tar.gz: 780ca66b8d6e569a994670b2e6f990444333dc03f109bd015c7f26924673e801281f611f5d08b14b48afb35b6177099747113e0bbdc10a07aebe4cee5f93c8ea
|
@@ -333,6 +333,17 @@ module Sunspot
|
|
333
333
|
end
|
334
334
|
end
|
335
335
|
|
336
|
+
def json_facet(*field_names)
|
337
|
+
options = Sunspot::Util.extract_options_from(field_names)
|
338
|
+
|
339
|
+
field_names.each do |field_name|
|
340
|
+
field = @setup.field(field_name)
|
341
|
+
facet = Sunspot::Util.parse_json_facet(field_name, options, @setup)
|
342
|
+
@search.add_json_facet(field, options)
|
343
|
+
@query.add_query_facet(facet)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
336
347
|
def stats(*field_names, &block)
|
337
348
|
options = Sunspot::Util.extract_options_from(field_names)
|
338
349
|
|
@@ -13,6 +13,13 @@ module Sunspot
|
|
13
13
|
@search_stats.add_facet(field)
|
14
14
|
end
|
15
15
|
end
|
16
|
+
|
17
|
+
def json_facet(field_name, options = {})
|
18
|
+
field = @setup.field(field_name)
|
19
|
+
facet = Sunspot::Util.parse_json_facet(field_name, options, @setup)
|
20
|
+
@query_stats.add_json_facet(facet)
|
21
|
+
end
|
22
|
+
|
16
23
|
end
|
17
24
|
end
|
18
25
|
end
|
data/lib/sunspot/query.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
%w(filter abstract_field_facet connective boost_query date_field_facet
|
2
|
-
range_facet abstract_fulltext dismax join
|
3
|
-
field_facet highlighting pagination restriction common_query spellcheck
|
1
|
+
%w(filter abstract_field_facet abstract_json_field_facet connective boost_query date_field_facet field_json_facet
|
2
|
+
range_facet range_json_facet date_field_json_facet abstract_fulltext dismax join
|
3
|
+
field_list field_facet highlighting pagination restriction common_query spellcheck
|
4
4
|
standard_query more_like_this more_like_this_query geo geofilt bbox query_facet
|
5
5
|
scope sort sort_composite text_field_boost function_query field_stats
|
6
6
|
composite_fulltext group group_query).each do |file|
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Query
|
3
|
+
class AbstractJsonFieldFacet
|
4
|
+
|
5
|
+
attr_accessor :field
|
6
|
+
|
7
|
+
DISTINCT_STRATEGIES = [:unique, :hll]
|
8
|
+
|
9
|
+
def initialize(field, options, setup)
|
10
|
+
@field, @options, @setup = field, options, setup
|
11
|
+
end
|
12
|
+
|
13
|
+
def init_params
|
14
|
+
params = {}
|
15
|
+
params[:limit] = @options[:limit] unless @options[:limit].nil?
|
16
|
+
params[:mincount] = @options[:minimum_count] unless @options[:minimum_count].nil?
|
17
|
+
params[:sort] = { @options[:sort] => @options[:sort_type]||'desc' } unless @options[:sort].nil?
|
18
|
+
params[:prefix] = @options[:prefix] unless @options[:prefix].nil?
|
19
|
+
params[:offset] = @options[:offset] unless @options[:offset].nil?
|
20
|
+
|
21
|
+
if !@options[:distinct].nil?
|
22
|
+
dist_opts = @options[:distinct]
|
23
|
+
raise Exception.new("Need to specify a strategy") if dist_opts[:strategy].nil?
|
24
|
+
raise Exception.new("The strategy must be one of #{DISTINCT_STRATEGIES}") unless DISTINCT_STRATEGIES.include?(dist_opts[:strategy])
|
25
|
+
@stategy = dist_opts[:strategy]
|
26
|
+
@group_by = dist_opts[:group_by].nil? ? @field : @setup.field(dist_opts[:group_by])
|
27
|
+
params[:field] = @group_by.indexed_name
|
28
|
+
params[:facet] = {}
|
29
|
+
params[:facet][:distinct] = "#{@stategy}(#{@field.indexed_name})"
|
30
|
+
end
|
31
|
+
|
32
|
+
params
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_params
|
36
|
+
query = field_name_with_local_params
|
37
|
+
nested_params = recursive_nested_params(@options)
|
38
|
+
|
39
|
+
if !nested_params.nil?
|
40
|
+
query[@field.name][:facet] ||= {}
|
41
|
+
query[@field.name][:facet].merge!(nested_params)
|
42
|
+
end
|
43
|
+
query
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_params
|
47
|
+
{ 'json.facet' => self.get_params.to_json }
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def recursive_nested_params(options)
|
53
|
+
if !options[:nested].nil? && options[:nested].is_a?(Hash)
|
54
|
+
opts = options[:nested]
|
55
|
+
field_name = opts[:field]
|
56
|
+
|
57
|
+
options = Sunspot::Util.extract_options_from([opts])
|
58
|
+
params = Sunspot::Util.parse_json_facet(field_name, options, @setup).field_name_with_local_params
|
59
|
+
if !opts.nil?
|
60
|
+
nested_params = recursive_nested_params(opts)
|
61
|
+
params[field_name][:facet] = nested_params unless nested_params.nil?
|
62
|
+
end
|
63
|
+
|
64
|
+
params
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Query
|
3
|
+
class DateFieldJsonFacet < AbstractJsonFieldFacet
|
4
|
+
|
5
|
+
def initialize(field, options, setup)
|
6
|
+
raise Exception.new('Need to specify a time_range') if options[:time_range].nil?
|
7
|
+
@start = options[:time_range].first
|
8
|
+
@end = options[:time_range].last
|
9
|
+
@gap = "+#{options[:gap] || 86400}SECONDS"
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def field_name_with_local_params
|
14
|
+
params = {}
|
15
|
+
params[:type] = 'range'
|
16
|
+
params[:field] = @field.indexed_name
|
17
|
+
params[:start] = @field.to_indexed(@start)
|
18
|
+
params[:end] = @field.to_indexed(@end)
|
19
|
+
params[:gap] = @gap
|
20
|
+
params.merge!(init_params)
|
21
|
+
{ @field.name => params }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Query
|
3
|
+
class FieldJsonFacet < AbstractJsonFieldFacet
|
4
|
+
|
5
|
+
def initialize(field, options, setup)
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def field_name_with_local_params
|
10
|
+
{
|
11
|
+
@field.name => {
|
12
|
+
type: 'terms',
|
13
|
+
field: @field.indexed_name,
|
14
|
+
}.merge!(init_params)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -10,9 +10,42 @@ module Sunspot
|
|
10
10
|
@facets << field
|
11
11
|
end
|
12
12
|
|
13
|
+
def add_json_facet(json_facet)
|
14
|
+
@json_facet = json_facet
|
15
|
+
end
|
16
|
+
|
13
17
|
def to_params
|
14
|
-
params = {
|
15
|
-
|
18
|
+
params = {}
|
19
|
+
if !@json_facet.nil?
|
20
|
+
params['json.facet'] = recursive_add_stats(@json_facet.get_params).to_json
|
21
|
+
else
|
22
|
+
params.merge!(:stats => true, :"stats.field" => [@field.indexed_name])
|
23
|
+
params[facet_key] = @facets.map(&:indexed_name) unless @facets.empty?
|
24
|
+
end
|
25
|
+
params
|
26
|
+
end
|
27
|
+
|
28
|
+
STATS_FUNCTIONS = [:min, :max, :sum, :avg, :sumsq]
|
29
|
+
|
30
|
+
def recursive_add_stats(query)
|
31
|
+
query.keys.each do |k|
|
32
|
+
if !query[k][:facet].nil?
|
33
|
+
query[k][:facet] = recursive_add_stats(query[k][:facet])
|
34
|
+
end
|
35
|
+
query[k][:facet] ||= {}
|
36
|
+
query[k][:sort] = { @options[:sort] => @options[:sort_type]||'desc' } unless @options[:sort].nil?
|
37
|
+
query[k][:facet].merge!(json_stats_params)
|
38
|
+
end
|
39
|
+
query
|
40
|
+
end
|
41
|
+
|
42
|
+
def json_stats_params
|
43
|
+
params = {}
|
44
|
+
STATS_FUNCTIONS.each { |s| params[s] = "#{s.to_s}(#{@field.indexed_name})" }
|
45
|
+
unless @options[:stats].nil?
|
46
|
+
to_remove = STATS_FUNCTIONS - @options[:stats]
|
47
|
+
to_remove.map { |s| params.delete(s)}
|
48
|
+
end
|
16
49
|
params
|
17
50
|
end
|
18
51
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Query
|
3
|
+
class RangeJsonFacet < AbstractJsonFieldFacet
|
4
|
+
|
5
|
+
SECONDS_IN_DAY = 86400
|
6
|
+
|
7
|
+
def initialize(field, options, setup)
|
8
|
+
raise Exception.new("Need to specify a range") if options[:range].nil?
|
9
|
+
@start = options[:range].first
|
10
|
+
@end = options[:range].last
|
11
|
+
@gap = options[:gap] || SECONDS_IN_DAY
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def field_name_with_local_params
|
16
|
+
{
|
17
|
+
@field.name => {
|
18
|
+
type: 'range',
|
19
|
+
field: @field.indexed_name,
|
20
|
+
start: @field.to_indexed(@start),
|
21
|
+
end: @field.to_indexed(@end),
|
22
|
+
gap: @gap
|
23
|
+
}.merge!(init_params)
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/sunspot/schema.rb
CHANGED
@@ -88,8 +88,16 @@ module Sunspot
|
|
88
88
|
# Return an XML representation of this schema using the ERB template
|
89
89
|
#
|
90
90
|
def to_xml
|
91
|
-
|
92
|
-
|
91
|
+
template_path = File.join(File.dirname(__FILE__), '..', '..', 'templates', 'schema.xml.erb')
|
92
|
+
template_text = File.read(template_path)
|
93
|
+
|
94
|
+
erb = if RUBY_VERSION >= '2.6'
|
95
|
+
ERB.new(template_text, trim_mode: '-')
|
96
|
+
else
|
97
|
+
ERB.new(template_text, nil, '-')
|
98
|
+
end
|
99
|
+
|
100
|
+
erb.result(binding)
|
93
101
|
end
|
94
102
|
|
95
103
|
private
|
data/lib/sunspot/search.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
%w(abstract_search standard_search more_like_this_search query_facet
|
2
|
-
date_facet range_facet
|
3
|
-
|
1
|
+
%w(abstract_search standard_search more_like_this_search query_facet
|
2
|
+
field_facet field_json_facet date_facet range_facet json_facet_stats
|
3
|
+
facet_row json_facet_row hit highlight field_group group hit_enumerable
|
4
|
+
stats_row stats_json_row field_stats stats_facet query_group).each do |file|
|
4
5
|
require File.join(File.dirname(__FILE__), 'search', file)
|
5
6
|
end
|
6
7
|
|
@@ -182,6 +182,10 @@ module Sunspot
|
|
182
182
|
end
|
183
183
|
end
|
184
184
|
|
185
|
+
def json_facet_stats(name, options = {})
|
186
|
+
JsonFacetStats.new(name, self, options)
|
187
|
+
end
|
188
|
+
|
185
189
|
#
|
186
190
|
# Deprecated in favor of optional second argument to #facet
|
187
191
|
#
|
@@ -193,6 +197,10 @@ module Sunspot
|
|
193
197
|
@solr_result['facet_counts']
|
194
198
|
end
|
195
199
|
|
200
|
+
def json_facet_response #:nodoc:
|
201
|
+
@solr_result['facets']
|
202
|
+
end
|
203
|
+
|
196
204
|
def stats_response #:nodoc:
|
197
205
|
@solr_result['stats']['stats_fields']
|
198
206
|
end
|
@@ -255,6 +263,11 @@ module Sunspot
|
|
255
263
|
add_stats(field.name, FieldStats.new(field, self))
|
256
264
|
end
|
257
265
|
|
266
|
+
def add_json_facet(field, options = {})
|
267
|
+
name = (options[:name] || field.name)
|
268
|
+
add_facet(name, FieldJsonFacet.new(field, self, options))
|
269
|
+
end
|
270
|
+
|
258
271
|
def highlights_for(doc) #:nodoc:
|
259
272
|
if @solr_result['highlighting']
|
260
273
|
@solr_result['highlighting'][doc['id']]
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Search
|
3
|
+
class FieldJsonFacet
|
4
|
+
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def initialize(field, search, options)
|
8
|
+
@name, @search, @options = name, search, options
|
9
|
+
@field = field
|
10
|
+
end
|
11
|
+
|
12
|
+
def rows
|
13
|
+
@rows ||=
|
14
|
+
begin
|
15
|
+
json_facet_response = @search.json_facet_response[@field.name.to_s]
|
16
|
+
data = json_facet_response.nil? ? [] : json_facet_response['buckets']
|
17
|
+
rows = []
|
18
|
+
data.each do |d|
|
19
|
+
rows << JsonFacetRow.new(d, self)
|
20
|
+
end
|
21
|
+
|
22
|
+
if @options[:sort] == :count
|
23
|
+
rows.sort! { |lrow, rrow| rrow.count <=> lrow.count }
|
24
|
+
else
|
25
|
+
rows.sort! { |lrow, rrow| lrow.value <=> rrow.value }
|
26
|
+
end
|
27
|
+
rows
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Search
|
3
|
+
class JsonFacetRow
|
4
|
+
attr_reader :value, :count, :nested
|
5
|
+
attr_writer :instance #:nodoc:
|
6
|
+
|
7
|
+
def initialize(data, facet) #:nodoc:
|
8
|
+
@value = data['val']
|
9
|
+
@count = data['distinct'] || data['count']
|
10
|
+
@facet = facet
|
11
|
+
@nested_key = data.keys.select { |k| data[k].is_a?(Hash) }.first
|
12
|
+
@nested = recursive_nested_initialization(data) unless @nested_key.nil?
|
13
|
+
end
|
14
|
+
|
15
|
+
#
|
16
|
+
# Return the instance referenced by this facet row. Only valid for field
|
17
|
+
# facets whose fields are defined with the :references key.
|
18
|
+
#
|
19
|
+
def instance
|
20
|
+
if !defined?(@instance)
|
21
|
+
@facet.populate_instances
|
22
|
+
end
|
23
|
+
@instance
|
24
|
+
end
|
25
|
+
|
26
|
+
def inspect
|
27
|
+
"<Sunspot::Search::FacetRow:#{value.inspect} (#{count}) #{nested.nil? ? '' : " nested_count=#{nested.size}"}>"
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def recursive_nested_initialization(data)
|
33
|
+
data[@nested_key]['buckets'].map do |d|
|
34
|
+
JsonFacetRow.new(d, @facet)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Search
|
3
|
+
class JsonFacetStats
|
4
|
+
def initialize(field, search, options)
|
5
|
+
@field, @search, @options = field, search, options
|
6
|
+
end
|
7
|
+
|
8
|
+
def rows
|
9
|
+
@rows ||=
|
10
|
+
begin
|
11
|
+
json_facet_response = @search.json_facet_response[@field.to_s]
|
12
|
+
data = json_facet_response.nil? ? [] : json_facet_response['buckets']
|
13
|
+
rows = []
|
14
|
+
data.each do |d|
|
15
|
+
rows << StatsJsonRow.new(d, nil, d['val'])
|
16
|
+
end
|
17
|
+
rows
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Search
|
3
|
+
class StatsJsonRow
|
4
|
+
attr_reader :data, :value, :nested
|
5
|
+
attr_writer :instance #:nodoc:
|
6
|
+
|
7
|
+
def initialize(data, facet = nil, value = nil) #:nodoc:
|
8
|
+
@data, @facet, @value = data, facet, value
|
9
|
+
@facet_fields = []
|
10
|
+
@nested_key = data.keys.select { |k| data[k].is_a?(Hash) }.first
|
11
|
+
@nested = recursive_nested_initialization(data) unless @nested_key.nil?
|
12
|
+
end
|
13
|
+
|
14
|
+
def min
|
15
|
+
data['min']
|
16
|
+
end
|
17
|
+
|
18
|
+
def max
|
19
|
+
data['max']
|
20
|
+
end
|
21
|
+
|
22
|
+
def count
|
23
|
+
data['count']
|
24
|
+
end
|
25
|
+
|
26
|
+
def sum
|
27
|
+
data['sum']
|
28
|
+
end
|
29
|
+
|
30
|
+
def missing
|
31
|
+
data['missing']
|
32
|
+
end
|
33
|
+
|
34
|
+
def sum_of_squares
|
35
|
+
data['sumsq']
|
36
|
+
end
|
37
|
+
alias :sumsq :sum_of_squares
|
38
|
+
|
39
|
+
def mean
|
40
|
+
data['avg']
|
41
|
+
end
|
42
|
+
alias :avg :mean
|
43
|
+
|
44
|
+
def standard_deviation
|
45
|
+
data['stddev']
|
46
|
+
end
|
47
|
+
|
48
|
+
def facet name
|
49
|
+
facets.find { |facet| facet.field.name == name.to_sym }
|
50
|
+
end
|
51
|
+
|
52
|
+
def facets
|
53
|
+
@facets ||= @facet_fields.map do |field|
|
54
|
+
StatsFacet.new(field, data['facets'][field.indexed_name])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def instance
|
59
|
+
if !defined?(@instance)
|
60
|
+
@facet.populate_instances
|
61
|
+
end
|
62
|
+
@instance
|
63
|
+
end
|
64
|
+
|
65
|
+
def inspect
|
66
|
+
"<Sunspot::Search::StatsJsonRow:#{value.inspect} min=#{min} max=#{max}"\
|
67
|
+
" count=#{count} sum=#{sum} missing=#{missing} sum_of_squares=#{sum_of_squares}"\
|
68
|
+
" mean=#{mean} standard_deviation=#{standard_deviation}"\
|
69
|
+
" #{nested.nil? ? '' : "nested_count=#{nested.size}"}>"
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def recursive_nested_initialization(data)
|
75
|
+
data[@nested_key]['buckets'].map do |d|
|
76
|
+
StatsJsonRow.new(d, @facet, d['val'])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -59,7 +59,9 @@ module Sunspot
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def inspect
|
62
|
-
"<Sunspot::Search::StatsRow:#{value.inspect} min=#{min} max=#{max}
|
62
|
+
"<Sunspot::Search::StatsRow:#{value.inspect} min=#{min} max=#{max}"\
|
63
|
+
" count=#{self.count} sum=#{sum} missing=#{missing} sum_of_squares=#{sum_of_squares}"\
|
64
|
+
" mean=#{mean} standard_deviation=#{standard_deviation}>"
|
63
65
|
end
|
64
66
|
end
|
65
67
|
end
|
data/lib/sunspot/session.rb
CHANGED
@@ -254,11 +254,13 @@ module Sunspot
|
|
254
254
|
# RSolr::Connection::Base:: The connection for this session
|
255
255
|
#
|
256
256
|
def connection
|
257
|
-
@connection ||=
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
257
|
+
@connection ||= self.class.connection_class.connect(
|
258
|
+
url: config.solr.url,
|
259
|
+
read_timeout: config.solr.read_timeout,
|
260
|
+
open_timeout: config.solr.open_timeout,
|
261
|
+
proxy: config.solr.proxy,
|
262
|
+
update_format: config.solr.update_format || :xml
|
263
|
+
)
|
262
264
|
end
|
263
265
|
|
264
266
|
def indexer
|
data/lib/sunspot/util.rb
CHANGED
@@ -188,6 +188,29 @@ module Sunspot
|
|
188
188
|
RSolr.solr_escape(value).gsub(/([\s\.])/, '\\\\\1')
|
189
189
|
end
|
190
190
|
|
191
|
+
def parse_json_facet(field_name, options, setup)
|
192
|
+
field = setup.field(field_name)
|
193
|
+
if options[:time_range]
|
194
|
+
unless field.type.is_a?(Sunspot::Type::TimeType)
|
195
|
+
raise(
|
196
|
+
ArgumentError,
|
197
|
+
':time_range can only be specified for Date or Time fields'
|
198
|
+
)
|
199
|
+
end
|
200
|
+
Sunspot::Query::DateFieldJsonFacet.new(field, options, setup)
|
201
|
+
elsif options[:range]
|
202
|
+
unless [Sunspot::Type::TimeType, Sunspot::Type::FloatType, Sunspot::Type::IntegerType ].find{|type| field.type.is_a?(type)}
|
203
|
+
raise(
|
204
|
+
ArgumentError,
|
205
|
+
':range can only be specified for date or numeric fields'
|
206
|
+
)
|
207
|
+
end
|
208
|
+
Sunspot::Query::RangeJsonFacet.new(field, options, setup)
|
209
|
+
else
|
210
|
+
Sunspot::Query::FieldJsonFacet.new(field, options, setup)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
191
214
|
private
|
192
215
|
|
193
216
|
#
|
data/lib/sunspot/version.rb
CHANGED
@@ -66,7 +66,9 @@ shared_examples_for 'fulltext query' do
|
|
66
66
|
end
|
67
67
|
|
68
68
|
it 'puts default dismax parameters in subquery' do
|
69
|
-
expect(subqueries(:q).last[:qf].split(' ').sort).to
|
69
|
+
expect(subqueries(:q).last[:qf].split(' ').sort).to(
|
70
|
+
eq(%w(backwards_title_text body_textsv tags_textv text_array_text title_text))
|
71
|
+
)
|
70
72
|
end
|
71
73
|
|
72
74
|
it 'puts field list in main query' do
|
@@ -78,14 +80,18 @@ shared_examples_for 'fulltext query' do
|
|
78
80
|
search = search do
|
79
81
|
keywords 'keyword search'
|
80
82
|
end
|
81
|
-
expect(connection.searches.last[:qf].split(' ').sort).to
|
83
|
+
expect(connection.searches.last[:qf].split(' ').sort).to(
|
84
|
+
eq(%w(backwards_title_text body_textsv tags_textv text_array_text title_text))
|
85
|
+
)
|
82
86
|
end
|
83
87
|
|
84
88
|
it 'searches both stored and unstored text fields' do
|
85
89
|
search Post, Namespaced::Comment do
|
86
90
|
keywords 'keyword search'
|
87
91
|
end
|
88
|
-
expect(connection.searches.last[:qf].split(' ').sort).to
|
92
|
+
expect(connection.searches.last[:qf].split(' ').sort).to(
|
93
|
+
eq(%w(author_name_text backwards_title_text body_text body_textsv tags_textv text_array_text title_text))
|
94
|
+
)
|
89
95
|
end
|
90
96
|
|
91
97
|
it 'searches only specified text fields when specified' do
|
@@ -101,7 +107,7 @@ shared_examples_for 'fulltext query' do
|
|
101
107
|
exclude_fields :backwards_title, :body_mlt
|
102
108
|
end
|
103
109
|
end
|
104
|
-
expect(connection.searches.last[:qf].split(' ').sort).to eq(%w(body_textsv tags_textv title_text))
|
110
|
+
expect(connection.searches.last[:qf].split(' ').sort).to eq(%w(body_textsv tags_textv text_array_text title_text))
|
105
111
|
end
|
106
112
|
|
107
113
|
it 'assigns boost to fields when specified' do
|
@@ -173,7 +179,9 @@ shared_examples_for 'fulltext query' do
|
|
173
179
|
boost_fields :title => 1.5
|
174
180
|
end
|
175
181
|
end
|
176
|
-
expect(connection.searches.last[:qf].split(' ').sort).to
|
182
|
+
expect(connection.searches.last[:qf].split(' ').sort).to(
|
183
|
+
eq(%w(backwards_title_text body_textsv tags_textv text_array_text title_text^1.5))
|
184
|
+
)
|
177
185
|
end
|
178
186
|
|
179
187
|
it 'ignores boost fields that do not apply' do
|
@@ -182,7 +190,9 @@ shared_examples_for 'fulltext query' do
|
|
182
190
|
boost_fields :bogus => 1.2, :title => 1.5
|
183
191
|
end
|
184
192
|
end
|
185
|
-
expect(connection.searches.last[:qf].split(' ').sort).to
|
193
|
+
expect(connection.searches.last[:qf].split(' ').sort).to(
|
194
|
+
eq(%w(backwards_title_text body_textsv tags_textv text_array_text title_text^1.5))
|
195
|
+
)
|
186
196
|
end
|
187
197
|
|
188
198
|
it 'sets default boost with default fields' do
|
@@ -2,6 +2,7 @@ module IntegrationHelper
|
|
2
2
|
def self.included(base)
|
3
3
|
base.before(:all) do
|
4
4
|
Sunspot.config.solr.url = ENV['SOLR_URL'] || 'http://localhost:8983/solr/default'
|
5
|
+
Sunspot.config.solr.update_format = ENV['UPDATE_FORMAT'].to_sym if ENV['UPDATE_FORMAT']
|
5
6
|
Sunspot.reset!(true)
|
6
7
|
end
|
7
8
|
end
|
@@ -156,6 +156,136 @@ describe 'search faceting' do
|
|
156
156
|
end
|
157
157
|
end
|
158
158
|
|
159
|
+
context 'json facet options' do
|
160
|
+
before :all do
|
161
|
+
Sunspot.remove_all
|
162
|
+
facet_values = %w(zero one two three four)
|
163
|
+
facet_values.each_with_index do |value, i|
|
164
|
+
i.times { Sunspot.index(Post.new(:title => value, :blog_id => 1)) }
|
165
|
+
end
|
166
|
+
Sunspot.index(Post.new(:blog_id => 1))
|
167
|
+
Sunspot.index(Post.new(:title => 'zero', :blog_id => 2))
|
168
|
+
Sunspot.commit
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'should return indexed elements' do
|
172
|
+
search = Sunspot.search(Post) do
|
173
|
+
json_facet(:title)
|
174
|
+
end
|
175
|
+
expect(search.facet(:title).rows.size).to eq(5)
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'should limit the number of facet rows' do
|
179
|
+
search = Sunspot.search(Post) do
|
180
|
+
json_facet :title, :limit => 3
|
181
|
+
end
|
182
|
+
expect(search.facet(:title).rows.size).to eq(3)
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'should not return zeros by default' do
|
186
|
+
search = Sunspot.search(Post) do
|
187
|
+
with :blog_id, 1
|
188
|
+
json_facet :title
|
189
|
+
end
|
190
|
+
expect(search.facet(:title).rows.map { |row| row.value }).not_to include('zero')
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'should return a specified minimum count' do
|
194
|
+
search = Sunspot.search(Post) do
|
195
|
+
with :blog_id, 1
|
196
|
+
json_facet :title, :minimum_count => 2
|
197
|
+
end
|
198
|
+
expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(four three two))
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'should order facets lexically' do
|
202
|
+
search = Sunspot.search(Post) do
|
203
|
+
with :blog_id, 1
|
204
|
+
json_facet :title, :sort => :index
|
205
|
+
end
|
206
|
+
expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(four one three two))
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'should order facets by count' do
|
210
|
+
search = Sunspot.search(Post) do
|
211
|
+
with :blog_id, 1
|
212
|
+
json_facet :title, :sort => :count
|
213
|
+
end
|
214
|
+
expect(search.facet(:title).rows.map { |row| row.value }).to eq(%w(four three two one))
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'should limit facet values by prefix' do
|
218
|
+
search = Sunspot.search(Post) do
|
219
|
+
with :blog_id, 1
|
220
|
+
json_facet :title, :prefix => 't'
|
221
|
+
end
|
222
|
+
expect(search.facet(:title).rows.map { |row| row.value }.sort).to eq(%w(three two))
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
226
|
+
|
227
|
+
context 'nested json facet' do
|
228
|
+
before :all do
|
229
|
+
Sunspot.remove_all
|
230
|
+
facet_values = %w(zero one two three four)
|
231
|
+
nested_facet_values = %w(alfa bravo charlie delta)
|
232
|
+
|
233
|
+
facet_values.each do |value|
|
234
|
+
nested_facet_values.each do |v2|
|
235
|
+
Sunspot.index(Post.new(:title => value, :author_name => v2, :blog_id => 1))
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
0.upto(9) { |i| Sunspot.index(Post.new(:title => 'zero', :author_name => "another#{i}", :blog_id => 1)) }
|
240
|
+
|
241
|
+
Sunspot.commit
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'should get nested' do
|
245
|
+
search = Sunspot.search(Post) do
|
246
|
+
json_facet(:title, nested: { field: :author_name } )
|
247
|
+
end
|
248
|
+
expect(search.facet(:title).rows.first.nested.size).to eq(4)
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'without limit take the first 10' do
|
252
|
+
search = Sunspot.search(Post) do
|
253
|
+
json_facet(:title, nested: { field: :author_name } )
|
254
|
+
end
|
255
|
+
expect(search.facet(:title).rows.last.nested.size).to eq(10)
|
256
|
+
end
|
257
|
+
|
258
|
+
it 'without limit' do
|
259
|
+
search = Sunspot.search(Post) do
|
260
|
+
json_facet(:title, nested: { field: :author_name, limit: -1 } )
|
261
|
+
end
|
262
|
+
expect(search.facet(:title).rows.last.nested.size).to eq(14)
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'works with distinct' do
|
266
|
+
search = Sunspot.search(Post) do
|
267
|
+
json_facet(:title, nested: { field: :author_name, distinct: { strategy: :unique } } )
|
268
|
+
end
|
269
|
+
expect(search.facet(:title).rows.first.nested.map(&:count).uniq.size).to eq(1)
|
270
|
+
end
|
271
|
+
|
272
|
+
it 'should limit the nested facet' do
|
273
|
+
search = Sunspot.search(Post) do
|
274
|
+
json_facet(:title, nested: { field: :author_name, limit: 2 } )
|
275
|
+
end
|
276
|
+
expect(search.facet(:title).rows.first.nested.size).to eq(2)
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'should work nested of nested' do
|
280
|
+
search = Sunspot.search(Post) do
|
281
|
+
json_facet(:title, nested: { field: :author_name, nested: { field: :title } } )
|
282
|
+
end
|
283
|
+
expect(search.facet(:title).rows.first.nested.first.nested.size).to eq(1)
|
284
|
+
expect(search.facet(:title).rows.first.nested.first.nested.first.nested).to eq(nil)
|
285
|
+
end
|
286
|
+
|
287
|
+
end
|
288
|
+
|
159
289
|
context 'prefix escaping' do
|
160
290
|
before do
|
161
291
|
Sunspot.remove_all
|
@@ -259,6 +389,57 @@ describe 'search faceting' do
|
|
259
389
|
end
|
260
390
|
end
|
261
391
|
|
392
|
+
context 'distinct field facets' do
|
393
|
+
before :all do
|
394
|
+
Sunspot.remove_all
|
395
|
+
|
396
|
+
Sunspot.index!(
|
397
|
+
(0..5).map { |i| Post.new(:blog_id => i, :title => 'title') }
|
398
|
+
)
|
399
|
+
|
400
|
+
0.upto(3) { |i| Sunspot.index(Post.new(:blog_id => i, :title => 'title')) }
|
401
|
+
|
402
|
+
Sunspot.index!(Post.new(:blog_id => 4, :title => 'other title'))
|
403
|
+
Sunspot.index!(Post.new(:blog_id => 5, :title => 'other title'))
|
404
|
+
|
405
|
+
Sunspot.index!(Post.new(:blog_id => 40, :title => 'title'))
|
406
|
+
Sunspot.index!(Post.new(:blog_id => 40, :title => 'title'))
|
407
|
+
|
408
|
+
Sunspot.index!(Post.new(:blog_id => 40, :title => 'other title'))
|
409
|
+
Sunspot.index!(Post.new(:blog_id => 40, :title => 'other title'))
|
410
|
+
end
|
411
|
+
|
412
|
+
it 'should return unique indexed elements for a field' do
|
413
|
+
search = Sunspot.search(Post) do
|
414
|
+
json_facet(:blog_id, distinct: { strategy: :unique })
|
415
|
+
end
|
416
|
+
|
417
|
+
expect(search.facet(:blog_id).rows.size).to eq(7)
|
418
|
+
expect(search.facet(:blog_id).rows.map(&:count).uniq.size).to eq(1)
|
419
|
+
end
|
420
|
+
|
421
|
+
it 'should return unique indexed elements for a field and facet on a field' do
|
422
|
+
search = Sunspot.search(Post) do
|
423
|
+
json_facet(:blog_id, distinct: { group_by: :title, strategy: :unique })
|
424
|
+
end
|
425
|
+
|
426
|
+
expect(search.facet(:blog_id).rows.size).to eq(2)
|
427
|
+
expect(search.facet(:blog_id).rows[0].count).to eq(3)
|
428
|
+
expect(search.facet(:blog_id).rows[1].count).to eq(7)
|
429
|
+
end
|
430
|
+
|
431
|
+
it 'should return unique indexed elements for a field and facet on a field with hll' do
|
432
|
+
search = Sunspot.search(Post) do
|
433
|
+
json_facet(:blog_id, distinct: { group_by: :title, strategy: :hll })
|
434
|
+
end
|
435
|
+
|
436
|
+
expect(search.facet(:blog_id).rows.size).to eq(2)
|
437
|
+
expect(search.facet(:blog_id).rows[0].count).to eq(3)
|
438
|
+
expect(search.facet(:blog_id).rows[1].count).to eq(7)
|
439
|
+
end
|
440
|
+
|
441
|
+
end
|
442
|
+
|
262
443
|
context 'date facets' do
|
263
444
|
before :all do
|
264
445
|
Sunspot.remove_all
|
@@ -278,6 +459,38 @@ describe 'search faceting' do
|
|
278
459
|
expect(search.facet(:published_at).rows.last.value).to eq((time + 60*60*24)..(time + 60*60*24*2))
|
279
460
|
expect(search.facet(:published_at).rows.last.count).to eq(1)
|
280
461
|
end
|
462
|
+
|
463
|
+
it 'json facet should return time ranges' do
|
464
|
+
days_diff = 15
|
465
|
+
time_from = Time.utc(2009, 7, 8)
|
466
|
+
time_to = Time.utc(2009, 7, 8 + days_diff)
|
467
|
+
search = Sunspot.search(Post) do
|
468
|
+
json_facet(
|
469
|
+
:published_at,
|
470
|
+
:time_range => time_from..time_to
|
471
|
+
)
|
472
|
+
end
|
473
|
+
|
474
|
+
expect(search.facet(:published_at).rows.size).to eq(days_diff)
|
475
|
+
expect(search.facet(:published_at).rows[0].count).to eq(2)
|
476
|
+
expect(search.facet(:published_at).rows[1].count).to eq(1)
|
477
|
+
end
|
478
|
+
|
479
|
+
it 'json facet should return time ranges with custom gap' do
|
480
|
+
days_diff = 10
|
481
|
+
time_from = Time.utc(2009, 7, 8)
|
482
|
+
time_to = Time.utc(2009, 7, 8 + days_diff)
|
483
|
+
search = Sunspot.search(Post) do
|
484
|
+
json_facet(
|
485
|
+
:published_at,
|
486
|
+
:time_range => time_from..time_to,
|
487
|
+
gap: 60*60*24*2
|
488
|
+
)
|
489
|
+
end
|
490
|
+
expect(search.facet(:published_at).rows.size).to eq(days_diff / 2)
|
491
|
+
expect(search.facet(:published_at).rows[0].count).to eq(3)
|
492
|
+
end
|
493
|
+
|
281
494
|
end
|
282
495
|
|
283
496
|
context 'class facets' do
|
@@ -332,7 +332,7 @@ describe 'scoped_search' do
|
|
332
332
|
expect(Sunspot.search(Post) do
|
333
333
|
without(:blog_id, [])
|
334
334
|
end.results).to eq(posts)
|
335
|
-
end
|
335
|
+
end
|
336
336
|
|
337
337
|
it 'should return results, ignoring any restriction in a conjunction that has been passed an empty array' do
|
338
338
|
posts = (1..3).map { |i| Post.new(:blog_id => i)}
|
@@ -3,9 +3,9 @@ require File.expand_path('../spec_helper', File.dirname(__FILE__))
|
|
3
3
|
describe 'search stats' do
|
4
4
|
before :each do
|
5
5
|
Sunspot.remove_all
|
6
|
-
@posts = Post.new(:ratings_average => 4.0, :blog_id => 2),
|
7
|
-
Post.new(:ratings_average => 4.0, :blog_id => 1),
|
8
|
-
Post.new(:ratings_average => 3.0, :blog_id => 2)
|
6
|
+
@posts = Post.new(:ratings_average => 4.0, :author_name => 'plinio', :blog_id => 2),
|
7
|
+
Post.new(:ratings_average => 4.0, :author_name => 'caio', :blog_id => 1),
|
8
|
+
Post.new(:ratings_average => 3.0, :author_name => 'sempronio', :blog_id => 2)
|
9
9
|
Sunspot.index!(@posts)
|
10
10
|
end
|
11
11
|
|
@@ -44,4 +44,45 @@ describe 'search stats' do
|
|
44
44
|
end.stats(:average_rating).facet(:blog_id).rows[1].max).to eq(4.0)
|
45
45
|
end
|
46
46
|
end
|
47
|
+
|
48
|
+
describe 'json facets' do
|
49
|
+
it 'returns minimum on facet row with two blog ids' do
|
50
|
+
expect(Sunspot.search(Post) do
|
51
|
+
stats :average_rating, sort: :min do
|
52
|
+
json_facet :blog_id
|
53
|
+
end
|
54
|
+
end.json_facet_stats(:blog_id).rows[1].min).to eq(3.0)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'returns maximum on facet row with two blog ids' do
|
58
|
+
expect(Sunspot.search(Post) do
|
59
|
+
stats :average_rating, sort: :max do
|
60
|
+
json_facet :blog_id
|
61
|
+
end
|
62
|
+
end.json_facet_stats(:blog_id).rows[1].max).to eq(4.0)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'returns only sum' do
|
66
|
+
search = Sunspot.search(Post) do
|
67
|
+
stats :average_rating, stats: [:sum] do
|
68
|
+
json_facet :blog_id
|
69
|
+
end
|
70
|
+
end
|
71
|
+
expect(search.json_facet_stats(:blog_id).rows[1].max).to eq(nil)
|
72
|
+
expect(search.json_facet_stats(:blog_id).rows[1].min).to eq(nil)
|
73
|
+
expect(search.json_facet_stats(:blog_id).rows[1].avg).to eq(nil)
|
74
|
+
expect(search.json_facet_stats(:blog_id).rows[1].sumsq).to eq(nil)
|
75
|
+
expect(search.json_facet_stats(:blog_id).rows[1].sum).to eq(4.0)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'works with nested facets' do
|
79
|
+
search = Sunspot.search(Post) do
|
80
|
+
stats :average_rating, sort: :min do
|
81
|
+
json_facet(:blog_id, nested: { field: :author_name, limit: 3, nested: { field: :average_rating } } )
|
82
|
+
end
|
83
|
+
end
|
84
|
+
expect(search.json_facet_stats(:blog_id).rows[1].nested.first.nested.first.min).to eq(4.0)
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
47
88
|
end
|
data/spec/mocks/post.rb
CHANGED
@@ -37,12 +37,16 @@ end
|
|
37
37
|
|
38
38
|
Sunspot.setup(Post) do
|
39
39
|
text :title, :boost => 2
|
40
|
+
text :text_array, :boost => 3 do
|
41
|
+
[title, title]
|
42
|
+
end
|
40
43
|
text :body, :stored => true, :more_like_this => true
|
41
44
|
text :backwards_title do
|
42
45
|
title.reverse if title
|
43
46
|
end
|
44
47
|
text :tags, :more_like_this => true
|
45
48
|
string :title, :stored => true
|
49
|
+
string :author_name
|
46
50
|
integer :blog_id, :references => Blog
|
47
51
|
integer :category_ids, :multiple => true
|
48
52
|
float :average_rating, :using => :ratings_average, :trie => true
|
data/spec/spec_helper.rb
CHANGED
@@ -23,14 +23,10 @@ RSpec.configure do |config|
|
|
23
23
|
config.order = 'random'
|
24
24
|
|
25
25
|
# Mock session available to all spec/api tests
|
26
|
-
config.include MockSessionHelper,
|
27
|
-
:type => :api,
|
28
|
-
:file_path => /spec[\\\/]api/
|
26
|
+
config.include MockSessionHelper, type: :api, file_path: /spec[\\\/]api/
|
29
27
|
|
30
28
|
# Real Solr instance is available to integration tests
|
31
|
-
config.include IntegrationHelper,
|
32
|
-
:type => :integration,
|
33
|
-
:file_path => /spec[\\\/]integration/
|
29
|
+
config.include IntegrationHelper, type: :integration, file_path: /spec[\\\/]integration/
|
34
30
|
|
35
31
|
# Nested under spec/api
|
36
32
|
[:indexer, :query, :search].each do |spec_type|
|
data/sunspot.gemspec
CHANGED
@@ -31,7 +31,7 @@ Gem::Specification.new do |s|
|
|
31
31
|
s.add_dependency 'pr_geohash', '~>1.0'
|
32
32
|
|
33
33
|
s.add_development_dependency 'rake', '< 12.3'
|
34
|
-
s.add_development_dependency 'rspec'
|
34
|
+
s.add_development_dependency 'rspec', '~> 3.7'
|
35
35
|
s.add_development_dependency 'appraisal', '2.2.0'
|
36
36
|
|
37
37
|
s.rdoc_options << '--webcvs=http://github.com/outoftime/sunspot/tree/master/%s' <<
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sunspot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mat Brown
|
@@ -30,7 +30,7 @@ authors:
|
|
30
30
|
autorequire:
|
31
31
|
bindir: bin
|
32
32
|
cert_chain: []
|
33
|
-
date: 2018-
|
33
|
+
date: 2018-04-08 00:00:00.000000000 Z
|
34
34
|
dependencies:
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: rsolr
|
@@ -84,16 +84,16 @@ dependencies:
|
|
84
84
|
name: rspec
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '3.7'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - "
|
94
|
+
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '3.7'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: appraisal
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -159,14 +159,17 @@ files:
|
|
159
159
|
- lib/sunspot/query.rb
|
160
160
|
- lib/sunspot/query/abstract_field_facet.rb
|
161
161
|
- lib/sunspot/query/abstract_fulltext.rb
|
162
|
+
- lib/sunspot/query/abstract_json_field_facet.rb
|
162
163
|
- lib/sunspot/query/bbox.rb
|
163
164
|
- lib/sunspot/query/boost_query.rb
|
164
165
|
- lib/sunspot/query/common_query.rb
|
165
166
|
- lib/sunspot/query/composite_fulltext.rb
|
166
167
|
- lib/sunspot/query/connective.rb
|
167
168
|
- lib/sunspot/query/date_field_facet.rb
|
169
|
+
- lib/sunspot/query/date_field_json_facet.rb
|
168
170
|
- lib/sunspot/query/dismax.rb
|
169
171
|
- lib/sunspot/query/field_facet.rb
|
172
|
+
- lib/sunspot/query/field_json_facet.rb
|
170
173
|
- lib/sunspot/query/field_list.rb
|
171
174
|
- lib/sunspot/query/field_stats.rb
|
172
175
|
- lib/sunspot/query/filter.rb
|
@@ -182,6 +185,7 @@ files:
|
|
182
185
|
- lib/sunspot/query/pagination.rb
|
183
186
|
- lib/sunspot/query/query_facet.rb
|
184
187
|
- lib/sunspot/query/range_facet.rb
|
188
|
+
- lib/sunspot/query/range_json_facet.rb
|
185
189
|
- lib/sunspot/query/restriction.rb
|
186
190
|
- lib/sunspot/query/scope.rb
|
187
191
|
- lib/sunspot/query/sort.rb
|
@@ -197,11 +201,14 @@ files:
|
|
197
201
|
- lib/sunspot/search/facet_row.rb
|
198
202
|
- lib/sunspot/search/field_facet.rb
|
199
203
|
- lib/sunspot/search/field_group.rb
|
204
|
+
- lib/sunspot/search/field_json_facet.rb
|
200
205
|
- lib/sunspot/search/field_stats.rb
|
201
206
|
- lib/sunspot/search/group.rb
|
202
207
|
- lib/sunspot/search/highlight.rb
|
203
208
|
- lib/sunspot/search/hit.rb
|
204
209
|
- lib/sunspot/search/hit_enumerable.rb
|
210
|
+
- lib/sunspot/search/json_facet_row.rb
|
211
|
+
- lib/sunspot/search/json_facet_stats.rb
|
205
212
|
- lib/sunspot/search/more_like_this_search.rb
|
206
213
|
- lib/sunspot/search/paginated_collection.rb
|
207
214
|
- lib/sunspot/search/query_facet.rb
|
@@ -209,6 +216,7 @@ files:
|
|
209
216
|
- lib/sunspot/search/range_facet.rb
|
210
217
|
- lib/sunspot/search/standard_search.rb
|
211
218
|
- lib/sunspot/search/stats_facet.rb
|
219
|
+
- lib/sunspot/search/stats_json_row.rb
|
212
220
|
- lib/sunspot/search/stats_row.rb
|
213
221
|
- lib/sunspot/session.rb
|
214
222
|
- lib/sunspot/session_proxy.rb
|
@@ -348,7 +356,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
348
356
|
version: '0'
|
349
357
|
requirements: []
|
350
358
|
rubyforge_project: sunspot
|
351
|
-
rubygems_version: 2.6
|
359
|
+
rubygems_version: 2.7.6
|
352
360
|
signing_key:
|
353
361
|
specification_version: 4
|
354
362
|
summary: Library for expressive, powerful interaction with the Solr search engine
|