thinking-sphinx 1.4.6 → 1.4.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|