sunspot 0.10.5 → 0.10.6
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 +13 -0
- data/README.rdoc +3 -3
- data/TODO +4 -5
- data/VERSION.yml +1 -1
- data/bin/sunspot-solr +18 -6
- data/lib/sunspot/dsl/field_query.rb +69 -18
- data/lib/sunspot/dsl/fields.rb +6 -5
- data/lib/sunspot/dsl/fulltext.rb +57 -1
- data/lib/sunspot/dsl/query.rb +30 -3
- data/lib/sunspot/dsl/query_facet.rb +8 -3
- data/lib/sunspot/dsl/search.rb +1 -1
- data/lib/sunspot/dsl.rb +1 -1
- data/lib/sunspot/field_factory.rb +6 -3
- data/lib/sunspot/query/abstract_field_facet.rb +43 -0
- data/lib/sunspot/query/date_field_facet.rb +14 -0
- data/lib/sunspot/query/dismax.rb +26 -7
- data/lib/sunspot/query/field_facet.rb +2 -122
- data/lib/sunspot/query/highlighting.rb +17 -5
- data/lib/sunspot/query/query.rb +12 -23
- data/lib/sunspot/query/query_facet.rb +4 -66
- data/lib/sunspot/query.rb +5 -1
- data/lib/sunspot/search/date_facet.rb +35 -0
- data/lib/sunspot/search/facet_row.rb +27 -0
- data/lib/sunspot/search/field_facet.rb +44 -0
- data/lib/sunspot/search/hit.rb +10 -6
- data/lib/sunspot/search/query_facet.rb +62 -0
- data/lib/sunspot/search.rb +22 -44
- data/lib/sunspot/setup.rb +22 -7
- data/lib/sunspot/type.rb +4 -0
- data/lib/sunspot/util.rb +8 -0
- data/lib/sunspot.rb +7 -6
- data/solr/solr/conf/solrconfig.xml +1 -2
- data/solr/solr/lib/locallucene.jar +0 -0
- data/solr/solr/lib/localsolr.jar +0 -0
- data/spec/api/indexer/attributes_spec.rb +5 -0
- data/spec/api/query/faceting_spec.rb +24 -0
- data/spec/api/query/fulltext_spec.rb +80 -1
- data/spec/api/query/highlighting_spec.rb +84 -6
- data/spec/api/search/faceting_spec.rb +45 -9
- data/spec/api/search/highlighting_spec.rb +2 -2
- data/spec/api/search/hits_spec.rb +5 -0
- data/spec/integration/faceting_spec.rb +19 -0
- data/spec/integration/keyword_search_spec.rb +101 -4
- data/spec/mocks/photo.rb +3 -0
- data/tasks/gemspec.rake +8 -2
- data/tasks/rcov.rake +2 -2
- metadata +9 -11
- data/lib/sunspot/facet.rb +0 -24
- data/lib/sunspot/facet_data.rb +0 -169
- data/lib/sunspot/facet_row.rb +0 -12
- data/lib/sunspot/instantiated_facet.rb +0 -39
- data/lib/sunspot/instantiated_facet_row.rb +0 -27
- data/lib/sunspot/query/fulltext_base_query.rb +0 -47
- data/lib/sunspot/query/query_facet_row.rb +0 -19
- data/lib/sunspot/query/query_field_facet.rb +0 -20
@@ -1,128 +1,8 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
1
|
module Sunspot
|
4
2
|
module Query
|
5
|
-
|
6
|
-
# Encapsulates a query component representing a field facet. Users create
|
7
|
-
# instances using DSL::Query#facet
|
8
|
-
#
|
9
|
-
class FieldFacet #:nodoc:
|
10
|
-
class <<self
|
11
|
-
protected :new
|
12
|
-
|
13
|
-
#
|
14
|
-
# Return the appropriate FieldFacet instance for the field and options.
|
15
|
-
# If a :time_range option is specified, and the field type is TimeType,
|
16
|
-
# build a DateFieldFacet. Otherwise, build a normal FieldFacet.
|
17
|
-
#
|
18
|
-
# ==== Returns
|
19
|
-
#
|
20
|
-
# FieldFacet:: FieldFacet instance of appropriate class.
|
21
|
-
#
|
22
|
-
def build(field, options)
|
23
|
-
if options.has_key?(:time_range)
|
24
|
-
unless field.type == Type::TimeType
|
25
|
-
raise(
|
26
|
-
ArgumentError,
|
27
|
-
":time_range key can only be specified for time fields"
|
28
|
-
)
|
29
|
-
end
|
30
|
-
DateFieldFacet.new(field, options)
|
31
|
-
elsif options.has_key?(:only)
|
32
|
-
QueryFieldFacet.new(field, options.delete(:only), options)
|
33
|
-
else
|
34
|
-
FieldFacet.new(field, options)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def initialize(field, options)
|
40
|
-
@field, @options = field, options
|
41
|
-
end
|
42
|
-
|
43
|
-
# ==== Returns
|
44
|
-
#
|
45
|
-
# Hash:: solr-ruby params for this field facet
|
46
|
-
#
|
3
|
+
class FieldFacet < AbstractFieldFacet
|
47
4
|
def to_params
|
48
|
-
|
49
|
-
params[param_key(:sort)] =
|
50
|
-
case @options[:sort]
|
51
|
-
when :count then 'true'
|
52
|
-
when :index then 'false'
|
53
|
-
when nil
|
54
|
-
else raise(ArgumentError, 'Allowed facet sort options are :count and :index')
|
55
|
-
end
|
56
|
-
params[param_key(:limit)] = @options[:limit]
|
57
|
-
params[param_key(:mincount)] =
|
58
|
-
if @options[:minimum_count] then @options[:minimum_count]
|
59
|
-
elsif @options[:zeros] then 0
|
60
|
-
else 1
|
61
|
-
end
|
62
|
-
params
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
#
|
68
|
-
# Given a facet parameter name, return the appropriate Solr parameter for
|
69
|
-
# this facet.
|
70
|
-
#
|
71
|
-
# ==== Returns
|
72
|
-
#
|
73
|
-
# Symbol:: Solr query parameter key
|
74
|
-
#
|
75
|
-
def param_key(name)
|
76
|
-
:"f.#{@field.indexed_name}.facet.#{name}"
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
class DateFieldFacet < FieldFacet #:nodoc:
|
81
|
-
#
|
82
|
-
# Convert the facet to date params.
|
83
|
-
#
|
84
|
-
def to_params
|
85
|
-
super.merge(
|
86
|
-
:"facet.date" => [@field.indexed_name],
|
87
|
-
param_key('date.start') => start_time.utc.xmlschema,
|
88
|
-
param_key('date.end') => end_time.utc.xmlschema,
|
89
|
-
param_key('date.gap') => "+#{interval}SECONDS"
|
90
|
-
)
|
91
|
-
end
|
92
|
-
|
93
|
-
private
|
94
|
-
|
95
|
-
#
|
96
|
-
# Start time for facet range
|
97
|
-
#
|
98
|
-
# ==== Returns
|
99
|
-
#
|
100
|
-
# Time:: Start time
|
101
|
-
#
|
102
|
-
def start_time
|
103
|
-
@options[:time_range].first
|
104
|
-
end
|
105
|
-
|
106
|
-
#
|
107
|
-
# End time for facet range
|
108
|
-
#
|
109
|
-
# ==== Returns
|
110
|
-
#
|
111
|
-
# Time:: End time
|
112
|
-
#
|
113
|
-
def end_time
|
114
|
-
@options[:time_range].last
|
115
|
-
end
|
116
|
-
|
117
|
-
#
|
118
|
-
# Time interval that each facet row should cover. Default is 1 day.
|
119
|
-
#
|
120
|
-
# ===== Returns
|
121
|
-
#
|
122
|
-
# Integer:: Time interval in seconds
|
123
|
-
#
|
124
|
-
def interval
|
125
|
-
@options[:time_interval] || 86400
|
5
|
+
super.merge(:"facet.field" => [@field.indexed_name])
|
126
6
|
end
|
127
7
|
end
|
128
8
|
end
|
@@ -22,22 +22,34 @@ module Sunspot
|
|
22
22
|
params[:"hl.fl"] = @fields.map { |field| field.indexed_name }
|
23
23
|
end
|
24
24
|
if max_snippets = @options[:max_snippets]
|
25
|
-
params
|
25
|
+
params.merge!(make_params('snippets', max_snippets))
|
26
26
|
end
|
27
27
|
if fragment_size = @options[:fragment_size]
|
28
|
-
params
|
28
|
+
params.merge!(make_params('fragsize', fragment_size))
|
29
29
|
end
|
30
30
|
if @options[:merge_contiguous_fragments]
|
31
|
-
params
|
31
|
+
params.merge!(make_params('mergeContiguous', 'true'))
|
32
32
|
end
|
33
33
|
if @options[:phrase_highlighter]
|
34
|
-
params
|
34
|
+
params.merge!(make_params('usePhraseHighlighter', 'true'))
|
35
35
|
if @options[:require_field_match]
|
36
|
-
params
|
36
|
+
params.merge!(make_params('requireFieldMatch', 'true'))
|
37
37
|
end
|
38
38
|
end
|
39
39
|
params
|
40
40
|
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def make_params(name, value)
|
45
|
+
if @fields.empty?
|
46
|
+
{ :"hl.#{name}" => value }
|
47
|
+
else
|
48
|
+
@fields.inject({}) do |hash, field|
|
49
|
+
hash.merge!(:"f.#{field.indexed_name}.hl.#{name}" => value)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
41
53
|
end
|
42
54
|
end
|
43
55
|
end
|
data/lib/sunspot/query/query.rb
CHANGED
@@ -5,9 +5,8 @@ module Sunspot
|
|
5
5
|
|
6
6
|
def initialize(types)
|
7
7
|
@scope = Scope.new
|
8
|
-
@field_facets = []
|
9
|
-
@query_facets = {}
|
10
8
|
@sort = SortComposite.new
|
9
|
+
@components = []
|
11
10
|
if types.length == 1
|
12
11
|
@scope.add_restriction(TypeField.instance, Restriction::EqualTo, types.first)
|
13
12
|
else
|
@@ -27,21 +26,18 @@ module Sunspot
|
|
27
26
|
@local = Local.new(coordinates, radius)
|
28
27
|
end
|
29
28
|
|
30
|
-
def
|
31
|
-
|
32
|
-
if facet.is_a?(QueryFacet)
|
33
|
-
@query_facets[field.name.to_sym] = facet
|
34
|
-
else
|
35
|
-
@field_facets << facet
|
36
|
-
end
|
29
|
+
def add_sort(sort)
|
30
|
+
@sort << sort
|
37
31
|
end
|
38
32
|
|
39
|
-
def
|
40
|
-
@
|
33
|
+
def add_field_facet(facet)
|
34
|
+
@components << facet
|
35
|
+
facet
|
41
36
|
end
|
42
37
|
|
43
|
-
def
|
44
|
-
@
|
38
|
+
def add_query_facet(facet)
|
39
|
+
@components << facet
|
40
|
+
facet
|
45
41
|
end
|
46
42
|
|
47
43
|
def paginate(page, per_page)
|
@@ -67,15 +63,12 @@ module Sunspot
|
|
67
63
|
@scope.to_params
|
68
64
|
end
|
69
65
|
Sunspot::Util.deep_merge!(params, @fulltext.to_params) if @fulltext
|
70
|
-
@field_facets.each do |facet|
|
71
|
-
Sunspot::Util.deep_merge!(params, facet.to_params)
|
72
|
-
end
|
73
|
-
@query_facets.values.each do |facet|
|
74
|
-
Sunspot::Util.deep_merge!(params, facet.to_params)
|
75
|
-
end
|
76
66
|
Sunspot::Util.deep_merge!(params, @sort.to_params)
|
77
67
|
Sunspot::Util.deep_merge!(params, @pagination.to_params) if @pagination
|
78
68
|
Sunspot::Util.deep_merge!(params, @local.to_params) if @local
|
69
|
+
@components.each do |component|
|
70
|
+
Sunspot::Util.deep_merge!(params, component.to_params)
|
71
|
+
end
|
79
72
|
@parameter_adjustment.call(params) if @parameter_adjustment
|
80
73
|
params[:q] ||= '*:*'
|
81
74
|
params
|
@@ -88,10 +81,6 @@ module Sunspot
|
|
88
81
|
def per_page
|
89
82
|
@pagination.per_page if @pagination
|
90
83
|
end
|
91
|
-
|
92
|
-
def query_facet(name)
|
93
|
-
@query_facets[name] if @query_facets
|
94
|
-
end
|
95
84
|
end
|
96
85
|
end
|
97
86
|
end
|
@@ -1,78 +1,16 @@
|
|
1
1
|
module Sunspot
|
2
2
|
module Query
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
#
|
7
|
-
#--
|
8
|
-
#
|
9
|
-
# The actual concept of a QueryFacet is somewhat artificial - it provides a
|
10
|
-
# grouping for the facet at the Sunspot level, which provides a nicer and
|
11
|
-
# more consistent API in Sunspot; Solr does not provide any grouping for
|
12
|
-
# query facet rows, instead returning each requested row individually, keyed
|
13
|
-
# by the boolean phrase used in the facet query.
|
14
|
-
#
|
15
|
-
class QueryFacet #:nodoc:
|
16
|
-
attr_reader :name #:nodoc:
|
17
|
-
attr_reader :field #:nodoc:
|
18
|
-
attr_reader :options #:nodoc:
|
19
|
-
|
20
|
-
def initialize(name, options, setup = nil) #:nodoc:
|
21
|
-
@name, @options, @setup = name, options, setup
|
22
|
-
@components = []
|
23
|
-
end
|
24
|
-
|
25
|
-
#
|
26
|
-
# Add a QueryFacetRow to this facet. The label argument becomes the value
|
27
|
-
# of the Sunspot::QueryFacetRow object corresponding to this query facet
|
28
|
-
# row.
|
29
|
-
#
|
30
|
-
# ==== Parameters
|
31
|
-
#
|
32
|
-
# label<Object>::
|
33
|
-
# An object that will become the value of the result row. Use whatever
|
34
|
-
# type is most intuitive.
|
35
|
-
#
|
36
|
-
# ==== Returns
|
37
|
-
#
|
38
|
-
# QueryFacetRow:: QueryFacetRow object containing scope for this row
|
39
|
-
#
|
40
|
-
def add_row(label)
|
41
|
-
@components << row = QueryFacetRow.new(label, @setup)
|
42
|
-
row
|
43
|
-
end
|
44
|
-
|
45
|
-
#
|
46
|
-
# Express this query facet as Solr parameters
|
47
|
-
#
|
48
|
-
# ==== Returns
|
49
|
-
#
|
50
|
-
# Hash:: Solr params hash
|
51
|
-
#
|
52
|
-
def to_params #:nodoc:
|
53
|
-
components = @components.map { |component| component.to_boolean_phrase }
|
54
|
-
components.compact!
|
55
|
-
if components.empty?
|
3
|
+
class QueryFacet < Connective::Conjunction
|
4
|
+
def to_params
|
5
|
+
if @components.empty?
|
56
6
|
{}
|
57
7
|
else
|
58
|
-
components = components.first if components.length == 1
|
59
8
|
{
|
60
9
|
:facet => 'true',
|
61
|
-
:"facet.query" =>
|
10
|
+
:"facet.query" => to_boolean_phrase
|
62
11
|
}
|
63
12
|
end
|
64
13
|
end
|
65
|
-
|
66
|
-
#
|
67
|
-
# Get query facet rows (used when constructing results)
|
68
|
-
#
|
69
|
-
# ==== Returns
|
70
|
-
#
|
71
|
-
# Array:: Array of QueryFacetRow objects.
|
72
|
-
#
|
73
|
-
def rows #:nodoc:
|
74
|
-
@components
|
75
|
-
end
|
76
14
|
end
|
77
15
|
end
|
78
16
|
end
|
data/lib/sunspot/query.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
-
%w(connective boost_query dismax
|
1
|
+
%w(abstract_field_facet connective boost_query date_field_facet dismax
|
2
|
+
field_facet highlighting local pagination restriction query query_facet
|
3
|
+
scope sort sort_composite text_field_boost).each do |file|
|
4
|
+
require(File.join(File.dirname(__FILE__), 'query', file))
|
5
|
+
end
|
2
6
|
module Sunspot
|
3
7
|
module Query #:nodoc:all
|
4
8
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Sunspot
|
2
|
+
class Search
|
3
|
+
class DateFacet
|
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_dates'][@field.indexed_name]
|
16
|
+
gap = (@options[:time_interval] || 86400).to_i
|
17
|
+
rows = []
|
18
|
+
data.each_pair do |value, count|
|
19
|
+
if value =~ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/
|
20
|
+
start_time = @field.cast(value)
|
21
|
+
end_time = start_time + gap
|
22
|
+
rows << FacetRow.new(start_time..end_time, count, self)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
if @options[:sort] == :count
|
26
|
+
rows.sort! { |lrow, rrow| rrow.count <=> lrow.count }
|
27
|
+
else
|
28
|
+
rows.sort! { |lrow, rrow| lrow.value.first <=> rrow.value.first }
|
29
|
+
end
|
30
|
+
rows
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Sunspot
|
2
|
+
class Search
|
3
|
+
class FacetRow
|
4
|
+
attr_reader :value, :count
|
5
|
+
attr_writer :instance #:nodoc:
|
6
|
+
|
7
|
+
def initialize(value, count, facet) #:nodoc:
|
8
|
+
@value, @count, @facet = value, count, facet
|
9
|
+
end
|
10
|
+
|
11
|
+
#
|
12
|
+
# Return the instance referenced by this facet row. Only valid for field
|
13
|
+
# facets whose fields are defined with the :references key.
|
14
|
+
#
|
15
|
+
def instance
|
16
|
+
if !defined?(@instance)
|
17
|
+
@facet.populate_instances
|
18
|
+
end
|
19
|
+
@instance
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
"<Sunspot::Search::FacetRow:#{value.inspect} (#{count})>"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Sunspot
|
2
|
+
class Search
|
3
|
+
class FieldFacet < QueryFacet
|
4
|
+
alias_method :field_name, :name
|
5
|
+
|
6
|
+
def initialize(field, search, options) #:nodoc:
|
7
|
+
super(field.name, search, options)
|
8
|
+
@field = field
|
9
|
+
end
|
10
|
+
|
11
|
+
def rows
|
12
|
+
@rows ||=
|
13
|
+
begin
|
14
|
+
rows = super
|
15
|
+
has_query_facets = !rows.empty?
|
16
|
+
if @search.facet_response['facet_fields']
|
17
|
+
if data = @search.facet_response['facet_fields'][@field.indexed_name]
|
18
|
+
data.each_slice(2) do |value, count|
|
19
|
+
rows << FacetRow.new(@field.cast(value), count, self)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
sort_rows!(rows) if has_query_facets
|
24
|
+
rows
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def populate_instances #:nodoc:
|
29
|
+
if reference = @field.reference
|
30
|
+
values_hash = rows.inject({}) do |hash, row|
|
31
|
+
hash[row.value] = row
|
32
|
+
hash
|
33
|
+
end
|
34
|
+
instances = Adapters::DataAccessor.create(Sunspot::Util.full_const_get(reference)).load_all(
|
35
|
+
values_hash.keys
|
36
|
+
)
|
37
|
+
instances.each do |instance|
|
38
|
+
values_hash[Adapters::InstanceAdapter.adapt(instance).id].instance = instance
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/sunspot/search/hit.rb
CHANGED
@@ -49,7 +49,7 @@ module Sunspot
|
|
49
49
|
highlights_cache.values.flatten
|
50
50
|
else
|
51
51
|
highlights_cache[field_name.to_sym]
|
52
|
-
end
|
52
|
+
end || []
|
53
53
|
end
|
54
54
|
|
55
55
|
#
|
@@ -64,11 +64,7 @@ module Sunspot
|
|
64
64
|
# The name of the field for which to retrieve the stored value.
|
65
65
|
#
|
66
66
|
def stored(field_name)
|
67
|
-
@stored_cache[field_name.to_sym] ||=
|
68
|
-
begin
|
69
|
-
field = setup.field(field_name)
|
70
|
-
field.cast(@stored_values[field.indexed_name])
|
71
|
-
end
|
67
|
+
@stored_cache[field_name.to_sym] ||= stored_value(field_name)
|
72
68
|
end
|
73
69
|
|
74
70
|
#
|
@@ -108,6 +104,14 @@ module Sunspot
|
|
108
104
|
cache
|
109
105
|
end
|
110
106
|
end
|
107
|
+
|
108
|
+
def stored_value(field_name)
|
109
|
+
setup.stored_fields(field_name).each do |field|
|
110
|
+
if value = @stored_values[field.indexed_name]
|
111
|
+
return field.cast(value)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
111
115
|
end
|
112
116
|
end
|
113
117
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Sunspot
|
2
|
+
class Search
|
3
|
+
class QueryFacet
|
4
|
+
RequestedFacet = Struct.new(:label, :boolean_phrase) #:nodoc:
|
5
|
+
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
def initialize(name, search, options) #:nodoc:
|
9
|
+
@name, @search, @options = name, search, options
|
10
|
+
@requested_facets = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def rows
|
14
|
+
@rows ||=
|
15
|
+
begin
|
16
|
+
data = @search.facet_response['facet_queries']
|
17
|
+
rows = []
|
18
|
+
minimum_count =
|
19
|
+
case
|
20
|
+
when @options[:minimum_count] then @options[:minimum_count]
|
21
|
+
when @options[:zeros] then 0
|
22
|
+
else 1
|
23
|
+
end
|
24
|
+
@requested_facets.each do |requested_facet|
|
25
|
+
count = data[requested_facet.boolean_phrase] || 0
|
26
|
+
if count >= minimum_count
|
27
|
+
rows << FacetRow.new(requested_facet.label, count, self)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
sort_rows!(rows)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_row(label, boolean_phrase) #:nodoc:
|
35
|
+
@requested_facets << RequestedFacet.new(label, boolean_phrase)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def sort_rows!(rows)
|
41
|
+
case @options[:sort] || (:count if @options[:limit])
|
42
|
+
when :count
|
43
|
+
rows.sort! { |lrow, rrow| rrow.count <=> lrow.count }
|
44
|
+
when :index
|
45
|
+
rows.sort! do |lrow, rrow|
|
46
|
+
if lrow.respond_to?(:<=>)
|
47
|
+
lrow.value <=> rrow.value
|
48
|
+
elsif lrow.respond_to?(:first) && rrow.respond_to?(:first) && lrow.first.respond_to?(:<=>)
|
49
|
+
lrow.first.value <=> rrow.first.value
|
50
|
+
else
|
51
|
+
lrow.value.to_s <=> rrow.value.to_s
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
if @options[:limit]
|
56
|
+
rows.slice!(@options[:limit], rows.length)
|
57
|
+
end
|
58
|
+
rows
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/sunspot/search.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
%w(
|
1
|
+
%w(query_facet field_facet date_facet facet_row hit
|
2
|
+
highlight).each do |file|
|
2
3
|
require File.join(File.dirname(__FILE__), 'search', file)
|
3
4
|
end
|
4
5
|
|
@@ -19,6 +20,7 @@ module Sunspot
|
|
19
20
|
def initialize(connection, setup, query, configuration) #:nodoc:
|
20
21
|
@connection, @setup, @query = connection, setup, query
|
21
22
|
@query.paginate(1, configuration.pagination.default_per_page)
|
23
|
+
@facets = {}
|
22
24
|
end
|
23
25
|
|
24
26
|
#
|
@@ -86,17 +88,7 @@ module Sunspot
|
|
86
88
|
# Sunspot::Facet object.
|
87
89
|
#
|
88
90
|
def facet(name)
|
89
|
-
|
90
|
-
begin
|
91
|
-
facet_data = query_facet_data(name) ||
|
92
|
-
begin
|
93
|
-
field = field(name)
|
94
|
-
date_facet_data(field) ||
|
95
|
-
FacetData::FieldFacetData.new(@solr_result['facet_counts']['facet_fields'][field.indexed_name], field)
|
96
|
-
end
|
97
|
-
facet_class = facet_data.reference ? InstantiatedFacet : Facet
|
98
|
-
facet_class.new(facet_data)
|
99
|
-
end
|
91
|
+
@facets[name]
|
100
92
|
end
|
101
93
|
|
102
94
|
#
|
@@ -126,11 +118,7 @@ module Sunspot
|
|
126
118
|
# #=> Facet for the dynamic field :cuisine in the :custom field definition
|
127
119
|
#
|
128
120
|
def dynamic_facet(base_name, dynamic_name)
|
129
|
-
(
|
130
|
-
begin
|
131
|
-
field = @setup.dynamic_field_factory(base_name).build(dynamic_name)
|
132
|
-
Facet.new(FacetData::FieldFacetData.new(@solr_result['facet_counts']['facet_fields'][field.indexed_name], field))
|
133
|
-
end
|
121
|
+
facet(:"#{base_name}:#{dynamic_name}")
|
134
122
|
end
|
135
123
|
|
136
124
|
#
|
@@ -188,6 +176,22 @@ module Sunspot
|
|
188
176
|
"<Sunspot::Search:#{query.to_params.inspect}>"
|
189
177
|
end
|
190
178
|
|
179
|
+
def add_field_facet(field, options = {}) #:nodoc:
|
180
|
+
@facets[field.name] = FieldFacet.new(field, self, options)
|
181
|
+
end
|
182
|
+
|
183
|
+
def add_date_facet(field, options) #:nodoc:
|
184
|
+
@facets[field.name] = DateFacet.new(field, self, options)
|
185
|
+
end
|
186
|
+
|
187
|
+
def add_query_facet(name, options) #:nodoc:
|
188
|
+
@facets[name] = QueryFacet.new(name, self, options)
|
189
|
+
end
|
190
|
+
|
191
|
+
def facet_response #:nodoc:
|
192
|
+
@solr_result['facet_counts']
|
193
|
+
end
|
194
|
+
|
191
195
|
private
|
192
196
|
|
193
197
|
def solr_response
|
@@ -198,41 +202,15 @@ module Sunspot
|
|
198
202
|
DSL::Search.new(self, @setup)
|
199
203
|
end
|
200
204
|
|
201
|
-
def date_facet_data(field)
|
202
|
-
if field.type == Type::TimeType
|
203
|
-
if @solr_result['facet_counts'].has_key?('facet_dates')
|
204
|
-
if facet_result = @solr_result['facet_counts']['facet_dates'][field.indexed_name]
|
205
|
-
FacetData::DateFacetData.new(facet_result, field)
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
def query_facet_data(name)
|
212
|
-
if query_facet = @query.query_facet(name.to_sym)
|
213
|
-
if @solr_result['facet_counts'].has_key?('facet_queries')
|
214
|
-
FacetData::QueryFacetData.new(
|
215
|
-
query_facet,
|
216
|
-
@solr_result['facet_counts']['facet_queries']
|
217
|
-
)
|
218
|
-
end
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
205
|
def highlights_for(doc)
|
223
206
|
if @solr_result['highlighting']
|
224
207
|
@solr_result['highlighting'][doc['id']]
|
225
208
|
end
|
226
209
|
end
|
227
|
-
|
228
|
-
def field(name)
|
229
|
-
@setup.field(name)
|
230
|
-
end
|
231
210
|
|
232
211
|
# Clear out all the cached ivars so the search can be called again.
|
233
212
|
def reset
|
234
|
-
@results = @hits = @total = @
|
235
|
-
@dynamic_facets_cache = @solr_response = @doc_ids = nil
|
213
|
+
@results = @hits = @total = @solr_response = @doc_ids = nil
|
236
214
|
end
|
237
215
|
end
|
238
216
|
end
|