flying-sphinx 0.6.6 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +7 -0
- data/flying-sphinx.gemspec +3 -3
- data/lib/flying_sphinx.rb +4 -0
- data/lib/flying_sphinx/api.rb +12 -15
- data/lib/flying_sphinx/configuration.rb +4 -123
- data/lib/flying_sphinx/delayed_delta.rb +21 -25
- data/lib/flying_sphinx/index_request.rb +15 -22
- data/lib/flying_sphinx/rails.rb +1 -0
- data/lib/flying_sphinx/railtie.rb +1 -0
- data/lib/flying_sphinx/setting_files.rb +55 -0
- data/lib/flying_sphinx/sphinx_configuration.rb +23 -0
- data/lib/flying_sphinx/tasks.rb +0 -1
- data/lib/flying_sphinx/tunnel.rb +1 -1
- data/lib/flying_sphinx/version.rb +1 -1
- data/spec/light_spec_helper.rb +7 -0
- data/spec/spec_helper.rb +2 -12
- data/spec/specs/api_spec.rb +92 -0
- data/spec/specs/configuration_spec.rb +14 -163
- data/spec/specs/index_request_spec.rb +63 -61
- data/spec/specs/setting_files_spec.rb +92 -0
- data/spec/specs/sphinx_configuration_spec.rb +35 -0
- metadata +34 -25
data/HISTORY
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
0.7.0 - 16th July 2012
|
2
|
+
* Print the indexing log.
|
3
|
+
* Distinguish between search server and SSH/indexing server, which allows for load balancers as the former.
|
4
|
+
* Send the gem version through as a header on API calls.
|
5
|
+
* Let flying-sphinx.com wrangle the Sphinx configuration.
|
6
|
+
* Use v3 of the flying-sphinx.com API
|
7
|
+
|
1
8
|
0.6.6 - 14th July 2012
|
2
9
|
* Don't complain about 201s for starting/stopping Sphinx.
|
3
10
|
* Relaxing the faraday_middleware dependency to allow 0.8 releases (Matthew Zikherman).
|
data/flying-sphinx.gemspec
CHANGED
@@ -25,10 +25,10 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.add_runtime_dependency 'faraday_middleware', ['~> 0.7']
|
26
26
|
s.add_runtime_dependency 'rash', ['~> 0.3.0']
|
27
27
|
|
28
|
-
s.add_development_dependency 'rake', ['0.
|
28
|
+
s.add_development_dependency 'rake', ['~> 0.9.2']
|
29
|
+
s.add_development_dependency 'rspec', ['~> 2.11']
|
30
|
+
s.add_development_dependency 'rspec-fire', ['~> 1.1.0']
|
29
31
|
s.add_development_dependency 'yajl-ruby', ['~> 0.8.2']
|
30
|
-
s.add_development_dependency 'rspec', ['~> 2.5.0']
|
31
|
-
s.add_development_dependency 'rcov', ['~> 0.9.9']
|
32
32
|
s.add_development_dependency 'fakeweb', ['~> 1.3.0']
|
33
33
|
s.add_development_dependency 'fakeweb-matcher', ['~> 1.2.2']
|
34
34
|
s.add_development_dependency 'delayed_job', ['~> 2.1.4']
|
data/lib/flying_sphinx.rb
CHANGED
@@ -2,6 +2,8 @@ module FlyingSphinx
|
|
2
2
|
#
|
3
3
|
end
|
4
4
|
|
5
|
+
require 'faraday'
|
6
|
+
require 'faraday_middleware'
|
5
7
|
require 'net/ssh'
|
6
8
|
require 'riddle/0.9.9'
|
7
9
|
|
@@ -11,6 +13,8 @@ require 'flying_sphinx/delayed_delta'
|
|
11
13
|
require 'flying_sphinx/flag_as_deleted_job'
|
12
14
|
require 'flying_sphinx/heroku_shared_adapter'
|
13
15
|
require 'flying_sphinx/index_request'
|
16
|
+
require 'flying_sphinx/setting_files'
|
17
|
+
require 'flying_sphinx/sphinx_configuration'
|
14
18
|
require 'flying_sphinx/tunnel'
|
15
19
|
require 'flying_sphinx/version'
|
16
20
|
|
data/lib/flying_sphinx/api.rb
CHANGED
@@ -1,14 +1,8 @@
|
|
1
|
-
require 'faraday'
|
2
|
-
require 'faraday_middleware'
|
3
|
-
|
4
1
|
class FlyingSphinx::API
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
APIVersion = 2
|
10
|
-
|
11
|
-
attr_reader :api_key, :identifier, :adapter
|
2
|
+
SERVER = 'https://flying-sphinx.com'
|
3
|
+
STAGING_SERVER = 'https://staging.flying-sphinx.com'
|
4
|
+
PATH = "/api/my/app"
|
5
|
+
VERSION = 3
|
12
6
|
|
13
7
|
def initialize(identifier, api_key, adapter = Faraday.default_adapter)
|
14
8
|
@api_key = api_key
|
@@ -38,22 +32,25 @@ class FlyingSphinx::API
|
|
38
32
|
|
39
33
|
private
|
40
34
|
|
35
|
+
attr_reader :api_key, :identifier, :adapter
|
36
|
+
|
41
37
|
def normalize_path(path)
|
42
|
-
path = (path == '/' ?
|
43
|
-
"#{
|
38
|
+
path = (path == '/' ? '' : "/#{path.gsub(/^\//, '')}")
|
39
|
+
"#{PATH}#{path}"
|
44
40
|
end
|
45
41
|
|
46
42
|
def api_headers
|
47
43
|
{
|
48
|
-
'Accept' => "application/vnd.flying-sphinx-v#{
|
49
|
-
'X-Flying-Sphinx-Token'
|
44
|
+
'Accept' => "application/vnd.flying-sphinx-v#{VERSION}+json",
|
45
|
+
'X-Flying-Sphinx-Token' => "#{identifier}:#{api_key}",
|
46
|
+
'X-Flying-Sphinx-Version' => FlyingSphinx::Version
|
50
47
|
}
|
51
48
|
end
|
52
49
|
|
53
50
|
def connection(connection_options = {})
|
54
51
|
options = {
|
55
52
|
:ssl => {:verify => false},
|
56
|
-
:url => (ENV['STAGED_SPHINX_API_KEY'] ?
|
53
|
+
:url => (ENV['STAGED_SPHINX_API_KEY'] ? STAGING_SERVER : SERVER),
|
57
54
|
:headers => api_headers
|
58
55
|
}
|
59
56
|
|
@@ -1,41 +1,17 @@
|
|
1
1
|
class FlyingSphinx::Configuration
|
2
|
-
attr_reader :
|
3
|
-
|
4
|
-
FileIndexSettings = [:stopwords, :wordforms, :exceptions]
|
5
|
-
FileSourceSettings = [:mysql_ssl_cert, :mysql_ssl_key, :mysql_ssl_ca]
|
6
|
-
FileSettings = FileIndexSettings + FileSourceSettings
|
2
|
+
attr_reader :host, :port, :ssh_server, :database_port
|
7
3
|
|
8
4
|
def initialize(identifier = nil, api_key = nil)
|
9
5
|
@identifier = identifier || identifier_from_env
|
10
6
|
@api_key = api_key || api_key_from_env
|
11
7
|
|
12
8
|
set_from_server
|
13
|
-
setup_environment_settings
|
14
9
|
end
|
15
10
|
|
16
11
|
def api
|
17
12
|
@api ||= FlyingSphinx::API.new(identifier, api_key)
|
18
13
|
end
|
19
14
|
|
20
|
-
def sphinx_configuration
|
21
|
-
thinking_sphinx.generate
|
22
|
-
set_database_settings
|
23
|
-
set_file_settings
|
24
|
-
|
25
|
-
riddle.render
|
26
|
-
end
|
27
|
-
|
28
|
-
def file_setting_pairs(setting)
|
29
|
-
@file_setting_pairs ||= {}
|
30
|
-
@file_setting_pairs[setting] ||= begin
|
31
|
-
pairs = {}
|
32
|
-
file_setting_sources(setting).each_with_index do |source, index|
|
33
|
-
pairs[source] = "#{base_path}/#{setting}/#{index}.txt"
|
34
|
-
end
|
35
|
-
pairs
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
15
|
def start_sphinx
|
40
16
|
api.post('start').success?
|
41
17
|
end
|
@@ -56,14 +32,16 @@ class FlyingSphinx::Configuration
|
|
56
32
|
|
57
33
|
private
|
58
34
|
|
35
|
+
attr_reader :identifier, :api_key
|
36
|
+
|
59
37
|
def set_from_server
|
60
38
|
response = api.get '/'
|
61
39
|
raise 'Invalid Flying Sphinx credentials' if response.status == 403
|
62
40
|
|
63
41
|
@host = response.body.server
|
64
42
|
@port = response.body.port
|
43
|
+
@ssh_server = response.body.ssh_server
|
65
44
|
@database_port = response.body.database_port
|
66
|
-
@mem_limit = response.body.mem_limit
|
67
45
|
rescue
|
68
46
|
# If the central Flying Sphinx server is down, let's use the environment
|
69
47
|
# variables so searching is still going to work.
|
@@ -71,103 +49,6 @@ class FlyingSphinx::Configuration
|
|
71
49
|
@port = port_from_env
|
72
50
|
end
|
73
51
|
|
74
|
-
def base_path
|
75
|
-
"/mnt/sphinx/flying-sphinx/#{identifier}"
|
76
|
-
end
|
77
|
-
|
78
|
-
def log_path
|
79
|
-
"#{base_path}/log"
|
80
|
-
end
|
81
|
-
|
82
|
-
def thinking_sphinx
|
83
|
-
ThinkingSphinx::Configuration.instance
|
84
|
-
end
|
85
|
-
|
86
|
-
def riddle
|
87
|
-
thinking_sphinx.configuration
|
88
|
-
end
|
89
|
-
|
90
|
-
def setup_environment_settings
|
91
|
-
ThinkingSphinx.remote_sphinx = true
|
92
|
-
|
93
|
-
set_searchd_settings
|
94
|
-
set_indexer_settings
|
95
|
-
set_path_settings
|
96
|
-
end
|
97
|
-
|
98
|
-
def set_path_settings
|
99
|
-
thinking_sphinx.searchd_file_path = "#{base_path}/indexes"
|
100
|
-
|
101
|
-
riddle.searchd.pid_file = "#{base_path}/searchd.pid"
|
102
|
-
riddle.searchd.log = "#{log_path}/searchd.log"
|
103
|
-
riddle.searchd.query_log = "#{log_path}/searchd.query.log"
|
104
|
-
end
|
105
|
-
|
106
|
-
def set_searchd_settings
|
107
|
-
thinking_sphinx.port = port
|
108
|
-
thinking_sphinx.address = host
|
109
|
-
|
110
|
-
if riddle.searchd.respond_to?(:client_key)
|
111
|
-
riddle.searchd.client_key = client_key
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def set_indexer_settings
|
116
|
-
riddle.indexer.mem_limit = mem_limit.to_s + 'M'
|
117
|
-
end
|
118
|
-
|
119
|
-
def set_database_settings
|
120
|
-
return unless FlyingSphinx::Tunnel.required?
|
121
|
-
|
122
|
-
riddle.indices.each do |index|
|
123
|
-
next unless index.respond_to?(:sources)
|
124
|
-
|
125
|
-
index.sources.each do |source|
|
126
|
-
source.sql_host = '127.0.0.1'
|
127
|
-
source.sql_port = database_port
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
def set_file_settings
|
133
|
-
riddle.indices.each do |index|
|
134
|
-
set_file_settings_for index, FileIndexSettings
|
135
|
-
|
136
|
-
next unless index.respond_to?(:sources)
|
137
|
-
|
138
|
-
index.sources.each do |source|
|
139
|
-
set_file_settings_for source, FileSourceSettings
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
def set_file_settings_for(object, settings)
|
145
|
-
settings.each do |setting|
|
146
|
-
next unless object.respond_to?(setting)
|
147
|
-
object.send "#{setting}=",
|
148
|
-
file_setting_pairs(setting)[object.send(setting)]
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
def file_setting_sources(setting)
|
153
|
-
@file_setting_sources ||= {}
|
154
|
-
@file_setting_sources[setting] ||= riddle.indices.collect { |index|
|
155
|
-
file_settings_for_index(index, setting)
|
156
|
-
}.flatten.compact.uniq
|
157
|
-
end
|
158
|
-
|
159
|
-
def file_settings_for_index(index, setting)
|
160
|
-
settings = Array(file_setting_for(index, setting))
|
161
|
-
settings += index.sources.collect { |source|
|
162
|
-
file_setting_for(source, setting)
|
163
|
-
} if index.respond_to?(:sources)
|
164
|
-
settings
|
165
|
-
end
|
166
|
-
|
167
|
-
def file_setting_for(object, setting)
|
168
|
-
object.respond_to?(setting) ? object.send(setting) : nil
|
169
|
-
end
|
170
|
-
|
171
52
|
def identifier_from_env
|
172
53
|
ENV['STAGED_SPHINX_IDENTIFIER'] || ENV['FLYING_SPHINX_IDENTIFIER']
|
173
54
|
end
|
@@ -2,19 +2,19 @@ class FlyingSphinx::DelayedDelta < ThinkingSphinx::Deltas::DefaultDelta
|
|
2
2
|
# Adds a job to the queue, if it doesn't already exist. This is to ensure
|
3
3
|
# multiple indexing requests for the same delta index don't get added, as the
|
4
4
|
# index only needs to be processed once.
|
5
|
-
#
|
5
|
+
#
|
6
6
|
# Because indexing jobs are all the same object, they all get serialised to
|
7
7
|
# the same YAML value.
|
8
|
-
#
|
8
|
+
#
|
9
9
|
# @param [Object] object The job, which must respond to the #perform method.
|
10
10
|
# @param [Integer] priority (0)
|
11
|
-
#
|
11
|
+
#
|
12
12
|
def self.enqueue(object, priority = 0)
|
13
13
|
return if duplicates_exist? object
|
14
|
-
|
14
|
+
|
15
15
|
enqueue_without_duplicates_check object, priority
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def self.enqueue_without_duplicates_check(object, priority = 0)
|
19
19
|
if defined?(Rails) && Rails.version.to_i <= 2
|
20
20
|
::Delayed::Job.enqueue(object, priority)
|
@@ -22,12 +22,12 @@ class FlyingSphinx::DelayedDelta < ThinkingSphinx::Deltas::DefaultDelta
|
|
22
22
|
::Delayed::Job.enqueue(object, :priority => priority)
|
23
23
|
end
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
# Checks whether a given job already exists in the queue.
|
27
|
-
#
|
27
|
+
#
|
28
28
|
# @param [Object] object The job
|
29
29
|
# @return [Boolean] True if a duplicate of the job already exists in the queue
|
30
|
-
#
|
30
|
+
#
|
31
31
|
def self.duplicates_exist?(object)
|
32
32
|
::Delayed::Job.count(
|
33
33
|
:conditions => {
|
@@ -36,16 +36,16 @@ class FlyingSphinx::DelayedDelta < ThinkingSphinx::Deltas::DefaultDelta
|
|
36
36
|
}
|
37
37
|
) > 0
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
# Adds a job to the queue for processing the given model's delta index. A job
|
41
41
|
# for hiding the instance in the core index is also created, if an instance is
|
42
42
|
# provided.
|
43
|
-
#
|
44
|
-
# Neither job will be queued if updates or deltas are disabled, or if the
|
43
|
+
#
|
44
|
+
# Neither job will be queued if updates or deltas are disabled, or if the
|
45
45
|
# instance (when given) is not toggled to be in the delta index. The first two
|
46
46
|
# options are controlled via ThinkingSphinx.updates_enabled? and
|
47
47
|
# ThinkingSphinx.deltas_enabled?.
|
48
|
-
#
|
48
|
+
#
|
49
49
|
# @param [Class] model the ActiveRecord model to index.
|
50
50
|
# @param [ActiveRecord::Base] instance the instance of the given model that
|
51
51
|
# has changed. Optional.
|
@@ -53,38 +53,34 @@ class FlyingSphinx::DelayedDelta < ThinkingSphinx::Deltas::DefaultDelta
|
|
53
53
|
#
|
54
54
|
def index(model, instance = nil)
|
55
55
|
return true if skip? instance
|
56
|
-
|
56
|
+
|
57
57
|
self.class.enqueue(
|
58
58
|
FlyingSphinx::IndexRequest.new(model.delta_index_names),
|
59
59
|
delayed_job_priority
|
60
60
|
)
|
61
|
-
|
61
|
+
|
62
62
|
self.class.enqueue_without_duplicates_check(
|
63
63
|
FlyingSphinx::FlagAsDeletedJob.new(
|
64
64
|
model.core_index_names, instance.sphinx_document_id
|
65
65
|
),
|
66
66
|
delayed_job_priority
|
67
67
|
) if instance
|
68
|
-
|
68
|
+
|
69
69
|
true
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
private
|
73
|
-
|
74
|
-
def config
|
75
|
-
@config ||= ThinkingSphinx::Configuration.instance
|
76
|
-
end
|
77
|
-
|
73
|
+
|
78
74
|
def delayed_job_priority
|
79
|
-
|
75
|
+
ThinkingSphinx::Configuration.instance.delayed_job_priority
|
80
76
|
end
|
81
|
-
|
77
|
+
|
82
78
|
# Checks whether jobs should be enqueued. Only true if updates and deltas are
|
83
79
|
# enabled, and the instance (if there is one) is toggled.
|
84
|
-
#
|
80
|
+
#
|
85
81
|
# @param [ActiveRecord::Base, NilClass] instance
|
86
82
|
# @return [Boolean]
|
87
|
-
#
|
83
|
+
#
|
88
84
|
def skip?(instance)
|
89
85
|
!ThinkingSphinx.updates_enabled? ||
|
90
86
|
!ThinkingSphinx.deltas_enabled? ||
|
@@ -29,8 +29,9 @@ class FlyingSphinx::IndexRequest
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def update_and_index
|
32
|
-
|
33
|
-
|
32
|
+
FlyingSphinx::SphinxConfiguration.new.upload_to api, tunnel?
|
33
|
+
FlyingSphinx::SettingFiles.new.upload_to api
|
34
|
+
|
34
35
|
index
|
35
36
|
end
|
36
37
|
|
@@ -40,7 +41,7 @@ class FlyingSphinx::IndexRequest
|
|
40
41
|
status = request_status
|
41
42
|
case status
|
42
43
|
when 'FINISHED'
|
43
|
-
|
44
|
+
"Index Request has completed:\n#{request_log}"
|
44
45
|
when 'FAILED'
|
45
46
|
'Index Request failed.'
|
46
47
|
when 'PENDING'
|
@@ -66,25 +67,8 @@ class FlyingSphinx::IndexRequest
|
|
66
67
|
@configuration ||= FlyingSphinx::Configuration.new
|
67
68
|
end
|
68
69
|
|
69
|
-
def update_sphinx_configuration
|
70
|
-
api.put '/',
|
71
|
-
:configuration => configuration.sphinx_configuration,
|
72
|
-
:sphinx_version => ThinkingSphinx::Configuration.instance.version
|
73
|
-
end
|
74
|
-
|
75
|
-
def update_sphinx_reference_files
|
76
|
-
FlyingSphinx::Configuration::FileSettings.each do |setting|
|
77
|
-
configuration.file_setting_pairs(setting).each do |local, remote|
|
78
|
-
api.post '/add_file',
|
79
|
-
:setting => setting.to_s,
|
80
|
-
:file_name => remote.split('/').last,
|
81
|
-
:content => open(local).read
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
70
|
def index
|
87
|
-
if
|
71
|
+
if tunnel?
|
88
72
|
tunnelled_index
|
89
73
|
else
|
90
74
|
direct_index
|
@@ -136,8 +120,17 @@ class FlyingSphinx::IndexRequest
|
|
136
120
|
end
|
137
121
|
end
|
138
122
|
|
123
|
+
def request_log
|
124
|
+
@request.log
|
125
|
+
end
|
126
|
+
|
139
127
|
def request_status
|
140
|
-
api.get("indices/#{index_id}").body
|
128
|
+
@request = api.get("indices/#{index_id}").body
|
129
|
+
@request.status
|
130
|
+
end
|
131
|
+
|
132
|
+
def tunnel?
|
133
|
+
FlyingSphinx::Tunnel.required?
|
141
134
|
end
|
142
135
|
|
143
136
|
def cancel_request
|
data/lib/flying_sphinx/rails.rb
CHANGED
@@ -4,6 +4,7 @@ if ENV['FLYING_SPHINX_IDENTIFIER'] || ENV['STAGED_SPHINX_IDENTIFIER']
|
|
4
4
|
ActionController::Dispatcher.to_prepare :flying_sphinx do
|
5
5
|
config = FlyingSphinx::Configuration.new
|
6
6
|
|
7
|
+
ThinkingSphinx.remote_sphinx = true
|
7
8
|
ThinkingSphinx::Configuration.instance.address = config.host
|
8
9
|
ThinkingSphinx::Configuration.instance.port = config.port
|
9
10
|
ThinkingSphinx::Configuration.instance.configuration.searchd.client_key =
|
@@ -6,6 +6,7 @@ class FlyingSphinx::Railtie < Rails::Railtie
|
|
6
6
|
initializer "flying_sphinx.set_sphinx_host_and_port" do |app|
|
7
7
|
config = FlyingSphinx::Configuration.new
|
8
8
|
|
9
|
+
ThinkingSphinx.remote_sphinx = true
|
9
10
|
ThinkingSphinx::Configuration.instance.address = config.host
|
10
11
|
ThinkingSphinx::Configuration.instance.port = config.port
|
11
12
|
ThinkingSphinx::Configuration.instance.configuration.searchd.client_key =
|