thinking-sphinx 1.4.12 → 1.4.13
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/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
|