skalee-thinking-sphinx 1.3.14.1
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/LICENCE +20 -0
- data/README.textile +201 -0
- data/Rakefile +3 -0
- data/VERSION +1 -0
- data/contribute.rb +385 -0
- data/cucumber.yml +1 -0
- data/features/abstract_inheritance.feature +10 -0
- data/features/alternate_primary_key.feature +27 -0
- data/features/attribute_transformation.feature +22 -0
- data/features/attribute_updates.feature +51 -0
- data/features/deleting_instances.feature +67 -0
- data/features/direct_attributes.feature +11 -0
- data/features/excerpts.feature +13 -0
- data/features/extensible_delta_indexing.feature +9 -0
- data/features/facets.feature +82 -0
- data/features/facets_across_model.feature +29 -0
- data/features/handling_edits.feature +92 -0
- data/features/retry_stale_indexes.feature +24 -0
- data/features/searching_across_models.feature +20 -0
- data/features/searching_by_index.feature +40 -0
- data/features/searching_by_model.feature +175 -0
- data/features/searching_with_find_arguments.feature +56 -0
- data/features/sphinx_detection.feature +25 -0
- data/features/sphinx_scopes.feature +42 -0
- data/features/step_definitions/alpha_steps.rb +16 -0
- data/features/step_definitions/beta_steps.rb +7 -0
- data/features/step_definitions/common_steps.rb +188 -0
- data/features/step_definitions/extensible_delta_indexing_steps.rb +7 -0
- data/features/step_definitions/facet_steps.rb +96 -0
- data/features/step_definitions/find_arguments_steps.rb +36 -0
- data/features/step_definitions/gamma_steps.rb +15 -0
- data/features/step_definitions/scope_steps.rb +15 -0
- data/features/step_definitions/search_steps.rb +89 -0
- data/features/step_definitions/sphinx_steps.rb +35 -0
- data/features/sti_searching.feature +19 -0
- data/features/support/database.example.yml +3 -0
- data/features/support/db/.gitignore +1 -0
- data/features/support/db/fixtures/alphas.rb +10 -0
- data/features/support/db/fixtures/authors.rb +1 -0
- data/features/support/db/fixtures/betas.rb +10 -0
- data/features/support/db/fixtures/boxes.rb +9 -0
- data/features/support/db/fixtures/categories.rb +1 -0
- data/features/support/db/fixtures/cats.rb +3 -0
- data/features/support/db/fixtures/comments.rb +24 -0
- data/features/support/db/fixtures/developers.rb +29 -0
- data/features/support/db/fixtures/dogs.rb +3 -0
- data/features/support/db/fixtures/extensible_betas.rb +10 -0
- data/features/support/db/fixtures/foxes.rb +3 -0
- data/features/support/db/fixtures/gammas.rb +10 -0
- data/features/support/db/fixtures/music.rb +4 -0
- data/features/support/db/fixtures/people.rb +1001 -0
- data/features/support/db/fixtures/posts.rb +6 -0
- data/features/support/db/fixtures/robots.rb +14 -0
- data/features/support/db/fixtures/tags.rb +27 -0
- data/features/support/db/migrations/create_alphas.rb +8 -0
- data/features/support/db/migrations/create_animals.rb +5 -0
- data/features/support/db/migrations/create_authors.rb +3 -0
- data/features/support/db/migrations/create_authors_posts.rb +6 -0
- data/features/support/db/migrations/create_betas.rb +5 -0
- data/features/support/db/migrations/create_boxes.rb +5 -0
- data/features/support/db/migrations/create_categories.rb +3 -0
- data/features/support/db/migrations/create_comments.rb +10 -0
- data/features/support/db/migrations/create_developers.rb +9 -0
- data/features/support/db/migrations/create_extensible_betas.rb +5 -0
- data/features/support/db/migrations/create_gammas.rb +3 -0
- data/features/support/db/migrations/create_genres.rb +3 -0
- data/features/support/db/migrations/create_music.rb +6 -0
- data/features/support/db/migrations/create_people.rb +13 -0
- data/features/support/db/migrations/create_posts.rb +5 -0
- data/features/support/db/migrations/create_robots.rb +4 -0
- data/features/support/db/migrations/create_taggings.rb +5 -0
- data/features/support/db/migrations/create_tags.rb +4 -0
- data/features/support/env.rb +21 -0
- data/features/support/lib/generic_delta_handler.rb +8 -0
- data/features/support/models/alpha.rb +22 -0
- data/features/support/models/animal.rb +5 -0
- data/features/support/models/author.rb +3 -0
- data/features/support/models/beta.rb +8 -0
- data/features/support/models/box.rb +8 -0
- data/features/support/models/cat.rb +3 -0
- data/features/support/models/category.rb +4 -0
- data/features/support/models/comment.rb +10 -0
- data/features/support/models/developer.rb +16 -0
- data/features/support/models/dog.rb +3 -0
- data/features/support/models/extensible_beta.rb +9 -0
- data/features/support/models/fox.rb +5 -0
- data/features/support/models/gamma.rb +5 -0
- data/features/support/models/genre.rb +3 -0
- data/features/support/models/medium.rb +5 -0
- data/features/support/models/music.rb +8 -0
- data/features/support/models/person.rb +23 -0
- data/features/support/models/post.rb +21 -0
- data/features/support/models/robot.rb +12 -0
- data/features/support/models/tag.rb +3 -0
- data/features/support/models/tagging.rb +4 -0
- data/ginger_scenarios.rb +28 -0
- data/init.rb +5 -0
- data/install.rb +5 -0
- data/lib/cucumber/thinking_sphinx/external_world.rb +8 -0
- data/lib/cucumber/thinking_sphinx/internal_world.rb +126 -0
- data/lib/cucumber/thinking_sphinx/sql_logger.rb +20 -0
- data/lib/thinking_sphinx/active_record/attribute_updates.rb +19 -0
- data/lib/thinking_sphinx/active_record/delta.rb +47 -0
- data/lib/thinking_sphinx/active_record/has_many_association.rb +29 -0
- data/lib/thinking_sphinx/active_record/scopes.rb +75 -0
- data/lib/thinking_sphinx/active_record.rb +348 -0
- data/lib/thinking_sphinx/adapters/abstract_adapter.rb +42 -0
- data/lib/thinking_sphinx/adapters/mysql_adapter.rb +54 -0
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +143 -0
- data/lib/thinking_sphinx/association.rb +164 -0
- data/lib/thinking_sphinx/attribute.rb +362 -0
- data/lib/thinking_sphinx/auto_version.rb +22 -0
- data/lib/thinking_sphinx/class_facet.rb +15 -0
- data/lib/thinking_sphinx/configuration.rb +300 -0
- data/lib/thinking_sphinx/context.rb +68 -0
- data/lib/thinking_sphinx/core/array.rb +7 -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 +100 -0
- data/lib/thinking_sphinx/excerpter.rb +22 -0
- data/lib/thinking_sphinx/facet.rb +125 -0
- data/lib/thinking_sphinx/facet_search.rb +136 -0
- data/lib/thinking_sphinx/field.rb +82 -0
- data/lib/thinking_sphinx/index/builder.rb +296 -0
- data/lib/thinking_sphinx/index/faux_column.rb +110 -0
- data/lib/thinking_sphinx/index.rb +157 -0
- data/lib/thinking_sphinx/property.rb +162 -0
- data/lib/thinking_sphinx/rails_additions.rb +150 -0
- data/lib/thinking_sphinx/search.rb +769 -0
- data/lib/thinking_sphinx/search_methods.rb +439 -0
- data/lib/thinking_sphinx/source/internal_properties.rb +46 -0
- data/lib/thinking_sphinx/source/sql.rb +130 -0
- data/lib/thinking_sphinx/source.rb +153 -0
- data/lib/thinking_sphinx/tasks.rb +131 -0
- data/lib/thinking_sphinx/test.rb +52 -0
- data/lib/thinking_sphinx.rb +225 -0
- data/rails/init.rb +16 -0
- data/recipes/thinking_sphinx.rb +3 -0
- data/spec/fixtures/data.sql +32 -0
- data/spec/fixtures/database.yml.default +3 -0
- data/spec/fixtures/models.rb +145 -0
- data/spec/fixtures/structure.sql +125 -0
- data/spec/spec_helper.rb +60 -0
- data/spec/sphinx_helper.rb +81 -0
- data/spec/thinking_sphinx/active_record/delta_spec.rb +128 -0
- data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +55 -0
- data/spec/thinking_sphinx/active_record/scopes_spec.rb +177 -0
- data/spec/thinking_sphinx/active_record_spec.rb +622 -0
- data/spec/thinking_sphinx/association_spec.rb +239 -0
- data/spec/thinking_sphinx/attribute_spec.rb +570 -0
- data/spec/thinking_sphinx/auto_version_spec.rb +39 -0
- data/spec/thinking_sphinx/configuration_spec.rb +234 -0
- data/spec/thinking_sphinx/context_spec.rb +119 -0
- data/spec/thinking_sphinx/core/array_spec.rb +9 -0
- data/spec/thinking_sphinx/core/string_spec.rb +9 -0
- data/spec/thinking_sphinx/excerpter_spec.rb +57 -0
- data/spec/thinking_sphinx/facet_search_spec.rb +176 -0
- data/spec/thinking_sphinx/facet_spec.rb +333 -0
- data/spec/thinking_sphinx/field_spec.rb +154 -0
- data/spec/thinking_sphinx/index/builder_spec.rb +479 -0
- data/spec/thinking_sphinx/index/faux_column_spec.rb +30 -0
- data/spec/thinking_sphinx/index_spec.rb +183 -0
- data/spec/thinking_sphinx/rails_additions_spec.rb +203 -0
- data/spec/thinking_sphinx/search_methods_spec.rb +152 -0
- data/spec/thinking_sphinx/search_spec.rb +1181 -0
- data/spec/thinking_sphinx/source_spec.rb +235 -0
- data/spec/thinking_sphinx_spec.rb +204 -0
- data/tasks/distribution.rb +41 -0
- data/tasks/rails.rake +1 -0
- data/tasks/testing.rb +72 -0
- data/vendor/after_commit/.gitignore +1 -0
- data/vendor/after_commit/lib/after_commit/active_record.rb +122 -0
- data/vendor/after_commit/lib/after_commit/connection_adapters.rb +168 -0
- data/vendor/after_commit/lib/after_commit/test_bypass.rb +30 -0
- data/vendor/after_commit/lib/after_commit.rb +70 -0
- data/vendor/riddle/lib/riddle/0.9.8.rb +1 -0
- data/vendor/riddle/lib/riddle/0.9.9/client/filter.rb +22 -0
- data/vendor/riddle/lib/riddle/0.9.9/client.rb +49 -0
- data/vendor/riddle/lib/riddle/0.9.9/configuration/searchd.rb +28 -0
- data/vendor/riddle/lib/riddle/0.9.9.rb +7 -0
- data/vendor/riddle/lib/riddle/auto_version.rb +11 -0
- data/vendor/riddle/lib/riddle/client/filter.rb +62 -0
- data/vendor/riddle/lib/riddle/client/message.rb +70 -0
- data/vendor/riddle/lib/riddle/client/response.rb +94 -0
- data/vendor/riddle/lib/riddle/client.rb +745 -0
- data/vendor/riddle/lib/riddle/configuration/distributed_index.rb +49 -0
- data/vendor/riddle/lib/riddle/configuration/index.rb +149 -0
- data/vendor/riddle/lib/riddle/configuration/indexer.rb +20 -0
- data/vendor/riddle/lib/riddle/configuration/remote_index.rb +17 -0
- data/vendor/riddle/lib/riddle/configuration/searchd.rb +28 -0
- data/vendor/riddle/lib/riddle/configuration/section.rb +43 -0
- data/vendor/riddle/lib/riddle/configuration/source.rb +23 -0
- data/vendor/riddle/lib/riddle/configuration/sql_source.rb +53 -0
- data/vendor/riddle/lib/riddle/configuration/xml_source.rb +29 -0
- data/vendor/riddle/lib/riddle/configuration.rb +33 -0
- data/vendor/riddle/lib/riddle/controller.rb +78 -0
- data/vendor/riddle/lib/riddle.rb +51 -0
- metadata +312 -0
@@ -0,0 +1,300 @@
|
|
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
|
+
# min prefix length:: 1
|
19
|
+
# min infix length:: 1
|
20
|
+
# mem limit:: 64M
|
21
|
+
# max matches:: 1000
|
22
|
+
# morphology:: nil
|
23
|
+
# charset type:: utf-8
|
24
|
+
# charset table:: nil
|
25
|
+
# ignore chars:: nil
|
26
|
+
# html strip:: false
|
27
|
+
# html remove elements:: ''
|
28
|
+
# searchd_binary_name:: searchd
|
29
|
+
# indexer_binary_name:: indexer
|
30
|
+
#
|
31
|
+
# If you want to change these settings, create a YAML file at
|
32
|
+
# config/sphinx.yml with settings for each environment, in a similar
|
33
|
+
# fashion to database.yml - using the following keys: config_file,
|
34
|
+
# searchd_log_file, query_log_file, pid_file, searchd_file_path, port,
|
35
|
+
# allow_star, enable_star, min_prefix_len, min_infix_len, mem_limit,
|
36
|
+
# max_matches, morphology, charset_type, charset_table, ignore_chars,
|
37
|
+
# html_strip, html_remove_elements, delayed_job_priority,
|
38
|
+
# searchd_binary_name, indexer_binary_name.
|
39
|
+
#
|
40
|
+
# I think you've got the idea.
|
41
|
+
#
|
42
|
+
# Each setting in the YAML file is optional - so only put in the ones you
|
43
|
+
# want to change.
|
44
|
+
#
|
45
|
+
# Keep in mind, if for some particular reason you're using a version of
|
46
|
+
# Sphinx older than 0.9.8 r871 (that's prior to the proper 0.9.8 release),
|
47
|
+
# don't set allow_star to true.
|
48
|
+
#
|
49
|
+
class Configuration
|
50
|
+
include Singleton
|
51
|
+
|
52
|
+
SourceOptions = %w( mysql_connect_flags mysql_ssl_cert mysql_ssl_key
|
53
|
+
mysql_ssl_ca sql_range_step sql_query_pre sql_query_post
|
54
|
+
sql_query_killlist sql_ranged_throttle sql_query_post_index unpack_zlib
|
55
|
+
unpack_mysqlcompress unpack_mysqlcompress_maxsize )
|
56
|
+
|
57
|
+
IndexOptions = %w( charset_table charset_type charset_dictpath docinfo
|
58
|
+
enable_star exceptions html_index_attrs html_remove_elements html_strip
|
59
|
+
index_exact_words ignore_chars inplace_docinfo_gap inplace_enable
|
60
|
+
inplace_hit_gap inplace_reloc_factor inplace_write_factor min_infix_len
|
61
|
+
min_prefix_len min_stemming_len min_word_len mlock morphology ngram_chars
|
62
|
+
ngram_len ondisk_dict overshort_step phrase_boundary phrase_boundary_step
|
63
|
+
preopen stopwords stopwords_step wordforms )
|
64
|
+
|
65
|
+
CustomOptions = %w( disable_range )
|
66
|
+
|
67
|
+
attr_accessor :searchd_file_path, :allow_star, :database_yml_file,
|
68
|
+
:app_root, :model_directories, :delayed_job_priority
|
69
|
+
|
70
|
+
attr_accessor :source_options, :index_options, :section_options
|
71
|
+
|
72
|
+
attr_reader :environment, :configuration, :controller
|
73
|
+
|
74
|
+
# Load in the configuration settings - this will look for config/sphinx.yml
|
75
|
+
# and parse it according to the current environment.
|
76
|
+
#
|
77
|
+
def initialize(app_root = Dir.pwd)
|
78
|
+
self.reset
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.configure(&block)
|
82
|
+
yield instance
|
83
|
+
instance.reset(instance.app_root)
|
84
|
+
end
|
85
|
+
|
86
|
+
def reset(custom_app_root=nil)
|
87
|
+
if custom_app_root
|
88
|
+
self.app_root = custom_app_root
|
89
|
+
else
|
90
|
+
self.app_root = RAILS_ROOT if defined?(RAILS_ROOT)
|
91
|
+
self.app_root = Merb.root if defined?(Merb)
|
92
|
+
self.app_root ||= app_root
|
93
|
+
end
|
94
|
+
|
95
|
+
@configuration = Riddle::Configuration.new
|
96
|
+
@configuration.searchd.pid_file = "#{self.app_root}/log/searchd.#{environment}.pid"
|
97
|
+
@configuration.searchd.log = "#{self.app_root}/log/searchd.log"
|
98
|
+
@configuration.searchd.query_log = "#{self.app_root}/log/searchd.query.log"
|
99
|
+
|
100
|
+
@controller = Riddle::Controller.new @configuration,
|
101
|
+
"#{self.app_root}/config/#{environment}.sphinx.conf"
|
102
|
+
|
103
|
+
self.address = "127.0.0.1"
|
104
|
+
self.port = 9312
|
105
|
+
self.database_yml_file = "#{self.app_root}/config/database.yml"
|
106
|
+
self.searchd_file_path = "#{self.app_root}/db/sphinx/#{environment}"
|
107
|
+
self.allow_star = false
|
108
|
+
self.model_directories = ["#{app_root}/app/models/"] +
|
109
|
+
Dir.glob("#{app_root}/vendor/plugins/*/app/models/")
|
110
|
+
self.delayed_job_priority = 0
|
111
|
+
|
112
|
+
self.source_options = {}
|
113
|
+
self.section_options = {}
|
114
|
+
self.index_options = {
|
115
|
+
:charset_type => "utf-8"
|
116
|
+
}
|
117
|
+
|
118
|
+
parse_config
|
119
|
+
|
120
|
+
self
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.environment
|
124
|
+
Thread.current[:thinking_sphinx_environment] ||= (
|
125
|
+
defined?(Merb) ? Merb.environment : ENV['RAILS_ENV']
|
126
|
+
) || "development"
|
127
|
+
end
|
128
|
+
|
129
|
+
def environment
|
130
|
+
self.class.environment
|
131
|
+
end
|
132
|
+
|
133
|
+
# Generate the config file for Sphinx by using all the settings defined and
|
134
|
+
# looping through all the models with indexes to build the relevant
|
135
|
+
# indexer and searchd configuration, and sources and indexes details.
|
136
|
+
#
|
137
|
+
def build(file_path=nil)
|
138
|
+
file_path ||= "#{self.config_file}"
|
139
|
+
|
140
|
+
@configuration.indexes.clear
|
141
|
+
|
142
|
+
ThinkingSphinx.context.indexed_models.each do |model|
|
143
|
+
model = model.constantize
|
144
|
+
model.define_indexes
|
145
|
+
@configuration.indexes.concat merge_with_section_options!(model.to_riddle)
|
146
|
+
end
|
147
|
+
|
148
|
+
open(file_path, "w") do |file|
|
149
|
+
file.write @configuration.render
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def address
|
154
|
+
@address
|
155
|
+
end
|
156
|
+
|
157
|
+
def address=(address)
|
158
|
+
@address = address
|
159
|
+
@configuration.searchd.address = address
|
160
|
+
end
|
161
|
+
|
162
|
+
def port
|
163
|
+
@port
|
164
|
+
end
|
165
|
+
|
166
|
+
def port=(port)
|
167
|
+
@port = port
|
168
|
+
@configuration.searchd.port = port
|
169
|
+
end
|
170
|
+
|
171
|
+
def pid_file
|
172
|
+
@configuration.searchd.pid_file
|
173
|
+
end
|
174
|
+
|
175
|
+
def pid_file=(pid_file)
|
176
|
+
@configuration.searchd.pid_file = pid_file
|
177
|
+
end
|
178
|
+
|
179
|
+
def searchd_log_file
|
180
|
+
@configuration.searchd.log
|
181
|
+
end
|
182
|
+
|
183
|
+
def searchd_log_file=(file)
|
184
|
+
@configuration.searchd.log = file
|
185
|
+
end
|
186
|
+
|
187
|
+
def query_log_file
|
188
|
+
@configuration.searchd.query_log
|
189
|
+
end
|
190
|
+
|
191
|
+
def query_log_file=(file)
|
192
|
+
@configuration.searchd.query_log = file
|
193
|
+
end
|
194
|
+
|
195
|
+
def config_file
|
196
|
+
@controller.path
|
197
|
+
end
|
198
|
+
|
199
|
+
def config_file=(file)
|
200
|
+
@controller.path = file
|
201
|
+
end
|
202
|
+
|
203
|
+
def bin_path
|
204
|
+
@controller.bin_path
|
205
|
+
end
|
206
|
+
|
207
|
+
def bin_path=(path)
|
208
|
+
@controller.bin_path = path
|
209
|
+
end
|
210
|
+
|
211
|
+
def searchd_binary_name
|
212
|
+
@controller.searchd_binary_name
|
213
|
+
end
|
214
|
+
|
215
|
+
def searchd_binary_name=(name)
|
216
|
+
@controller.searchd_binary_name = name
|
217
|
+
end
|
218
|
+
|
219
|
+
def indexer_binary_name
|
220
|
+
@controller.indexer_binary_name
|
221
|
+
end
|
222
|
+
|
223
|
+
def indexer_binary_name=(name)
|
224
|
+
@controller.indexer_binary_name = name
|
225
|
+
end
|
226
|
+
|
227
|
+
def client
|
228
|
+
client = Riddle::Client.new address, port
|
229
|
+
client.max_matches = configuration.searchd.max_matches || 1000
|
230
|
+
client
|
231
|
+
end
|
232
|
+
|
233
|
+
def models_by_crc
|
234
|
+
@models_by_crc ||= begin
|
235
|
+
ThinkingSphinx.context.indexed_models.inject({}) do |hash, model|
|
236
|
+
hash[model.constantize.to_crc32] = model
|
237
|
+
Object.subclasses_of(model.constantize).each { |subclass|
|
238
|
+
hash[subclass.to_crc32] = subclass.name
|
239
|
+
}
|
240
|
+
hash
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
private
|
246
|
+
|
247
|
+
# Parse the config/sphinx.yml file - if it exists - then use the attribute
|
248
|
+
# accessors to set the appropriate values. Nothing too clever.
|
249
|
+
#
|
250
|
+
def parse_config
|
251
|
+
path = "#{app_root}/config/sphinx.yml"
|
252
|
+
return unless File.exists?(path)
|
253
|
+
|
254
|
+
conf = YAML::load(ERB.new(IO.read(path)).result)[environment]
|
255
|
+
|
256
|
+
conf.each do |key,value|
|
257
|
+
self.send("#{key}=", value) if self.respond_to?("#{key}=")
|
258
|
+
|
259
|
+
if value.is_a?(Hash)
|
260
|
+
self.section_options[key] = value
|
261
|
+
else
|
262
|
+
set_sphinx_setting self.source_options, key, value, SourceOptions
|
263
|
+
set_sphinx_setting self.index_options, key, value, IndexOptions
|
264
|
+
set_sphinx_setting self.index_options, key, value, CustomOptions
|
265
|
+
set_sphinx_setting @configuration.searchd, key, value
|
266
|
+
set_sphinx_setting @configuration.indexer, key, value
|
267
|
+
end
|
268
|
+
end unless conf.nil?
|
269
|
+
|
270
|
+
self.bin_path += '/' unless self.bin_path.blank?
|
271
|
+
|
272
|
+
if self.allow_star
|
273
|
+
self.index_options[:enable_star] = true
|
274
|
+
self.index_options[:min_prefix_len] = 1
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def set_sphinx_setting(object, key, value, allowed = {})
|
279
|
+
if object.is_a?(Hash)
|
280
|
+
object[key.to_sym] = value if allowed.include?(key.to_s)
|
281
|
+
else
|
282
|
+
object.send("#{key}=", value) if object.respond_to?("#{key}")
|
283
|
+
send("#{key}=", value) if self.respond_to?("#{key}")
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
def merge_with_section_options!(indexes)
|
288
|
+
indexes.each do |index|
|
289
|
+
if nested_values = section_options[index.name]
|
290
|
+
nested_values.each_pair {|key, val| index.send(:"#{key}=",val) }
|
291
|
+
end
|
292
|
+
|
293
|
+
if index.respond_to?(:sources)
|
294
|
+
merge_with_section_options!(index.sources)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
indexes
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class ThinkingSphinx::Context
|
2
|
+
attr_reader :indexed_models
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@indexed_models = []
|
6
|
+
end
|
7
|
+
|
8
|
+
def prepare
|
9
|
+
load_models
|
10
|
+
add_indexed_models
|
11
|
+
end
|
12
|
+
|
13
|
+
def define_indexes
|
14
|
+
indexed_models.each { |model|
|
15
|
+
model.constantize.define_indexes
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_indexed_model(model)
|
20
|
+
model = model.name if model.is_a?(Class)
|
21
|
+
|
22
|
+
indexed_models << model
|
23
|
+
indexed_models.uniq!
|
24
|
+
indexed_models.sort!
|
25
|
+
end
|
26
|
+
|
27
|
+
def superclass_indexed_models
|
28
|
+
klasses = indexed_models.collect { |name| name.constantize }
|
29
|
+
klasses.reject { |klass|
|
30
|
+
klass.superclass.ancestors.any? { |ancestor| klasses.include?(ancestor) }
|
31
|
+
}.collect { |klass| klass.name }
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def add_indexed_models
|
37
|
+
Object.subclasses_of(ActiveRecord::Base).each do |klass|
|
38
|
+
add_indexed_model klass if klass.has_sphinx_indexes?
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Make sure all models are loaded - without reloading any that
|
43
|
+
# ActiveRecord::Base is already aware of (otherwise we start to hit some
|
44
|
+
# messy dependencies issues).
|
45
|
+
#
|
46
|
+
def load_models
|
47
|
+
ThinkingSphinx::Configuration.instance.model_directories.each do |base|
|
48
|
+
Dir["#{base}**/*.rb"].each do |file|
|
49
|
+
model_name = file.gsub(/^#{base}([\w_\/\\]+)\.rb/, '\1')
|
50
|
+
|
51
|
+
next if model_name.nil?
|
52
|
+
next if ::ActiveRecord::Base.send(:subclasses).detect { |model|
|
53
|
+
model.name == model_name
|
54
|
+
}
|
55
|
+
|
56
|
+
begin
|
57
|
+
model_name.camelize.constantize
|
58
|
+
rescue LoadError
|
59
|
+
model_name.gsub!(/.*[\/\\]/, '').nil? ? next : retry
|
60
|
+
rescue NameError
|
61
|
+
next
|
62
|
+
rescue StandardError
|
63
|
+
STDERR.puts "Warning: Error loading #{file}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
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.delta = true
|
24
|
+
end
|
25
|
+
|
26
|
+
def toggled(instance)
|
27
|
+
instance.delta
|
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,100 @@
|
|
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://www.sphinxsearch.com/downloads/sphinx-0.9.8.1.tar.gz >> sphinx.log
|
36
|
+
tar xzvf sphinx-0.9.8.1.tar.gz
|
37
|
+
cd sphinx-0.9.8.1
|
38
|
+
./configure #{args.join(" ")}
|
39
|
+
make
|
40
|
+
#{try_sudo} make install
|
41
|
+
rm -rf sphinx-0.9.8.1 sphinx-0.9.8.1.tar.gz
|
42
|
+
CMD
|
43
|
+
run commands.split(/\n\s+/).join(" && ")
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "Install Thinking Sphinx as a gem from GitHub"
|
47
|
+
task :ts do
|
48
|
+
run "#{try_sudo} gem install thinking-sphinx --source http://gemcutter.org"
|
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
|
+
configure
|
65
|
+
rake "thinking_sphinx:start"
|
66
|
+
end
|
67
|
+
|
68
|
+
desc "Stop the Sphinx daemon"
|
69
|
+
task :stop do
|
70
|
+
configure
|
71
|
+
rake "thinking_sphinx:stop"
|
72
|
+
end
|
73
|
+
|
74
|
+
desc "Stop and then start the Sphinx daemon"
|
75
|
+
task :restart do
|
76
|
+
stop
|
77
|
+
start
|
78
|
+
end
|
79
|
+
|
80
|
+
desc "Stop, re-index and then start the Sphinx daemon"
|
81
|
+
task :rebuild do
|
82
|
+
stop
|
83
|
+
index
|
84
|
+
start
|
85
|
+
end
|
86
|
+
|
87
|
+
desc "Add the shared folder for sphinx files for the production environment"
|
88
|
+
task :shared_sphinx_folder, :roles => :web do
|
89
|
+
run "mkdir -p #{shared_path}/db/sphinx/production"
|
90
|
+
end
|
91
|
+
|
92
|
+
def rake(*tasks)
|
93
|
+
rails_env = fetch(:rails_env, "production")
|
94
|
+
rake = fetch(:rake, "rake")
|
95
|
+
tasks.each do |t|
|
96
|
+
run "if [ -d #{release_path} ]; then cd #{release_path}; else cd #{current_path}; fi; #{rake} RAILS_ENV=#{rails_env} #{t}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ThinkingSphinx
|
2
|
+
class Excerpter
|
3
|
+
CoreMethods = %w( kind_of? object_id respond_to? should should_not stub! )
|
4
|
+
# Hide most methods, to allow them to be passed through to the instance.
|
5
|
+
instance_methods.select { |method|
|
6
|
+
method.to_s[/^__/].nil? && !CoreMethods.include?(method.to_s)
|
7
|
+
}.each { |method|
|
8
|
+
undef_method method
|
9
|
+
}
|
10
|
+
|
11
|
+
def initialize(search, instance)
|
12
|
+
@search = search
|
13
|
+
@instance = instance
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(method, *args, &block)
|
17
|
+
string = CGI::escapeHTML @instance.send(method, *args, &block).to_s
|
18
|
+
|
19
|
+
@search.excerpt_for(string, @instance.class)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|