thinking-sphinx 2.0.12 → 2.0.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/HISTORY +10 -0
- data/lib/thinking_sphinx/active_record/collection_proxy.rb +12 -5
- 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 +34 -17
- 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
data/HISTORY
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
2.0.13 - August 10th 2012
|
2
|
+
* 1.4.13 changes.
|
3
|
+
|
1
4
|
2.0.12 - May 14th 2012
|
2
5
|
* STI fix when generating WHERE clauses for sql_query.
|
3
6
|
* 1.4.12 changes.
|
@@ -61,6 +64,13 @@
|
|
61
64
|
* Rails 3 support.
|
62
65
|
* 1.4.0 changes.
|
63
66
|
|
67
|
+
1.4.13 - August 10th 2012
|
68
|
+
* Sphinx 2.0.5 support.
|
69
|
+
* Hard retries for Sphinx exceptions (Andrew Hunter).
|
70
|
+
* Add support for association-filtered faceting (Andrew White).
|
71
|
+
* Cast PostgreSQL timestamps to their floored integers (instead of rounding up).
|
72
|
+
* Don't add array_accum to PostgreSQL v80311 (8.3.?) or newer.
|
73
|
+
|
64
74
|
1.4.12 - May 14th 2012
|
65
75
|
* Updating Riddle references to 1.5.2.
|
66
76
|
* Can explicitly specify available types for STI tables instead of automatically discovering them with "SELECT DISTINCT type FROM <table>" (Cedric Maion).
|
@@ -2,16 +2,23 @@ module ThinkingSphinx
|
|
2
2
|
module ActiveRecord
|
3
3
|
module CollectionProxy
|
4
4
|
def search(*args)
|
5
|
-
|
6
|
-
|
7
|
-
options[:with].merge! default_filter
|
5
|
+
proxy_association.klass.search(*association_args(args))
|
6
|
+
end
|
8
7
|
|
9
|
-
|
10
|
-
proxy_association.klass.
|
8
|
+
def facets(*args)
|
9
|
+
proxy_association.klass.facets(*association_args(args))
|
11
10
|
end
|
12
11
|
|
13
12
|
private
|
14
13
|
|
14
|
+
def association_args(args)
|
15
|
+
options = args.extract_options!
|
16
|
+
options[:with] ||= {}
|
17
|
+
options[:with].merge! default_filter
|
18
|
+
|
19
|
+
args + [options]
|
20
|
+
end
|
21
|
+
|
15
22
|
def attribute_for_foreign_key
|
16
23
|
if proxy_association.reflection.through_reflection
|
17
24
|
foreign_key = proxy_association.reflection.through_reflection.foreign_key
|
@@ -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
|
|
@@ -111,6 +113,7 @@ module ThinkingSphinx
|
|
111
113
|
self.delayed_job_priority = 0
|
112
114
|
self.indexed_models = []
|
113
115
|
self.shuffle = false
|
116
|
+
self.hard_retry_count = 0
|
114
117
|
|
115
118
|
self.source_options = {}
|
116
119
|
self.index_options = {
|
@@ -420,27 +420,40 @@ module ThinkingSphinx
|
|
420
420
|
def populate
|
421
421
|
return if @populated
|
422
422
|
@populated = true
|
423
|
+
retries = hard_retries
|
423
424
|
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
425
|
+
begin
|
426
|
+
retry_on_stale_index do
|
427
|
+
begin
|
428
|
+
log query do
|
429
|
+
@results = client.query query, indexes, comment
|
430
|
+
end
|
431
|
+
total = @results[:total_found].to_i
|
432
|
+
log "Found #{total} result#{'s' unless total == 1}"
|
433
|
+
|
434
|
+
log "Sphinx Daemon returned warning: #{warning}" if warning?
|
435
|
+
|
436
|
+
if error?
|
437
|
+
log "Sphinx Daemon returned error: #{error}"
|
438
|
+
raise SphinxError.new(error, @results) unless options[:ignore_errors]
|
439
|
+
end
|
440
|
+
rescue Errno::ECONNREFUSED => err
|
441
|
+
raise ThinkingSphinx::ConnectionError,
|
442
|
+
'Connection to Sphinx Daemon (searchd) failed.'
|
428
443
|
end
|
429
|
-
total = @results[:total_found].to_i
|
430
|
-
log "Found #{total} result#{'s' unless total == 1}"
|
431
|
-
|
432
|
-
log "Sphinx Daemon returned warning: #{warning}" if warning?
|
433
444
|
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
445
|
+
compose_results
|
446
|
+
end
|
447
|
+
rescue => e
|
448
|
+
log 'Caught Sphinx exception: %s (%s %s left)' % [
|
449
|
+
e.message, retries, (retries == 1 ? 'try' : 'tries')
|
450
|
+
]
|
451
|
+
retries -= 1
|
452
|
+
if retries >= 0
|
453
|
+
retry
|
454
|
+
else
|
455
|
+
raise e
|
441
456
|
end
|
442
|
-
|
443
|
-
compose_results
|
444
457
|
end
|
445
458
|
end
|
446
459
|
|
@@ -861,6 +874,10 @@ module ThinkingSphinx
|
|
861
874
|
end
|
862
875
|
end
|
863
876
|
|
877
|
+
def hard_retries
|
878
|
+
options[:hard_retry_count] || config.hard_retry_count
|
879
|
+
end
|
880
|
+
|
864
881
|
def include_for_class(klass)
|
865
882
|
includes = options[:include] || klass.sphinx_index_options[:include]
|
866
883
|
|
@@ -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: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 2
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 2.0.
|
9
|
+
- 13
|
10
|
+
version: 2.0.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
|
@@ -40,12 +40,12 @@ dependencies:
|
|
40
40
|
requirements:
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
hash:
|
43
|
+
hash: 5
|
44
44
|
segments:
|
45
45
|
- 1
|
46
46
|
- 5
|
47
|
-
-
|
48
|
-
version: 1.5.
|
47
|
+
- 3
|
48
|
+
version: 1.5.3
|
49
49
|
version_requirements: *id002
|
50
50
|
prerelease: false
|
51
51
|
name: riddle
|