dpickett-thinking-sphinx 1.1.12 → 1.1.23
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +19 -0
- data/lib/thinking_sphinx.rb +36 -2
- data/lib/thinking_sphinx/active_record.rb +18 -3
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +9 -3
- data/lib/thinking_sphinx/association.rb +4 -1
- data/lib/thinking_sphinx/attribute.rb +85 -43
- data/lib/thinking_sphinx/configuration.rb +33 -12
- data/lib/thinking_sphinx/deltas.rb +9 -6
- data/lib/thinking_sphinx/deltas/datetime_delta.rb +3 -3
- data/lib/thinking_sphinx/deltas/default_delta.rb +4 -4
- data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +1 -1
- data/lib/thinking_sphinx/deploy/capistrano.rb +82 -64
- data/lib/thinking_sphinx/facet.rb +58 -21
- data/lib/thinking_sphinx/facet_collection.rb +12 -13
- data/lib/thinking_sphinx/field.rb +3 -1
- data/lib/thinking_sphinx/index.rb +28 -353
- data/lib/thinking_sphinx/index/builder.rb +255 -232
- data/lib/thinking_sphinx/property.rb +29 -2
- data/lib/thinking_sphinx/search.rb +32 -96
- data/lib/thinking_sphinx/search/facets.rb +104 -0
- data/lib/thinking_sphinx/source.rb +150 -0
- data/lib/thinking_sphinx/source/internal_properties.rb +46 -0
- data/lib/thinking_sphinx/source/sql.rb +128 -0
- data/lib/thinking_sphinx/tasks.rb +42 -8
- data/rails/init.rb +14 -0
- data/spec/unit/thinking_sphinx/active_record/delta_spec.rb +5 -5
- data/spec/unit/thinking_sphinx/active_record/search_spec.rb +4 -4
- data/spec/unit/thinking_sphinx/active_record_spec.rb +52 -39
- data/spec/unit/thinking_sphinx/association_spec.rb +4 -5
- data/spec/unit/thinking_sphinx/attribute_spec.rb +209 -19
- data/spec/unit/thinking_sphinx/collection_spec.rb +7 -6
- data/spec/unit/thinking_sphinx/configuration_spec.rb +93 -7
- data/spec/unit/thinking_sphinx/facet_spec.rb +256 -0
- data/spec/unit/thinking_sphinx/field_spec.rb +26 -17
- data/spec/unit/thinking_sphinx/index/builder_spec.rb +351 -1
- data/spec/unit/thinking_sphinx/index_spec.rb +3 -102
- data/spec/unit/thinking_sphinx/rails_additions_spec.rb +13 -5
- data/spec/unit/thinking_sphinx/search_spec.rb +154 -29
- data/spec/unit/thinking_sphinx/source_spec.rb +217 -0
- data/spec/unit/thinking_sphinx_spec.rb +22 -4
- data/tasks/distribution.rb +19 -0
- data/vendor/riddle/lib/riddle.rb +1 -1
- data/vendor/riddle/lib/riddle/configuration/section.rb +7 -1
- metadata +26 -3
data/README.textile
CHANGED
@@ -25,11 +25,18 @@ Then install the ginger gem. The steps are the same, except that you might need
|
|
25
25
|
cd ginger
|
26
26
|
rake gem
|
27
27
|
sudo gem install pkg/ginger-1.1.0.gem
|
28
|
+
|
29
|
+
Alternatively, install the ginger gem directly from the freelancing-god github repository
|
30
|
+
|
31
|
+
sudo gem sources -a http://gems.github.com
|
32
|
+
sudo gem install freelancing-god-ginger
|
28
33
|
|
29
34
|
Then set up your database:
|
30
35
|
|
31
36
|
cp spec/fixtures/database.yml.default spec/fixtures/database.yml
|
32
37
|
mysqladmin -u root create thinking_sphinx
|
38
|
+
|
39
|
+
This last step can be done automatically by the contribute.rb script if all dependencies are met.
|
33
40
|
|
34
41
|
Make sure you don't have another Sphinx daemon (searchd) running. If you do, quit it with "rake ts:stop"
|
35
42
|
in the app root.
|
@@ -124,3 +131,15 @@ Since I first released this library, there's been quite a few people who have su
|
|
124
131
|
* Mark Lane
|
125
132
|
* Eric Lindvall
|
126
133
|
* Lawrence Pit
|
134
|
+
* Mike Bailey
|
135
|
+
* Bill Leeper
|
136
|
+
* Michael Reinsch
|
137
|
+
* Anderson Dias
|
138
|
+
* Jerome Riga
|
139
|
+
* Tien Dung
|
140
|
+
* Johannes Kaefer
|
141
|
+
* Paul Campbell
|
142
|
+
* Matthew Beale
|
143
|
+
* Tom Simnett
|
144
|
+
* Erik Ostrom
|
145
|
+
* Ole Riesenberg
|
data/lib/thinking_sphinx.rb
CHANGED
@@ -18,6 +18,7 @@ require 'thinking_sphinx/class_facet'
|
|
18
18
|
require 'thinking_sphinx/facet_collection'
|
19
19
|
require 'thinking_sphinx/field'
|
20
20
|
require 'thinking_sphinx/index'
|
21
|
+
require 'thinking_sphinx/source'
|
21
22
|
require 'thinking_sphinx/rails_additions'
|
22
23
|
require 'thinking_sphinx/search'
|
23
24
|
require 'thinking_sphinx/deltas'
|
@@ -36,7 +37,7 @@ module ThinkingSphinx
|
|
36
37
|
module Version #:nodoc:
|
37
38
|
Major = 1
|
38
39
|
Minor = 1
|
39
|
-
Tiny =
|
40
|
+
Tiny = 23
|
40
41
|
|
41
42
|
String = [Major, Minor, Tiny].join('.')
|
42
43
|
end
|
@@ -137,7 +138,39 @@ module ThinkingSphinx
|
|
137
138
|
)
|
138
139
|
end
|
139
140
|
|
141
|
+
@@remote_sphinx = false
|
142
|
+
|
143
|
+
# An indication of whether Sphinx is running on a remote machine instead of
|
144
|
+
# the same machine.
|
145
|
+
#
|
146
|
+
def self.remote_sphinx?
|
147
|
+
@@remote_sphinx
|
148
|
+
end
|
149
|
+
|
150
|
+
# Tells Thinking Sphinx that Sphinx is running on a different machine, and
|
151
|
+
# thus it can't reliably guess whether it is running or not (ie: the
|
152
|
+
# #sphinx_running? method), and so just assumes it is.
|
153
|
+
#
|
154
|
+
# Useful for multi-machine deployments. Set it in your production.rb file.
|
155
|
+
#
|
156
|
+
# ThinkingSphinx.remote_sphinx = true
|
157
|
+
#
|
158
|
+
def self.remote_sphinx=(value)
|
159
|
+
@@remote_sphinx = value
|
160
|
+
end
|
161
|
+
|
162
|
+
# Check if Sphinx is running. If remote_sphinx is set to true (indicating
|
163
|
+
# Sphinx is on a different machine), this will always return true, and you
|
164
|
+
# will have to handle any connection errors yourself.
|
165
|
+
#
|
140
166
|
def self.sphinx_running?
|
167
|
+
remote_sphinx? || sphinx_running_by_pid?
|
168
|
+
end
|
169
|
+
|
170
|
+
# Check if Sphinx is actually running, provided the pid is on the same
|
171
|
+
# machine as this code.
|
172
|
+
#
|
173
|
+
def self.sphinx_running_by_pid?
|
141
174
|
!!sphinx_pid && pid_active?(sphinx_pid)
|
142
175
|
end
|
143
176
|
|
@@ -174,7 +207,8 @@ module ThinkingSphinx
|
|
174
207
|
end
|
175
208
|
|
176
209
|
def self.mysql?
|
177
|
-
::ActiveRecord::Base.connection.class.name.demodulize == "MysqlAdapter" ||
|
210
|
+
::ActiveRecord::Base.connection.class.name.demodulize == "MysqlAdapter" ||
|
211
|
+
::ActiveRecord::Base.connection.class.name.demodulize == "MysqlplusAdapter" || (
|
178
212
|
jruby? && ::ActiveRecord::Base.connection.config[:adapter] == "jdbcmysql"
|
179
213
|
)
|
180
214
|
end
|
@@ -66,7 +66,7 @@ module ThinkingSphinx
|
|
66
66
|
return unless ThinkingSphinx.define_indexes?
|
67
67
|
|
68
68
|
self.sphinx_indexes ||= []
|
69
|
-
index = Index.
|
69
|
+
index = ThinkingSphinx::Index::Builder.generate(self, &block)
|
70
70
|
|
71
71
|
self.sphinx_indexes << index
|
72
72
|
unless ThinkingSphinx.indexed_models.include?(self.name)
|
@@ -83,6 +83,17 @@ module ThinkingSphinx
|
|
83
83
|
include ThinkingSphinx::ActiveRecord::AttributeUpdates
|
84
84
|
|
85
85
|
index
|
86
|
+
|
87
|
+
# We want to make sure that if the database doesn't exist, then Thinking
|
88
|
+
# Sphinx doesn't mind when running non-TS tasks (like db:create, db:drop
|
89
|
+
# and db:migrate). It's a bit hacky, but I can't think of a better way.
|
90
|
+
rescue StandardError => err
|
91
|
+
case err.class.name
|
92
|
+
when "Mysql::Error", "Java::JavaSql::SQLException", "ActiveRecord::StatementInvalid"
|
93
|
+
return
|
94
|
+
else
|
95
|
+
raise err
|
96
|
+
end
|
86
97
|
end
|
87
98
|
alias_method :sphinx_index, :define_index
|
88
99
|
|
@@ -151,7 +162,9 @@ module ThinkingSphinx
|
|
151
162
|
self.sphinx_indexes.select { |ts_index|
|
152
163
|
ts_index.model == self
|
153
164
|
}.each_with_index do |ts_index, i|
|
154
|
-
index.sources
|
165
|
+
index.sources += ts_index.sources.collect { |source|
|
166
|
+
source.to_riddle_for_core(offset, i)
|
167
|
+
}
|
155
168
|
end
|
156
169
|
|
157
170
|
index
|
@@ -163,7 +176,9 @@ module ThinkingSphinx
|
|
163
176
|
index.path = File.join(ThinkingSphinx::Configuration.instance.searchd_file_path, index.name)
|
164
177
|
|
165
178
|
self.sphinx_indexes.each_with_index do |ts_index, i|
|
166
|
-
index.sources
|
179
|
+
index.sources += ts_index.sources.collect { |source|
|
180
|
+
source.to_riddle_for_delta(offset, i)
|
181
|
+
} if ts_index.delta?
|
167
182
|
end
|
168
183
|
|
169
184
|
index
|
@@ -11,7 +11,12 @@ module ThinkingSphinx
|
|
11
11
|
|
12
12
|
def concatenate(clause, separator = ' ')
|
13
13
|
clause.split(', ').collect { |field|
|
14
|
-
|
14
|
+
case field
|
15
|
+
when /COALESCE/, "'')"
|
16
|
+
field
|
17
|
+
else
|
18
|
+
"COALESCE(CAST(#{field} as varchar), '')"
|
19
|
+
end
|
15
20
|
}.join(" || '#{separator}' || ")
|
16
21
|
end
|
17
22
|
|
@@ -32,7 +37,8 @@ module ThinkingSphinx
|
|
32
37
|
end
|
33
38
|
|
34
39
|
def convert_nulls(clause, default = '')
|
35
|
-
default = "'#{default}'"
|
40
|
+
default = "'#{default}'" if default.is_a?(String)
|
41
|
+
default = 'NULL' if default.nil?
|
36
42
|
|
37
43
|
"COALESCE(#{clause}, #{default})"
|
38
44
|
end
|
@@ -127,4 +133,4 @@ module ThinkingSphinx
|
|
127
133
|
execute function, true
|
128
134
|
end
|
129
135
|
end
|
130
|
-
end
|
136
|
+
end
|
@@ -103,13 +103,16 @@ module ThinkingSphinx
|
|
103
103
|
if @reflection.options[:through]
|
104
104
|
@reflection.source_reflection.options[:foreign_key] ||
|
105
105
|
@reflection.source_reflection.primary_key_name
|
106
|
+
elsif @reflection.macro == :has_and_belongs_to_many
|
107
|
+
@reflection.association_foreign_key
|
106
108
|
else
|
107
109
|
nil
|
108
110
|
end
|
109
111
|
end
|
110
112
|
|
111
113
|
def table
|
112
|
-
if @reflection.options[:through]
|
114
|
+
if @reflection.options[:through] ||
|
115
|
+
@reflection.macro == :has_and_belongs_to_many
|
113
116
|
@join.aliased_join_table_name
|
114
117
|
else
|
115
118
|
@join.aliased_table_name
|
@@ -9,7 +9,7 @@ module ThinkingSphinx
|
|
9
9
|
# associations. Which can get messy. Use Index.link!, it really helps.
|
10
10
|
#
|
11
11
|
class Attribute < ThinkingSphinx::Property
|
12
|
-
attr_accessor :
|
12
|
+
attr_accessor :query_source
|
13
13
|
|
14
14
|
# To create a new attribute, you'll need to pass in either a single Column
|
15
15
|
# or an array of them, and some (optional) options.
|
@@ -67,15 +67,17 @@ module ThinkingSphinx
|
|
67
67
|
# If you're creating attributes for latitude and longitude, don't forget
|
68
68
|
# that Sphinx expects these values to be in radians.
|
69
69
|
#
|
70
|
-
def initialize(columns, options = {})
|
70
|
+
def initialize(source, columns, options = {})
|
71
71
|
super
|
72
72
|
|
73
|
-
@type
|
74
|
-
@
|
75
|
-
@crc
|
73
|
+
@type = options[:type]
|
74
|
+
@query_source = options[:source]
|
75
|
+
@crc = options[:crc]
|
76
76
|
|
77
|
-
@type
|
78
|
-
@type
|
77
|
+
@type ||= :multi unless @query_source.nil?
|
78
|
+
@type = :integer if @type == :string && @crc
|
79
|
+
|
80
|
+
source.attributes << self
|
79
81
|
end
|
80
82
|
|
81
83
|
# Get the part of the SELECT clause related to this attribute. Don't forget
|
@@ -87,17 +89,17 @@ module ThinkingSphinx
|
|
87
89
|
def to_select_sql
|
88
90
|
return nil unless include_as_association?
|
89
91
|
|
92
|
+
separator = all_ints? || @crc ? ',' : ' '
|
93
|
+
|
90
94
|
clause = @columns.collect { |column|
|
91
|
-
column_with_prefix(column)
|
95
|
+
part = column_with_prefix(column)
|
96
|
+
type == :string ? adapter.convert_nulls(part) : part
|
92
97
|
}.join(', ')
|
93
98
|
|
94
|
-
separator = all_ints? ? ',' : ' '
|
95
|
-
|
96
|
-
clause = adapter.concatenate(clause, separator) if concat_ws?
|
97
|
-
clause = adapter.group_concatenate(clause, separator) if is_many?
|
98
99
|
clause = adapter.cast_to_datetime(clause) if type == :datetime
|
99
|
-
clause = adapter.convert_nulls(clause) if type == :string
|
100
100
|
clause = adapter.crc(clause) if @crc
|
101
|
+
clause = adapter.concatenate(clause, separator) if concat_ws?
|
102
|
+
clause = adapter.group_concatenate(clause, separator) if is_many?
|
101
103
|
|
102
104
|
"#{clause} AS #{quote_column(unique_name)}"
|
103
105
|
end
|
@@ -114,7 +116,7 @@ module ThinkingSphinx
|
|
114
116
|
end
|
115
117
|
|
116
118
|
def include_as_association?
|
117
|
-
! (type == :multi && (
|
119
|
+
! (type == :multi && (query_source == :query || query_source == :ranged_query))
|
118
120
|
end
|
119
121
|
|
120
122
|
# Returns the configuration value that should be used for
|
@@ -122,10 +124,10 @@ module ThinkingSphinx
|
|
122
124
|
# Special case is the multi-valued attribute that needs some
|
123
125
|
# extra configuration.
|
124
126
|
#
|
125
|
-
def config_value(offset = nil)
|
127
|
+
def config_value(offset = nil, delta = false)
|
126
128
|
if type == :multi
|
127
129
|
multi_config = include_as_association? ? "field" :
|
128
|
-
source_value(offset).gsub(/\
|
130
|
+
source_value(offset, delta).gsub(/\s+/m, " ").strip
|
129
131
|
"uint #{unique_name} from #{multi_config}"
|
130
132
|
else
|
131
133
|
unique_name
|
@@ -168,37 +170,65 @@ module ThinkingSphinx
|
|
168
170
|
object.send(column.__name)
|
169
171
|
end
|
170
172
|
|
173
|
+
def all_ints?
|
174
|
+
@columns.all? { |col|
|
175
|
+
klasses = @associations[col].empty? ? [@model] :
|
176
|
+
@associations[col].collect { |assoc| assoc.reflection.klass }
|
177
|
+
klasses.all? { |klass|
|
178
|
+
column = klass.columns.detect { |column| column.name == col.__name.to_s }
|
179
|
+
!column.nil? && column.type == :integer
|
180
|
+
}
|
181
|
+
}
|
182
|
+
end
|
183
|
+
|
171
184
|
private
|
172
185
|
|
173
|
-
def source_value(offset)
|
186
|
+
def source_value(offset, delta)
|
174
187
|
if is_string?
|
175
|
-
"#{
|
176
|
-
|
177
|
-
|
188
|
+
return "#{query_source.to_s.dasherize}; #{columns.first.__name}"
|
189
|
+
end
|
190
|
+
|
191
|
+
query = query(offset)
|
192
|
+
|
193
|
+
if query_source == :ranged_query
|
194
|
+
query += query_clause
|
195
|
+
query += " AND #{query_delta.strip}" if delta
|
196
|
+
"ranged-query; #{query}; #{range_query}"
|
178
197
|
else
|
179
|
-
|
198
|
+
query += "WHERE #{query_delta.strip}" if delta
|
199
|
+
"query; #{query}"
|
180
200
|
end
|
181
201
|
end
|
182
202
|
|
183
203
|
def query(offset)
|
184
|
-
|
185
|
-
|
204
|
+
base_assoc = base_association_for_mva
|
205
|
+
end_assoc = end_association_for_mva
|
206
|
+
raise "Could not determine SQL for MVA" if base_assoc.nil?
|
186
207
|
|
187
208
|
<<-SQL
|
188
|
-
SELECT #{foreign_key_for_mva
|
209
|
+
SELECT #{foreign_key_for_mva base_assoc}
|
189
210
|
#{ThinkingSphinx.unique_id_expression(offset)} AS #{quote_column('id')},
|
190
|
-
#{primary_key_for_mva(
|
191
|
-
FROM #{quote_table_name
|
211
|
+
#{primary_key_for_mva(end_assoc)} AS #{quote_column(unique_name)}
|
212
|
+
FROM #{quote_table_name base_assoc.table} #{association_joins}
|
192
213
|
SQL
|
193
214
|
end
|
194
215
|
|
195
216
|
def query_clause
|
196
|
-
foreign_key = foreign_key_for_mva
|
217
|
+
foreign_key = foreign_key_for_mva base_association_for_mva
|
197
218
|
"WHERE #{foreign_key} >= $start AND #{foreign_key} <= $end"
|
198
219
|
end
|
199
220
|
|
221
|
+
def query_delta
|
222
|
+
foreign_key = foreign_key_for_mva base_association_for_mva
|
223
|
+
<<-SQL
|
224
|
+
#{foreign_key} IN (SELECT #{quote_column model.primary_key}
|
225
|
+
FROM #{model.quoted_table_name}
|
226
|
+
WHERE #{@source.index.delta_object.clause(model, true)})
|
227
|
+
SQL
|
228
|
+
end
|
229
|
+
|
200
230
|
def range_query
|
201
|
-
assoc =
|
231
|
+
assoc = base_association_for_mva
|
202
232
|
foreign_key = foreign_key_for_mva assoc
|
203
233
|
"SELECT MIN(#{foreign_key}), MAX(#{foreign_key}) FROM #{quote_table_name assoc.table}"
|
204
234
|
end
|
@@ -213,27 +243,38 @@ FROM #{quote_table_name assoc.table}
|
|
213
243
|
quote_with_table assoc.table, assoc.reflection.primary_key_name
|
214
244
|
end
|
215
245
|
|
216
|
-
def
|
246
|
+
def end_association_for_mva
|
217
247
|
@association_for_mva ||= associations[columns.first].detect { |assoc|
|
218
248
|
assoc.has_column?(columns.first.__name)
|
219
249
|
}
|
220
250
|
end
|
221
251
|
|
252
|
+
def base_association_for_mva
|
253
|
+
@first_association_for_mva ||= begin
|
254
|
+
assoc = end_association_for_mva
|
255
|
+
while !assoc.parent.nil?
|
256
|
+
assoc = assoc.parent
|
257
|
+
end
|
258
|
+
|
259
|
+
assoc
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def association_joins
|
264
|
+
joins = []
|
265
|
+
assoc = end_association_for_mva
|
266
|
+
while assoc != base_association_for_mva
|
267
|
+
joins << assoc.to_sql
|
268
|
+
assoc = assoc.parent
|
269
|
+
end
|
270
|
+
|
271
|
+
joins.join(' ')
|
272
|
+
end
|
273
|
+
|
222
274
|
def is_many_ints?
|
223
275
|
concat_ws? && all_ints?
|
224
276
|
end
|
225
277
|
|
226
|
-
def all_ints?
|
227
|
-
@columns.all? { |col|
|
228
|
-
klasses = @associations[col].empty? ? [@model] :
|
229
|
-
@associations[col].collect { |assoc| assoc.reflection.klass }
|
230
|
-
klasses.all? { |klass|
|
231
|
-
column = klass.columns.detect { |column| column.name == col.__name.to_s }
|
232
|
-
!column.nil? && column.type == :integer
|
233
|
-
}
|
234
|
-
}
|
235
|
-
end
|
236
|
-
|
237
278
|
def type_from_database
|
238
279
|
klass = @associations.values.flatten.first ?
|
239
280
|
@associations.values.flatten.first.reflection.klass : @model
|
@@ -254,9 +295,10 @@ FROM #{quote_table_name assoc.table}
|
|
254
295
|
else
|
255
296
|
raise <<-MESSAGE
|
256
297
|
|
257
|
-
Cannot automatically map
|
258
|
-
type (integer, float, boolean, datetime, string as ordinal).
|
259
|
-
explicitly convert the column's value in your define_index
|
298
|
+
Cannot automatically map attribute #{unique_name} in #{@model.name} to an
|
299
|
+
equivalent Sphinx type (integer, float, boolean, datetime, string as ordinal).
|
300
|
+
You could try to explicitly convert the column's value in your define_index
|
301
|
+
block:
|
260
302
|
has "CAST(column AS INT)", :type => :integer, :as => :column
|
261
303
|
MESSAGE
|
262
304
|
end
|
@@ -19,12 +19,14 @@ module ThinkingSphinx
|
|
19
19
|
# min infix length:: 1
|
20
20
|
# mem limit:: 64M
|
21
21
|
# max matches:: 1000
|
22
|
-
# morphology::
|
22
|
+
# morphology:: nil
|
23
23
|
# charset type:: utf-8
|
24
24
|
# charset table:: nil
|
25
25
|
# ignore chars:: nil
|
26
26
|
# html strip:: false
|
27
27
|
# html remove elements:: ''
|
28
|
+
# searchd_binary_name:: searchd
|
29
|
+
# indexer_binary_name:: indexer
|
28
30
|
#
|
29
31
|
# If you want to change these settings, create a YAML file at
|
30
32
|
# config/sphinx.yml with settings for each environment, in a similar
|
@@ -32,7 +34,8 @@ module ThinkingSphinx
|
|
32
34
|
# searchd_log_file, query_log_file, pid_file, searchd_file_path, port,
|
33
35
|
# allow_star, enable_star, min_prefix_len, min_infix_len, mem_limit,
|
34
36
|
# max_matches, morphology, charset_type, charset_table, ignore_chars,
|
35
|
-
# html_strip, html_remove_elements, delayed_job_priority
|
37
|
+
# html_strip, html_remove_elements, delayed_job_priority,
|
38
|
+
# searchd_binary_name, indexer_binary_name.
|
36
39
|
#
|
37
40
|
# I think you've got the idea.
|
38
41
|
#
|
@@ -54,11 +57,13 @@ module ThinkingSphinx
|
|
54
57
|
min_infix_len min_prefix_len min_word_len mlock morphology ngram_chars
|
55
58
|
ngram_len phrase_boundary phrase_boundary_step preopen stopwords
|
56
59
|
wordforms )
|
60
|
+
|
61
|
+
CustomOptions = %w( disable_range )
|
57
62
|
|
58
63
|
attr_accessor :config_file, :searchd_log_file, :query_log_file,
|
59
64
|
:pid_file, :searchd_file_path, :address, :port, :allow_star,
|
60
65
|
:database_yml_file, :app_root, :bin_path, :model_directories,
|
61
|
-
:delayed_job_priority
|
66
|
+
:delayed_job_priority, :searchd_binary_name, :indexer_binary_name
|
62
67
|
|
63
68
|
attr_accessor :source_options, :index_options
|
64
69
|
|
@@ -71,10 +76,19 @@ module ThinkingSphinx
|
|
71
76
|
self.reset
|
72
77
|
end
|
73
78
|
|
74
|
-
def
|
75
|
-
|
76
|
-
|
77
|
-
|
79
|
+
def self.configure(&block)
|
80
|
+
yield instance
|
81
|
+
instance.reset(instance.app_root)
|
82
|
+
end
|
83
|
+
|
84
|
+
def reset(custom_app_root=nil)
|
85
|
+
if custom_app_root
|
86
|
+
self.app_root = custom_app_root
|
87
|
+
else
|
88
|
+
self.app_root = RAILS_ROOT if defined?(RAILS_ROOT)
|
89
|
+
self.app_root = Merb.root if defined?(Merb)
|
90
|
+
self.app_root ||= app_root
|
91
|
+
end
|
78
92
|
|
79
93
|
@configuration = Riddle::Configuration.new
|
80
94
|
@configuration.searchd.address = "127.0.0.1"
|
@@ -94,9 +108,11 @@ module ThinkingSphinx
|
|
94
108
|
|
95
109
|
self.source_options = {}
|
96
110
|
self.index_options = {
|
97
|
-
:charset_type => "utf-8"
|
98
|
-
:morphology => "stem_en"
|
111
|
+
:charset_type => "utf-8"
|
99
112
|
}
|
113
|
+
|
114
|
+
self.searchd_binary_name = "searchd"
|
115
|
+
self.indexer_binary_name = "indexer"
|
100
116
|
|
101
117
|
parse_config
|
102
118
|
|
@@ -141,6 +157,8 @@ module ThinkingSphinx
|
|
141
157
|
# messy dependencies issues).
|
142
158
|
#
|
143
159
|
def load_models
|
160
|
+
return if defined?(Rails) && Rails.configuration.cache_classes
|
161
|
+
|
144
162
|
self.model_directories.each do |base|
|
145
163
|
Dir["#{base}**/*.rb"].each do |file|
|
146
164
|
model_name = file.gsub(/^#{base}([\w_\/\\]+)\.rb/, '\1')
|
@@ -156,6 +174,8 @@ module ThinkingSphinx
|
|
156
174
|
model_name.gsub!(/.*[\/\\]/, '').nil? ? next : retry
|
157
175
|
rescue NameError
|
158
176
|
next
|
177
|
+
rescue StandardError
|
178
|
+
puts "Warning: Error loading #{file}"
|
159
179
|
end
|
160
180
|
end
|
161
181
|
end
|
@@ -213,10 +233,11 @@ module ThinkingSphinx
|
|
213
233
|
conf = YAML::load(ERB.new(IO.read(path)).result)[environment]
|
214
234
|
|
215
235
|
conf.each do |key,value|
|
216
|
-
self.send("#{key}=", value) if self.
|
236
|
+
self.send("#{key}=", value) if self.respond_to?("#{key}=")
|
217
237
|
|
218
238
|
set_sphinx_setting self.source_options, key, value, SourceOptions
|
219
239
|
set_sphinx_setting self.index_options, key, value, IndexOptions
|
240
|
+
set_sphinx_setting self.index_options, key, value, CustomOptions
|
220
241
|
set_sphinx_setting @configuration.searchd, key, value
|
221
242
|
set_sphinx_setting @configuration.indexer, key, value
|
222
243
|
end unless conf.nil?
|
@@ -233,8 +254,8 @@ module ThinkingSphinx
|
|
233
254
|
if object.is_a?(Hash)
|
234
255
|
object[key.to_sym] = value if allowed.include?(key.to_s)
|
235
256
|
else
|
236
|
-
object.send("#{key}=", value) if object.
|
237
|
-
send("#{key}=", value) if self.
|
257
|
+
object.send("#{key}=", value) if object.respond_to?("#{key}")
|
258
|
+
send("#{key}=", value) if self.respond_to?("#{key}")
|
238
259
|
end
|
239
260
|
end
|
240
261
|
end
|