sunspot 2.2.7 → 2.5.0
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.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/Appraisals +7 -0
- data/Gemfile +0 -8
- data/lib/sunspot/adapters.rb +4 -1
- data/lib/sunspot/configuration.rb +1 -0
- data/lib/sunspot/data_extractor.rb +36 -6
- data/lib/sunspot/dsl/field_query.rb +11 -0
- data/lib/sunspot/dsl/field_stats.rb +7 -0
- data/lib/sunspot/dsl/fields.rb +16 -0
- data/lib/sunspot/dsl/group.rb +10 -0
- data/lib/sunspot/dsl/scope.rb +23 -18
- data/lib/sunspot/field.rb +11 -0
- data/lib/sunspot/field_factory.rb +6 -2
- data/lib/sunspot/query/abstract_json_field_facet.rb +70 -0
- data/lib/sunspot/query/bbox.rb +5 -1
- 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/group.rb +4 -5
- data/lib/sunspot/query/join.rb +2 -4
- data/lib/sunspot/query/range_json_facet.rb +28 -0
- data/lib/sunspot/query/restriction.rb +19 -4
- data/lib/sunspot/query.rb +3 -3
- data/lib/sunspot/schema.rb +10 -2
- data/lib/sunspot/search/abstract_search.rb +14 -1
- data/lib/sunspot/search/field_json_facet.rb +33 -0
- data/lib/sunspot/search/hit.rb +6 -1
- data/lib/sunspot/search/hit_enumerable.rb +4 -1
- data/lib/sunspot/search/json_facet_row.rb +40 -0
- data/lib/sunspot/search/json_facet_stats.rb +23 -0
- data/lib/sunspot/search/standard_search.rb +2 -3
- data/lib/sunspot/search/stats_json_row.rb +82 -0
- data/lib/sunspot/search/stats_row.rb +3 -1
- data/lib/sunspot/search.rb +4 -3
- data/lib/sunspot/session.rb +13 -5
- data/lib/sunspot/setup.rb +31 -0
- data/lib/sunspot/util.rb +23 -0
- data/lib/sunspot/version.rb +1 -1
- data/spec/api/adapters_spec.rb +32 -19
- data/spec/api/batcher_spec.rb +15 -15
- data/spec/api/binding_spec.rb +3 -3
- data/spec/api/class_set_spec.rb +3 -3
- data/spec/api/data_extractor_spec.rb +39 -0
- data/spec/api/hit_enumerable_spec.rb +32 -9
- data/spec/api/indexer/attributes_spec.rb +31 -31
- data/spec/api/indexer/batch_spec.rb +8 -7
- data/spec/api/indexer/dynamic_fields_spec.rb +8 -8
- data/spec/api/indexer/fixed_fields_spec.rb +12 -12
- data/spec/api/indexer/fulltext_spec.rb +8 -8
- data/spec/api/indexer/removal_spec.rb +14 -14
- data/spec/api/indexer_spec.rb +2 -2
- data/spec/api/query/advanced_manipulation_examples.rb +3 -3
- data/spec/api/query/connectives_examples.rb +26 -14
- data/spec/api/query/dsl_spec.rb +17 -9
- data/spec/api/query/dynamic_fields_examples.rb +18 -18
- data/spec/api/query/faceting_examples.rb +62 -62
- data/spec/api/query/fulltext_examples.rb +63 -58
- data/spec/api/query/function_spec.rb +26 -26
- data/spec/api/query/geo_examples.rb +6 -6
- data/spec/api/query/group_spec.rb +6 -6
- data/spec/api/query/highlighting_examples.rb +26 -26
- data/spec/api/query/join_spec.rb +2 -2
- data/spec/api/query/more_like_this_spec.rb +29 -29
- data/spec/api/query/ordering_pagination_examples.rb +25 -25
- data/spec/api/query/scope_examples.rb +39 -39
- data/spec/api/query/spatial_examples.rb +3 -3
- data/spec/api/query/spellcheck_examples.rb +3 -3
- data/spec/api/query/standard_spec.rb +1 -1
- data/spec/api/query/stats_examples.rb +8 -8
- data/spec/api/query/text_field_scoping_examples.rb +5 -5
- data/spec/api/query/types_spec.rb +4 -4
- data/spec/api/search/cursor_paginated_collection_spec.rb +12 -12
- data/spec/api/search/dynamic_fields_spec.rb +4 -4
- data/spec/api/search/faceting_spec.rb +55 -52
- data/spec/api/search/highlighting_spec.rb +7 -7
- data/spec/api/search/hits_spec.rb +43 -29
- data/spec/api/search/paginated_collection_spec.rb +18 -18
- data/spec/api/search/results_spec.rb +13 -13
- data/spec/api/search/search_spec.rb +3 -3
- data/spec/api/search/stats_spec.rb +10 -10
- data/spec/api/session_proxy/class_sharding_session_proxy_spec.rb +19 -18
- data/spec/api/session_proxy/id_sharding_session_proxy_spec.rb +9 -9
- data/spec/api/session_proxy/master_slave_session_proxy_spec.rb +10 -6
- data/spec/api/session_proxy/retry_5xx_session_proxy_spec.rb +10 -10
- data/spec/api/session_proxy/sharding_session_proxy_spec.rb +14 -13
- data/spec/api/session_proxy/silent_fail_session_proxy_spec.rb +2 -2
- data/spec/api/session_proxy/spec_helper.rb +1 -1
- data/spec/api/session_proxy/thread_local_session_proxy_spec.rb +9 -5
- data/spec/api/session_spec.rb +42 -42
- data/spec/api/sunspot_spec.rb +7 -4
- data/spec/helpers/integration_helper.rb +1 -0
- data/spec/integration/atomic_updates_spec.rb +25 -11
- data/spec/integration/dynamic_fields_spec.rb +10 -10
- data/spec/integration/faceting_spec.rb +252 -39
- data/spec/integration/field_grouping_spec.rb +35 -16
- data/spec/integration/field_lists_spec.rb +57 -0
- data/spec/integration/geospatial_spec.rb +34 -8
- data/spec/integration/highlighting_spec.rb +5 -5
- data/spec/integration/indexing_spec.rb +5 -5
- data/spec/integration/join_spec.rb +45 -0
- data/spec/integration/keyword_search_spec.rb +47 -45
- data/spec/integration/local_search_spec.rb +4 -4
- data/spec/integration/more_like_this_spec.rb +7 -7
- data/spec/integration/scoped_search_spec.rb +108 -108
- data/spec/integration/spellcheck_spec.rb +52 -7
- data/spec/integration/stats_spec.rb +54 -13
- data/spec/integration/stored_fields_spec.rb +1 -1
- data/spec/integration/test_pagination.rb +4 -4
- data/spec/integration/unicode_spec.rb +1 -1
- data/spec/mocks/adapters.rb +33 -0
- data/spec/mocks/photo.rb +14 -4
- data/spec/mocks/post.rb +9 -1
- data/spec/spec_helper.rb +11 -10
- data/sunspot.gemspec +3 -1
- metadata +49 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 179de5f5261bdb69d21038a0b2e36fbd2812e1fc71ef4c1efd77979a03e58179
|
4
|
+
data.tar.gz: 1f7f40d9737400cf61c23515c61ebde70140b1c1bf9df800d7e19ce27c3cbd0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad59d5868f3461648d29c77b6368d7c5145ef6247ecca38878bf4f03bb3d2ab73fea2decf629936d58282b8067345198f6bff82be1347bb0cc92cb4537722d28
|
7
|
+
data.tar.gz: 3c4fd67940331fbdacffd665ca624119038bf12da2aa2b041adbd8260aef3921660b83803a912cf81384c7269f6b46d3b7fad1c883c34e1a1ba2ccbade2fd6dc
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/Appraisals
ADDED
data/Gemfile
CHANGED
data/lib/sunspot/adapters.rb
CHANGED
@@ -63,7 +63,10 @@ module Sunspot
|
|
63
63
|
# String:: ID for use in Solr
|
64
64
|
#
|
65
65
|
def index_id #:nodoc:
|
66
|
-
|
66
|
+
setup = Sunspot::Setup.for(@instance.class)
|
67
|
+
id_prefix = setup ? setup.id_prefix_for(@instance) : nil
|
68
|
+
|
69
|
+
InstanceAdapter.index_id_for("#{id_prefix}#{@instance.class.name}", id)
|
67
70
|
end
|
68
71
|
|
69
72
|
class <<self
|
@@ -5,16 +5,46 @@ module Sunspot
|
|
5
5
|
# method, which takes an object and returns the value extracted from it.
|
6
6
|
#
|
7
7
|
module DataExtractor #:nodoc: all
|
8
|
+
#
|
9
|
+
# Abstract extractor to perform common actions on extracted values
|
10
|
+
#
|
11
|
+
class AbstractExtractor
|
12
|
+
BLACKLIST_REGEXP = /[\x0-\x8\xB\xC\xE-\x1F\x7f]/
|
13
|
+
|
14
|
+
def value_for(object)
|
15
|
+
extract_value_from(object)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def extract_value_from(object)
|
21
|
+
case object
|
22
|
+
when String
|
23
|
+
remove_blacklisted_chars(object)
|
24
|
+
when Array
|
25
|
+
object.map { |o| extract_value_from(o) }
|
26
|
+
when Hash
|
27
|
+
object.inject({}) { |h, (k, v)| h.merge(extract_value_from(k) => extract_value_from(v)) }
|
28
|
+
else
|
29
|
+
object
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def remove_blacklisted_chars(object)
|
34
|
+
object.gsub(BLACKLIST_REGEXP, '')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
8
38
|
#
|
9
39
|
# AttributeExtractors extract data by simply calling a method on the block.
|
10
40
|
#
|
11
|
-
class AttributeExtractor
|
41
|
+
class AttributeExtractor < AbstractExtractor
|
12
42
|
def initialize(attribute_name)
|
13
43
|
@attribute_name = attribute_name
|
14
44
|
end
|
15
45
|
|
16
46
|
def value_for(object)
|
17
|
-
object.send(@attribute_name)
|
47
|
+
super object.send(@attribute_name)
|
18
48
|
end
|
19
49
|
end
|
20
50
|
|
@@ -24,26 +54,26 @@ module Sunspot
|
|
24
54
|
# as the argument to the block. Either way, the return value of the block is
|
25
55
|
# the value returned by the extractor.
|
26
56
|
#
|
27
|
-
class BlockExtractor
|
57
|
+
class BlockExtractor < AbstractExtractor
|
28
58
|
def initialize(&block)
|
29
59
|
@block = block
|
30
60
|
end
|
31
61
|
|
32
62
|
def value_for(object)
|
33
|
-
Util.instance_eval_or_call(object, &@block)
|
63
|
+
super Util.instance_eval_or_call(object, &@block)
|
34
64
|
end
|
35
65
|
end
|
36
66
|
|
37
67
|
#
|
38
68
|
# Constant data extractors simply return the same value for every object.
|
39
69
|
#
|
40
|
-
class Constant
|
70
|
+
class Constant < AbstractExtractor
|
41
71
|
def initialize(value)
|
42
72
|
@value = value
|
43
73
|
end
|
44
74
|
|
45
75
|
def value_for(object)
|
46
|
-
@value
|
76
|
+
super @value
|
47
77
|
end
|
48
78
|
end
|
49
79
|
end
|
@@ -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/dsl/fields.rb
CHANGED
@@ -55,6 +55,22 @@ module Sunspot
|
|
55
55
|
@setup.add_document_boost(attr_name, &block)
|
56
56
|
end
|
57
57
|
|
58
|
+
#
|
59
|
+
# If you use the compositeId router for shards, you can send documents
|
60
|
+
# with a prefix in the document ID which will be used to calculate the
|
61
|
+
# hash Solr uses to determine the shard a document is sent to for indexing.
|
62
|
+
# The prefix can be anything you’d like it to be (it doesn’t have to be
|
63
|
+
# the shard name, for example), but it must be consistent so Solr
|
64
|
+
# behaves consistently.
|
65
|
+
#
|
66
|
+
# ==== Parameters
|
67
|
+
#
|
68
|
+
# attr_name<Symbol,String>:: Attribute name to call or a string constant
|
69
|
+
#
|
70
|
+
def id_prefix(attr_name = nil, &block)
|
71
|
+
@setup.add_id_prefix(attr_name, &block)
|
72
|
+
end
|
73
|
+
|
58
74
|
# method_missing is used to provide access to typed fields, because
|
59
75
|
# developers should be able to add new Sunspot::Type implementations
|
60
76
|
# dynamically and have them recognized inside the Fields DSL. Like #text,
|
data/lib/sunspot/dsl/group.rb
CHANGED
@@ -59,6 +59,16 @@ module Sunspot
|
|
59
59
|
@group.truncate = true
|
60
60
|
end
|
61
61
|
|
62
|
+
#
|
63
|
+
# The group.ngroups option true return the total number of groups
|
64
|
+
# this is expensive and sometimes you don't need it!
|
65
|
+
# If ngroups is false paginated_collection last_page? and total_pages wont't work.
|
66
|
+
# Defaults to true.
|
67
|
+
#
|
68
|
+
def ngroups(enabled)
|
69
|
+
@group.ngroups = enabled
|
70
|
+
end
|
71
|
+
|
62
72
|
# Specify the order that results should be returned in. This method can
|
63
73
|
# be called multiple times; precedence will be in the order given.
|
64
74
|
#
|
data/lib/sunspot/dsl/scope.rb
CHANGED
@@ -14,7 +14,12 @@ module Sunspot
|
|
14
14
|
|
15
15
|
# Build a restriction to return only fields of the type in the results.
|
16
16
|
def field_list(*args)
|
17
|
-
@
|
17
|
+
list = args.flatten.map { |field| @setup.field(field.to_sym).indexed_name.to_sym }
|
18
|
+
@query.add_field_list(Sunspot::Query::FieldList.new([:id] + list)) unless list.empty?
|
19
|
+
end
|
20
|
+
|
21
|
+
def without_stored_fields
|
22
|
+
@query.add_field_list(Sunspot::Query::FieldList.new([:id]))
|
18
23
|
end
|
19
24
|
|
20
25
|
#
|
@@ -194,25 +199,25 @@ module Sunspot
|
|
194
199
|
|
195
200
|
def add_restriction(negated, *args)
|
196
201
|
case args.first
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
end
|
206
|
-
else # args are instances
|
207
|
-
@scope.add_restriction(
|
208
|
-
negated,
|
209
|
-
IdField.instance,
|
210
|
-
Sunspot::Query::Restriction::AnyOf,
|
211
|
-
args.flatten.map { |instance|
|
212
|
-
Sunspot::Adapters::InstanceAdapter.adapt(instance).index_id }
|
213
|
-
)
|
202
|
+
when String, Symbol
|
203
|
+
raise ArgumentError if args.length > 2
|
204
|
+
field = @setup.field(args[0].to_sym)
|
205
|
+
if args.length > 1
|
206
|
+
value = args[1]
|
207
|
+
@scope.add_shorthand_restriction(negated, field, value)
|
208
|
+
else # NONE
|
209
|
+
DSL::Restriction.new(field, @scope, negated)
|
214
210
|
end
|
211
|
+
else # args are instances
|
212
|
+
@scope.add_restriction(
|
213
|
+
negated,
|
214
|
+
IdField.instance,
|
215
|
+
Sunspot::Query::Restriction::AnyOf,
|
216
|
+
args.flatten.map { |instance|
|
217
|
+
Sunspot::Adapters::InstanceAdapter.adapt(instance).index_id }
|
218
|
+
)
|
215
219
|
end
|
220
|
+
end
|
216
221
|
end
|
217
222
|
end
|
218
223
|
end
|
data/lib/sunspot/field.rb
CHANGED
@@ -93,6 +93,17 @@ module Sunspot
|
|
93
93
|
!!@joined
|
94
94
|
end
|
95
95
|
|
96
|
+
#
|
97
|
+
# Whether the field is stored or not.
|
98
|
+
#
|
99
|
+
# ==== Returns
|
100
|
+
#
|
101
|
+
# Boolean:: True if this field is a stored field
|
102
|
+
#
|
103
|
+
def stored?
|
104
|
+
!!@stored
|
105
|
+
end
|
106
|
+
|
96
107
|
def hash
|
97
108
|
indexed_name.hash
|
98
109
|
end
|
@@ -72,11 +72,15 @@ module Sunspot
|
|
72
72
|
# into the Solr document for indexing.
|
73
73
|
#
|
74
74
|
def populate_document(document, model, options = {}) #:nodoc:
|
75
|
+
atomic_operation = options[:update] == :set
|
75
76
|
value = extract_value(model, options)
|
76
|
-
|
77
|
-
Util.Array(@field.to_indexed(value))
|
77
|
+
if value != nil || atomic_operation
|
78
|
+
indexed_values = Util.Array(@field.to_indexed(value))
|
79
|
+
indexed_values = [nil] if indexed_values.empty? && atomic_operation
|
80
|
+
indexed_values.each do |scalar_value|
|
78
81
|
field_options = {}
|
79
82
|
field_options[:boost] = @field.boost if @field.boost
|
83
|
+
field_options[:null] = true if scalar_value.nil? && atomic_operation
|
80
84
|
document.add_field(
|
81
85
|
@field.indexed_name.to_sym,
|
82
86
|
scalar_value,
|
@@ -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
|
data/lib/sunspot/query/bbox.rb
CHANGED
@@ -5,8 +5,12 @@ module Sunspot
|
|
5
5
|
@field, @first_corner, @second_corner = field, first_corner, second_corner
|
6
6
|
end
|
7
7
|
|
8
|
+
def to_solr_conditional
|
9
|
+
"[#{@first_corner.join(",")} TO #{@second_corner.join(",")}]"
|
10
|
+
end
|
11
|
+
|
8
12
|
def to_params
|
9
|
-
filter = "#{@field.indexed_name}
|
13
|
+
filter = "#{@field.indexed_name}:#{to_solr_conditional}"
|
10
14
|
|
11
15
|
{:fq => filter}
|
12
16
|
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
|
|
data/lib/sunspot/query/group.rb
CHANGED
@@ -4,7 +4,7 @@ module Sunspot
|
|
4
4
|
# A Group groups by the unique values of a given field, or by given queries.
|
5
5
|
#
|
6
6
|
class Group
|
7
|
-
attr_accessor :limit, :truncate
|
7
|
+
attr_accessor :limit, :truncate, :ngroups
|
8
8
|
attr_reader :fields, :queries
|
9
9
|
|
10
10
|
def initialize
|
@@ -30,16 +30,15 @@ module Sunspot
|
|
30
30
|
|
31
31
|
def to_params
|
32
32
|
params = {
|
33
|
-
:group =>
|
34
|
-
:"group.ngroups" =>
|
33
|
+
:group => 'true',
|
34
|
+
:"group.ngroups" => @ngroups.nil? ? 'true' : @ngroups.to_s
|
35
35
|
}
|
36
36
|
|
37
|
-
params.merge!(@sort.to_params(
|
37
|
+
params.merge!(@sort.to_params('group.'))
|
38
38
|
params[:"group.field"] = @fields.map(&:indexed_name) if @fields.any?
|
39
39
|
params[:"group.query"] = @queries.map(&:to_boolean_phrase) if @queries.any?
|
40
40
|
params[:"group.limit"] = @limit if @limit
|
41
41
|
params[:"group.truncate"] = @truncate if @truncate
|
42
|
-
|
43
42
|
params
|
44
43
|
end
|
45
44
|
end
|
data/lib/sunspot/query/join.rb
CHANGED
@@ -42,12 +42,10 @@ module Sunspot
|
|
42
42
|
keywords = escape_quotes(params.delete(:q))
|
43
43
|
options = params.map { |key, value| escape_param(key, value) }.join(' ')
|
44
44
|
q_name = "q#{@target.name}#{self.object_id}"
|
45
|
-
fq_name = "f#{q_name}"
|
46
45
|
|
47
46
|
{
|
48
|
-
:q
|
49
|
-
q_name => "_query_:\"{!edismax #{options}}#{keywords}\""
|
50
|
-
fq_name => "type:#{@target.name}"
|
47
|
+
:q => "_query_:\"{!join from=#{@from} to=#{@to} v=$#{q_name}}\"",
|
48
|
+
q_name => "_query_:\"{!field f=type}#{@target.name}\"+_query_:\"{!edismax #{options}}#{keywords}\""
|
51
49
|
}
|
52
50
|
end
|
53
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
|
@@ -135,7 +135,7 @@ module Sunspot
|
|
135
135
|
|
136
136
|
protected
|
137
137
|
|
138
|
-
#
|
138
|
+
#
|
139
139
|
# Return escaped Solr API representation of given value
|
140
140
|
#
|
141
141
|
# ==== Parameters
|
@@ -158,9 +158,13 @@ module Sunspot
|
|
158
158
|
end
|
159
159
|
|
160
160
|
class InRadius < Base
|
161
|
-
def initialize(negated, field,
|
162
|
-
@lat, @lon, @radius =
|
163
|
-
super negated, field,
|
161
|
+
def initialize(negated, field, *value)
|
162
|
+
@lat, @lon, @radius = value
|
163
|
+
super negated, field, value
|
164
|
+
end
|
165
|
+
|
166
|
+
def negate
|
167
|
+
self.class.new(!@negated, @field, *@value)
|
164
168
|
end
|
165
169
|
|
166
170
|
private
|
@@ -169,6 +173,17 @@ module Sunspot
|
|
169
173
|
end
|
170
174
|
end
|
171
175
|
|
176
|
+
class InBoundingBox < Base
|
177
|
+
def initialize(negated, field, first_corner, second_corner)
|
178
|
+
@bbox = Sunspot::Query::Bbox.new(field, first_corner, second_corner)
|
179
|
+
super negated, field, [first_corner, second_corner]
|
180
|
+
end
|
181
|
+
|
182
|
+
def to_solr_conditional
|
183
|
+
@bbox.to_solr_conditional
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
172
187
|
#
|
173
188
|
# Results must have field with value equal to given value. If the value
|
174
189
|
# is nil, results must have no value for the given field.
|
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|
|
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
|