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,194 @@
|
|
1
|
+
require 'thinking_sphinx/source/internal_properties'
|
2
|
+
require 'thinking_sphinx/source/sql'
|
3
|
+
|
4
|
+
module ThinkingSphinx
|
5
|
+
class Source
|
6
|
+
include ThinkingSphinx::Source::InternalProperties
|
7
|
+
include ThinkingSphinx::Source::SQL
|
8
|
+
|
9
|
+
attr_accessor :model, :fields, :attributes, :joins, :conditions, :groupings,
|
10
|
+
:options
|
11
|
+
attr_reader :base, :index, :database_configuration
|
12
|
+
|
13
|
+
def initialize(index, options = {})
|
14
|
+
@index = index
|
15
|
+
@model = index.model
|
16
|
+
@fields = []
|
17
|
+
@attributes = []
|
18
|
+
@joins = []
|
19
|
+
@conditions = []
|
20
|
+
@groupings = []
|
21
|
+
@options = options
|
22
|
+
@associations = {}
|
23
|
+
@database_configuration = @model.connection.
|
24
|
+
instance_variable_get(:@config).clone
|
25
|
+
|
26
|
+
@base = join_dependency_class.new(
|
27
|
+
@model, [], initial_joins
|
28
|
+
)
|
29
|
+
|
30
|
+
unless @model.descends_from_active_record?
|
31
|
+
stored_class = @model.store_full_sti_class ? @model.name : @model.name.demodulize
|
32
|
+
@conditions << "#{@model.quoted_table_name}.#{quote_column(@model.inheritance_column)} = '#{stored_class}'"
|
33
|
+
end
|
34
|
+
|
35
|
+
add_internal_attributes_and_facets
|
36
|
+
end
|
37
|
+
|
38
|
+
def name
|
39
|
+
index.name
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_riddle_for_core(offset, position)
|
43
|
+
source = Riddle::Configuration::SQLSource.new(
|
44
|
+
"#{index.core_name}_#{position}", adapter.sphinx_identifier
|
45
|
+
)
|
46
|
+
|
47
|
+
set_source_database_settings source
|
48
|
+
set_source_fields source
|
49
|
+
set_source_attributes source, offset
|
50
|
+
set_source_settings source
|
51
|
+
set_source_sql source, offset
|
52
|
+
|
53
|
+
source
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_riddle_for_delta(offset, position)
|
57
|
+
source = Riddle::Configuration::SQLSource.new(
|
58
|
+
"#{index.delta_name}_#{position}", adapter.sphinx_identifier
|
59
|
+
)
|
60
|
+
source.parent = "#{index.core_name}_#{position}"
|
61
|
+
|
62
|
+
set_source_database_settings source
|
63
|
+
set_source_fields source
|
64
|
+
set_source_attributes source, offset, true
|
65
|
+
set_source_settings source
|
66
|
+
set_source_sql source, offset, true
|
67
|
+
|
68
|
+
source
|
69
|
+
end
|
70
|
+
|
71
|
+
def delta?
|
72
|
+
!@index.delta_object.nil?
|
73
|
+
end
|
74
|
+
|
75
|
+
# Gets the association stack for a specific key.
|
76
|
+
#
|
77
|
+
def association(key)
|
78
|
+
@associations[key] ||= Association.children(@model, key)
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def adapter
|
84
|
+
@adapter ||= @model.sphinx_database_adapter
|
85
|
+
end
|
86
|
+
|
87
|
+
def available_attributes
|
88
|
+
attributes.select { |attrib| attrib.available? }
|
89
|
+
end
|
90
|
+
|
91
|
+
def set_source_database_settings(source)
|
92
|
+
config = @database_configuration
|
93
|
+
|
94
|
+
source.sql_host = config[:host] || "localhost"
|
95
|
+
source.sql_user = config[:username] || config[:user] || 'root'
|
96
|
+
source.sql_pass = (config[:password].to_s || "").gsub('#', '\#')
|
97
|
+
source.sql_db = config[:database]
|
98
|
+
source.sql_port = config[:port]
|
99
|
+
source.sql_sock = config[:socket]
|
100
|
+
end
|
101
|
+
|
102
|
+
def set_source_fields(source)
|
103
|
+
fields.each do |field|
|
104
|
+
source.sql_file_field << field.unique_name if field.file?
|
105
|
+
source.sql_field_string << field.unique_name if field.with_attribute?
|
106
|
+
source.sql_field_str2wordcount << field.unique_name if field.with_wordcount?
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def set_source_attributes(source, offset, delta = false)
|
111
|
+
available_attributes.each do |attrib|
|
112
|
+
source.send(attrib.type_to_config) << attrib.config_value(offset, delta)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def set_source_sql(source, offset, delta = false)
|
117
|
+
source.sql_query = to_sql(:offset => offset, :delta => delta).gsub(/\n/, ' ')
|
118
|
+
source.sql_query_range = to_sql_query_range(:delta => delta)
|
119
|
+
source.sql_query_info = to_sql_query_info(offset)
|
120
|
+
|
121
|
+
source.sql_query_pre += send(!delta ? :sql_query_pre_for_core : :sql_query_pre_for_delta)
|
122
|
+
|
123
|
+
if @index.local_options[:group_concat_max_len]
|
124
|
+
source.sql_query_pre << "SET SESSION group_concat_max_len = #{@index.local_options[:group_concat_max_len]}"
|
125
|
+
end
|
126
|
+
|
127
|
+
source.sql_query_pre += [adapter.utf8_query_pre].compact if utf8?
|
128
|
+
source.sql_query_pre << adapter.utc_query_pre
|
129
|
+
end
|
130
|
+
|
131
|
+
def set_source_settings(source)
|
132
|
+
config = ThinkingSphinx::Configuration.instance
|
133
|
+
config.source_options.each do |key, value|
|
134
|
+
source.send("#{key}=".to_sym, value)
|
135
|
+
end
|
136
|
+
|
137
|
+
source_options = ThinkingSphinx::Configuration::SourceOptions
|
138
|
+
@options.each do |key, value|
|
139
|
+
if source_options.include?(key.to_s) && !value.nil?
|
140
|
+
source.send("#{key}=".to_sym, value)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Returns all associations used amongst all the fields and attributes.
|
146
|
+
# This includes all associations between the model and what the actual
|
147
|
+
# columns are from.
|
148
|
+
#
|
149
|
+
def all_associations
|
150
|
+
@all_associations ||= (
|
151
|
+
# field associations
|
152
|
+
@fields.collect { |field|
|
153
|
+
field.associations.values
|
154
|
+
}.flatten +
|
155
|
+
# attribute associations
|
156
|
+
@attributes.collect { |attrib|
|
157
|
+
attrib.associations.values if attrib.include_as_association?
|
158
|
+
}.compact.flatten +
|
159
|
+
# explicit joins
|
160
|
+
@joins.collect { |join|
|
161
|
+
join.associations
|
162
|
+
}.flatten
|
163
|
+
).uniq.collect { |assoc|
|
164
|
+
# get ancestors as well as column-level associations
|
165
|
+
assoc.ancestors
|
166
|
+
}.flatten.uniq
|
167
|
+
end
|
168
|
+
|
169
|
+
def utf8?
|
170
|
+
@index.options[:charset_type] =~ /utf-8|zh_cn.utf-8/
|
171
|
+
end
|
172
|
+
|
173
|
+
def join_dependency_class
|
174
|
+
if rails_3_1?
|
175
|
+
::ActiveRecord::Associations::JoinDependency
|
176
|
+
else
|
177
|
+
::ActiveRecord::Associations::ClassMethods::JoinDependency
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def initial_joins
|
182
|
+
if rails_3_1?
|
183
|
+
[]
|
184
|
+
else
|
185
|
+
nil
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def rails_3_1?
|
190
|
+
::ActiveRecord::Associations.constants.include?(:JoinDependency) ||
|
191
|
+
::ActiveRecord::Associations.constants.include?('JoinDependency')
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'timeout'
|
3
|
+
|
4
|
+
namespace :thinking_sphinx do
|
5
|
+
task :app_env do
|
6
|
+
if defined?(Rails)
|
7
|
+
Rails.application.require_environment!
|
8
|
+
Rails.configuration.cache_classes = false
|
9
|
+
elsif defined?(Merb)
|
10
|
+
Rake::Task[:merb_env].invoke
|
11
|
+
elsif defined?(Sinatra)
|
12
|
+
Sinatra::Application.environment = ENV['RACK_ENV']
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Output the current Thinking Sphinx version"
|
17
|
+
task :version => :app_env do
|
18
|
+
puts "Thinking Sphinx v" + ThinkingSphinx::Version
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "Stop if running, then start a Sphinx searchd daemon using Thinking Sphinx's settings"
|
22
|
+
task :running_start => :app_env do
|
23
|
+
Rake::Task["thinking_sphinx:stop"].invoke if sphinx_running?
|
24
|
+
Rake::Task["thinking_sphinx:start"].invoke
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Start a Sphinx searchd daemon using Thinking Sphinx's settings"
|
28
|
+
task :start => :app_env do
|
29
|
+
config = ThinkingSphinx::Configuration.instance
|
30
|
+
|
31
|
+
FileUtils.mkdir_p config.searchd_file_path
|
32
|
+
raise RuntimeError, "searchd is already running." if sphinx_running?
|
33
|
+
|
34
|
+
Dir["#{config.searchd_file_path}/*.spl"].each { |file| File.delete(file) }
|
35
|
+
|
36
|
+
config.controller.start
|
37
|
+
|
38
|
+
if sphinx_running?
|
39
|
+
puts "Started successfully (pid #{sphinx_pid})."
|
40
|
+
else
|
41
|
+
puts "Failed to start searchd daemon. Check #{config.searchd_log_file}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "Stop Sphinx using Thinking Sphinx's settings"
|
46
|
+
task :stop => :app_env do
|
47
|
+
unless sphinx_running?
|
48
|
+
puts "searchd is not running"
|
49
|
+
else
|
50
|
+
config = ThinkingSphinx::Configuration.instance
|
51
|
+
pid = sphinx_pid
|
52
|
+
config.controller.stop
|
53
|
+
|
54
|
+
# Ensure searchd is stopped, but don't try too hard
|
55
|
+
Timeout.timeout(config.stop_timeout) do
|
56
|
+
sleep(1) until config.controller.stop
|
57
|
+
end
|
58
|
+
|
59
|
+
puts "Stopped search daemon (pid #{pid})."
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
desc "Restart Sphinx"
|
64
|
+
task :restart => [:app_env, :stop, :start]
|
65
|
+
|
66
|
+
desc "Generate the Sphinx configuration file using Thinking Sphinx's settings"
|
67
|
+
task :configure => :app_env do
|
68
|
+
config = ThinkingSphinx::Configuration.instance
|
69
|
+
puts "Generating Configuration to #{config.config_file}"
|
70
|
+
config.build
|
71
|
+
end
|
72
|
+
|
73
|
+
desc "Index data for Sphinx using Thinking Sphinx's settings"
|
74
|
+
task :index => :app_env do
|
75
|
+
config = ThinkingSphinx::Configuration.instance
|
76
|
+
unless ENV["INDEX_ONLY"] == "true"
|
77
|
+
puts "Generating Configuration to #{config.config_file}"
|
78
|
+
config.build
|
79
|
+
end
|
80
|
+
|
81
|
+
FileUtils.mkdir_p config.searchd_file_path
|
82
|
+
config.controller.index :verbose => true
|
83
|
+
end
|
84
|
+
|
85
|
+
desc "Reindex Sphinx without regenerating the configuration file"
|
86
|
+
task :reindex => :app_env do
|
87
|
+
config = ThinkingSphinx::Configuration.instance
|
88
|
+
FileUtils.mkdir_p config.searchd_file_path
|
89
|
+
output = config.controller.index
|
90
|
+
puts output
|
91
|
+
config.touch_reindex_file(output)
|
92
|
+
end
|
93
|
+
|
94
|
+
desc "Stop Sphinx (if it's running), rebuild the indexes, and start Sphinx"
|
95
|
+
task :rebuild => :app_env do
|
96
|
+
Rake::Task["thinking_sphinx:stop"].invoke if sphinx_running?
|
97
|
+
Rake::Task["thinking_sphinx:index"].invoke
|
98
|
+
Rake::Task["thinking_sphinx:start"].invoke
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
namespace :ts do
|
103
|
+
desc "Output the current Thinking Sphinx version"
|
104
|
+
task :version => "thinking_sphinx:version"
|
105
|
+
desc "Stop if running, then start a Sphinx searchd daemon using Thinking Sphinx's settings"
|
106
|
+
task :run => "thinking_sphinx:running_start"
|
107
|
+
desc "Start a Sphinx searchd daemon using Thinking Sphinx's settings"
|
108
|
+
task :start => "thinking_sphinx:start"
|
109
|
+
desc "Stop Sphinx using Thinking Sphinx's settings"
|
110
|
+
task :stop => "thinking_sphinx:stop"
|
111
|
+
desc "Index data for Sphinx using Thinking Sphinx's settings"
|
112
|
+
task :in => "thinking_sphinx:index"
|
113
|
+
task :index => "thinking_sphinx:index"
|
114
|
+
desc "Reindex Sphinx without regenerating the configuration file"
|
115
|
+
task :reindex => "thinking_sphinx:reindex"
|
116
|
+
desc "Restart Sphinx"
|
117
|
+
task :restart => "thinking_sphinx:restart"
|
118
|
+
desc "Generate the Sphinx configuration file using Thinking Sphinx's settings"
|
119
|
+
task :conf => "thinking_sphinx:configure"
|
120
|
+
desc "Generate the Sphinx configuration file using Thinking Sphinx's settings"
|
121
|
+
task :config => "thinking_sphinx:configure"
|
122
|
+
desc "Stop Sphinx (if it's running), rebuild the indexes, and start Sphinx"
|
123
|
+
task :rebuild => "thinking_sphinx:rebuild"
|
124
|
+
end
|
125
|
+
|
126
|
+
def sphinx_pid
|
127
|
+
ThinkingSphinx.sphinx_pid
|
128
|
+
end
|
129
|
+
|
130
|
+
def sphinx_running?
|
131
|
+
ThinkingSphinx.sphinx_running?
|
132
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class ThinkingSphinx::Test
|
2
|
+
def self.init(suppress_delta_output = true)
|
3
|
+
set_flags suppress_delta_output
|
4
|
+
create_indexes_folder
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.start
|
8
|
+
config.build
|
9
|
+
config.controller.index
|
10
|
+
config.controller.start
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.start_with_autostop
|
14
|
+
autostop
|
15
|
+
start
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.stop
|
19
|
+
config.controller.stop
|
20
|
+
sleep(0.5) # Ensure Sphinx has shut down completely
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.autostop
|
24
|
+
Kernel.at_exit do
|
25
|
+
ThinkingSphinx::Test.stop
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.run(&block)
|
30
|
+
begin
|
31
|
+
start
|
32
|
+
yield
|
33
|
+
ensure
|
34
|
+
stop
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.config
|
39
|
+
@config ||= ::ThinkingSphinx::Configuration.instance
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.index(*indexes)
|
43
|
+
config.controller.index *indexes
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.set_flags(suppress_delta_output)
|
47
|
+
::ThinkingSphinx.deltas_enabled = true
|
48
|
+
::ThinkingSphinx.updates_enabled = true
|
49
|
+
::ThinkingSphinx.suppress_delta_output = suppress_delta_output
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.create_indexes_folder
|
53
|
+
FileUtils.mkdir_p config.searchd_file_path
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,296 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'active_record'
|
3
|
+
require 'yaml'
|
4
|
+
require 'riddle'
|
5
|
+
|
6
|
+
require 'thinking_sphinx/auto_version'
|
7
|
+
require 'thinking_sphinx/core/string'
|
8
|
+
require 'thinking_sphinx/property'
|
9
|
+
require 'thinking_sphinx/active_record'
|
10
|
+
require 'thinking_sphinx/association'
|
11
|
+
require 'thinking_sphinx/attribute'
|
12
|
+
require 'thinking_sphinx/bundled_search'
|
13
|
+
require 'thinking_sphinx/configuration'
|
14
|
+
require 'thinking_sphinx/context'
|
15
|
+
require 'thinking_sphinx/excerpter'
|
16
|
+
require 'thinking_sphinx/facet'
|
17
|
+
require 'thinking_sphinx/class_facet'
|
18
|
+
require 'thinking_sphinx/facet_search'
|
19
|
+
require 'thinking_sphinx/field'
|
20
|
+
require 'thinking_sphinx/index'
|
21
|
+
require 'thinking_sphinx/join'
|
22
|
+
require 'thinking_sphinx/source'
|
23
|
+
require 'thinking_sphinx/search'
|
24
|
+
require 'thinking_sphinx/search_methods'
|
25
|
+
require 'thinking_sphinx/deltas'
|
26
|
+
|
27
|
+
require 'thinking_sphinx/adapters/abstract_adapter'
|
28
|
+
require 'thinking_sphinx/adapters/mysql_adapter'
|
29
|
+
require 'thinking_sphinx/adapters/postgresql_adapter'
|
30
|
+
|
31
|
+
require 'thinking_sphinx/railtie' if defined?(Rails)
|
32
|
+
|
33
|
+
module ThinkingSphinx
|
34
|
+
mattr_accessor :database_adapter
|
35
|
+
|
36
|
+
# A ConnectionError will get thrown when a connection to Sphinx can't be
|
37
|
+
# made.
|
38
|
+
class ConnectionError < StandardError
|
39
|
+
end
|
40
|
+
|
41
|
+
# A StaleIdsException is thrown by Collection.instances_from_matches if there
|
42
|
+
# are records in Sphinx but not in the database, so the search can be retried.
|
43
|
+
class StaleIdsException < StandardError
|
44
|
+
attr_accessor :ids
|
45
|
+
def initialize(ids)
|
46
|
+
self.ids = ids
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# A SphinxError occurs when Sphinx responds with an error due to problematic
|
51
|
+
# queries or indexes.
|
52
|
+
class SphinxError < RuntimeError
|
53
|
+
attr_accessor :results
|
54
|
+
def initialize(message = nil, results = nil)
|
55
|
+
super(message)
|
56
|
+
self.results = results
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# The collection of indexed models. Keep in mind that Rails lazily loads
|
61
|
+
# its classes, so this may not actually be populated with _all_ the models
|
62
|
+
# that have Sphinx indexes.
|
63
|
+
@@sphinx_mutex = Mutex.new
|
64
|
+
@@context = nil
|
65
|
+
@@define_indexes = true
|
66
|
+
@@deltas_enabled = nil
|
67
|
+
@@updates_enabled = nil
|
68
|
+
@@suppress_delta_output = false
|
69
|
+
@@remote_sphinx = false
|
70
|
+
@@use_group_by_shortcut = nil
|
71
|
+
|
72
|
+
def self.mutex
|
73
|
+
@@sphinx_mutex
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.context
|
77
|
+
if @@context.nil?
|
78
|
+
mutex.synchronize do
|
79
|
+
if @@context.nil?
|
80
|
+
@@context = ThinkingSphinx::Context.new
|
81
|
+
@@context.prepare
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
@@context
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.reset_context!(context = nil)
|
90
|
+
mutex.synchronize do
|
91
|
+
@@context = context
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.unique_id_expression(adapter, offset = nil)
|
96
|
+
"* #{adapter.cast_to_int context.indexed_models.size} + #{offset || 0}"
|
97
|
+
end
|
98
|
+
|
99
|
+
# Check if index definition is disabled.
|
100
|
+
#
|
101
|
+
def self.define_indexes?
|
102
|
+
@@define_indexes
|
103
|
+
end
|
104
|
+
|
105
|
+
# Enable/disable indexes - you may want to do this while migrating data.
|
106
|
+
#
|
107
|
+
# ThinkingSphinx.define_indexes = false
|
108
|
+
#
|
109
|
+
def self.define_indexes=(value)
|
110
|
+
mutex.synchronize do
|
111
|
+
@@define_indexes = value
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Check if delta indexing is enabled/disabled.
|
116
|
+
#
|
117
|
+
def self.deltas_enabled?
|
118
|
+
if @@deltas_enabled.nil?
|
119
|
+
mutex.synchronize do
|
120
|
+
if @@deltas_enabled.nil?
|
121
|
+
@@deltas_enabled = (
|
122
|
+
ThinkingSphinx::Configuration.environment != "test"
|
123
|
+
)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
@@deltas_enabled && !deltas_suspended?
|
129
|
+
end
|
130
|
+
|
131
|
+
# Enable/disable delta indexing.
|
132
|
+
#
|
133
|
+
# ThinkingSphinx.deltas_enabled = false
|
134
|
+
#
|
135
|
+
def self.deltas_enabled=(value)
|
136
|
+
mutex.synchronize do
|
137
|
+
@@deltas_enabled = value
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Check if delta indexing is suspended.
|
142
|
+
#
|
143
|
+
def self.deltas_suspended?
|
144
|
+
if Thread.current[:thinking_sphinx_deltas_suspended].nil?
|
145
|
+
Thread.current[:thinking_sphinx_deltas_suspended] = false
|
146
|
+
end
|
147
|
+
|
148
|
+
Thread.current[:thinking_sphinx_deltas_suspended]
|
149
|
+
end
|
150
|
+
|
151
|
+
# Suspend/resume delta indexing.
|
152
|
+
#
|
153
|
+
# ThinkingSphinx.deltas_suspended = false
|
154
|
+
#
|
155
|
+
def self.deltas_suspended=(value)
|
156
|
+
Thread.current[:thinking_sphinx_deltas_suspended] = value
|
157
|
+
end
|
158
|
+
|
159
|
+
# Check if updates are enabled. True by default, unless within the test
|
160
|
+
# environment.
|
161
|
+
#
|
162
|
+
def self.updates_enabled?
|
163
|
+
if @@updates_enabled.nil?
|
164
|
+
mutex.synchronize do
|
165
|
+
if @@updates_enabled.nil?
|
166
|
+
@@updates_enabled = (
|
167
|
+
ThinkingSphinx::Configuration.environment != "test"
|
168
|
+
)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
@@updates_enabled
|
174
|
+
end
|
175
|
+
|
176
|
+
# Enable/disable updates to Sphinx
|
177
|
+
#
|
178
|
+
# ThinkingSphinx.updates_enabled = false
|
179
|
+
#
|
180
|
+
def self.updates_enabled=(value)
|
181
|
+
mutex.synchronize do
|
182
|
+
@@updates_enabled = value
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.suppress_delta_output?
|
187
|
+
@@suppress_delta_output
|
188
|
+
end
|
189
|
+
|
190
|
+
def self.suppress_delta_output=(value)
|
191
|
+
mutex.synchronize do
|
192
|
+
@@suppress_delta_output = value
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# Checks to see if MySQL will allow simplistic GROUP BY statements. If not,
|
197
|
+
# or if not using MySQL, this will return false.
|
198
|
+
#
|
199
|
+
def self.use_group_by_shortcut?
|
200
|
+
if @@use_group_by_shortcut.nil?
|
201
|
+
mutex.synchronize do
|
202
|
+
if @@use_group_by_shortcut.nil?
|
203
|
+
@@use_group_by_shortcut = !!(
|
204
|
+
mysql? && ::ActiveRecord::Base.connection.select_all(
|
205
|
+
"SELECT @@global.sql_mode, @@session.sql_mode;"
|
206
|
+
).all? { |key, value|
|
207
|
+
value.nil? || value[/ONLY_FULL_GROUP_BY/].nil?
|
208
|
+
}
|
209
|
+
)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
@@use_group_by_shortcut
|
215
|
+
end
|
216
|
+
|
217
|
+
def self.reset_use_group_by_shortcut
|
218
|
+
mutex.synchronize do
|
219
|
+
@@use_group_by_shortcut = nil
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# An indication of whether Sphinx is running on a remote machine instead of
|
224
|
+
# the same machine.
|
225
|
+
#
|
226
|
+
def self.remote_sphinx?
|
227
|
+
@@remote_sphinx
|
228
|
+
end
|
229
|
+
|
230
|
+
# Tells Thinking Sphinx that Sphinx is running on a different machine, and
|
231
|
+
# thus it can't reliably guess whether it is running or not (ie: the
|
232
|
+
# #sphinx_running? method), and so just assumes it is.
|
233
|
+
#
|
234
|
+
# Useful for multi-machine deployments. Set it in your production.rb file.
|
235
|
+
#
|
236
|
+
# ThinkingSphinx.remote_sphinx = true
|
237
|
+
#
|
238
|
+
def self.remote_sphinx=(value)
|
239
|
+
mutex.synchronize do
|
240
|
+
@@remote_sphinx = value
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# Check if Sphinx is running. If remote_sphinx is set to true (indicating
|
245
|
+
# Sphinx is on a different machine), this will always return true, and you
|
246
|
+
# will have to handle any connection errors yourself.
|
247
|
+
#
|
248
|
+
def self.sphinx_running?
|
249
|
+
remote_sphinx? || sphinx_running_by_pid?
|
250
|
+
end
|
251
|
+
|
252
|
+
# Check if Sphinx is actually running, provided the pid is on the same
|
253
|
+
# machine as this code.
|
254
|
+
#
|
255
|
+
def self.sphinx_running_by_pid?
|
256
|
+
!!sphinx_pid && pid_active?(sphinx_pid)
|
257
|
+
end
|
258
|
+
|
259
|
+
def self.sphinx_pid
|
260
|
+
if File.exists?(ThinkingSphinx::Configuration.instance.pid_file)
|
261
|
+
File.read(ThinkingSphinx::Configuration.instance.pid_file)[/\d+/]
|
262
|
+
else
|
263
|
+
nil
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def self.pid_active?(pid)
|
268
|
+
!!Process.kill(0, pid.to_i)
|
269
|
+
rescue Errno::EPERM => e
|
270
|
+
true
|
271
|
+
rescue Exception => e
|
272
|
+
false
|
273
|
+
end
|
274
|
+
|
275
|
+
def self.microsoft?
|
276
|
+
RUBY_PLATFORM =~ /mswin/
|
277
|
+
end
|
278
|
+
|
279
|
+
def self.jruby?
|
280
|
+
defined?(JRUBY_VERSION)
|
281
|
+
end
|
282
|
+
|
283
|
+
def self.mysql?
|
284
|
+
::ActiveRecord::Base.connection.class.name.demodulize == "MysqlAdapter" ||
|
285
|
+
::ActiveRecord::Base.connection.class.name.demodulize == "Mysql2Adapter" ||
|
286
|
+
::ActiveRecord::Base.connection.class.name.demodulize == "MysqlplusAdapter" || (
|
287
|
+
jruby? && ::ActiveRecord::Base.connection.config[:adapter] == "jdbcmysql"
|
288
|
+
)
|
289
|
+
end
|
290
|
+
|
291
|
+
def self.rails_3_1?
|
292
|
+
!!defined?(::ActiveRecord::Associations::CollectionProxy)
|
293
|
+
end
|
294
|
+
|
295
|
+
extend ThinkingSphinx::SearchMethods::ClassMethods
|
296
|
+
end
|