DrMark-thinking-sphinx 1.1.15 → 1.2.5
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 +22 -0
- data/VERSION.yml +4 -0
- data/lib/thinking_sphinx/active_record/scopes.rb +39 -0
- data/lib/thinking_sphinx/active_record.rb +27 -7
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +9 -3
- data/lib/thinking_sphinx/association.rb +4 -1
- data/lib/thinking_sphinx/attribute.rb +91 -30
- data/lib/thinking_sphinx/configuration.rb +51 -12
- data/lib/thinking_sphinx/deltas/datetime_delta.rb +2 -2
- data/lib/thinking_sphinx/deltas/default_delta.rb +1 -1
- data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +1 -1
- data/lib/thinking_sphinx/deltas/delayed_delta.rb +3 -0
- data/lib/thinking_sphinx/deploy/capistrano.rb +25 -8
- data/lib/thinking_sphinx/excerpter.rb +22 -0
- data/lib/thinking_sphinx/facet.rb +1 -1
- data/lib/thinking_sphinx/facet_search.rb +134 -0
- data/lib/thinking_sphinx/index.rb +2 -1
- data/lib/thinking_sphinx/rails_additions.rb +14 -0
- data/lib/thinking_sphinx/search.rb +599 -658
- data/lib/thinking_sphinx/search_methods.rb +421 -0
- data/lib/thinking_sphinx/source/internal_properties.rb +1 -1
- data/lib/thinking_sphinx/source/sql.rb +17 -13
- data/lib/thinking_sphinx/source.rb +6 -6
- data/lib/thinking_sphinx/tasks.rb +42 -8
- data/lib/thinking_sphinx.rb +82 -54
- data/rails/init.rb +14 -0
- data/spec/{unit → lib}/thinking_sphinx/active_record/delta_spec.rb +5 -5
- data/spec/{unit → lib}/thinking_sphinx/active_record/has_many_association_spec.rb +0 -0
- data/spec/lib/thinking_sphinx/active_record/scopes_spec.rb +96 -0
- data/spec/{unit → lib}/thinking_sphinx/active_record_spec.rb +51 -31
- data/spec/{unit → lib}/thinking_sphinx/association_spec.rb +4 -5
- data/spec/lib/thinking_sphinx/attribute_spec.rb +465 -0
- data/spec/{unit → lib}/thinking_sphinx/configuration_spec.rb +161 -29
- data/spec/{unit → lib}/thinking_sphinx/core/string_spec.rb +0 -0
- data/spec/lib/thinking_sphinx/excerpter_spec.rb +49 -0
- data/spec/lib/thinking_sphinx/facet_search_spec.rb +176 -0
- data/spec/{unit → lib}/thinking_sphinx/facet_spec.rb +24 -0
- data/spec/{unit → lib}/thinking_sphinx/field_spec.rb +8 -8
- data/spec/{unit → lib}/thinking_sphinx/index/builder_spec.rb +6 -2
- data/spec/{unit → lib}/thinking_sphinx/index/faux_column_spec.rb +0 -0
- data/spec/lib/thinking_sphinx/index_spec.rb +45 -0
- data/spec/{unit → lib}/thinking_sphinx/rails_additions_spec.rb +25 -5
- data/spec/lib/thinking_sphinx/search_methods_spec.rb +152 -0
- data/spec/lib/thinking_sphinx/search_spec.rb +960 -0
- data/spec/{unit → lib}/thinking_sphinx/source_spec.rb +63 -2
- data/spec/{unit → lib}/thinking_sphinx_spec.rb +32 -4
- data/tasks/distribution.rb +36 -35
- data/vendor/riddle/lib/riddle/client/message.rb +4 -3
- data/vendor/riddle/lib/riddle/client.rb +3 -0
- data/vendor/riddle/lib/riddle/configuration/section.rb +8 -2
- data/vendor/riddle/lib/riddle/controller.rb +17 -7
- data/vendor/riddle/lib/riddle.rb +1 -1
- metadata +79 -83
- data/lib/thinking_sphinx/active_record/search.rb +0 -57
- data/lib/thinking_sphinx/collection.rb +0 -148
- data/lib/thinking_sphinx/facet_collection.rb +0 -59
- data/lib/thinking_sphinx/search/facets.rb +0 -98
- data/spec/unit/thinking_sphinx/active_record/search_spec.rb +0 -107
- data/spec/unit/thinking_sphinx/attribute_spec.rb +0 -232
- data/spec/unit/thinking_sphinx/collection_spec.rb +0 -14
- data/spec/unit/thinking_sphinx/facet_collection_spec.rb +0 -64
- data/spec/unit/thinking_sphinx/index_spec.rb +0 -139
- data/spec/unit/thinking_sphinx/search_spec.rb +0 -130
@@ -1,64 +0,0 @@
|
|
1
|
-
require 'spec/spec_helper'
|
2
|
-
|
3
|
-
describe ThinkingSphinx::FacetCollection do
|
4
|
-
before do
|
5
|
-
@facet_collection = ThinkingSphinx::FacetCollection.new([])
|
6
|
-
end
|
7
|
-
|
8
|
-
# TODO fix nasty hack when we have internet!
|
9
|
-
def mock_results
|
10
|
-
return @results if defined? @results
|
11
|
-
@result = Person.find(:first)
|
12
|
-
@results = [@result]
|
13
|
-
@results.stub!(:each_with_groupby_and_count).and_yield(@result, @result.city.to_crc32, 1)
|
14
|
-
@results
|
15
|
-
end
|
16
|
-
|
17
|
-
describe "#add_from_results" do
|
18
|
-
describe "with empty result set" do
|
19
|
-
before do
|
20
|
-
@facet_collection.add_from_results('attribute_facet', [])
|
21
|
-
end
|
22
|
-
|
23
|
-
it "should add key as attribute" do
|
24
|
-
@facet_collection.should have_key(:attribute)
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should return an empty hash for the facet results" do
|
28
|
-
@facet_collection[:attribute].should be_empty
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
describe "with non-empty result set" do
|
33
|
-
before do
|
34
|
-
@facet_collection.add_from_results('city_facet', mock_results)
|
35
|
-
end
|
36
|
-
|
37
|
-
it "should return a hash" do
|
38
|
-
@facet_collection.should be_a_kind_of(Hash)
|
39
|
-
end
|
40
|
-
|
41
|
-
it "should add key as attribute" do
|
42
|
-
@facet_collection.keys.should include(:city)
|
43
|
-
end
|
44
|
-
|
45
|
-
it "should return a hash" do
|
46
|
-
@facet_collection[:city].should == {@result.city => 1}
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
describe "#for" do
|
52
|
-
before do
|
53
|
-
@facet_collection.add_from_results('city_facet', mock_results)
|
54
|
-
end
|
55
|
-
|
56
|
-
it "should return the search results for the attribute and key pair" do
|
57
|
-
ThinkingSphinx::Search.should_receive(:search) do |options|
|
58
|
-
options[:with].should have_key('city_facet')
|
59
|
-
options[:with]['city_facet'].should == @result.city.to_crc32
|
60
|
-
end
|
61
|
-
@facet_collection.for(:city => @result.city)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
@@ -1,139 +0,0 @@
|
|
1
|
-
require 'spec/spec_helper'
|
2
|
-
|
3
|
-
describe ThinkingSphinx::Index do
|
4
|
-
describe "prefix_fields method" do
|
5
|
-
before :each do
|
6
|
-
@index = ThinkingSphinx::Index.new(Person)
|
7
|
-
|
8
|
-
@field_a = ThinkingSphinx::Field.stub_instance(:prefixes => true)
|
9
|
-
@field_b = ThinkingSphinx::Field.stub_instance(:prefixes => false)
|
10
|
-
@field_c = ThinkingSphinx::Field.stub_instance(:prefixes => true)
|
11
|
-
|
12
|
-
@index.stub_method(:fields => [@field_a, @field_b, @field_c])
|
13
|
-
end
|
14
|
-
|
15
|
-
it "should return fields that are flagged as prefixed" do
|
16
|
-
@index.prefix_fields.should include(@field_a)
|
17
|
-
@index.prefix_fields.should include(@field_c)
|
18
|
-
end
|
19
|
-
|
20
|
-
it "should not return fields that aren't flagged as prefixed" do
|
21
|
-
@index.prefix_fields.should_not include(@field_b)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
describe "infix_fields method" do
|
26
|
-
before :each do
|
27
|
-
@index = ThinkingSphinx::Index.new(Person)
|
28
|
-
|
29
|
-
@field_a = ThinkingSphinx::Field.stub_instance(:infixes => true)
|
30
|
-
@field_b = ThinkingSphinx::Field.stub_instance(:infixes => false)
|
31
|
-
@field_c = ThinkingSphinx::Field.stub_instance(:infixes => true)
|
32
|
-
|
33
|
-
@index.stub_method(:fields => [@field_a, @field_b, @field_c])
|
34
|
-
end
|
35
|
-
|
36
|
-
it "should return fields that are flagged as infixed" do
|
37
|
-
@index.infix_fields.should include(@field_a)
|
38
|
-
@index.infix_fields.should include(@field_c)
|
39
|
-
end
|
40
|
-
|
41
|
-
it "should not return fields that aren't flagged as infixed" do
|
42
|
-
@index.infix_fields.should_not include(@field_b)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
describe "multi-value attribute as ranged-query with has-many association" do
|
47
|
-
before :each do
|
48
|
-
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
49
|
-
indexes first_name
|
50
|
-
has tags(:id), :as => :tag_ids, :source => :ranged_query
|
51
|
-
end
|
52
|
-
|
53
|
-
@sql = @index.sources.first.to_riddle_for_core(0, 0).sql_query
|
54
|
-
end
|
55
|
-
|
56
|
-
it "should not include attribute in select-clause sql_query" do
|
57
|
-
@sql.should_not match(/tag_ids/)
|
58
|
-
@sql.should_not match(/GROUP_CONCAT\(`tags`.`id`/)
|
59
|
-
end
|
60
|
-
|
61
|
-
it "should not join with association table" do
|
62
|
-
@sql.should_not match(/LEFT OUTER JOIN `tags`/)
|
63
|
-
end
|
64
|
-
|
65
|
-
it "should include sql_attr_multi as ranged-query" do
|
66
|
-
attribute = @index.attributes.detect { |attrib| attrib.unique_name == :tag_ids }
|
67
|
-
attribute.type_to_config.should == :sql_attr_multi
|
68
|
-
|
69
|
-
declaration, query, range_query = attribute.send(:config_value).split('; ')
|
70
|
-
declaration.should == "uint tag_ids from ranged-query"
|
71
|
-
query.should == "SELECT `tags`.`person_id` #{ThinkingSphinx.unique_id_expression} AS `id`, `tags`.`id` AS `tag_ids` FROM `tags` WHERE `tags`.`person_id` >= $start AND `tags`.`person_id` <= $end"
|
72
|
-
range_query.should == "SELECT MIN(`tags`.`person_id`), MAX(`tags`.`person_id`) FROM `tags`"
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
describe "multi-value attribute as ranged-query with has-many-through association" do
|
77
|
-
before :each do
|
78
|
-
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
79
|
-
indexes first_name
|
80
|
-
has football_teams(:id), :as => :football_teams_ids, :source => :ranged_query
|
81
|
-
end
|
82
|
-
|
83
|
-
@sql = @index.sources.first.to_riddle_for_core(0, 0).sql_query
|
84
|
-
end
|
85
|
-
|
86
|
-
it "should not include attribute in select-clause sql_query" do
|
87
|
-
@sql.should_not match(/football_teams_ids/)
|
88
|
-
@sql.should_not match(/GROUP_CONCAT\(`tags`.`football_team_id`/)
|
89
|
-
end
|
90
|
-
|
91
|
-
it "should not join with association table" do
|
92
|
-
@sql.should_not match(/LEFT OUTER JOIN `tags`/)
|
93
|
-
end
|
94
|
-
|
95
|
-
it "should include sql_attr_multi as ranged-query" do
|
96
|
-
attribute = @index.attributes.detect { |attrib|
|
97
|
-
attrib.unique_name == :football_teams_ids
|
98
|
-
}
|
99
|
-
attribute.type_to_config.should == :sql_attr_multi
|
100
|
-
|
101
|
-
declaration, query, range_query = attribute.send(:config_value).split('; ')
|
102
|
-
declaration.should == "uint football_teams_ids from ranged-query"
|
103
|
-
query.should == "SELECT `tags`.`person_id` #{ThinkingSphinx.unique_id_expression} AS `id`, `tags`.`football_team_id` AS `football_teams_ids` FROM `tags` WHERE `tags`.`person_id` >= $start AND `tags`.`person_id` <= $end"
|
104
|
-
range_query.should == "SELECT MIN(`tags`.`person_id`), MAX(`tags`.`person_id`) FROM `tags`"
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
describe "multi-value attribute as ranged-query with has-many-through association and foreign_key" do
|
109
|
-
before :each do
|
110
|
-
@index = ThinkingSphinx::Index::Builder.generate(Person) do
|
111
|
-
indexes first_name
|
112
|
-
has friends(:id), :as => :friend_ids, :source => :ranged_query
|
113
|
-
end
|
114
|
-
|
115
|
-
@sql = @index.sources.first.to_riddle_for_core(0, 0).sql_query
|
116
|
-
end
|
117
|
-
|
118
|
-
it "should not include attribute in select-clause sql_query" do
|
119
|
-
@sql.should_not match(/friend_ids/)
|
120
|
-
@sql.should_not match(/GROUP_CONCAT\(`friendships`.`friend_id`/)
|
121
|
-
end
|
122
|
-
|
123
|
-
it "should not join with association table" do
|
124
|
-
@sql.should_not match(/LEFT OUTER JOIN `friendships`/)
|
125
|
-
end
|
126
|
-
|
127
|
-
it "should include sql_attr_multi as ranged-query" do
|
128
|
-
attribute = @index.attributes.detect { |attrib|
|
129
|
-
attrib.unique_name == :friend_ids
|
130
|
-
}
|
131
|
-
attribute.type_to_config.should == :sql_attr_multi
|
132
|
-
|
133
|
-
declaration, query, range_query = attribute.send(:config_value).split('; ')
|
134
|
-
declaration.should == "uint friend_ids from ranged-query"
|
135
|
-
query.should == "SELECT `friendships`.`person_id` #{ThinkingSphinx.unique_id_expression} AS `id`, `friendships`.`friend_id` AS `friend_ids` FROM `friendships` WHERE `friendships`.`person_id` >= $start AND `friendships`.`person_id` <= $end"
|
136
|
-
range_query.should == "SELECT MIN(`friendships`.`person_id`), MAX(`friendships`.`person_id`) FROM `friendships`"
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
@@ -1,130 +0,0 @@
|
|
1
|
-
require 'spec/spec_helper'
|
2
|
-
require 'will_paginate/collection'
|
3
|
-
|
4
|
-
describe ThinkingSphinx::Search do
|
5
|
-
describe "search method" do
|
6
|
-
before :each do
|
7
|
-
@client = Riddle::Client.stub_instance(
|
8
|
-
:filters => [],
|
9
|
-
:filters= => true,
|
10
|
-
:id_range= => true,
|
11
|
-
:sort_mode => :asc,
|
12
|
-
:limit => 5,
|
13
|
-
:offset= => 0,
|
14
|
-
:sort_mode= => true,
|
15
|
-
:query => {
|
16
|
-
:matches => [],
|
17
|
-
:total => 50
|
18
|
-
}
|
19
|
-
)
|
20
|
-
|
21
|
-
ThinkingSphinx::Search.stub_methods(
|
22
|
-
:client_from_options => @client,
|
23
|
-
:search_conditions => ["", []]
|
24
|
-
)
|
25
|
-
end
|
26
|
-
|
27
|
-
describe ":star option" do
|
28
|
-
|
29
|
-
it "should not apply by default" do
|
30
|
-
ThinkingSphinx::Search.search "foo bar"
|
31
|
-
@client.should have_received(:query).with("foo bar")
|
32
|
-
end
|
33
|
-
|
34
|
-
it "should apply when passed, and handle full extended syntax" do
|
35
|
-
input = %{a b* c (d | e) 123 5&6 (f_f g) !h "i j" "k l"~10 "m n"/3 @o p -(q|r)}
|
36
|
-
expected = %{*a* b* *c* (*d* | *e*) *123* *5*&*6* (*f_f* *g*) !*h* "i j" "k l"~10 "m n"/3 @o *p* -(*q*|*r*)}
|
37
|
-
ThinkingSphinx::Search.search input, :star => true
|
38
|
-
@client.should have_received(:query).with(expected)
|
39
|
-
end
|
40
|
-
|
41
|
-
it "should default to /\w+/ as token" do
|
42
|
-
ThinkingSphinx::Search.search "foo@bar.com", :star => true
|
43
|
-
@client.should have_received(:query).with("*foo*@*bar*.*com*")
|
44
|
-
end
|
45
|
-
|
46
|
-
it "should honour custom token" do
|
47
|
-
ThinkingSphinx::Search.search "foo@bar.com -foo-bar", :star => /[\w@.-]+/u
|
48
|
-
@client.should have_received(:query).with("*foo@bar.com* -*foo-bar*")
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
describe "facets method" do
|
55
|
-
before :each do
|
56
|
-
@person = Person.find(:first)
|
57
|
-
|
58
|
-
@city_results = [@person]
|
59
|
-
@city_results.stub!(:each_with_groupby_and_count).
|
60
|
-
and_yield(@person, @person.city.to_crc32, 1)
|
61
|
-
|
62
|
-
@birthday_results = [@person]
|
63
|
-
@birthday_results.stub!(:each_with_groupby_and_count).
|
64
|
-
and_yield(@person, @person.birthday.to_i, 1)
|
65
|
-
|
66
|
-
ThinkingSphinx::Search.stub!(:search).and_return(@city_results, @birthday_results)
|
67
|
-
|
68
|
-
@config = ThinkingSphinx::Configuration.instance
|
69
|
-
@config.configuration.searchd.max_matches = 10_000
|
70
|
-
end
|
71
|
-
|
72
|
-
it "should use the system-set max_matches for limit on facet calls" do
|
73
|
-
ThinkingSphinx::Search.should_receive(:search) do |options|
|
74
|
-
options[:max_matches].should == 10_000
|
75
|
-
options[:limit].should == 10_000
|
76
|
-
end
|
77
|
-
|
78
|
-
ThinkingSphinx::Search.facets :all_attributes => true
|
79
|
-
end
|
80
|
-
|
81
|
-
it "should use the default max-matches if there is no explicit setting" do
|
82
|
-
@config.configuration.searchd.max_matches = nil
|
83
|
-
ThinkingSphinx::Search.should_receive(:search) do |options|
|
84
|
-
options[:max_matches].should == 1000
|
85
|
-
options[:limit].should == 1000
|
86
|
-
end
|
87
|
-
|
88
|
-
ThinkingSphinx::Search.facets :all_attributes => true
|
89
|
-
end
|
90
|
-
|
91
|
-
it "should ignore user-provided max_matches and limit on facet calls" do
|
92
|
-
ThinkingSphinx::Search.should_receive(:search) do |options|
|
93
|
-
options[:max_matches].should == 10_000
|
94
|
-
options[:limit].should == 10_000
|
95
|
-
end
|
96
|
-
|
97
|
-
ThinkingSphinx::Search.facets(
|
98
|
-
:all_attributes => true,
|
99
|
-
:max_matches => 500,
|
100
|
-
:limit => 200
|
101
|
-
)
|
102
|
-
end
|
103
|
-
|
104
|
-
describe "conflicting facets" do
|
105
|
-
before :each do
|
106
|
-
@index = ThinkingSphinx::Index::Builder.generate(Alpha) do
|
107
|
-
indexes :name
|
108
|
-
has :value, :as => :city, :facet => true
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
after :each do
|
113
|
-
Alpha.sphinx_facets.delete_at(-1)
|
114
|
-
Alpha.sphinx_indexes.delete_at(-1)
|
115
|
-
end
|
116
|
-
|
117
|
-
it "should raise an error if searching with facets of same name but different type" do
|
118
|
-
lambda {
|
119
|
-
ThinkingSphinx::Search.facets :all_attributes => true
|
120
|
-
}.should raise_error
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
describe ThinkingSphinx::Search, "playing nice with Search model" do
|
127
|
-
it "should not conflict with models called Search" do
|
128
|
-
lambda { Search.find(:all) }.should_not raise_error
|
129
|
-
end
|
130
|
-
end
|