flying-sphinx 0.6.6 → 0.7.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.
- 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 =
|