thinking-sphinx 3.0.6 → 3.1.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +11 -6
- data/Appraisals +5 -5
- data/Gemfile +3 -3
- data/HISTORY +32 -0
- data/README.textile +16 -5
- data/gemfiles/rails_3_2.gemfile +2 -1
- data/gemfiles/rails_4_0.gemfile +3 -2
- data/gemfiles/{rails_3_1.gemfile → rails_4_1.gemfile} +3 -2
- data/lib/thinking_sphinx.rb +5 -0
- data/lib/thinking_sphinx/active_record.rb +2 -1
- data/lib/thinking_sphinx/active_record/association_proxy/attribute_finder.rb +1 -1
- data/lib/thinking_sphinx/active_record/callbacks/delete_callbacks.rb +6 -7
- data/lib/thinking_sphinx/active_record/callbacks/delta_callbacks.rb +2 -2
- data/lib/thinking_sphinx/active_record/callbacks/update_callbacks.rb +1 -1
- data/lib/thinking_sphinx/active_record/column_sql_presenter.rb +34 -0
- data/lib/thinking_sphinx/active_record/database_adapters/mysql_adapter.rb +4 -0
- data/lib/thinking_sphinx/active_record/database_adapters/postgresql_adapter.rb +4 -0
- data/lib/thinking_sphinx/active_record/index.rb +2 -1
- data/lib/thinking_sphinx/active_record/interpreter.rb +7 -0
- data/lib/thinking_sphinx/active_record/property.rb +1 -1
- data/lib/thinking_sphinx/active_record/property_sql_presenter.rb +10 -16
- data/lib/thinking_sphinx/active_record/sql_builder.rb +7 -1
- data/lib/thinking_sphinx/active_record/sql_builder/query.rb +0 -7
- data/lib/thinking_sphinx/active_record/sql_source.rb +20 -20
- data/lib/thinking_sphinx/active_record/sql_source/template.rb +1 -1
- data/lib/thinking_sphinx/capistrano.rb +6 -65
- data/lib/thinking_sphinx/capistrano/v2.rb +58 -0
- data/lib/thinking_sphinx/capistrano/v3.rb +101 -0
- data/lib/thinking_sphinx/configuration.rb +8 -3
- data/lib/thinking_sphinx/configuration/distributed_indices.rb +29 -0
- data/lib/thinking_sphinx/connection.rb +90 -34
- data/lib/thinking_sphinx/controller.rb +20 -0
- data/lib/thinking_sphinx/core/index.rb +4 -0
- data/lib/thinking_sphinx/deletion.rb +15 -11
- data/lib/thinking_sphinx/deltas.rb +9 -0
- data/lib/thinking_sphinx/deltas/default_delta.rb +2 -0
- data/lib/thinking_sphinx/distributed.rb +5 -0
- data/lib/thinking_sphinx/distributed/index.rb +24 -0
- data/lib/thinking_sphinx/excerpter.rb +7 -3
- data/lib/thinking_sphinx/facet_search.rb +1 -1
- data/lib/thinking_sphinx/index.rb +2 -6
- data/lib/thinking_sphinx/index_set.rb +10 -8
- data/lib/thinking_sphinx/middlewares.rb +0 -2
- data/lib/thinking_sphinx/middlewares/active_record_translator.rb +1 -0
- data/lib/thinking_sphinx/middlewares/geographer.rb +1 -1
- data/lib/thinking_sphinx/middlewares/sphinxql.rb +8 -6
- data/lib/thinking_sphinx/middlewares/utf8.rb +6 -1
- data/lib/thinking_sphinx/query.rb +9 -0
- data/lib/thinking_sphinx/railtie.rb +0 -13
- data/lib/thinking_sphinx/search/query.rb +3 -21
- data/lib/thinking_sphinx/sphinxql.rb +1 -1
- data/lib/thinking_sphinx/wildcard.rb +34 -0
- data/spec/acceptance/geosearching_spec.rb +13 -0
- data/spec/acceptance/indexing_spec.rb +27 -0
- data/spec/acceptance/remove_deleted_records_spec.rb +8 -0
- data/spec/acceptance/searching_with_sti_spec.rb +7 -0
- data/spec/acceptance/searching_within_a_model_spec.rb +8 -0
- data/spec/acceptance/sorting_search_results_spec.rb +1 -1
- data/spec/acceptance/spec_helper.rb +13 -0
- data/spec/acceptance/specifying_sql_spec.rb +2 -2
- data/spec/acceptance/support/sphinx_controller.rb +5 -5
- data/spec/acceptance/support/sphinx_helpers.rb +3 -0
- data/spec/acceptance/suspended_deltas_spec.rb +34 -0
- data/spec/internal/config/database.yml +1 -0
- data/spec/thinking_sphinx/active_record/callbacks/delete_callbacks_spec.rb +13 -6
- data/spec/thinking_sphinx/active_record/callbacks/update_callbacks_spec.rb +2 -2
- data/spec/thinking_sphinx/active_record/database_adapters/mysql_adapter_spec.rb +7 -0
- data/spec/thinking_sphinx/active_record/database_adapters/postgresql_adapter_spec.rb +6 -0
- data/spec/thinking_sphinx/active_record/interpreter_spec.rb +27 -0
- data/spec/thinking_sphinx/active_record/property_sql_presenter_spec.rb +18 -7
- data/spec/thinking_sphinx/active_record/sql_builder_spec.rb +17 -7
- data/spec/thinking_sphinx/active_record/sql_source_spec.rb +84 -82
- data/spec/thinking_sphinx/configuration_spec.rb +5 -4
- data/spec/thinking_sphinx/connection_spec.rb +1 -1
- data/spec/thinking_sphinx/deletion_spec.rb +10 -28
- data/spec/thinking_sphinx/excerpter_spec.rb +3 -3
- data/spec/thinking_sphinx/facet_search_spec.rb +13 -4
- data/spec/thinking_sphinx/index_set_spec.rb +9 -4
- data/spec/thinking_sphinx/middlewares/active_record_translator_spec.rb +8 -0
- data/spec/thinking_sphinx/middlewares/geographer_spec.rb +7 -7
- data/spec/thinking_sphinx/middlewares/sphinxql_spec.rb +17 -1
- data/spec/thinking_sphinx/search/query_spec.rb +10 -53
- data/spec/thinking_sphinx/wildcard_spec.rb +41 -0
- data/thinking-sphinx.gemspec +6 -5
- metadata +38 -14
- data/lib/thinking_sphinx/active_record/associations.rb +0 -98
- data/spec/thinking_sphinx/active_record/associations_spec.rb +0 -230
|
@@ -24,6 +24,12 @@ module ThinkingSphinx
|
|
|
24
24
|
query.to_query
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
def sql_query_post_index
|
|
28
|
+
return [] unless delta_processor && !source.delta?
|
|
29
|
+
|
|
30
|
+
[delta_processor.reset_query]
|
|
31
|
+
end
|
|
32
|
+
|
|
27
33
|
private
|
|
28
34
|
|
|
29
35
|
delegate :adapter, :model, :delta_processor, :to => :source
|
|
@@ -47,7 +53,7 @@ module ThinkingSphinx
|
|
|
47
53
|
end
|
|
48
54
|
|
|
49
55
|
def associations
|
|
50
|
-
@associations ||=
|
|
56
|
+
@associations ||= Joiner::Joins.new(model).tap do |assocs|
|
|
51
57
|
source.associations.reject(&:string?).each do |association|
|
|
52
58
|
assocs.add_join_to association.stack
|
|
53
59
|
end
|
|
@@ -18,17 +18,10 @@ module ThinkingSphinx
|
|
|
18
18
|
|
|
19
19
|
def filter_by_query_pre
|
|
20
20
|
scope_by_time_zone
|
|
21
|
-
scope_by_delta_processor
|
|
22
21
|
scope_by_session
|
|
23
22
|
scope_by_utf8
|
|
24
23
|
end
|
|
25
24
|
|
|
26
|
-
def scope_by_delta_processor
|
|
27
|
-
return unless delta_processor && !source.delta?
|
|
28
|
-
|
|
29
|
-
self.scope << delta_processor.reset_query
|
|
30
|
-
end
|
|
31
|
-
|
|
32
25
|
def scope_by_session
|
|
33
26
|
return unless max_len = source.options[:group_concat_max_len]
|
|
34
27
|
|
|
@@ -6,13 +6,13 @@ module ThinkingSphinx
|
|
|
6
6
|
attr_accessor :fields, :attributes, :associations, :conditions,
|
|
7
7
|
:groupings, :polymorphs
|
|
8
8
|
|
|
9
|
-
OPTIONS = [:name, :offset, :delta_processor, :delta?, :
|
|
10
|
-
:group_concat_max_len, :utf8?, :position,
|
|
9
|
+
OPTIONS = [:name, :offset, :delta_processor, :delta?, :delta_options,
|
|
10
|
+
:disable_range?, :group_concat_max_len, :utf8?, :position,
|
|
11
|
+
:minimal_group_by?]
|
|
11
12
|
|
|
12
13
|
def initialize(model, options = {})
|
|
13
14
|
@model = model
|
|
14
|
-
@database_settings =
|
|
15
|
-
instance_variable_get(:@config).clone
|
|
15
|
+
@database_settings = model.connection.instance_variable_get(:@config).clone
|
|
16
16
|
@options = {
|
|
17
17
|
:utf8? => (@database_settings[:encoding] == 'utf8')
|
|
18
18
|
}.merge options
|
|
@@ -38,7 +38,7 @@ module ThinkingSphinx
|
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def delta_processor
|
|
41
|
-
options[:delta_processor].try(:new, adapter)
|
|
41
|
+
options[:delta_processor].try(:new, adapter, @options[:delta_options] || {})
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def delta?
|
|
@@ -67,6 +67,15 @@ module ThinkingSphinx
|
|
|
67
67
|
super
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
+
def set_database_settings(settings)
|
|
71
|
+
@sql_host ||= settings[:host] || 'localhost'
|
|
72
|
+
@sql_user ||= settings[:username] || settings[:user] || ENV['USER']
|
|
73
|
+
@sql_pass ||= settings[:password].to_s.gsub('#', '\#')
|
|
74
|
+
@sql_db ||= settings[:database]
|
|
75
|
+
@sql_port ||= settings[:port]
|
|
76
|
+
@sql_sock ||= settings[:socket]
|
|
77
|
+
end
|
|
78
|
+
|
|
70
79
|
def type
|
|
71
80
|
@type ||= case adapter
|
|
72
81
|
when DatabaseAdapters::MySQLAdapter
|
|
@@ -107,10 +116,11 @@ module ThinkingSphinx
|
|
|
107
116
|
end
|
|
108
117
|
|
|
109
118
|
def build_sql_query
|
|
110
|
-
@sql_query
|
|
111
|
-
@sql_query_range
|
|
112
|
-
@sql_query_info
|
|
113
|
-
@sql_query_pre
|
|
119
|
+
@sql_query = builder.sql_query
|
|
120
|
+
@sql_query_range ||= builder.sql_query_range
|
|
121
|
+
@sql_query_info ||= builder.sql_query_info
|
|
122
|
+
@sql_query_pre += builder.sql_query_pre
|
|
123
|
+
@sql_query_post_index += builder.sql_query_post_index
|
|
114
124
|
end
|
|
115
125
|
|
|
116
126
|
def config
|
|
@@ -121,7 +131,7 @@ module ThinkingSphinx
|
|
|
121
131
|
polymorphs.each &:morph!
|
|
122
132
|
append_presenter_to_attribute_array
|
|
123
133
|
|
|
124
|
-
set_database_settings
|
|
134
|
+
set_database_settings database_settings
|
|
125
135
|
build_sql_fields
|
|
126
136
|
build_sql_query
|
|
127
137
|
|
|
@@ -131,16 +141,6 @@ module ThinkingSphinx
|
|
|
131
141
|
def properties
|
|
132
142
|
fields + attributes
|
|
133
143
|
end
|
|
134
|
-
|
|
135
|
-
def set_database_settings
|
|
136
|
-
@sql_host ||= database_settings[:host] || 'localhost'
|
|
137
|
-
@sql_user ||= database_settings[:username] || database_settings[:user] ||
|
|
138
|
-
ENV['USER']
|
|
139
|
-
@sql_pass ||= database_settings[:password].to_s.gsub('#', '\#')
|
|
140
|
-
@sql_db ||= database_settings[:database]
|
|
141
|
-
@sql_port ||= database_settings[:port]
|
|
142
|
-
@sql_sock ||= database_settings[:socket]
|
|
143
|
-
end
|
|
144
144
|
end
|
|
145
145
|
end
|
|
146
146
|
end
|
|
@@ -33,7 +33,7 @@ class ThinkingSphinx::ActiveRecord::SQLSource::Template
|
|
|
33
33
|
if inheriting?
|
|
34
34
|
adapter = source.adapter
|
|
35
35
|
quoted_column = "#{adapter.quoted_table_name}.#{adapter.quote(model.inheritance_column)}"
|
|
36
|
-
source.adapter.
|
|
36
|
+
source.adapter.convert_blank quoted_column, "'#{model.sti_name}'"
|
|
37
37
|
else
|
|
38
38
|
"'#{model.name}'"
|
|
39
39
|
end
|
|
@@ -1,67 +1,8 @@
|
|
|
1
|
-
Capistrano::
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
namespace :thinking_sphinx do
|
|
6
|
-
desc 'Generate the Sphinx configuration file.'
|
|
7
|
-
task :configure, fetch(:thinking_sphinx_options) do
|
|
8
|
-
rake 'ts:configure'
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
desc 'Build Sphinx indexes into the shared path and symlink them into your release.'
|
|
12
|
-
task :index, fetch(:thinking_sphinx_options) do
|
|
13
|
-
rake 'ts:index'
|
|
14
|
-
end
|
|
15
|
-
after 'thinking_sphinx:index', 'thinking_sphinx:symlink_indexes'
|
|
16
|
-
|
|
17
|
-
desc 'Start the Sphinx search daemon.'
|
|
18
|
-
task :start, fetch(:thinking_sphinx_options) do
|
|
19
|
-
rake 'ts:start'
|
|
20
|
-
end
|
|
21
|
-
before 'thinking_sphinx:start', 'thinking_sphinx:configure'
|
|
22
|
-
|
|
23
|
-
desc 'Stop the Sphinx search daemon.'
|
|
24
|
-
task :stop, fetch(:thinking_sphinx_options) do
|
|
25
|
-
rake 'ts:stop'
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
desc 'Restart the Sphinx search daemon.'
|
|
29
|
-
task :restart, fetch(:thinking_sphinx_options) do
|
|
30
|
-
rake 'ts:stop ts:configure ts:start'
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
desc <<-DESC
|
|
34
|
-
Stop, reindex, and then start the Sphinx search daemon. This task must be executed \
|
|
35
|
-
if you alter the structure of your indexes.
|
|
36
|
-
DESC
|
|
37
|
-
task :rebuild, fetch(:thinking_sphinx_options) do
|
|
38
|
-
rake 'ts:rebuild'
|
|
39
|
-
end
|
|
40
|
-
after 'thinking_sphinx:rebuild', 'thinking_sphinx:symlink_indexes'
|
|
41
|
-
|
|
42
|
-
desc 'Create the shared folder for sphinx indexes.'
|
|
43
|
-
task :shared_sphinx_folder, fetch(:thinking_sphinx_options) do
|
|
44
|
-
rails_env = fetch(:rails_env, 'production')
|
|
45
|
-
run "mkdir -p #{shared_path}/db/sphinx/#{rails_env}"
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
desc 'Symlink Sphinx indexes from the shared folder to the latest release.'
|
|
49
|
-
task :symlink_indexes, fetch(:thinking_sphinx_options) do
|
|
50
|
-
run "if [ -d #{release_path} ]; then ln -nfs #{shared_path}/db/sphinx #{release_path}/db/sphinx; else ln -nfs #{shared_path}/db/sphinx #{current_path}/db/sphinx; fi;"
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# Logical flow for deploying an app
|
|
54
|
-
after 'deploy:cold', 'thinking_sphinx:index'
|
|
55
|
-
after 'deploy:cold', 'thinking_sphinx:start'
|
|
56
|
-
after 'deploy:setup', 'thinking_sphinx:shared_sphinx_folder'
|
|
57
|
-
after 'deploy:finalize_update', 'thinking_sphinx:symlink_indexes'
|
|
58
|
-
|
|
59
|
-
def rake(tasks)
|
|
60
|
-
rails_env = fetch(:rails_env, 'production')
|
|
61
|
-
rake = fetch(:rake, 'rake')
|
|
62
|
-
tasks += ' INDEX_ONLY=true' if ENV['INDEX_ONLY'] == 'true'
|
|
63
|
-
|
|
64
|
-
run "if [ -d #{release_path} ]; then cd #{release_path}; else cd #{current_path}; fi; if [ -f Rakefile ]; then #{rake} RAILS_ENV=#{rails_env} #{tasks}; fi;"
|
|
65
|
-
end
|
|
1
|
+
if defined?(Capistrano::VERSION)
|
|
2
|
+
if Gem::Version.new(Capistrano::VERSION).release >= Gem::Version.new('3.0.0')
|
|
3
|
+
recipe_version = 3
|
|
66
4
|
end
|
|
67
5
|
end
|
|
6
|
+
|
|
7
|
+
recipe_version ||= 2
|
|
8
|
+
require_relative "capistrano/v#{recipe_version}"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
|
2
|
+
_cset(:thinking_sphinx_roles) { :db }
|
|
3
|
+
_cset(:thinking_sphinx_options) { {:roles => fetch(:thinking_sphinx_roles)} }
|
|
4
|
+
|
|
5
|
+
namespace :thinking_sphinx do
|
|
6
|
+
desc 'Generate the Sphinx configuration file.'
|
|
7
|
+
task :configure, fetch(:thinking_sphinx_options) do
|
|
8
|
+
rake 'ts:configure'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
desc 'Build Sphinx indexes into the shared path.'
|
|
12
|
+
task :index, fetch(:thinking_sphinx_options) do
|
|
13
|
+
rake 'ts:index'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
desc 'Generate Sphinx indexes into the shared path.'
|
|
17
|
+
task :generate, fetch(:thinking_sphinx_options) do
|
|
18
|
+
rake 'ts:generate'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
desc 'Start the Sphinx search daemon.'
|
|
22
|
+
task :start, fetch(:thinking_sphinx_options) do
|
|
23
|
+
rake 'ts:start'
|
|
24
|
+
end
|
|
25
|
+
before 'thinking_sphinx:start', 'thinking_sphinx:configure'
|
|
26
|
+
|
|
27
|
+
desc 'Stop the Sphinx search daemon.'
|
|
28
|
+
task :stop, fetch(:thinking_sphinx_options) do
|
|
29
|
+
rake 'ts:stop'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
desc 'Restart the Sphinx search daemon.'
|
|
33
|
+
task :restart, fetch(:thinking_sphinx_options) do
|
|
34
|
+
rake 'ts:stop ts:configure ts:start'
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
desc <<-DESC
|
|
38
|
+
Stop, reindex, and then start the Sphinx search daemon. This task must be executed \
|
|
39
|
+
if you alter the structure of your indexes.
|
|
40
|
+
DESC
|
|
41
|
+
task :rebuild, fetch(:thinking_sphinx_options) do
|
|
42
|
+
rake 'ts:rebuild'
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
desc 'Stop Sphinx, clear Sphinx index files, generate configuration file, start Sphinx, repopulate all data.'
|
|
46
|
+
task :regenerate, fetch(:thinking_sphinx_options) do
|
|
47
|
+
rake 'ts:regenerate'
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def rake(tasks)
|
|
51
|
+
rails_env = fetch(:rails_env, 'production')
|
|
52
|
+
rake = fetch(:rake, 'rake')
|
|
53
|
+
tasks += ' INDEX_ONLY=true' if ENV['INDEX_ONLY'] == 'true'
|
|
54
|
+
|
|
55
|
+
run "if [ -d #{release_path} ]; then cd #{release_path}; else cd #{current_path}; fi; if [ -f Rakefile ]; then #{rake} RAILS_ENV=#{rails_env} #{tasks}; fi;"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
namespace :load do
|
|
2
|
+
task :defaults do
|
|
3
|
+
set :thinking_sphinx_roles, :db
|
|
4
|
+
end
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
namespace :thinking_sphinx do
|
|
8
|
+
desc <<-DESC
|
|
9
|
+
Stop, reindex, and then start the Sphinx search daemon. This task must be executed \
|
|
10
|
+
if you alter the structure of your indexes.
|
|
11
|
+
DESC
|
|
12
|
+
task :rebuild do
|
|
13
|
+
on roles fetch(:thinking_sphinx_roles) do
|
|
14
|
+
within current_path do
|
|
15
|
+
with rails_env: fetch(:stage) do
|
|
16
|
+
execute :rake, "ts:rebuild"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
desc 'Stop Sphinx, clear Sphinx index files, generate configuration file, start Sphinx, repopulate all data.'
|
|
23
|
+
task :regenerate do
|
|
24
|
+
on roles fetch(:thinking_sphinx_options) do
|
|
25
|
+
within current_path do
|
|
26
|
+
with rails_env: fetch(:stage) do
|
|
27
|
+
execute :rake, 'ts:regenerate'
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
desc 'Build Sphinx indexes into the shared path.'
|
|
34
|
+
task :index do
|
|
35
|
+
on roles fetch(:thinking_sphinx_roles) do
|
|
36
|
+
within current_path do
|
|
37
|
+
with rails_env: fetch(:stage) do
|
|
38
|
+
execute :rake, 'ts:index'
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
desc 'Generate Sphinx indexes into the shared path.'
|
|
45
|
+
task :generate do
|
|
46
|
+
on roles fetch(:thinking_sphinx_options) do
|
|
47
|
+
within current_path do
|
|
48
|
+
with rails_env: fetch(:stage) do
|
|
49
|
+
execute :rake, 'ts:generate'
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
desc 'Restart the Sphinx search daemon.'
|
|
56
|
+
task :restart do
|
|
57
|
+
on roles fetch(:thinking_sphinx_roles) do
|
|
58
|
+
within current_path do
|
|
59
|
+
with rails_env: fetch(:stage) do
|
|
60
|
+
%w(stop configure start).each do |task|
|
|
61
|
+
execute :rake, "ts:#{task}"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
desc 'Start the Sphinx search daemon.'
|
|
69
|
+
task :start do
|
|
70
|
+
on roles fetch(:thinking_sphinx_roles) do
|
|
71
|
+
within current_path do
|
|
72
|
+
with rails_env: fetch(:stage) do
|
|
73
|
+
execute :rake, 'ts:start'
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
before :start, 'thinking_sphinx:configure'
|
|
79
|
+
|
|
80
|
+
desc 'Generate the Sphinx configuration file.'
|
|
81
|
+
task :configure do
|
|
82
|
+
on roles fetch(:thinking_sphinx_roles) do
|
|
83
|
+
within current_path do
|
|
84
|
+
with rails_env: fetch(:stage) do
|
|
85
|
+
execute :rake, 'ts:configure'
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
desc 'Stop the Sphinx search daemon.'
|
|
92
|
+
task :stop do
|
|
93
|
+
on roles fetch(:thinking_sphinx_roles) do
|
|
94
|
+
within current_path do
|
|
95
|
+
with rails_env: fetch(:stage) do
|
|
96
|
+
execute :rake, 'ts:stop'
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -27,7 +27,7 @@ class ThinkingSphinx::Configuration < Riddle::Configuration
|
|
|
27
27
|
|
|
28
28
|
def controller
|
|
29
29
|
@controller ||= begin
|
|
30
|
-
rc =
|
|
30
|
+
rc = ThinkingSphinx::Controller.new self, configuration_file
|
|
31
31
|
rc.bin_path = bin_path.gsub(/([^\/])$/, '\1/') if bin_path.present?
|
|
32
32
|
rc
|
|
33
33
|
end
|
|
@@ -50,8 +50,9 @@ class ThinkingSphinx::Configuration < Riddle::Configuration
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def engine_indice_paths
|
|
53
|
-
Rails::Engine
|
|
54
|
-
engine.paths
|
|
53
|
+
Rails::Engine.subclasses.collect(&:instance).collect do |engine|
|
|
54
|
+
engine.paths.add 'app/indices' unless engine.paths['app/indices']
|
|
55
|
+
engine.paths['app/indices'].existent
|
|
55
56
|
end
|
|
56
57
|
end
|
|
57
58
|
|
|
@@ -73,6 +74,8 @@ class ThinkingSphinx::Configuration < Riddle::Configuration
|
|
|
73
74
|
end
|
|
74
75
|
end
|
|
75
76
|
|
|
77
|
+
ThinkingSphinx::Configuration::DistributedIndices.new(indices).reconcile
|
|
78
|
+
|
|
76
79
|
@preloaded_indices = true
|
|
77
80
|
end
|
|
78
81
|
|
|
@@ -104,6 +107,7 @@ class ThinkingSphinx::Configuration < Riddle::Configuration
|
|
|
104
107
|
searchd.address = settings['address'].presence || Defaults::ADDRESS
|
|
105
108
|
searchd.mysql41 = settings['mysql41'] || settings['port'] || Defaults::PORT
|
|
106
109
|
searchd.workers = 'threads'
|
|
110
|
+
searchd.mysql_version_string = '5.5.21' if RUBY_PLATFORM == 'java'
|
|
107
111
|
end
|
|
108
112
|
|
|
109
113
|
def configure_searchd_log_files
|
|
@@ -165,4 +169,5 @@ end
|
|
|
165
169
|
|
|
166
170
|
require 'thinking_sphinx/configuration/consistent_ids'
|
|
167
171
|
require 'thinking_sphinx/configuration/defaults'
|
|
172
|
+
require 'thinking_sphinx/configuration/distributed_indices'
|
|
168
173
|
require 'thinking_sphinx/configuration/minimum_fields'
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
class ThinkingSphinx::Configuration::DistributedIndices
|
|
2
|
+
def initialize(indices)
|
|
3
|
+
@indices = indices
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def reconcile
|
|
7
|
+
grouped_indices.each do |reference, indices|
|
|
8
|
+
append distributed_index(reference, indices)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
attr_reader :indices
|
|
15
|
+
|
|
16
|
+
def append(index)
|
|
17
|
+
ThinkingSphinx::Configuration.instance.indices << index
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def distributed_index(reference, indices)
|
|
21
|
+
index = ThinkingSphinx::Distributed::Index.new reference
|
|
22
|
+
index.local_indices += indices.collect &:name
|
|
23
|
+
index
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def grouped_indices
|
|
27
|
+
indices.group_by &:reference
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -16,7 +16,6 @@ module ThinkingSphinx::Connection
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def self.connection_class
|
|
19
|
-
raise "Sphinx's MySQL protocol does not work with JDBC." if RUBY_PLATFORM == 'java'
|
|
20
19
|
return ThinkingSphinx::Connection::JRuby if RUBY_PLATFORM == 'java'
|
|
21
20
|
|
|
22
21
|
ThinkingSphinx::Connection::MRI
|
|
@@ -36,7 +35,7 @@ module ThinkingSphinx::Connection
|
|
|
36
35
|
pool.take do |connection|
|
|
37
36
|
begin
|
|
38
37
|
yield connection
|
|
39
|
-
rescue ThinkingSphinx::QueryExecutionError,
|
|
38
|
+
rescue ThinkingSphinx::QueryExecutionError, connection.base_error => error
|
|
40
39
|
original = ThinkingSphinx::SphinxError.new_from_mysql error
|
|
41
40
|
raise original if original.is_a?(ThinkingSphinx::QueryError)
|
|
42
41
|
raise Innertube::Pool::BadResource
|
|
@@ -53,65 +52,122 @@ module ThinkingSphinx::Connection
|
|
|
53
52
|
end
|
|
54
53
|
end
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
def self.persistent?
|
|
56
|
+
@persistent
|
|
57
|
+
end
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
:port => port,
|
|
63
|
-
:flags => Mysql2::Client::MULTI_STATEMENTS
|
|
64
|
-
}.merge(options))
|
|
65
|
-
rescue Mysql2::Error => error
|
|
66
|
-
raise ThinkingSphinx::SphinxError.new_from_mysql error
|
|
67
|
-
end
|
|
59
|
+
def self.persistent=(persist)
|
|
60
|
+
@persistent = persist
|
|
61
|
+
end
|
|
68
62
|
|
|
63
|
+
@persistent = true
|
|
64
|
+
|
|
65
|
+
class Client
|
|
69
66
|
def close
|
|
70
|
-
client.close
|
|
67
|
+
client.close unless ThinkingSphinx::Connection.persistent?
|
|
71
68
|
end
|
|
72
69
|
|
|
73
70
|
def execute(statement)
|
|
74
|
-
|
|
71
|
+
query(statement).first
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def query_all(*statements)
|
|
75
|
+
query *statements
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
def close_and_clear
|
|
81
|
+
client.close
|
|
82
|
+
@client = nil
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def query(*statements)
|
|
86
|
+
results_for *statements
|
|
75
87
|
rescue => error
|
|
76
88
|
wrapper = ThinkingSphinx::QueryExecutionError.new error.message
|
|
77
|
-
wrapper.statement =
|
|
89
|
+
wrapper.statement = statements.join('; ')
|
|
78
90
|
raise wrapper
|
|
91
|
+
ensure
|
|
92
|
+
close_and_clear unless ThinkingSphinx::Connection.persistent?
|
|
79
93
|
end
|
|
94
|
+
end
|
|
80
95
|
|
|
81
|
-
|
|
82
|
-
|
|
96
|
+
class MRI < Client
|
|
97
|
+
def initialize(address, port, options)
|
|
98
|
+
@address, @port, @options = address, port, options
|
|
83
99
|
end
|
|
84
100
|
|
|
85
|
-
def
|
|
101
|
+
def base_error
|
|
102
|
+
Mysql2::Error
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
private
|
|
106
|
+
|
|
107
|
+
attr_reader :address, :port, :options
|
|
108
|
+
|
|
109
|
+
def client
|
|
110
|
+
@client ||= Mysql2::Client.new({
|
|
111
|
+
:host => address,
|
|
112
|
+
:port => port,
|
|
113
|
+
:flags => Mysql2::Client::MULTI_STATEMENTS
|
|
114
|
+
}.merge(options))
|
|
115
|
+
rescue base_error => error
|
|
116
|
+
raise ThinkingSphinx::SphinxError.new_from_mysql error
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def results_for(*statements)
|
|
86
120
|
results = [client.query(statements.join('; '))]
|
|
87
121
|
results << client.store_result while client.next_result
|
|
88
122
|
results
|
|
89
|
-
rescue => error
|
|
90
|
-
wrapper = ThinkingSphinx::QueryExecutionError.new error.message
|
|
91
|
-
wrapper.statement = statements.join('; ')
|
|
92
|
-
raise wrapper
|
|
93
123
|
end
|
|
94
124
|
end
|
|
95
125
|
|
|
96
|
-
class JRuby
|
|
97
|
-
attr_reader :
|
|
126
|
+
class JRuby < Client
|
|
127
|
+
attr_reader :address, :options
|
|
98
128
|
|
|
99
129
|
def initialize(address, port, options)
|
|
100
|
-
address = "jdbc:mysql://#{address}:#{
|
|
101
|
-
@
|
|
102
|
-
options[:username], options[:password]
|
|
130
|
+
@address = "jdbc:mysql://#{address}:#{port}?allowMultiQueries=true"
|
|
131
|
+
@options = options
|
|
103
132
|
end
|
|
104
133
|
|
|
105
|
-
def
|
|
106
|
-
|
|
134
|
+
def base_error
|
|
135
|
+
Java::JavaSql::SQLException
|
|
107
136
|
end
|
|
108
137
|
|
|
109
|
-
|
|
110
|
-
|
|
138
|
+
private
|
|
139
|
+
|
|
140
|
+
def client
|
|
141
|
+
@client ||= java.sql.DriverManager.getConnection address,
|
|
142
|
+
options[:username], options[:password]
|
|
143
|
+
rescue base_error => error
|
|
144
|
+
raise ThinkingSphinx::SphinxError.new_from_mysql error
|
|
111
145
|
end
|
|
112
146
|
|
|
113
|
-
def
|
|
114
|
-
|
|
147
|
+
def results_for(*statements)
|
|
148
|
+
statement = client.createStatement
|
|
149
|
+
statement.execute statements.join('; ')
|
|
150
|
+
|
|
151
|
+
results = [set_to_array(statement.getResultSet)]
|
|
152
|
+
results << set_to_array(statement.getResultSet) while statement.getMoreResults
|
|
153
|
+
results.compact
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def set_to_array(set)
|
|
157
|
+
return nil if set.nil?
|
|
158
|
+
|
|
159
|
+
meta = set.meta_data
|
|
160
|
+
rows = []
|
|
161
|
+
|
|
162
|
+
while set.next
|
|
163
|
+
rows << (1..meta.column_count).inject({}) do |row, index|
|
|
164
|
+
name = meta.column_name index
|
|
165
|
+
row[name] = set.get_object(index)
|
|
166
|
+
row
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
rows
|
|
115
171
|
end
|
|
116
172
|
end
|
|
117
173
|
end
|