thinking-sphinx 2.0.6 → 2.0.7
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 +157 -0
- data/lib/cucumber/thinking_sphinx/external_world.rb +12 -0
- data/lib/cucumber/thinking_sphinx/internal_world.rb +127 -0
- data/lib/cucumber/thinking_sphinx/sql_logger.rb +20 -0
- data/lib/thinking-sphinx.rb +1 -0
- data/lib/thinking_sphinx/action_controller.rb +31 -0
- data/lib/thinking_sphinx/active_record/attribute_updates.rb +53 -0
- data/lib/thinking_sphinx/active_record/collection_proxy.rb +40 -0
- data/lib/thinking_sphinx/active_record/collection_proxy_with_scopes.rb +27 -0
- data/lib/thinking_sphinx/active_record/delta.rb +65 -0
- data/lib/thinking_sphinx/active_record/has_many_association.rb +37 -0
- data/lib/thinking_sphinx/active_record/has_many_association_with_scopes.rb +21 -0
- data/lib/thinking_sphinx/active_record/log_subscriber.rb +61 -0
- data/lib/thinking_sphinx/active_record/scopes.rb +110 -0
- data/lib/thinking_sphinx/active_record.rb +383 -0
- data/lib/thinking_sphinx/adapters/abstract_adapter.rb +87 -0
- data/lib/thinking_sphinx/adapters/mysql_adapter.rb +62 -0
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +171 -0
- data/lib/thinking_sphinx/association.rb +229 -0
- data/lib/thinking_sphinx/attribute.rb +407 -0
- data/lib/thinking_sphinx/auto_version.rb +38 -0
- data/lib/thinking_sphinx/bundled_search.rb +44 -0
- data/lib/thinking_sphinx/class_facet.rb +20 -0
- data/lib/thinking_sphinx/configuration.rb +335 -0
- data/lib/thinking_sphinx/context.rb +77 -0
- data/lib/thinking_sphinx/core/string.rb +15 -0
- data/lib/thinking_sphinx/deltas/default_delta.rb +62 -0
- data/lib/thinking_sphinx/deltas.rb +28 -0
- data/lib/thinking_sphinx/deploy/capistrano.rb +99 -0
- data/lib/thinking_sphinx/excerpter.rb +23 -0
- data/lib/thinking_sphinx/facet.rb +128 -0
- data/lib/thinking_sphinx/facet_search.rb +170 -0
- data/lib/thinking_sphinx/field.rb +98 -0
- data/lib/thinking_sphinx/index/builder.rb +312 -0
- data/lib/thinking_sphinx/index/faux_column.rb +118 -0
- data/lib/thinking_sphinx/index.rb +157 -0
- data/lib/thinking_sphinx/join.rb +37 -0
- data/lib/thinking_sphinx/property.rb +185 -0
- data/lib/thinking_sphinx/railtie.rb +46 -0
- data/lib/thinking_sphinx/search.rb +995 -0
- data/lib/thinking_sphinx/search_methods.rb +439 -0
- data/lib/thinking_sphinx/sinatra.rb +7 -0
- data/lib/thinking_sphinx/source/internal_properties.rb +51 -0
- data/lib/thinking_sphinx/source/sql.rb +157 -0
- data/lib/thinking_sphinx/source.rb +194 -0
- data/lib/thinking_sphinx/tasks.rb +132 -0
- data/lib/thinking_sphinx/test.rb +55 -0
- data/lib/thinking_sphinx/version.rb +3 -0
- data/lib/thinking_sphinx.rb +296 -0
- metadata +53 -4
@@ -0,0 +1,335 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'singleton'
|
3
|
+
|
4
|
+
module ThinkingSphinx
|
5
|
+
# This class both keeps track of the configuration settings for Sphinx and
|
6
|
+
# also generates the resulting file for Sphinx to use.
|
7
|
+
#
|
8
|
+
# Here are the default settings, relative to Rails.root where relevant:
|
9
|
+
#
|
10
|
+
# config file:: config/#{environment}.sphinx.conf
|
11
|
+
# searchd log file:: log/searchd.log
|
12
|
+
# query log file:: log/searchd.query.log
|
13
|
+
# pid file:: log/searchd.#{environment}.pid
|
14
|
+
# searchd files:: db/sphinx/#{environment}/
|
15
|
+
# address:: 127.0.0.1
|
16
|
+
# port:: 9312
|
17
|
+
# allow star:: false
|
18
|
+
# stop timeout:: 5
|
19
|
+
# min prefix length:: 1
|
20
|
+
# min infix length:: 1
|
21
|
+
# mem limit:: 64M
|
22
|
+
# max matches:: 1000
|
23
|
+
# morphology:: nil
|
24
|
+
# charset type:: utf-8
|
25
|
+
# charset table:: nil
|
26
|
+
# ignore chars:: nil
|
27
|
+
# html strip:: false
|
28
|
+
# html remove elements:: ''
|
29
|
+
# searchd_binary_name:: searchd
|
30
|
+
# indexer_binary_name:: indexer
|
31
|
+
#
|
32
|
+
# If you want to change these settings, create a YAML file at
|
33
|
+
# config/sphinx.yml with settings for each environment, in a similar
|
34
|
+
# fashion to database.yml - using the following keys: config_file,
|
35
|
+
# searchd_log_file, query_log_file, pid_file, searchd_file_path, port,
|
36
|
+
# allow_star, enable_star, min_prefix_len, min_infix_len, mem_limit,
|
37
|
+
# max_matches, morphology, charset_type, charset_table, ignore_chars,
|
38
|
+
# html_strip, html_remove_elements, delayed_job_priority,
|
39
|
+
# searchd_binary_name, indexer_binary_name.
|
40
|
+
#
|
41
|
+
# I think you've got the idea.
|
42
|
+
#
|
43
|
+
# Each setting in the YAML file is optional - so only put in the ones you
|
44
|
+
# want to change.
|
45
|
+
#
|
46
|
+
# Keep in mind, if for some particular reason you're using a version of
|
47
|
+
# Sphinx older than 0.9.8 r871 (that's prior to the proper 0.9.8 release),
|
48
|
+
# don't set allow_star to true.
|
49
|
+
#
|
50
|
+
class Configuration
|
51
|
+
include Singleton
|
52
|
+
|
53
|
+
SourceOptions = Riddle::Configuration::SQLSource.settings.map { |setting|
|
54
|
+
setting.to_s
|
55
|
+
} - %w( type sql_query_pre sql_query sql_joined_field sql_file_field
|
56
|
+
sql_query_range sql_attr_uint sql_attr_bool sql_attr_bigint sql_query_info
|
57
|
+
sql_attr_timestamp sql_attr_str2ordinal sql_attr_float sql_attr_multi
|
58
|
+
sql_attr_string sql_attr_str2wordcount sql_column_buffers sql_field_string
|
59
|
+
sql_field_str2wordcount )
|
60
|
+
IndexOptions = Riddle::Configuration::Index.settings.map { |setting|
|
61
|
+
setting.to_s
|
62
|
+
} - %w( source prefix_fields infix_fields )
|
63
|
+
CustomOptions = %w( disable_range use_64_bit )
|
64
|
+
|
65
|
+
attr_accessor :searchd_file_path, :allow_star, :app_root,
|
66
|
+
:model_directories, :delayed_job_priority, :indexed_models, :use_64_bit,
|
67
|
+
:touched_reindex_file, :stop_timeout, :version
|
68
|
+
|
69
|
+
attr_accessor :source_options, :index_options
|
70
|
+
|
71
|
+
attr_reader :configuration, :controller
|
72
|
+
|
73
|
+
@@environment = nil
|
74
|
+
|
75
|
+
# Load in the configuration settings - this will look for config/sphinx.yml
|
76
|
+
# and parse it according to the current environment.
|
77
|
+
#
|
78
|
+
def initialize(app_root = Dir.pwd)
|
79
|
+
self.reset
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.configure(&block)
|
83
|
+
yield instance
|
84
|
+
instance.reset(instance.app_root)
|
85
|
+
end
|
86
|
+
|
87
|
+
def reset(custom_app_root=nil)
|
88
|
+
if custom_app_root
|
89
|
+
self.app_root = custom_app_root
|
90
|
+
else
|
91
|
+
self.app_root = Merb.root if defined?(Merb)
|
92
|
+
self.app_root = Sinatra::Application.root if defined?(Sinatra)
|
93
|
+
self.app_root = Rails.root if defined?(Rails)
|
94
|
+
self.app_root ||= app_root
|
95
|
+
end
|
96
|
+
|
97
|
+
@configuration = Riddle::Configuration.new
|
98
|
+
@configuration.searchd.pid_file = "#{self.app_root}/log/searchd.#{environment}.pid"
|
99
|
+
@configuration.searchd.log = "#{self.app_root}/log/searchd.log"
|
100
|
+
@configuration.searchd.query_log = "#{self.app_root}/log/searchd.query.log"
|
101
|
+
|
102
|
+
@controller = Riddle::Controller.new @configuration,
|
103
|
+
"#{self.app_root}/config/#{environment}.sphinx.conf"
|
104
|
+
|
105
|
+
self.address = "127.0.0.1"
|
106
|
+
self.port = 9312
|
107
|
+
self.searchd_file_path = "#{self.app_root}/db/sphinx/#{environment}"
|
108
|
+
self.allow_star = false
|
109
|
+
self.stop_timeout = 5
|
110
|
+
self.model_directories = ["#{app_root}/app/models/"] +
|
111
|
+
Dir.glob("#{app_root}/vendor/plugins/*/app/models/")
|
112
|
+
self.delayed_job_priority = 0
|
113
|
+
self.indexed_models = []
|
114
|
+
|
115
|
+
self.source_options = {}
|
116
|
+
self.index_options = {
|
117
|
+
:charset_type => "utf-8"
|
118
|
+
}
|
119
|
+
|
120
|
+
self.version = nil
|
121
|
+
parse_config
|
122
|
+
self.version ||= @controller.sphinx_version
|
123
|
+
|
124
|
+
self
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.environment
|
128
|
+
@@environment ||= if defined?(Merb)
|
129
|
+
Merb.environment
|
130
|
+
elsif defined?(Rails)
|
131
|
+
Rails.env
|
132
|
+
elsif defined?(Sinatra)
|
133
|
+
Sinatra::Application.environment.to_s
|
134
|
+
else
|
135
|
+
ENV['RAILS_ENV'] || 'development'
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.reset_environment
|
140
|
+
ThinkingSphinx.mutex.synchronize do
|
141
|
+
@@environment = nil
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def environment
|
146
|
+
self.class.environment
|
147
|
+
end
|
148
|
+
|
149
|
+
def generate
|
150
|
+
@configuration.indexes.clear
|
151
|
+
|
152
|
+
ThinkingSphinx.context.indexed_models.each do |model|
|
153
|
+
model = model.constantize
|
154
|
+
model.define_indexes
|
155
|
+
@configuration.indexes.concat model.to_riddle
|
156
|
+
|
157
|
+
enforce_common_attribute_types
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Generate the config file for Sphinx by using all the settings defined and
|
162
|
+
# looping through all the models with indexes to build the relevant
|
163
|
+
# indexer and searchd configuration, and sources and indexes details.
|
164
|
+
#
|
165
|
+
def build(file_path=nil)
|
166
|
+
file_path ||= "#{self.config_file}"
|
167
|
+
|
168
|
+
generate
|
169
|
+
|
170
|
+
open(file_path, "w") do |file|
|
171
|
+
file.write @configuration.render
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def address
|
176
|
+
@address
|
177
|
+
end
|
178
|
+
|
179
|
+
def address=(address)
|
180
|
+
@address = address
|
181
|
+
@configuration.searchd.address = address
|
182
|
+
end
|
183
|
+
|
184
|
+
def port
|
185
|
+
@port
|
186
|
+
end
|
187
|
+
|
188
|
+
def port=(port)
|
189
|
+
@port = port
|
190
|
+
@configuration.searchd.port = port
|
191
|
+
end
|
192
|
+
|
193
|
+
def pid_file
|
194
|
+
@configuration.searchd.pid_file
|
195
|
+
end
|
196
|
+
|
197
|
+
def pid_file=(pid_file)
|
198
|
+
@configuration.searchd.pid_file = pid_file
|
199
|
+
end
|
200
|
+
|
201
|
+
def searchd_log_file
|
202
|
+
@configuration.searchd.log
|
203
|
+
end
|
204
|
+
|
205
|
+
def searchd_log_file=(file)
|
206
|
+
@configuration.searchd.log = file
|
207
|
+
end
|
208
|
+
|
209
|
+
def query_log_file
|
210
|
+
@configuration.searchd.query_log
|
211
|
+
end
|
212
|
+
|
213
|
+
def query_log_file=(file)
|
214
|
+
@configuration.searchd.query_log = file
|
215
|
+
end
|
216
|
+
|
217
|
+
def config_file
|
218
|
+
@controller.path
|
219
|
+
end
|
220
|
+
|
221
|
+
def config_file=(file)
|
222
|
+
@controller.path = file
|
223
|
+
end
|
224
|
+
|
225
|
+
def bin_path
|
226
|
+
@controller.bin_path
|
227
|
+
end
|
228
|
+
|
229
|
+
def bin_path=(path)
|
230
|
+
@controller.bin_path = path
|
231
|
+
end
|
232
|
+
|
233
|
+
def searchd_binary_name
|
234
|
+
@controller.searchd_binary_name
|
235
|
+
end
|
236
|
+
|
237
|
+
def searchd_binary_name=(name)
|
238
|
+
@controller.searchd_binary_name = name
|
239
|
+
end
|
240
|
+
|
241
|
+
def indexer_binary_name
|
242
|
+
@controller.indexer_binary_name
|
243
|
+
end
|
244
|
+
|
245
|
+
def indexer_binary_name=(name)
|
246
|
+
@controller.indexer_binary_name = name
|
247
|
+
end
|
248
|
+
|
249
|
+
attr_accessor :timeout
|
250
|
+
|
251
|
+
def client
|
252
|
+
client = Riddle::Client.new address, port,
|
253
|
+
configuration.searchd.client_key
|
254
|
+
client.max_matches = configuration.searchd.max_matches || 1000
|
255
|
+
client.timeout = timeout || 0
|
256
|
+
client
|
257
|
+
end
|
258
|
+
|
259
|
+
def models_by_crc
|
260
|
+
@models_by_crc ||= begin
|
261
|
+
ThinkingSphinx.context.indexed_models.inject({}) do |hash, model|
|
262
|
+
hash[model.constantize.to_crc32] = model
|
263
|
+
model.constantize.descendants.each { |subclass|
|
264
|
+
hash[subclass.to_crc32] = subclass.name
|
265
|
+
}
|
266
|
+
hash
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
def touch_reindex_file(output)
|
272
|
+
return FileUtils.touch(@touched_reindex_file) if @touched_reindex_file and output =~ /succesfully sent SIGHUP to searchd/
|
273
|
+
false
|
274
|
+
end
|
275
|
+
|
276
|
+
private
|
277
|
+
|
278
|
+
# Parse the config/sphinx.yml file - if it exists - then use the attribute
|
279
|
+
# accessors to set the appropriate values. Nothing too clever.
|
280
|
+
#
|
281
|
+
def parse_config
|
282
|
+
path = "#{app_root}/config/sphinx.yml"
|
283
|
+
return unless File.exists?(path)
|
284
|
+
|
285
|
+
conf = YAML::load(ERB.new(IO.read(path)).result)[environment]
|
286
|
+
|
287
|
+
conf.each do |key,value|
|
288
|
+
self.send("#{key}=", value) if self.respond_to?("#{key}=")
|
289
|
+
|
290
|
+
set_sphinx_setting self.source_options, key, value, SourceOptions
|
291
|
+
set_sphinx_setting self.index_options, key, value, IndexOptions
|
292
|
+
set_sphinx_setting self.index_options, key, value, CustomOptions
|
293
|
+
set_sphinx_setting @configuration.searchd, key, value
|
294
|
+
set_sphinx_setting @configuration.indexer, key, value
|
295
|
+
end unless conf.nil?
|
296
|
+
|
297
|
+
self.bin_path += '/' unless self.bin_path.blank?
|
298
|
+
|
299
|
+
if self.allow_star
|
300
|
+
self.index_options[:enable_star] = true
|
301
|
+
self.index_options[:min_prefix_len] = 1
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
def set_sphinx_setting(object, key, value, allowed = {})
|
306
|
+
if object.is_a?(Hash)
|
307
|
+
object[key.to_sym] = value if allowed.include?(key.to_s)
|
308
|
+
else
|
309
|
+
object.send("#{key}=", value) if object.respond_to?("#{key}")
|
310
|
+
send("#{key}=", value) if self.respond_to?("#{key}")
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
def enforce_common_attribute_types
|
315
|
+
sql_indexes = configuration.indexes.reject { |index|
|
316
|
+
index.is_a? Riddle::Configuration::DistributedIndex
|
317
|
+
}
|
318
|
+
|
319
|
+
return unless sql_indexes.any? { |index|
|
320
|
+
index.sources.any? { |source|
|
321
|
+
source.sql_attr_bigint.include? :sphinx_internal_id
|
322
|
+
}
|
323
|
+
}
|
324
|
+
|
325
|
+
sql_indexes.each { |index|
|
326
|
+
index.sources.each { |source|
|
327
|
+
next if source.sql_attr_bigint.include? :sphinx_internal_id
|
328
|
+
|
329
|
+
source.sql_attr_bigint << :sphinx_internal_id
|
330
|
+
source.sql_attr_uint.delete :sphinx_internal_id
|
331
|
+
}
|
332
|
+
}
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
class ThinkingSphinx::Context
|
2
|
+
attr_reader :indexed_models
|
3
|
+
|
4
|
+
def initialize(*models)
|
5
|
+
@indexed_models = []
|
6
|
+
end
|
7
|
+
|
8
|
+
def prepare
|
9
|
+
ThinkingSphinx::Configuration.instance.indexed_models.each do |model|
|
10
|
+
add_indexed_model model
|
11
|
+
end
|
12
|
+
|
13
|
+
return unless indexed_models.empty?
|
14
|
+
|
15
|
+
load_models
|
16
|
+
add_indexed_models
|
17
|
+
end
|
18
|
+
|
19
|
+
def define_indexes
|
20
|
+
indexed_models.each { |model|
|
21
|
+
model.constantize.define_indexes
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_indexed_model(model)
|
26
|
+
model = model.name if model.is_a?(Class)
|
27
|
+
|
28
|
+
indexed_models << model
|
29
|
+
indexed_models.uniq!
|
30
|
+
indexed_models.sort!
|
31
|
+
end
|
32
|
+
|
33
|
+
def superclass_indexed_models
|
34
|
+
klasses = indexed_models.collect { |name| name.constantize }
|
35
|
+
klasses.reject { |klass|
|
36
|
+
klass.superclass.ancestors.any? { |ancestor| klasses.include?(ancestor) }
|
37
|
+
}.collect { |klass| klass.name }
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def add_indexed_models
|
43
|
+
ActiveRecord::Base.descendants.each do |klass|
|
44
|
+
add_indexed_model klass if klass.has_sphinx_indexes?
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Make sure all models are loaded - without reloading any that
|
49
|
+
# ActiveRecord::Base is already aware of (otherwise we start to hit some
|
50
|
+
# messy dependencies issues).
|
51
|
+
#
|
52
|
+
def load_models
|
53
|
+
ThinkingSphinx::Configuration.instance.model_directories.each do |base|
|
54
|
+
Dir["#{base}**/*.rb"].each do |file|
|
55
|
+
model_name = file.gsub(/^#{base}([\w_\/\\]+)\.rb/, '\1')
|
56
|
+
|
57
|
+
next if model_name.nil?
|
58
|
+
camelized_model = model_name.camelize
|
59
|
+
next if ::ActiveRecord::Base.descendants.detect { |model|
|
60
|
+
model.name == camelized_model
|
61
|
+
}
|
62
|
+
|
63
|
+
begin
|
64
|
+
camelized_model.constantize
|
65
|
+
rescue LoadError
|
66
|
+
model_name.gsub!(/.*[\/\\]/, '').nil? ? next : retry
|
67
|
+
rescue NameError
|
68
|
+
next
|
69
|
+
rescue StandardError => err
|
70
|
+
STDERR.puts "Warning: Error loading #{file}:"
|
71
|
+
STDERR.puts err.message
|
72
|
+
STDERR.puts err.backtrace.join("\n"), ''
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module ThinkingSphinx
|
2
|
+
module Deltas
|
3
|
+
class DefaultDelta
|
4
|
+
attr_accessor :column
|
5
|
+
|
6
|
+
def initialize(index, options)
|
7
|
+
@index = index
|
8
|
+
@column = options.delete(:delta_column) || :delta
|
9
|
+
end
|
10
|
+
|
11
|
+
def index(model, instance = nil)
|
12
|
+
return true unless ThinkingSphinx.updates_enabled? &&
|
13
|
+
ThinkingSphinx.deltas_enabled?
|
14
|
+
return true if instance && !toggled(instance)
|
15
|
+
|
16
|
+
update_delta_indexes model
|
17
|
+
delete_from_core model, instance if instance
|
18
|
+
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def toggle(instance)
|
23
|
+
instance.send "#{@column}=", true
|
24
|
+
end
|
25
|
+
|
26
|
+
def toggled(instance)
|
27
|
+
instance.send "#{@column}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def reset_query(model)
|
31
|
+
"UPDATE #{model.quoted_table_name} SET " +
|
32
|
+
"#{model.connection.quote_column_name(@column.to_s)} = #{adapter.boolean(false)} " +
|
33
|
+
"WHERE #{model.connection.quote_column_name(@column.to_s)} = #{adapter.boolean(true)}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def clause(model, toggled)
|
37
|
+
"#{model.quoted_table_name}.#{model.connection.quote_column_name(@column.to_s)}" +
|
38
|
+
" = #{adapter.boolean(toggled)}"
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def update_delta_indexes(model)
|
44
|
+
config = ThinkingSphinx::Configuration.instance
|
45
|
+
rotate = ThinkingSphinx.sphinx_running? ? "--rotate" : ""
|
46
|
+
|
47
|
+
output = `#{config.bin_path}#{config.indexer_binary_name} --config "#{config.config_file}" #{rotate} #{model.delta_index_names.join(' ')}`
|
48
|
+
puts(output) unless ThinkingSphinx.suppress_delta_output?
|
49
|
+
end
|
50
|
+
|
51
|
+
def delete_from_core(model, instance)
|
52
|
+
model.core_index_names.each do |index_name|
|
53
|
+
model.delete_in_index index_name, instance.sphinx_document_id
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def adapter
|
58
|
+
@adapter = @index.model.sphinx_database_adapter
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'thinking_sphinx/deltas/default_delta'
|
2
|
+
|
3
|
+
module ThinkingSphinx
|
4
|
+
module Deltas
|
5
|
+
def self.parse(index)
|
6
|
+
delta_option = index.local_options.delete(:delta)
|
7
|
+
case delta_option
|
8
|
+
when TrueClass, :default
|
9
|
+
DefaultDelta.new index, index.local_options
|
10
|
+
when :delayed
|
11
|
+
DelayedDelta.new index, index.local_options
|
12
|
+
when :datetime
|
13
|
+
DatetimeDelta.new index, index.local_options
|
14
|
+
when FalseClass, nil
|
15
|
+
nil
|
16
|
+
else
|
17
|
+
if delta_option.is_a?(String)
|
18
|
+
delta_option = Kernel.const_get(delta_option)
|
19
|
+
end
|
20
|
+
if delta_option.ancestors.include?(ThinkingSphinx::Deltas::DefaultDelta)
|
21
|
+
delta_option.new index, index.local_options
|
22
|
+
else
|
23
|
+
raise "Unknown delta type"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
namespace :thinking_sphinx do
|
3
|
+
namespace :install do
|
4
|
+
desc <<-DESC
|
5
|
+
Install Sphinx by source
|
6
|
+
|
7
|
+
If Postgres is available, Sphinx will use it.
|
8
|
+
|
9
|
+
If the variable :thinking_sphinx_configure_args is set, it will
|
10
|
+
be passed to the Sphinx configure script. You can use this to
|
11
|
+
install Sphinx in a non-standard location:
|
12
|
+
|
13
|
+
set :thinking_sphinx_configure_args, "--prefix=$HOME/software"
|
14
|
+
DESC
|
15
|
+
|
16
|
+
task :sphinx do
|
17
|
+
with_postgres = false
|
18
|
+
begin
|
19
|
+
run "which pg_config" do |channel, stream, data|
|
20
|
+
with_postgres = !(data.nil? || data == "")
|
21
|
+
end
|
22
|
+
rescue Capistrano::CommandError => e
|
23
|
+
puts "Continuing despite error: #{e.message}"
|
24
|
+
end
|
25
|
+
|
26
|
+
args = []
|
27
|
+
if with_postgres
|
28
|
+
run "pg_config --pkgincludedir" do |channel, stream, data|
|
29
|
+
args << "--with-pgsql=#{data}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
args << fetch(:thinking_sphinx_configure_args, '')
|
33
|
+
|
34
|
+
commands = <<-CMD
|
35
|
+
wget -q http://sphinxsearch.com/downloads/sphinx-0.9.9.tar.gz >> sphinx.log
|
36
|
+
tar xzvf sphinx-0.9.9.tar.gz
|
37
|
+
cd sphinx-0.9.9
|
38
|
+
./configure #{args.join(" ")}
|
39
|
+
make
|
40
|
+
#{try_sudo} make install
|
41
|
+
rm -rf sphinx-0.9.9 sphinx-0.9.9.tar.gz
|
42
|
+
CMD
|
43
|
+
run commands.split(/\n\s+/).join(" && ")
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "Install Thinking Sphinx as a gem"
|
47
|
+
task :ts do
|
48
|
+
run "#{try_sudo} gem install thinking-sphinx"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "Generate the Sphinx configuration file"
|
53
|
+
task :configure do
|
54
|
+
rake "thinking_sphinx:configure"
|
55
|
+
end
|
56
|
+
|
57
|
+
desc "Index data"
|
58
|
+
task :index do
|
59
|
+
rake "thinking_sphinx:index"
|
60
|
+
end
|
61
|
+
|
62
|
+
desc "Start the Sphinx daemon"
|
63
|
+
task :start do
|
64
|
+
rake "thinking_sphinx:configure thinking_sphinx:start"
|
65
|
+
end
|
66
|
+
|
67
|
+
desc "Stop the Sphinx daemon"
|
68
|
+
task :stop do
|
69
|
+
rake "thinking_sphinx:configure thinking_sphinx:stop"
|
70
|
+
end
|
71
|
+
|
72
|
+
desc "Stop and then start the Sphinx daemon"
|
73
|
+
task :restart do
|
74
|
+
rake "thinking_sphinx:configure thinking_sphinx:stop \
|
75
|
+
thinking_sphinx:start"
|
76
|
+
end
|
77
|
+
|
78
|
+
desc "Stop, re-index and then start the Sphinx daemon"
|
79
|
+
task :rebuild do
|
80
|
+
rake "thinking_sphinx:configure thinking_sphinx:stop \
|
81
|
+
thinking_sphinx:reindex \
|
82
|
+
thinking_sphinx:start"
|
83
|
+
end
|
84
|
+
|
85
|
+
desc "Add the shared folder for sphinx files"
|
86
|
+
task :shared_sphinx_folder, :roles => :web do
|
87
|
+
rails_env = fetch(:rails_env, "production")
|
88
|
+
run "mkdir -p #{shared_path}/sphinx/#{rails_env}"
|
89
|
+
end
|
90
|
+
|
91
|
+
def rake(*tasks)
|
92
|
+
rails_env = fetch(:rails_env, "production")
|
93
|
+
rake = fetch(:rake, "rake")
|
94
|
+
tasks.each do |t|
|
95
|
+
run "if [ -d #{release_path} ]; then cd #{release_path}; else cd #{current_path}; fi; #{rake} RAILS_ENV=#{rails_env} #{t}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ThinkingSphinx
|
2
|
+
class Excerpter
|
3
|
+
CoreMethods = %w( kind_of? object_id respond_to? respond_to_missing? should
|
4
|
+
should_not stub! )
|
5
|
+
# Hide most methods, to allow them to be passed through to the instance.
|
6
|
+
instance_methods.select { |method|
|
7
|
+
method.to_s[/^__/].nil? && !CoreMethods.include?(method.to_s)
|
8
|
+
}.each { |method|
|
9
|
+
undef_method method
|
10
|
+
}
|
11
|
+
|
12
|
+
def initialize(search, instance)
|
13
|
+
@search = search
|
14
|
+
@instance = instance
|
15
|
+
end
|
16
|
+
|
17
|
+
def method_missing(method, *args, &block)
|
18
|
+
string = @instance.send(method, *args, &block).to_s
|
19
|
+
|
20
|
+
@search.excerpt_for(string, @instance.class)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|