outoftime-sunspot 0.8.9 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +13 -21
- data/Rakefile +0 -2
- data/TODO +2 -15
- data/VERSION.yml +2 -2
- data/bin/sunspot-configure-solr +46 -0
- data/bin/sunspot-solr +15 -7
- data/lib/sunspot/adapters.rb +5 -1
- data/lib/sunspot/composite_setup.rb +186 -0
- data/lib/sunspot/configuration.rb +7 -1
- data/lib/sunspot/data_extractor.rb +10 -0
- data/lib/sunspot/date_facet.rb +36 -0
- data/lib/sunspot/date_facet_row.rb +17 -0
- data/lib/sunspot/dsl/field_query.rb +72 -0
- data/lib/sunspot/dsl/fields.rb +30 -3
- data/lib/sunspot/dsl/query.rb +16 -35
- data/lib/sunspot/dsl/query_facet.rb +31 -0
- data/lib/sunspot/dsl/scope.rb +76 -20
- data/lib/sunspot/dsl/search.rb +30 -0
- data/lib/sunspot/dsl.rb +1 -1
- data/lib/sunspot/facet.rb +17 -3
- data/lib/sunspot/facet_row.rb +4 -4
- data/lib/sunspot/field.rb +130 -207
- data/lib/sunspot/field_factory.rb +126 -0
- data/lib/sunspot/indexer.rb +61 -14
- data/lib/sunspot/instantiated_facet.rb +38 -0
- data/lib/sunspot/instantiated_facet_row.rb +12 -0
- data/lib/sunspot/query/base_query.rb +90 -0
- data/lib/sunspot/query/connective.rb +77 -0
- data/lib/sunspot/query/dynamic_query.rb +39 -56
- data/lib/sunspot/query/field_facet.rb +132 -4
- data/lib/sunspot/query/field_query.rb +57 -0
- data/lib/sunspot/query/pagination.rb +1 -1
- data/lib/sunspot/query/query_facet.rb +72 -0
- data/lib/sunspot/query/query_facet_row.rb +19 -0
- data/lib/sunspot/query/restriction.rb +9 -7
- data/lib/sunspot/query/scope.rb +165 -0
- data/lib/sunspot/query/sort.rb +17 -14
- data/lib/sunspot/query/sort_composite.rb +33 -0
- data/lib/sunspot/query.rb +162 -351
- data/lib/sunspot/query_facet.rb +33 -0
- data/lib/sunspot/query_facet_row.rb +21 -0
- data/lib/sunspot/schema.rb +165 -0
- data/lib/sunspot/search/hit.rb +62 -0
- data/lib/sunspot/search.rb +104 -41
- data/lib/sunspot/session.rb +64 -32
- data/lib/sunspot/setup.rb +119 -48
- data/lib/sunspot/type.rb +48 -2
- data/lib/sunspot.rb +74 -8
- data/solr/solr/conf/schema.xml +44 -225
- data/spec/api/build_search_spec.rb +557 -63
- data/spec/api/indexer_spec.rb +156 -74
- data/spec/api/query_spec.rb +55 -31
- data/spec/api/search_retrieval_spec.rb +210 -33
- data/spec/api/session_spec.rb +81 -26
- data/spec/api/sunspot_spec.rb +5 -7
- data/spec/integration/faceting_spec.rb +130 -0
- data/spec/integration/keyword_search_spec.rb +72 -31
- data/spec/integration/scoped_search_spec.rb +13 -0
- data/spec/integration/stored_fields_spec.rb +10 -0
- data/spec/mocks/blog.rb +3 -0
- data/spec/mocks/comment.rb +12 -23
- data/spec/mocks/connection.rb +84 -0
- data/spec/mocks/mock_adapter.rb +11 -3
- data/spec/mocks/mock_record.rb +41 -0
- data/spec/mocks/photo.rb +8 -0
- data/spec/mocks/post.rb +18 -23
- data/spec/spec_helper.rb +29 -14
- data/tasks/gemspec.rake +4 -3
- data/tasks/rdoc.rake +2 -2
- data/tasks/schema.rake +19 -0
- data/templates/schema.xml.haml +24 -0
- metadata +48 -7
- data/spec/mocks/base_class.rb +0 -2
@@ -0,0 +1,165 @@
|
|
1
|
+
using_rubygems = false
|
2
|
+
begin
|
3
|
+
require 'haml'
|
4
|
+
rescue LoadError => e
|
5
|
+
if using_rubygems
|
6
|
+
raise(e)
|
7
|
+
else
|
8
|
+
using_rubygems = true
|
9
|
+
require 'rubygems'
|
10
|
+
retry
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Sunspot
|
15
|
+
#
|
16
|
+
# Object that encapsulates schema information for building a Solr schema.xml
|
17
|
+
# file. This class is used by the schema:compile task as well as the
|
18
|
+
# sunspot-configure-solr executable.
|
19
|
+
#
|
20
|
+
class Schema #:nodoc:all
|
21
|
+
FieldType = Struct.new(:name, :class_name, :suffix)
|
22
|
+
FieldVariant = Struct.new(:attribute, :suffix)
|
23
|
+
|
24
|
+
DEFAULT_TOKENIZER = 'solr.StandardTokenizerFactory'
|
25
|
+
DEFAULT_FILTERS = %w(solr.StandardFilterFactory solr.LowerCaseFilterFactory)
|
26
|
+
|
27
|
+
FIELD_TYPES = [
|
28
|
+
FieldType.new('boolean', 'Bool', 'b'),
|
29
|
+
FieldType.new('sfloat', 'SortableFloat', 'f'),
|
30
|
+
FieldType.new('date', 'Date', 'd'),
|
31
|
+
FieldType.new('sint', 'SortableInt', 'i'),
|
32
|
+
FieldType.new('string', 'Str', 's')
|
33
|
+
]
|
34
|
+
|
35
|
+
FIELD_VARIANTS = [
|
36
|
+
FieldVariant.new('multiValued', 'm'),
|
37
|
+
FieldVariant.new('stored', 's')
|
38
|
+
]
|
39
|
+
|
40
|
+
attr_reader :tokenizer, :filters
|
41
|
+
|
42
|
+
def initialize
|
43
|
+
@tokenizer = DEFAULT_TOKENIZER
|
44
|
+
@filters = DEFAULT_FILTERS.dup
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Attribute field types defined in the schema
|
49
|
+
#
|
50
|
+
def types
|
51
|
+
FIELD_TYPES
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# DynamicField instances representing all the available types and variants
|
56
|
+
#
|
57
|
+
def dynamic_fields
|
58
|
+
fields = []
|
59
|
+
for field_variants in variant_combinations
|
60
|
+
for type in FIELD_TYPES
|
61
|
+
fields << DynamicField.new(type, field_variants)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
fields
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Which tokenizer to use for text fields
|
69
|
+
#
|
70
|
+
def tokenizer=(tokenizer)
|
71
|
+
@tokenizer =
|
72
|
+
if tokenizer =~ /\./
|
73
|
+
tokenizer
|
74
|
+
else
|
75
|
+
"solr.#{tokenizer}TokenizerFactory"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# Add a filter for text field tokenization
|
81
|
+
#
|
82
|
+
def add_filter(filter)
|
83
|
+
@filters <<
|
84
|
+
if filter =~ /\./
|
85
|
+
filter
|
86
|
+
else
|
87
|
+
"solr.#{filter}FilterFactory"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
# Return an XML representation of this schema using the Haml template
|
93
|
+
#
|
94
|
+
def to_xml
|
95
|
+
template = File.read(
|
96
|
+
File.join(
|
97
|
+
File.dirname(__FILE__),
|
98
|
+
'..',
|
99
|
+
'..',
|
100
|
+
'templates',
|
101
|
+
'schema.xml.haml'
|
102
|
+
)
|
103
|
+
)
|
104
|
+
engine = Haml::Engine.new(template)
|
105
|
+
engine.render(Object.new, :schema => self)
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
#
|
111
|
+
# All of the possible combinations of variants
|
112
|
+
#
|
113
|
+
def variant_combinations
|
114
|
+
combinations = []
|
115
|
+
0.upto(2 ** FIELD_VARIANTS.length - 1) do |b|
|
116
|
+
combinations << combination = []
|
117
|
+
FIELD_VARIANTS.each_with_index do |variant, i|
|
118
|
+
combination << variant if b & 1<<i > 0
|
119
|
+
end
|
120
|
+
end
|
121
|
+
combinations
|
122
|
+
end
|
123
|
+
|
124
|
+
#
|
125
|
+
# Represents a dynamic field (in the Solr schema sense, not the Sunspot
|
126
|
+
# sense).
|
127
|
+
#
|
128
|
+
class DynamicField
|
129
|
+
def initialize(type, field_variants)
|
130
|
+
@type, @field_variants = type, field_variants
|
131
|
+
end
|
132
|
+
|
133
|
+
#
|
134
|
+
# Name of the field in the schema
|
135
|
+
#
|
136
|
+
def name
|
137
|
+
variant_suffixes = @field_variants.map { |variant| variant.suffix }.join
|
138
|
+
"*_#{@type.suffix}#{variant_suffixes}"
|
139
|
+
end
|
140
|
+
|
141
|
+
#
|
142
|
+
# Name of the type as defined in the schema
|
143
|
+
#
|
144
|
+
def type
|
145
|
+
@type.name
|
146
|
+
end
|
147
|
+
|
148
|
+
#
|
149
|
+
# Implement magic methods to ask if a field is of a particular variant.
|
150
|
+
# Returns "true" if the field is of that variant and "false" otherwise.
|
151
|
+
#
|
152
|
+
def method_missing(name, *args, &block)
|
153
|
+
if name.to_s =~ /\?$/ && args.empty?
|
154
|
+
if @field_variants.any? { |variant| "#{variant.attribute}?" == name.to_s }
|
155
|
+
'true'
|
156
|
+
else
|
157
|
+
'false'
|
158
|
+
end
|
159
|
+
else
|
160
|
+
super(name.to_sym, *args, &block)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Sunspot
|
2
|
+
class Search
|
3
|
+
class Hit
|
4
|
+
SPECIAL_KEYS = Set.new(%w(id type score)) #:nodoc:
|
5
|
+
|
6
|
+
#
|
7
|
+
# Primary key of object associated with this hit, as string.
|
8
|
+
#
|
9
|
+
attr_reader :primary_key
|
10
|
+
#
|
11
|
+
# Class name of object associated with this hit, as string.
|
12
|
+
#
|
13
|
+
attr_reader :class_name
|
14
|
+
#
|
15
|
+
# Keyword relevance score associated with this result. Nil if this hit
|
16
|
+
# is not from a keyword search.
|
17
|
+
#
|
18
|
+
attr_reader :score
|
19
|
+
|
20
|
+
attr_writer :instance #:nodoc:
|
21
|
+
|
22
|
+
def initialize(raw_hit, search) #:nodoc:
|
23
|
+
@class_name, @primary_key = *raw_hit['id'].match(/([^ ]+) (.+)/)[1..2]
|
24
|
+
@score = raw_hit['score']
|
25
|
+
@search = search
|
26
|
+
@stored_values = raw_hit
|
27
|
+
@stored_cache = {}
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# Retrieve stored field value. For any attribute field configured with
|
32
|
+
# :stored => true, the Hit object will contain the stored value for
|
33
|
+
# that field. The value of this field will be typecast according to the
|
34
|
+
# type of the field.
|
35
|
+
#
|
36
|
+
# ==== Parameters
|
37
|
+
#
|
38
|
+
# field_name<Symbol>::
|
39
|
+
# The name of the field for which to retrieve the stored value.
|
40
|
+
#
|
41
|
+
def stored(field_name)
|
42
|
+
@stored_cache[field_name.to_sym] ||=
|
43
|
+
begin
|
44
|
+
field = Sunspot::Setup.for(@class_name).field(field_name)
|
45
|
+
field.cast(@stored_values[field.indexed_name])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# Retrieve the instance associated with this hit. This is lazy-loaded, but
|
51
|
+
# the first time it is called on any hit, all the hits for the search will
|
52
|
+
# load their instances using the adapter's #load_all method.
|
53
|
+
#
|
54
|
+
def instance
|
55
|
+
if @instance.nil?
|
56
|
+
@search.populate_hits!
|
57
|
+
end
|
58
|
+
@instance
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/sunspot/search.rb
CHANGED
@@ -1,22 +1,21 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'search', 'hit')
|
2
|
+
|
1
3
|
module Sunspot
|
2
4
|
#
|
3
5
|
# This class encapsulates the results of a Solr search. It provides access
|
4
6
|
# to search results, total result count, facets, and pagination information.
|
5
|
-
# Instances of Search are returned by the Sunspot.search
|
7
|
+
# Instances of Search are returned by the Sunspot.search and
|
8
|
+
# Sunspot.new_search methods.
|
6
9
|
#
|
7
10
|
class Search
|
8
|
-
# Objects of this class are returned by the #raw_results method.
|
9
|
-
RawResult = Struct.new(:class_name, :primary_key)
|
10
|
-
|
11
11
|
# Query information for this search. If you wish to build the query without
|
12
12
|
# using the search DSL, this method allows you to access the query API
|
13
13
|
# directly. See Sunspot#new_search for how to construct the search object
|
14
14
|
# in this case.
|
15
15
|
attr_reader :query
|
16
16
|
|
17
|
-
def initialize(connection, query) #:nodoc:
|
18
|
-
@connection = connection
|
19
|
-
@query = query
|
17
|
+
def initialize(connection, setup, query) #:nodoc:
|
18
|
+
@connection, @setup, @query = connection, setup, query
|
20
19
|
end
|
21
20
|
|
22
21
|
#
|
@@ -28,7 +27,7 @@ module Sunspot
|
|
28
27
|
#
|
29
28
|
def execute!
|
30
29
|
params = @query.to_params
|
31
|
-
@solr_result = @connection.
|
30
|
+
@solr_result = @connection.select(params)
|
32
31
|
self
|
33
32
|
end
|
34
33
|
|
@@ -43,27 +42,27 @@ module Sunspot
|
|
43
42
|
#
|
44
43
|
def results
|
45
44
|
@results ||= if @query.page && defined?(WillPaginate::Collection)
|
46
|
-
WillPaginate::Collection.create(@query.page, @query.per_page,
|
47
|
-
pager.replace(
|
45
|
+
WillPaginate::Collection.create(@query.page, @query.per_page, total) do |pager|
|
46
|
+
pager.replace(hits.map { |hit| hit.instance })
|
48
47
|
end
|
49
48
|
else
|
50
|
-
|
49
|
+
hits.map { |hit| hit.instance }
|
51
50
|
end
|
52
51
|
end
|
53
52
|
|
54
53
|
#
|
55
|
-
# Access raw
|
56
|
-
#
|
57
|
-
#
|
58
|
-
# #class_name and #primary_key
|
54
|
+
# Access raw Solr result information. Returns a collection of Hit objects
|
55
|
+
# that contain the class name, primary key, keyword relevance score (if
|
56
|
+
# applicable), and any stored fields.
|
59
57
|
#
|
60
58
|
# ==== Returns
|
61
59
|
#
|
62
|
-
# Array:: Ordered collection of
|
60
|
+
# Array:: Ordered collection of Hit objects
|
63
61
|
#
|
64
|
-
def
|
65
|
-
@
|
62
|
+
def hits
|
63
|
+
@hits ||= solr_response['docs'].map { |doc| Hit.new(doc, self) }
|
66
64
|
end
|
65
|
+
alias_method :raw_results, :hits
|
67
66
|
|
68
67
|
#
|
69
68
|
# The total number of documents matching the query parameters
|
@@ -73,7 +72,7 @@ module Sunspot
|
|
73
72
|
# Integer:: Total matching documents
|
74
73
|
#
|
75
74
|
def total
|
76
|
-
@total ||=
|
75
|
+
@total ||= solr_response['numFound']
|
77
76
|
end
|
78
77
|
|
79
78
|
#
|
@@ -91,8 +90,15 @@ module Sunspot
|
|
91
90
|
def facet(field_name)
|
92
91
|
(@facets_cache ||= {})[field_name.to_sym] ||=
|
93
92
|
begin
|
94
|
-
|
95
|
-
|
93
|
+
query_facet(field_name) ||
|
94
|
+
begin
|
95
|
+
field = field(field_name)
|
96
|
+
date_facet(field) ||
|
97
|
+
begin
|
98
|
+
facet_class = field.reference ? InstantiatedFacet : Facet
|
99
|
+
facet_class.new(@solr_result['facet_counts']['facet_fields'][field.indexed_name], field)
|
100
|
+
end
|
101
|
+
end
|
96
102
|
end
|
97
103
|
end
|
98
104
|
|
@@ -125,35 +131,92 @@ module Sunspot
|
|
125
131
|
def dynamic_facet(base_name, dynamic_name)
|
126
132
|
(@dynamic_facets_cache ||= {})[[base_name.to_sym, dynamic_name.to_sym]] ||=
|
127
133
|
begin
|
128
|
-
field = @
|
129
|
-
Facet.new(@solr_result
|
134
|
+
field = @setup.dynamic_field_factory(base_name).build(dynamic_name)
|
135
|
+
Facet.new(@solr_result['facet_counts']['facet_fields'][field.indexed_name], field)
|
130
136
|
end
|
131
137
|
end
|
132
138
|
|
133
|
-
|
139
|
+
#
|
140
|
+
# Get the data accessor that will be used to load a particular class out of
|
141
|
+
# persistent storage. Data accessors can implement any methods that may be
|
142
|
+
# useful for refining how data is loaded out of storage. When building a
|
143
|
+
# search manually (e.g., using the Sunspot#new_search method), this should
|
144
|
+
# be used before calling #execute(). Use the
|
145
|
+
# Sunspot::DSL::Search#data_accessor_for method when building searches using
|
146
|
+
# the block DSL.
|
147
|
+
#
|
148
|
+
def data_accessor_for(clazz)
|
149
|
+
(@data_accessors ||= {})[clazz.name.to_sym] ||=
|
150
|
+
Adapters::DataAccessor.create(clazz)
|
151
|
+
end
|
134
152
|
|
135
153
|
#
|
136
|
-
#
|
137
|
-
# returned by Solr.
|
138
|
-
#
|
139
|
-
# ==== Returns
|
154
|
+
# Build this search using a DSL block.
|
140
155
|
#
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
156
|
+
def build(&block) #:nodoc:
|
157
|
+
Util.instance_eval_or_call(dsl, &block)
|
158
|
+
self
|
159
|
+
end
|
160
|
+
|
161
|
+
def populate_hits! #:nodoc:
|
162
|
+
type_hit_hash = Hash.new { |h, k| h[k] = [] }
|
163
|
+
id_hit_hash = {}
|
164
|
+
for hit in hits
|
165
|
+
type_hit_hash[hit.class_name] << hit
|
166
|
+
id_hit_hash[hit.primary_key] = hit
|
167
|
+
end
|
168
|
+
type_hit_hash.each_pair do |class_name, hits|
|
169
|
+
ids = hits.map { |hit| hit.primary_key }
|
170
|
+
for instance in data_accessor_for(Util.full_const_get(class_name)).load_all(ids)
|
171
|
+
hit = id_hit_hash[Adapters::InstanceAdapter.adapt(instance).id.to_s]
|
172
|
+
hit.instance = instance
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
private
|
178
|
+
|
179
|
+
def solr_response
|
180
|
+
@solr_response ||= @solr_result['response']
|
181
|
+
end
|
182
|
+
|
183
|
+
def doc_ids
|
184
|
+
@doc_ids ||= solr_response['docs'].map { |doc| doc['id'] }
|
185
|
+
end
|
186
|
+
|
187
|
+
def dsl
|
188
|
+
DSL::Search.new(self)
|
189
|
+
end
|
190
|
+
|
191
|
+
def raw_facet(field)
|
192
|
+
if field.type == Type::TimeType
|
193
|
+
@solr_result['facet_counts']['facet_dates'][field.indexed_name]
|
194
|
+
end || @solr_result['facet_counts']['facet_fields'][field.indexed_name]
|
195
|
+
end
|
196
|
+
|
197
|
+
def date_facet(field)
|
198
|
+
if field.type == Type::TimeType
|
199
|
+
if @solr_result['facet_counts'].has_key?('facet_dates')
|
200
|
+
if facet_result = @solr_result['facet_counts']['facet_dates'][field.indexed_name]
|
201
|
+
DateFacet.new(facet_result, field)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def query_facet(name)
|
208
|
+
if query_facet = @query.query_facet(name.to_sym)
|
209
|
+
if @solr_result['facet_counts'].has_key?('facet_queries')
|
210
|
+
QueryFacet.new(
|
211
|
+
query_facet,
|
212
|
+
@solr_result['facet_counts']['facet_queries']
|
213
|
+
)
|
214
|
+
end
|
152
215
|
end
|
153
216
|
end
|
154
217
|
|
155
|
-
def
|
156
|
-
@
|
218
|
+
def field(name)
|
219
|
+
@setup.field(name)
|
157
220
|
end
|
158
221
|
end
|
159
222
|
end
|
data/lib/sunspot/session.rb
CHANGED
@@ -8,6 +8,20 @@ module Sunspot
|
|
8
8
|
# again here.
|
9
9
|
#
|
10
10
|
class Session
|
11
|
+
class <<self
|
12
|
+
attr_writer :connection_class #:nodoc:
|
13
|
+
|
14
|
+
#
|
15
|
+
# For testing purposes
|
16
|
+
#
|
17
|
+
def connection_class #:nodoc:
|
18
|
+
@connection_class ||= RSolr::Connection
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Sunspot::Configuration object for this session
|
24
|
+
#
|
11
25
|
attr_reader :config
|
12
26
|
|
13
27
|
#
|
@@ -27,7 +41,13 @@ module Sunspot
|
|
27
41
|
#
|
28
42
|
def new_search(*types)
|
29
43
|
types.flatten!
|
30
|
-
|
44
|
+
setup =
|
45
|
+
if types.length == 1
|
46
|
+
Setup.for(types.first)
|
47
|
+
else
|
48
|
+
CompositeSetup.for(types)
|
49
|
+
end
|
50
|
+
Search.new(connection, setup, Query::Query.new(setup, @config))
|
31
51
|
end
|
32
52
|
|
33
53
|
#
|
@@ -36,7 +56,7 @@ module Sunspot
|
|
36
56
|
def search(*types, &block)
|
37
57
|
options = types.last.is_a?(Hash) ? types.pop : {}
|
38
58
|
search = new_search(*types)
|
39
|
-
search.
|
59
|
+
search.build(&block) if block
|
40
60
|
search.query.options = options
|
41
61
|
search.execute!
|
42
62
|
end
|
@@ -44,20 +64,10 @@ module Sunspot
|
|
44
64
|
#
|
45
65
|
# See Sunspot.index
|
46
66
|
#
|
47
|
-
#--
|
48
|
-
# FIXME The fact that we have to break this out by class and index each
|
49
|
-
# class separately is artificial, imposed by the fact that indexers
|
50
|
-
# are initialized with a particular setup, and are responsible for
|
51
|
-
# sending add messages to Solr. It might be worth considering a
|
52
|
-
# singleton indexer (per session) and have the indexer itself find
|
53
|
-
# the appropriate setup to use for each object.
|
54
|
-
#
|
55
67
|
def index(*objects)
|
56
68
|
objects.flatten!
|
57
69
|
@updates += objects.length
|
58
|
-
objects
|
59
|
-
indexer_for(objs.first).add(objs)
|
60
|
-
end
|
70
|
+
indexer.add(objects)
|
61
71
|
end
|
62
72
|
|
63
73
|
#
|
@@ -83,7 +93,7 @@ module Sunspot
|
|
83
93
|
objects.flatten!
|
84
94
|
@updates += objects.length
|
85
95
|
for object in objects
|
86
|
-
|
96
|
+
indexer.remove(object)
|
87
97
|
end
|
88
98
|
end
|
89
99
|
|
@@ -95,6 +105,27 @@ module Sunspot
|
|
95
105
|
commit
|
96
106
|
end
|
97
107
|
|
108
|
+
#
|
109
|
+
# See Sunspot.remove_by_id
|
110
|
+
#
|
111
|
+
def remove_by_id(clazz, id)
|
112
|
+
class_name =
|
113
|
+
if clazz.is_a?(Class)
|
114
|
+
clazz.name
|
115
|
+
else
|
116
|
+
clazz.to_s
|
117
|
+
end
|
118
|
+
indexer.remove_by_id(class_name, id)
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# See Sunspot.remove_by_id!
|
123
|
+
#
|
124
|
+
def remove_by_id!(clazz, id)
|
125
|
+
remove_by_id(clazz, id)
|
126
|
+
commit
|
127
|
+
end
|
128
|
+
|
98
129
|
#
|
99
130
|
# See Sunspot.remove_all
|
100
131
|
#
|
@@ -106,7 +137,7 @@ module Sunspot
|
|
106
137
|
else
|
107
138
|
@updates += classes.length
|
108
139
|
for clazz in classes
|
109
|
-
|
140
|
+
indexer.remove_all(clazz)
|
110
141
|
end
|
111
142
|
end
|
112
143
|
end
|
@@ -133,26 +164,16 @@ module Sunspot
|
|
133
164
|
commit if dirty?
|
134
165
|
end
|
135
166
|
|
136
|
-
private
|
137
|
-
|
138
167
|
#
|
139
|
-
#
|
140
|
-
#
|
141
|
-
# ==== Parameters
|
142
|
-
#
|
143
|
-
# object<Object>:: The object whose setup is to be retrieved
|
144
|
-
#
|
145
|
-
# ==== Returns
|
146
|
-
#
|
147
|
-
# Sunspot::Setup:: The setup for the object's class
|
168
|
+
# See Sunspot.batch
|
148
169
|
#
|
149
|
-
def
|
150
|
-
|
170
|
+
def batch
|
171
|
+
indexer.start_batch
|
172
|
+
yield
|
173
|
+
indexer.flush_batch
|
151
174
|
end
|
152
175
|
|
153
|
-
|
154
|
-
setup_for(object).indexer(connection)
|
155
|
-
end
|
176
|
+
private
|
156
177
|
|
157
178
|
#
|
158
179
|
# Retrieve the Solr connection for this session, creating one if it does not
|
@@ -163,7 +184,18 @@ module Sunspot
|
|
163
184
|
# Solr::Connection:: The connection for this session
|
164
185
|
#
|
165
186
|
def connection
|
166
|
-
@connection ||=
|
187
|
+
@connection ||=
|
188
|
+
begin
|
189
|
+
connection = self.class.connection_class.new(
|
190
|
+
RSolr::Adapter::HTTP.new(:url => config.solr.url)
|
191
|
+
)
|
192
|
+
connection.adapter.connector.adapter_name = config.http_client
|
193
|
+
connection
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def indexer
|
198
|
+
@indexer ||= Indexer.new(connection)
|
167
199
|
end
|
168
200
|
end
|
169
201
|
end
|