thinking-sphinx 1.4.6 → 1.4.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/README.textile +6 -1
- data/features/searching_by_model.feature +24 -30
- data/features/thinking_sphinx/db/.gitignore +1 -0
- data/features/thinking_sphinx/db/fixtures/post_keywords.txt +1 -0
- data/lib/cucumber/thinking_sphinx/internal_world.rb +26 -26
- data/lib/thinking_sphinx.rb +17 -26
- data/lib/thinking_sphinx/active_record.rb +69 -74
- data/lib/thinking_sphinx/active_record/attribute_updates.rb +11 -10
- data/lib/thinking_sphinx/active_record/has_many_association.rb +2 -1
- data/lib/thinking_sphinx/adapters/abstract_adapter.rb +11 -11
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +34 -20
- data/lib/thinking_sphinx/association.rb +12 -7
- data/lib/thinking_sphinx/attribute.rb +64 -61
- data/lib/thinking_sphinx/configuration.rb +32 -36
- data/lib/thinking_sphinx/context.rb +3 -2
- data/lib/thinking_sphinx/deploy/capistrano.rb +7 -9
- data/lib/thinking_sphinx/search.rb +201 -178
- data/lib/thinking_sphinx/source/sql.rb +1 -1
- data/lib/thinking_sphinx/tasks.rb +21 -19
- data/lib/thinking_sphinx/version.rb +3 -0
- data/spec/fixtures/data.sql +32 -0
- data/spec/fixtures/database.yml.default +3 -0
- data/spec/fixtures/models.rb +161 -0
- data/spec/fixtures/structure.sql +146 -0
- data/spec/spec_helper.rb +57 -0
- data/spec/sphinx_helper.rb +61 -0
- data/spec/thinking_sphinx/active_record/delta_spec.rb +24 -24
- data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +22 -0
- data/spec/thinking_sphinx/active_record/scopes_spec.rb +25 -25
- data/spec/thinking_sphinx/active_record_spec.rb +110 -109
- data/spec/thinking_sphinx/adapters/abstract_adapter_spec.rb +38 -38
- data/spec/thinking_sphinx/association_spec.rb +20 -2
- data/spec/thinking_sphinx/context_spec.rb +61 -64
- data/spec/thinking_sphinx/search_spec.rb +7 -0
- data/spec/thinking_sphinx_spec.rb +47 -46
- metadata +50 -98
- data/VERSION +0 -1
- data/tasks/distribution.rb +0 -34
- data/tasks/testing.rb +0 -80
data/README.textile
CHANGED
@@ -122,7 +122,6 @@ Since I first released this library, there's been quite a few people who have su
|
|
122
122
|
* Andrei Bocan
|
123
123
|
* László Bácsi
|
124
124
|
* Peter Wagenet
|
125
|
-
* Max Lapshin
|
126
125
|
* Martin Emde
|
127
126
|
* David Wennergren
|
128
127
|
* Mark Lane
|
@@ -192,3 +191,9 @@ Since I first released this library, there's been quite a few people who have su
|
|
192
191
|
* Ryan Mohr
|
193
192
|
* Alex Chee
|
194
193
|
* Bruno Santschi
|
194
|
+
* Lars Weiler
|
195
|
+
* Andrey Deryabin
|
196
|
+
* Andrew White
|
197
|
+
* Rémi Prévost
|
198
|
+
* Justin Tanner
|
199
|
+
* Josh Goebel
|
@@ -2,19 +2,19 @@ Feature: Searching on a single model
|
|
2
2
|
In order to use Thinking Sphinx's core functionality
|
3
3
|
A developer
|
4
4
|
Should be able to search on a single model
|
5
|
-
|
5
|
+
|
6
6
|
Scenario: Searching using a basic query
|
7
7
|
Given Sphinx is running
|
8
8
|
And I am searching on people
|
9
9
|
When I search for James
|
10
10
|
Then I should get 3 results
|
11
|
-
|
11
|
+
|
12
12
|
Scenario: Searching on a specific field
|
13
13
|
Given Sphinx is running
|
14
14
|
And I am searching on people
|
15
15
|
When I search for James on first_name
|
16
16
|
Then I should get 2 results
|
17
|
-
|
17
|
+
|
18
18
|
Scenario: Searching on multiple fields
|
19
19
|
Given Sphinx is running
|
20
20
|
And I am searching on people
|
@@ -25,32 +25,32 @@ Feature: Searching on a single model
|
|
25
25
|
Scenario: Searching on association content
|
26
26
|
Given Sphinx is running
|
27
27
|
And I am searching on posts
|
28
|
-
|
28
|
+
|
29
29
|
When I search for "Waffles"
|
30
30
|
Then I should get 1 result
|
31
31
|
|
32
32
|
When I search for "Turtle"
|
33
33
|
Then I should get 1 result
|
34
|
-
|
34
|
+
|
35
35
|
Scenario: Searching with a filter
|
36
36
|
Given Sphinx is running
|
37
37
|
And I am searching on alphas
|
38
38
|
When I filter by 1 on value
|
39
39
|
Then I should get 1 result
|
40
|
-
|
40
|
+
|
41
41
|
Scenario: Searching with multiple filters
|
42
42
|
Given Sphinx is running
|
43
43
|
And I am searching on boxes
|
44
44
|
When I filter by 2 on width
|
45
45
|
And I filter by 2 on length
|
46
46
|
Then I should get 1 result
|
47
|
-
|
47
|
+
|
48
48
|
Scenario: Searching with a ranged time filter
|
49
49
|
Given Sphinx is running
|
50
50
|
And I am searching on people
|
51
51
|
When I filter by birthday between 1975 and 1976
|
52
52
|
Then I should get 16 results
|
53
|
-
|
53
|
+
|
54
54
|
Scenario: Searching to filter multiple values on an MVA
|
55
55
|
Given Sphinx is running
|
56
56
|
And I am searching on boxes
|
@@ -59,31 +59,25 @@ Feature: Searching on a single model
|
|
59
59
|
When I clear existing filters
|
60
60
|
And I filter by both 11 and 12 on dimensions
|
61
61
|
Then I should get 1 result
|
62
|
-
|
62
|
+
|
63
63
|
Scenario: Filtering on timestamp MVAs
|
64
64
|
Given Sphinx is running
|
65
65
|
And I am searching on posts
|
66
66
|
When I filter by 2001-01-01 on comments_created_at
|
67
67
|
Then I should get 1 result
|
68
|
-
|
69
|
-
Scenario: Filtering on a wordcount attribute
|
70
|
-
Given Sphinx is running
|
71
|
-
And I am searching on developers
|
72
|
-
When I filter between 0 and 1 on state_wordcount
|
73
|
-
Then I should get 5 results
|
74
|
-
|
68
|
+
|
75
69
|
Scenario: Searching by NULL/0 values in MVAs
|
76
70
|
Given Sphinx is running
|
77
71
|
And I am searching on boxes
|
78
72
|
When I filter by 0 on dimensions
|
79
73
|
Then I should get 1 result
|
80
|
-
|
74
|
+
|
81
75
|
Given Sphinx is running
|
82
76
|
And I am searching on developers
|
83
77
|
When I clear existing filters
|
84
78
|
And I filter by 0 on tag_ids
|
85
79
|
Then I should get 1 result
|
86
|
-
|
80
|
+
|
87
81
|
Scenario: Searching on a MVA configured as ranged_query
|
88
82
|
Given Sphinx is running
|
89
83
|
And I am searching on posts
|
@@ -95,59 +89,59 @@ Feature: Searching on a single model
|
|
95
89
|
When I clear existing filters
|
96
90
|
And I filter by 10 on comment_ids
|
97
91
|
Then I should get 0 results
|
98
|
-
|
92
|
+
|
99
93
|
Scenario: Searching with ordering by attribute
|
100
94
|
Given Sphinx is running
|
101
95
|
And I am searching on alphas
|
102
96
|
When I order by value
|
103
97
|
Then I should get 10 results
|
104
98
|
And the value of each result should indicate order
|
105
|
-
|
99
|
+
|
106
100
|
Scenario: Intepreting Sphinx Internal Identifiers
|
107
101
|
Given Sphinx is running
|
108
102
|
And I am searching on people
|
109
103
|
Then I should get 20 results
|
110
104
|
And each result id should match the corresponding sphinx internal id
|
111
|
-
|
105
|
+
|
112
106
|
Scenario: Retrieving weightings
|
113
107
|
Given Sphinx is running
|
114
108
|
And I am searching on people
|
115
109
|
When I search for "Ellie Ford"
|
116
110
|
And I set match mode to any
|
117
111
|
Then I can iterate by result and weighting
|
118
|
-
|
112
|
+
|
119
113
|
Scenario: Retrieving group counts
|
120
114
|
Given Sphinx is running
|
121
115
|
And I am searching on people
|
122
116
|
When I group results by the birthday attribute
|
123
117
|
Then I can iterate by result and count
|
124
|
-
|
118
|
+
|
125
119
|
Scenario: Retrieving group values
|
126
120
|
Given Sphinx is running
|
127
121
|
And I am searching on people
|
128
122
|
When I group results by the birthday attribute
|
129
123
|
Then I can iterate by result and group
|
130
|
-
|
124
|
+
|
131
125
|
Scenario: Retrieving both group values and counts
|
132
126
|
Given Sphinx is running
|
133
127
|
And I am searching on people
|
134
128
|
When I group results by the birthday attribute
|
135
129
|
Then I can iterate by result and group and count
|
136
|
-
|
130
|
+
|
137
131
|
Scenario: Searching for ids
|
138
132
|
Given Sphinx is running
|
139
133
|
And I am searching on people
|
140
134
|
When I search for Ellie
|
141
135
|
And I am searching for ids
|
142
136
|
Then I should have an array of integers
|
143
|
-
|
137
|
+
|
144
138
|
Scenario: Search results should match Sphinx's order
|
145
139
|
Given Sphinx is running
|
146
140
|
And I am searching on people
|
147
141
|
When I search for Ellie
|
148
142
|
And I order by "sphinx_internal_id DESC"
|
149
143
|
Then searching for ids should match the record ids of the normal search results
|
150
|
-
|
144
|
+
|
151
145
|
Scenario: Retrieving total result count when total is less than a page
|
152
146
|
Given Sphinx is running
|
153
147
|
And I am searching on people
|
@@ -160,7 +154,7 @@ Feature: Searching on a single model
|
|
160
154
|
And I am searching on people
|
161
155
|
When I am retrieving the result count
|
162
156
|
Then I should get a value of 1000
|
163
|
-
|
157
|
+
|
164
158
|
Scenario: Searching with Unicode Characters
|
165
159
|
Given Sphinx is running
|
166
160
|
And I am searching on people
|
@@ -172,10 +166,10 @@ Feature: Searching on a single model
|
|
172
166
|
And I am searching on posts
|
173
167
|
When I search for "Shakespeare"
|
174
168
|
Then I should get 1 result
|
175
|
-
|
169
|
+
|
176
170
|
Scenario: Searching on content from file field
|
177
171
|
Given Sphinx is running
|
178
172
|
And I am searching on posts
|
179
173
|
When I search for "foo bar baz"
|
180
174
|
Then I should get 1 result
|
181
|
-
|
175
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
database.yml
|
@@ -0,0 +1 @@
|
|
1
|
+
foo bar baz
|
@@ -7,7 +7,7 @@ module Cucumber
|
|
7
7
|
:models_directory, :fixtures_directory, :database_file
|
8
8
|
attr_accessor :adapter, :database, :username,
|
9
9
|
:password, :host
|
10
|
-
|
10
|
+
|
11
11
|
def initialize
|
12
12
|
pwd = Dir.pwd
|
13
13
|
@temporary_directory = "#{pwd}/tmp"
|
@@ -15,55 +15,55 @@ module Cucumber
|
|
15
15
|
@models_directory = "#{pwd}/features/thinking_sphinx/models"
|
16
16
|
@fixtures_directory = "#{pwd}/features/thinking_sphinx/db/fixtures"
|
17
17
|
@database_file = "#{pwd}/features/thinking_sphinx/database.yml"
|
18
|
-
|
19
|
-
@adapter = ENV['DATABASE'] || 'mysql'
|
18
|
+
|
19
|
+
@adapter = (ENV['DATABASE'] || 'mysql').gsub /^mysql$/, 'mysql2'
|
20
20
|
@database = 'thinking_sphinx'
|
21
|
-
@username = '
|
21
|
+
@username = @adapter[/mysql/] ? 'root' : 'postgres'
|
22
22
|
# @password = 'thinking_sphinx'
|
23
23
|
@host = 'localhost'
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def setup
|
27
27
|
make_temporary_directory
|
28
|
-
|
28
|
+
|
29
29
|
configure_cleanup
|
30
30
|
configure_thinking_sphinx
|
31
31
|
configure_active_record
|
32
|
-
|
32
|
+
|
33
33
|
prepare_data
|
34
34
|
setup_sphinx
|
35
|
-
|
35
|
+
|
36
36
|
self
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
def configure_database
|
40
40
|
ActiveRecord::Base.establish_connection database_settings
|
41
41
|
self
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
private
|
45
|
-
|
45
|
+
|
46
46
|
def config
|
47
47
|
@config ||= ::ThinkingSphinx::Configuration.instance
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
def make_temporary_directory
|
51
51
|
FileUtils.mkdir_p temporary_directory
|
52
52
|
Dir["#{temporary_directory}/*"].each do |file|
|
53
53
|
FileUtils.rm_rf file
|
54
54
|
end
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
def configure_thinking_sphinx
|
58
58
|
config.config_file = "#{temporary_directory}/sphinx.conf"
|
59
59
|
config.searchd_log_file = "#{temporary_directory}/searchd.log"
|
60
60
|
config.query_log_file = "#{temporary_directory}/searchd.query.log"
|
61
61
|
config.pid_file = "#{temporary_directory}/searchd.pid"
|
62
62
|
config.searchd_file_path = "#{temporary_directory}/indexes/"
|
63
|
-
|
63
|
+
|
64
64
|
::ThinkingSphinx.suppress_delta_output = true
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
def configure_cleanup
|
68
68
|
Kernel.at_exit do
|
69
69
|
::ThinkingSphinx::Configuration.instance.controller.stop
|
@@ -71,13 +71,13 @@ module Cucumber
|
|
71
71
|
ActiveRecord::Base.logger.close
|
72
72
|
end
|
73
73
|
end
|
74
|
-
|
74
|
+
|
75
75
|
def yaml_database_settings
|
76
76
|
return {} unless File.exist?(@database_file)
|
77
|
-
|
77
|
+
|
78
78
|
YAML.load open(@database_file)
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
def database_settings
|
82
82
|
{
|
83
83
|
'adapter' => @adapter,
|
@@ -87,37 +87,37 @@ module Cucumber
|
|
87
87
|
'host' => @host
|
88
88
|
}.merge yaml_database_settings
|
89
89
|
end
|
90
|
-
|
90
|
+
|
91
91
|
def configure_active_record
|
92
92
|
ActiveRecord::Base.logger = Logger.new(
|
93
93
|
open("#{temporary_directory}/active_record.log", "a")
|
94
94
|
)
|
95
|
-
|
95
|
+
|
96
96
|
ActiveRecord::Base.connection.class.send(
|
97
97
|
:include, Cucumber::ThinkingSphinx::SqlLogger
|
98
98
|
)
|
99
99
|
end
|
100
|
-
|
100
|
+
|
101
101
|
def prepare_data
|
102
102
|
::ThinkingSphinx.deltas_enabled = false
|
103
|
-
|
103
|
+
|
104
104
|
load_files migrations_directory
|
105
105
|
load_files models_directory
|
106
106
|
load_files fixtures_directory
|
107
|
-
|
107
|
+
|
108
108
|
::ThinkingSphinx.deltas_enabled = true
|
109
109
|
end
|
110
|
-
|
110
|
+
|
111
111
|
def load_files(path)
|
112
112
|
files = Dir["#{path}/*.rb"].sort!
|
113
113
|
files.each do |file|
|
114
114
|
require file.gsub(/\.rb$/, '')
|
115
115
|
end
|
116
116
|
end
|
117
|
-
|
117
|
+
|
118
118
|
def setup_sphinx
|
119
119
|
FileUtils.mkdir_p config.searchd_file_path
|
120
|
-
|
120
|
+
|
121
121
|
config.build
|
122
122
|
config.controller.index
|
123
123
|
config.controller.start
|
data/lib/thinking_sphinx.rb
CHANGED
@@ -38,7 +38,7 @@ Merb::Plugins.add_rakefiles(
|
|
38
38
|
|
39
39
|
module ThinkingSphinx
|
40
40
|
mattr_accessor :database_adapter
|
41
|
-
|
41
|
+
|
42
42
|
# A ConnectionError will get thrown when a connection to Sphinx can't be
|
43
43
|
# made.
|
44
44
|
class ConnectionError < StandardError
|
@@ -52,7 +52,7 @@ module ThinkingSphinx
|
|
52
52
|
self.ids = ids
|
53
53
|
end
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
# A SphinxError occurs when Sphinx responds with an error due to problematic
|
57
57
|
# queries or indexes.
|
58
58
|
class SphinxError < RuntimeError
|
@@ -62,17 +62,7 @@ module ThinkingSphinx
|
|
62
62
|
self.results = results
|
63
63
|
end
|
64
64
|
end
|
65
|
-
|
66
|
-
# The current version of Thinking Sphinx.
|
67
|
-
#
|
68
|
-
# @return [String] The version number as a string
|
69
|
-
#
|
70
|
-
def self.version
|
71
|
-
open(File.join(File.dirname(__FILE__), '../VERSION')) { |f|
|
72
|
-
f.read.strip
|
73
|
-
}
|
74
|
-
end
|
75
|
-
|
65
|
+
|
76
66
|
# The collection of indexed models. Keep in mind that Rails lazily loads
|
77
67
|
# its classes, so this may not actually be populated with _all_ the models
|
78
68
|
# that have Sphinx indexes.
|
@@ -84,11 +74,11 @@ module ThinkingSphinx
|
|
84
74
|
@@suppress_delta_output = false
|
85
75
|
@@remote_sphinx = false
|
86
76
|
@@use_group_by_shortcut = nil
|
87
|
-
|
77
|
+
|
88
78
|
def self.mutex
|
89
79
|
@@sphinx_mutex
|
90
80
|
end
|
91
|
-
|
81
|
+
|
92
82
|
def self.context
|
93
83
|
if @@context.nil?
|
94
84
|
mutex.synchronize do
|
@@ -98,10 +88,10 @@ module ThinkingSphinx
|
|
98
88
|
end
|
99
89
|
end
|
100
90
|
end
|
101
|
-
|
91
|
+
|
102
92
|
@@context
|
103
93
|
end
|
104
|
-
|
94
|
+
|
105
95
|
def self.reset_context!(context = nil)
|
106
96
|
mutex.synchronize do
|
107
97
|
@@context = context
|
@@ -127,7 +117,7 @@ module ThinkingSphinx
|
|
127
117
|
@@define_indexes = value
|
128
118
|
end
|
129
119
|
end
|
130
|
-
|
120
|
+
|
131
121
|
# Check if delta indexing is enabled/disabled.
|
132
122
|
#
|
133
123
|
def self.deltas_enabled?
|
@@ -140,10 +130,10 @@ module ThinkingSphinx
|
|
140
130
|
end
|
141
131
|
end
|
142
132
|
end
|
143
|
-
|
133
|
+
|
144
134
|
@@deltas_enabled && !deltas_suspended?
|
145
135
|
end
|
146
|
-
|
136
|
+
|
147
137
|
# Enable/disable delta indexing.
|
148
138
|
#
|
149
139
|
# ThinkingSphinx.deltas_enabled = false
|
@@ -160,7 +150,7 @@ module ThinkingSphinx
|
|
160
150
|
if Thread.current[:thinking_sphinx_deltas_suspended].nil?
|
161
151
|
Thread.current[:thinking_sphinx_deltas_suspended] = false
|
162
152
|
end
|
163
|
-
|
153
|
+
|
164
154
|
Thread.current[:thinking_sphinx_deltas_suspended]
|
165
155
|
end
|
166
156
|
|
@@ -185,7 +175,7 @@ module ThinkingSphinx
|
|
185
175
|
end
|
186
176
|
end
|
187
177
|
end
|
188
|
-
|
178
|
+
|
189
179
|
@@updates_enabled
|
190
180
|
end
|
191
181
|
|
@@ -208,7 +198,7 @@ module ThinkingSphinx
|
|
208
198
|
@@suppress_delta_output = value
|
209
199
|
end
|
210
200
|
end
|
211
|
-
|
201
|
+
|
212
202
|
# Checks to see if MySQL will allow simplistic GROUP BY statements. If not,
|
213
203
|
# or if not using MySQL, this will return false.
|
214
204
|
#
|
@@ -226,10 +216,10 @@ module ThinkingSphinx
|
|
226
216
|
end
|
227
217
|
end
|
228
218
|
end
|
229
|
-
|
219
|
+
|
230
220
|
@@use_group_by_shortcut
|
231
221
|
end
|
232
|
-
|
222
|
+
|
233
223
|
def self.reset_use_group_by_shortcut
|
234
224
|
mutex.synchronize do
|
235
225
|
@@use_group_by_shortcut = nil
|
@@ -298,11 +288,12 @@ module ThinkingSphinx
|
|
298
288
|
|
299
289
|
def self.mysql?
|
300
290
|
::ActiveRecord::Base.connection.class.name.demodulize == "MysqlAdapter" ||
|
291
|
+
::ActiveRecord::Base.connection.class.name.demodulize == "Mysql2Adapter" ||
|
301
292
|
::ActiveRecord::Base.connection.class.name.demodulize == "MysqlplusAdapter" || (
|
302
293
|
jruby? && ::ActiveRecord::Base.connection.config[:adapter] == "jdbcmysql"
|
303
294
|
)
|
304
295
|
end
|
305
|
-
|
296
|
+
|
306
297
|
extend ThinkingSphinx::SearchMethods::ClassMethods
|
307
298
|
end
|
308
299
|
|