thinking-sphinx 1.4.12 → 1.4.13
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/thinking_sphinx/active_record/has_many_association.rb +13 -6
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +3 -3
- data/lib/thinking_sphinx/auto_version.rb +1 -1
- data/lib/thinking_sphinx/bundled_search.rb +10 -10
- data/lib/thinking_sphinx/configuration.rb +4 -1
- data/lib/thinking_sphinx/search.rb +36 -19
- data/lib/thinking_sphinx/version.rb +1 -1
- data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +74 -0
- data/spec/thinking_sphinx/auto_version_spec.rb +16 -0
- data/spec/thinking_sphinx/search_spec.rb +32 -0
- metadata +7 -7
@@ -2,16 +2,23 @@ module ThinkingSphinx
|
|
2
2
|
module ActiveRecord
|
3
3
|
module HasManyAssociation
|
4
4
|
def search(*args)
|
5
|
-
|
5
|
+
@reflection.klass.search(*association_args(args))
|
6
|
+
end
|
7
|
+
|
8
|
+
def facets(*args)
|
9
|
+
@reflection.klass.facets(*association_args(args))
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def association_args(args)
|
15
|
+
options = args.extract_options!
|
6
16
|
options[:with] ||= {}
|
7
17
|
options[:with].merge! default_filter
|
8
|
-
|
9
|
-
args
|
10
|
-
@reflection.klass.search(*args)
|
18
|
+
|
19
|
+
args + [options]
|
11
20
|
end
|
12
21
|
|
13
|
-
private
|
14
|
-
|
15
22
|
def attribute_for_foreign_key
|
16
23
|
foreign_key = @reflection.primary_key_name
|
17
24
|
stack = [@reflection.options[:through]].compact
|
@@ -33,9 +33,9 @@ module ThinkingSphinx
|
|
33
33
|
|
34
34
|
def cast_to_datetime(clause)
|
35
35
|
if ThinkingSphinx::Configuration.instance.use_64_bit
|
36
|
-
"cast(extract(epoch from #{clause}) as bigint)"
|
36
|
+
"cast(floor(extract(epoch from #{clause})) as bigint)"
|
37
37
|
else
|
38
|
-
"cast(extract(epoch from #{clause}) as int)"
|
38
|
+
"cast(floor(extract(epoch from #{clause})) as int)"
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -109,7 +109,7 @@ module ThinkingSphinx
|
|
109
109
|
end
|
110
110
|
|
111
111
|
def create_array_accum_function
|
112
|
-
if server_version >=
|
112
|
+
if server_version >= 80311
|
113
113
|
return
|
114
114
|
elsif server_version > 80200
|
115
115
|
execute <<-SQL
|
@@ -1,41 +1,41 @@
|
|
1
1
|
module ThinkingSphinx
|
2
2
|
class BundledSearch
|
3
3
|
attr_reader :client
|
4
|
-
|
4
|
+
|
5
5
|
def initialize
|
6
6
|
@searches = []
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
def search(*args)
|
10
10
|
@searches << ThinkingSphinx.search(*args)
|
11
11
|
@searches.last.append_to client
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def search_for_ids(*args)
|
15
15
|
@searches << ThinkingSphinx.search_for_ids(*args)
|
16
16
|
@searches.last.append_to client
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def searches
|
20
20
|
populate
|
21
21
|
@searches
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
private
|
25
|
-
|
25
|
+
|
26
26
|
def client
|
27
27
|
@client ||= ThinkingSphinx::Configuration.instance.client
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
def populated?
|
31
31
|
@populated
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
def populate
|
35
35
|
return if populated?
|
36
|
-
|
36
|
+
|
37
37
|
@populated = true
|
38
|
-
|
38
|
+
|
39
39
|
client.run.each_with_index do |results, index|
|
40
40
|
searches[index].populate_from_queue results
|
41
41
|
end
|
@@ -28,6 +28,7 @@ module ThinkingSphinx
|
|
28
28
|
# html remove elements:: ''
|
29
29
|
# searchd_binary_name:: searchd
|
30
30
|
# indexer_binary_name:: indexer
|
31
|
+
# hard_retry_count:: 0
|
31
32
|
#
|
32
33
|
# If you want to change these settings, create a YAML file at
|
33
34
|
# config/sphinx.yml with settings for each environment, in a similar
|
@@ -64,7 +65,8 @@ module ThinkingSphinx
|
|
64
65
|
|
65
66
|
attr_accessor :searchd_file_path, :allow_star, :app_root,
|
66
67
|
:model_directories, :delayed_job_priority, :indexed_models, :use_64_bit,
|
67
|
-
:touched_reindex_file, :stop_timeout, :version, :shuffle
|
68
|
+
:touched_reindex_file, :stop_timeout, :version, :shuffle,
|
69
|
+
:hard_retry_count
|
68
70
|
|
69
71
|
attr_accessor :source_options, :index_options
|
70
72
|
|
@@ -112,6 +114,7 @@ module ThinkingSphinx
|
|
112
114
|
self.delayed_job_priority = 0
|
113
115
|
self.indexed_models = []
|
114
116
|
self.shuffle = false
|
117
|
+
self.hard_retry_count = 0
|
115
118
|
|
116
119
|
self.source_options = {}
|
117
120
|
self.index_options = {
|
@@ -405,28 +405,41 @@ module ThinkingSphinx
|
|
405
405
|
def populate
|
406
406
|
return if @populated
|
407
407
|
@populated = true
|
408
|
+
retries = hard_retries
|
408
409
|
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
"
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
410
|
+
begin
|
411
|
+
retry_on_stale_index do
|
412
|
+
begin
|
413
|
+
log "Querying: '#{query}'"
|
414
|
+
runtime = Benchmark.realtime {
|
415
|
+
@results = client.query query, indexes, comment
|
416
|
+
}
|
417
|
+
log "Found #{@results[:total_found]} results", :debug,
|
418
|
+
"Sphinx (#{sprintf("%f", runtime)}s)"
|
419
|
+
|
420
|
+
log "Sphinx Daemon returned warning: #{warning}", :error if warning?
|
421
|
+
|
422
|
+
if error?
|
423
|
+
log "Sphinx Daemon returned error: #{error}", :error
|
424
|
+
raise SphinxError.new(error, @results) unless options[:ignore_errors]
|
425
|
+
end
|
426
|
+
rescue Errno::ECONNREFUSED => err
|
427
|
+
raise ThinkingSphinx::ConnectionError,
|
428
|
+
'Connection to Sphinx Daemon (searchd) failed.'
|
423
429
|
end
|
424
|
-
rescue Errno::ECONNREFUSED => err
|
425
|
-
raise ThinkingSphinx::ConnectionError,
|
426
|
-
'Connection to Sphinx Daemon (searchd) failed.'
|
427
|
-
end
|
428
430
|
|
429
|
-
|
431
|
+
compose_results
|
432
|
+
end
|
433
|
+
rescue => e
|
434
|
+
log 'Caught Sphinx exception: %s (%s %s left)' % [
|
435
|
+
e.message, retries, (retries == 1 ? 'try' : 'tries')
|
436
|
+
]
|
437
|
+
retries -= 1
|
438
|
+
if retries >= 0
|
439
|
+
retry
|
440
|
+
else
|
441
|
+
raise e
|
442
|
+
end
|
430
443
|
end
|
431
444
|
end
|
432
445
|
|
@@ -847,6 +860,10 @@ module ThinkingSphinx
|
|
847
860
|
end
|
848
861
|
end
|
849
862
|
|
863
|
+
def hard_retries
|
864
|
+
options[:hard_retry_count] || config.hard_retry_count
|
865
|
+
end
|
866
|
+
|
850
867
|
def include_for_class(klass)
|
851
868
|
includes = options[:include] || klass.sphinx_index_options[:include]
|
852
869
|
|
@@ -41,6 +41,46 @@ describe 'ThinkingSphinx::ActiveRecord::HasManyAssociation' do
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
describe "facets method" do
|
45
|
+
before :each do
|
46
|
+
Friendship.stub!(:facets => true)
|
47
|
+
|
48
|
+
@person = Person.find(:first)
|
49
|
+
@index = Friendship.sphinx_indexes.first
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should raise an error if the required attribute doesn't exist" do
|
53
|
+
@index.stub!(:attributes => [])
|
54
|
+
|
55
|
+
lambda { @person.friendships.facets "test" }.should raise_error(RuntimeError)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should add a filter for the attribute into a normal facets call" do
|
59
|
+
Friendship.should_receive(:facets) do |query, options|
|
60
|
+
options[:with][:person_id].should == @person.id
|
61
|
+
end
|
62
|
+
|
63
|
+
@person.friendships.facets "test"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should add a filter for an aliased attribute into a normal facets call" do
|
67
|
+
@team = CricketTeam.new
|
68
|
+
@team.stub!(:id => 1)
|
69
|
+
|
70
|
+
Person.should_receive(:facets).with do |query, options|
|
71
|
+
options[:with][:team_id].should == @team.id
|
72
|
+
end
|
73
|
+
|
74
|
+
@team.people.facets "test"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should define indexes for the reflection class" do
|
78
|
+
Friendship.should_receive(:define_indexes)
|
79
|
+
|
80
|
+
@person.friendships.facets 'test'
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
44
84
|
describe "search method for has_many :through" do
|
45
85
|
before :each do
|
46
86
|
Person.stub!(:search => true)
|
@@ -75,6 +115,40 @@ describe 'ThinkingSphinx::ActiveRecord::HasManyAssociation' do
|
|
75
115
|
end
|
76
116
|
end
|
77
117
|
|
118
|
+
describe "facets method for has_many :through" do
|
119
|
+
before :each do
|
120
|
+
Person.stub!(:facets => true)
|
121
|
+
|
122
|
+
@person = Person.find(:first)
|
123
|
+
@index = Person.sphinx_indexes.first
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should raise an error if the required attribute doesn't exist" do
|
127
|
+
@index.stub!(:attributes => [])
|
128
|
+
|
129
|
+
lambda { @person.friends.facets "test" }.should raise_error(RuntimeError)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should add a filter for the attribute into a normal facets call" do
|
133
|
+
Person.should_receive(:facets).with do |query, options|
|
134
|
+
options[:with][:friendly_ids].should == @person.id
|
135
|
+
end
|
136
|
+
|
137
|
+
@person.friends.facets "test"
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should add a filter for an aliased attribute into a normal facets call" do
|
141
|
+
@team = FootballTeam.new
|
142
|
+
@team.stub!(:id => 1)
|
143
|
+
|
144
|
+
Person.should_receive(:facets).with do |query, options|
|
145
|
+
options[:with][:football_team_id].should == @team.id
|
146
|
+
end
|
147
|
+
|
148
|
+
@team.people.facets "test"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
78
152
|
describe 'filtering sphinx scopes' do
|
79
153
|
before :each do
|
80
154
|
Friendship.stub!(:search => Friendship)
|
@@ -62,6 +62,22 @@ describe ThinkingSphinx::AutoVersion do
|
|
62
62
|
ThinkingSphinx::AutoVersion.detect
|
63
63
|
end
|
64
64
|
|
65
|
+
it "should require 2.1.0 if using Sphinx 2.0.3" do
|
66
|
+
ThinkingSphinx::AutoVersion.should_receive(:require).
|
67
|
+
with('riddle/2.1.0')
|
68
|
+
|
69
|
+
@config.stub!(:version => '2.0.4-release')
|
70
|
+
ThinkingSphinx::AutoVersion.detect
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should require 2.1.0 if using Sphinx 2.0.3" do
|
74
|
+
ThinkingSphinx::AutoVersion.should_receive(:require).
|
75
|
+
with('riddle/2.1.0')
|
76
|
+
|
77
|
+
@config.stub!(:version => '2.0.5-release')
|
78
|
+
ThinkingSphinx::AutoVersion.detect
|
79
|
+
end
|
80
|
+
|
65
81
|
it "should require 2.1.0 if using Sphinx 2.1.0 dev" do
|
66
82
|
ThinkingSphinx::AutoVersion.should_receive(:require).
|
67
83
|
with('riddle/2.1.0')
|
@@ -411,6 +411,38 @@ describe ThinkingSphinx::Search do
|
|
411
411
|
'baz @foo bar @(foo,bar) baz', :star => true
|
412
412
|
).first
|
413
413
|
end
|
414
|
+
|
415
|
+
it "should try retry query up to the hard_retry_count option times if it catches an exception" do
|
416
|
+
@client.should_receive(:query).exactly(4).and_raise("Test Exception")
|
417
|
+
|
418
|
+
expect { ThinkingSphinx::Search.new(:hard_retry_count => 3).first }.
|
419
|
+
to raise_error("Test Exception")
|
420
|
+
end
|
421
|
+
|
422
|
+
it "should not retry query if hard_retry_count option is not set" do
|
423
|
+
@client.should_receive(:query).exactly(1).and_raise("Test Exception")
|
424
|
+
|
425
|
+
expect { ThinkingSphinx::Search.new.first }.
|
426
|
+
to raise_error("Test Exception")
|
427
|
+
end
|
428
|
+
|
429
|
+
it "should allow the hard_retry_count to be globally set as a configuration option" do
|
430
|
+
@config.hard_retry_count = 2
|
431
|
+
|
432
|
+
@client.should_receive(:query).exactly(3).and_raise("Test Exception")
|
433
|
+
|
434
|
+
expect { ThinkingSphinx::Search.new.first }.
|
435
|
+
to raise_error("Test Exception")
|
436
|
+
end
|
437
|
+
|
438
|
+
it "should give priority to the hard_retry_count search option over the globally configured option" do
|
439
|
+
@config.hard_retry_count = 4
|
440
|
+
|
441
|
+
@client.should_receive(:query).exactly(2).and_raise("Test Exception")
|
442
|
+
|
443
|
+
expect { ThinkingSphinx::Search.new(:hard_retry_count => 1).first }.
|
444
|
+
to raise_error("Test Exception")
|
445
|
+
end
|
414
446
|
end
|
415
447
|
|
416
448
|
describe 'comment' do
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thinking-sphinx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 29
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 4
|
9
|
-
-
|
10
|
-
version: 1.4.
|
9
|
+
- 13
|
10
|
+
version: 1.4.13
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Pat Allan
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
18
|
+
date: 2012-08-10 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
type: :runtime
|
@@ -64,12 +64,12 @@ dependencies:
|
|
64
64
|
requirements:
|
65
65
|
- - ">="
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
hash:
|
67
|
+
hash: 5
|
68
68
|
segments:
|
69
69
|
- 1
|
70
70
|
- 5
|
71
|
-
-
|
72
|
-
version: 1.5.
|
71
|
+
- 3
|
72
|
+
version: 1.5.3
|
73
73
|
version_requirements: *id003
|
74
74
|
prerelease: false
|
75
75
|
name: riddle
|