sphinx 0.9.10.2122 → 2.1.1.3711
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/.gitignore +5 -2
- data/.travis.yml +8 -0
- data/CHANGELOG.md +71 -0
- data/Gemfile +4 -0
- data/README.md +221 -0
- data/Rakefile +40 -35
- data/lib/sphinx.rb +3 -8
- data/lib/sphinx/client.rb +223 -70
- data/lib/sphinx/constants.rb +23 -8
- data/lib/sphinx/response.rb +6 -6
- data/lib/sphinx/timeout.rb +1 -2
- data/lib/sphinx/version.rb +3 -0
- data/spec/client_response_spec.rb +77 -64
- data/spec/client_spec.rb +68 -31
- data/spec/client_validations_spec.rb +61 -7
- data/spec/fixtures/requests/default_search.dat +0 -0
- data/spec/fixtures/requests/default_search_index.dat +0 -0
- data/spec/fixtures/requests/excerpt_custom.dat +0 -0
- data/spec/fixtures/requests/excerpt_default.dat +0 -0
- data/spec/fixtures/requests/excerpt_flags.dat +0 -0
- data/spec/fixtures/requests/field_weights.dat +0 -0
- data/spec/fixtures/requests/filter.dat +0 -0
- data/spec/fixtures/requests/filter_exclude.dat +0 -0
- data/spec/fixtures/requests/filter_float_range.dat +0 -0
- data/spec/fixtures/requests/filter_float_range_exclude.dat +0 -0
- data/spec/fixtures/requests/filter_range.dat +0 -0
- data/spec/fixtures/requests/filter_range_exclude.dat +0 -0
- data/spec/fixtures/requests/filter_range_int64.dat +0 -0
- data/spec/fixtures/requests/filter_ranges.dat +0 -0
- data/spec/fixtures/requests/filters.dat +0 -0
- data/spec/fixtures/requests/filters_different.dat +0 -0
- data/spec/fixtures/requests/geo_anchor.dat +0 -0
- data/spec/fixtures/requests/group_by_attr.dat +0 -0
- data/spec/fixtures/requests/group_by_attrpair.dat +0 -0
- data/spec/fixtures/requests/group_by_day.dat +0 -0
- data/spec/fixtures/requests/group_by_day_sort.dat +0 -0
- data/spec/fixtures/requests/group_by_month.dat +0 -0
- data/spec/fixtures/requests/group_by_week.dat +0 -0
- data/spec/fixtures/requests/group_by_year.dat +0 -0
- data/spec/fixtures/requests/group_distinct.dat +0 -0
- data/spec/fixtures/requests/id_range.dat +0 -0
- data/spec/fixtures/requests/id_range64.dat +0 -0
- data/spec/fixtures/requests/index_weights.dat +0 -0
- data/spec/fixtures/requests/keywords.dat +0 -0
- data/spec/fixtures/requests/limits.dat +0 -0
- data/spec/fixtures/requests/limits_cutoff.dat +0 -0
- data/spec/fixtures/requests/limits_max.dat +0 -0
- data/spec/fixtures/requests/limits_max_cutoff.dat +0 -0
- data/spec/fixtures/requests/match_all.dat +0 -0
- data/spec/fixtures/requests/match_any.dat +0 -0
- data/spec/fixtures/requests/match_boolean.dat +0 -0
- data/spec/fixtures/requests/match_extended.dat +0 -0
- data/spec/fixtures/requests/match_extended2.dat +0 -0
- data/spec/fixtures/requests/match_fullscan.dat +0 -0
- data/spec/fixtures/requests/match_phrase.dat +0 -0
- data/spec/fixtures/requests/max_query_time.dat +0 -0
- data/spec/fixtures/requests/miltiple_queries.dat +0 -0
- data/spec/fixtures/requests/outer_select.dat +0 -0
- data/spec/fixtures/requests/override.dat +0 -0
- data/spec/fixtures/{default_search.php → requests/php/default_search.php} +1 -1
- data/spec/fixtures/{default_search_index.php → requests/php/default_search_index.php} +1 -1
- data/spec/fixtures/{excerpt_custom.php → requests/php/excerpt_custom.php} +1 -1
- data/spec/fixtures/{excerpt_default.php → requests/php/excerpt_default.php} +1 -1
- data/spec/fixtures/{excerpt_flags.php → requests/php/excerpt_flags.php} +1 -1
- data/spec/fixtures/{field_weights.php → requests/php/field_weights.php} +1 -1
- data/spec/fixtures/{filter.php → requests/php/filter.php} +1 -1
- data/spec/fixtures/{filter_exclude.php → requests/php/filter_exclude.php} +1 -1
- data/spec/fixtures/{filter_float_range.php → requests/php/filter_float_range.php} +1 -1
- data/spec/fixtures/{filter_float_range_exclude.php → requests/php/filter_float_range_exclude.php} +1 -1
- data/spec/fixtures/{filter_range.php → requests/php/filter_range.php} +1 -1
- data/spec/fixtures/{filter_range_exclude.php → requests/php/filter_range_exclude.php} +1 -1
- data/spec/fixtures/{filter_range_int64.php → requests/php/filter_range_int64.php} +1 -1
- data/spec/fixtures/{filter_ranges.php → requests/php/filter_ranges.php} +1 -1
- data/spec/fixtures/{filters.php → requests/php/filters.php} +1 -1
- data/spec/fixtures/{filters_different.php → requests/php/filters_different.php} +1 -1
- data/spec/fixtures/{geo_anchor.php → requests/php/geo_anchor.php} +1 -1
- data/spec/fixtures/{group_by_attr.php → requests/php/group_by_attr.php} +1 -1
- data/spec/fixtures/{group_by_attrpair.php → requests/php/group_by_attrpair.php} +1 -1
- data/spec/fixtures/{group_by_day.php → requests/php/group_by_day.php} +1 -1
- data/spec/fixtures/{group_by_day_sort.php → requests/php/group_by_day_sort.php} +1 -1
- data/spec/fixtures/{group_by_month.php → requests/php/group_by_month.php} +1 -1
- data/spec/fixtures/{group_by_week.php → requests/php/group_by_week.php} +1 -1
- data/spec/fixtures/{group_by_year.php → requests/php/group_by_year.php} +1 -1
- data/spec/fixtures/{group_distinct.php → requests/php/group_distinct.php} +1 -1
- data/spec/fixtures/{id_range.php → requests/php/id_range.php} +1 -1
- data/spec/fixtures/{id_range64.php → requests/php/id_range64.php} +1 -1
- data/spec/fixtures/{index_weights.php → requests/php/index_weights.php} +1 -1
- data/spec/fixtures/{keywords.php → requests/php/keywords.php} +1 -1
- data/spec/fixtures/{limits.php → requests/php/limits.php} +1 -1
- data/spec/fixtures/{limits_cutoff.php → requests/php/limits_cutoff.php} +1 -1
- data/spec/fixtures/{limits_max.php → requests/php/limits_max.php} +1 -1
- data/spec/fixtures/{limits_max_cutoff.php → requests/php/limits_max_cutoff.php} +1 -1
- data/spec/fixtures/{match_all.php → requests/php/match_all.php} +1 -1
- data/spec/fixtures/{match_any.php → requests/php/match_any.php} +1 -1
- data/spec/fixtures/{match_boolean.php → requests/php/match_boolean.php} +1 -1
- data/spec/fixtures/{match_extended.php → requests/php/match_extended.php} +1 -1
- data/spec/fixtures/{match_extended2.php → requests/php/match_extended2.php} +1 -1
- data/spec/fixtures/{match_fullscan.php → requests/php/match_fullscan.php} +1 -1
- data/spec/fixtures/{match_phrase.php → requests/php/match_phrase.php} +1 -1
- data/spec/fixtures/{max_query_time.php → requests/php/max_query_time.php} +1 -1
- data/spec/fixtures/{miltiple_queries.php → requests/php/miltiple_queries.php} +1 -1
- data/spec/fixtures/requests/php/outer_select.php +9 -0
- data/spec/fixtures/{set_override.php → requests/php/override.php} +1 -1
- data/spec/fixtures/requests/php/query_flag.php +13 -0
- data/spec/fixtures/requests/php/query_flag_after_reset.php +19 -0
- data/spec/fixtures/{ranking_bm25.php → requests/php/ranking_bm25.php} +1 -1
- data/spec/fixtures/requests/php/ranking_expr.php +9 -0
- data/spec/fixtures/{ranking_fieldmask.php → requests/php/ranking_fieldmask.php} +1 -1
- data/spec/fixtures/{ranking_matchany.php → requests/php/ranking_matchany.php} +1 -1
- data/spec/fixtures/{ranking_none.php → requests/php/ranking_none.php} +1 -1
- data/spec/fixtures/{ranking_proximity.php → requests/php/ranking_proximity.php} +1 -1
- data/spec/fixtures/{ranking_proximity_bm25.php → requests/php/ranking_proximity_bm25.php} +1 -1
- data/spec/fixtures/{ranking_sph04.php → requests/php/ranking_sph04.php} +1 -1
- data/spec/fixtures/{ranking_wordcount.php → requests/php/ranking_wordcount.php} +1 -1
- data/spec/fixtures/{retries.php → requests/php/retries.php} +1 -1
- data/spec/fixtures/{retries_delay.php → requests/php/retries_delay.php} +1 -1
- data/spec/fixtures/{select.php → requests/php/select.php} +1 -1
- data/spec/fixtures/{sort_attr_asc.php → requests/php/sort_attr_asc.php} +1 -1
- data/spec/fixtures/{sort_attr_desc.php → requests/php/sort_attr_desc.php} +1 -1
- data/spec/fixtures/{sort_expr.php → requests/php/sort_expr.php} +1 -1
- data/spec/fixtures/{sort_extended.php → requests/php/sort_extended.php} +1 -1
- data/spec/fixtures/{sort_relevance.php → requests/php/sort_relevance.php} +1 -1
- data/spec/fixtures/{sort_time_segments.php → requests/php/sort_time_segments.php} +1 -1
- data/spec/fixtures/{update_attributes.php → requests/php/update_attributes.php} +1 -1
- data/spec/fixtures/{update_attributes_mva.php → requests/php/update_attributes_mva.php} +1 -1
- data/spec/fixtures/{weights.php → requests/php/weights.php} +1 -1
- data/spec/fixtures/requests/query_flag.dat +0 -0
- data/spec/fixtures/requests/query_flag_after_reset.dat +0 -0
- data/spec/fixtures/requests/ranking_bm25.dat +0 -0
- data/spec/fixtures/requests/ranking_expr.dat +0 -0
- data/spec/fixtures/requests/ranking_fieldmask.dat +0 -0
- data/spec/fixtures/requests/ranking_matchany.dat +0 -0
- data/spec/fixtures/requests/ranking_none.dat +0 -0
- data/spec/fixtures/requests/ranking_proximity.dat +0 -0
- data/spec/fixtures/requests/ranking_proximity_bm25.dat +0 -0
- data/spec/fixtures/requests/ranking_sph04.dat +0 -0
- data/spec/fixtures/requests/ranking_wordcount.dat +0 -0
- data/spec/fixtures/requests/retries.dat +0 -0
- data/spec/fixtures/requests/retries_delay.dat +0 -0
- data/spec/fixtures/requests/select.dat +0 -0
- data/spec/fixtures/requests/sort_attr_asc.dat +0 -0
- data/spec/fixtures/requests/sort_attr_desc.dat +0 -0
- data/spec/fixtures/requests/sort_expr.dat +0 -0
- data/spec/fixtures/requests/sort_extended.dat +0 -0
- data/spec/fixtures/requests/sort_relevance.dat +0 -0
- data/spec/fixtures/requests/sort_time_segments.dat +0 -0
- data/spec/fixtures/requests/update_attributes.dat +0 -0
- data/spec/fixtures/requests/update_attributes_mva.dat +0 -0
- data/spec/fixtures/requests/weights.dat +0 -0
- data/spec/fixtures/responses/build_excerpts.dat +0 -0
- data/spec/fixtures/responses/build_keywords.dat +0 -0
- data/spec/fixtures/responses/flush_attributes.dat +0 -0
- data/spec/fixtures/responses/flush_attrs.dat +2 -0
- data/spec/fixtures/responses/open.dat +0 -0
- data/spec/fixtures/responses/open_twice.dat +0 -0
- data/spec/fixtures/responses/php/build_excerpts.php +8 -0
- data/spec/fixtures/responses/php/build_keywords.php +8 -0
- data/spec/fixtures/responses/php/flush_attributes.php +8 -0
- data/spec/fixtures/responses/php/open.php +8 -0
- data/spec/fixtures/responses/php/open_twice.php +9 -0
- data/spec/fixtures/responses/php/query.php +8 -0
- data/spec/fixtures/responses/php/query_error.php +8 -0
- data/spec/fixtures/responses/php/query_id64.php +8 -0
- data/spec/fixtures/responses/php/run_queries.php +10 -0
- data/spec/fixtures/responses/php/run_queries_error.php +9 -0
- data/spec/fixtures/responses/php/status.php +8 -0
- data/spec/fixtures/responses/php/update_attributes.php +8 -0
- data/spec/fixtures/responses/php/update_attributes_mva.php +8 -0
- data/spec/fixtures/responses/query.dat +0 -0
- data/spec/fixtures/responses/query_error.dat +0 -0
- data/spec/fixtures/responses/query_id64.dat +0 -0
- data/spec/fixtures/responses/run_queries.dat +0 -0
- data/spec/fixtures/responses/run_queries_error.dat +0 -0
- data/spec/fixtures/responses/status.dat +0 -0
- data/spec/fixtures/responses/update_attributes.dat +0 -0
- data/spec/fixtures/responses/update_attributes_mva.dat +0 -0
- data/spec/fixtures/sphinxapi.php +217 -45
- data/spec/spec_helper.rb +18 -3
- data/spec/sphinx/sphinx-id64.conf +6 -6
- data/spec/sphinx/sphinx.conf +6 -6
- data/sphinx.gemspec +19 -121
- metadata +268 -105
- data/README.rdoc +0 -243
- data/VERSION.yml +0 -5
- data/init.rb +0 -1
data/lib/sphinx/constants.rb
CHANGED
@@ -24,9 +24,6 @@ module Sphinx
|
|
24
24
|
# status command
|
25
25
|
# @private
|
26
26
|
SEARCHD_COMMAND_STATUS = 5
|
27
|
-
# query command
|
28
|
-
# @private
|
29
|
-
SEARCHD_COMMAND_QUERY = 6
|
30
27
|
# flushattrs command
|
31
28
|
# @private
|
32
29
|
SEARCHD_COMMAND_FLUSHATTRS = 7
|
@@ -37,13 +34,13 @@ module Sphinx
|
|
37
34
|
|
38
35
|
# search command version
|
39
36
|
# @private
|
40
|
-
VER_COMMAND_SEARCH =
|
37
|
+
VER_COMMAND_SEARCH = 0x11D
|
41
38
|
# excerpt command version
|
42
39
|
# @private
|
43
|
-
VER_COMMAND_EXCERPT =
|
40
|
+
VER_COMMAND_EXCERPT = 0x104
|
44
41
|
# update command version
|
45
42
|
# @private
|
46
|
-
VER_COMMAND_UPDATE =
|
43
|
+
VER_COMMAND_UPDATE = 0x103
|
47
44
|
# keywords command version
|
48
45
|
# @private
|
49
46
|
VER_COMMAND_KEYWORDS = 0x100
|
@@ -116,6 +113,8 @@ module Sphinx
|
|
116
113
|
SPH_RANK_FIELDMASK = 6
|
117
114
|
# codename SPH04, phrase proximity + bm25 + head/exact boost
|
118
115
|
SPH_RANK_SPH04 = 7
|
116
|
+
# lets you specify the ranking formula in run time
|
117
|
+
SPH_RANK_EXPR = 8
|
119
118
|
|
120
119
|
#=================================================================
|
121
120
|
# Known sort modes
|
@@ -164,8 +163,12 @@ module Sphinx
|
|
164
163
|
SPH_ATTR_BIGINT = 6
|
165
164
|
# string (binary; in-memory)
|
166
165
|
SPH_ATTR_STRING = 7
|
166
|
+
# ???
|
167
|
+
SPH_ATTR_FACTORS = 1001
|
167
168
|
# this attr has multiple values (0 or more)
|
168
|
-
SPH_ATTR_MULTI =
|
169
|
+
SPH_ATTR_MULTI = 0x40000001
|
170
|
+
# this attr has multiple 64-bit values (0 or more)
|
171
|
+
SPH_ATTR_MULTI64 = 0x40000002
|
169
172
|
|
170
173
|
#=================================================================
|
171
174
|
# Known grouping functions
|
@@ -183,7 +186,19 @@ module Sphinx
|
|
183
186
|
SPH_GROUPBY_ATTR = 4
|
184
187
|
# group by sequential attrs pair
|
185
188
|
SPH_GROUPBY_ATTRPAIR = 5
|
189
|
+
|
190
|
+
#=================================================================
|
191
|
+
# Known query flags
|
192
|
+
#=================================================================
|
193
|
+
|
194
|
+
QUERY_FLAGS = HashWithIndifferentAccess.new(
|
195
|
+
:reverse_scan => { :values => [ 0, 1 ], :index => 0 },
|
196
|
+
:sort_method => { :values => ['pq', 'kbuffer' ], :index => 1 },
|
197
|
+
:max_predicted_time => { :values => lambda { |x| x > 0 }, :index => 2 },
|
198
|
+
:boolean_simplify => { :values => [ false, true ], :index => 3 },
|
199
|
+
:idf => { :values => [ 'normalized', 'plain' ], :index => 4 }
|
200
|
+
)
|
186
201
|
end
|
187
202
|
|
188
203
|
include Constants
|
189
|
-
end
|
204
|
+
end
|
data/lib/sphinx/response.rb
CHANGED
@@ -10,17 +10,17 @@ module Sphinx
|
|
10
10
|
@position = 0
|
11
11
|
@size = response.length
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
# Gets current stream position.
|
15
15
|
def position
|
16
16
|
@position
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
# Gets response size.
|
20
20
|
def size
|
21
21
|
@size
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
# Returns <tt>true</tt> when response stream is out.
|
25
25
|
def eof?
|
26
26
|
@position >= @size
|
@@ -50,7 +50,7 @@ module Sphinx
|
|
50
50
|
@position += length
|
51
51
|
return values
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
# Get string from stream.
|
55
55
|
def get_string
|
56
56
|
length = get_int
|
@@ -59,7 +59,7 @@ module Sphinx
|
|
59
59
|
@position += length
|
60
60
|
return value
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
# Get float from stream.
|
64
64
|
def get_float
|
65
65
|
raise EOFError if @position + 4 > @size
|
@@ -68,4 +68,4 @@ module Sphinx
|
|
68
68
|
return ([uval].pack('L')).unpack('f*').first
|
69
69
|
end
|
70
70
|
end
|
71
|
-
end
|
71
|
+
end
|
data/lib/sphinx/timeout.rb
CHANGED
@@ -12,8 +12,7 @@ module Sphinx
|
|
12
12
|
require 'system_timer'
|
13
13
|
Timeout = ::SystemTimer
|
14
14
|
end
|
15
|
-
rescue LoadError
|
16
|
-
puts "[sphinx] Could not load SystemTimer gem, falling back to Ruby's slower/unsafe timeout library: #{e.message}"
|
15
|
+
rescue LoadError
|
17
16
|
require 'timeout'
|
18
17
|
Timeout = ::Timeout
|
19
18
|
end
|
@@ -6,30 +6,41 @@ describe Sphinx::Client, 'connected' do
|
|
6
6
|
before :each do
|
7
7
|
@sphinx = Sphinx::Client.new
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
|
+
def mock_sphinx_response(fixture)
|
11
|
+
response = sphinx_fixture(fixture, :response)
|
12
|
+
@sock = SphinxFakeSocket.new(response, 'rb')
|
13
|
+
servers = @sphinx.instance_variable_get(:@servers)
|
14
|
+
servers.first.stub(:get_socket => @sock)
|
15
|
+
end
|
16
|
+
|
10
17
|
context 'in Query method' do
|
11
18
|
it 'should parse response' do
|
19
|
+
mock_sphinx_response('query')
|
12
20
|
result = @sphinx.Query('wifi', 'test1')
|
13
21
|
validate_results_wifi(result)
|
14
22
|
end
|
15
23
|
|
16
24
|
it 'should process 64-bit keys' do
|
25
|
+
mock_sphinx_response('query_id64')
|
17
26
|
result = @sphinx.Query('wifi', 'test2')
|
18
|
-
result['total_found'].should
|
19
|
-
result['matches'].length.should
|
20
|
-
result['matches'][0]['id'].should
|
21
|
-
result['matches'][1]['id'].should
|
22
|
-
result['matches'][2]['id'].should
|
27
|
+
result['total_found'].should eq(3)
|
28
|
+
result['matches'].length.should eq(3)
|
29
|
+
result['matches'][0]['id'].should eq(4294967298)
|
30
|
+
result['matches'][1]['id'].should eq(4294967299)
|
31
|
+
result['matches'][2]['id'].should eq(4294967297)
|
23
32
|
end
|
24
33
|
|
25
34
|
it 'should process errors in Query method' do
|
35
|
+
mock_sphinx_response('query_error')
|
26
36
|
@sphinx.Query('wifi', 'fakeindex').should be_false
|
27
|
-
@sphinx.GetLastError.
|
37
|
+
@sphinx.GetLastError.should =~ /unknown local index/
|
28
38
|
end
|
29
39
|
end
|
30
|
-
|
40
|
+
|
31
41
|
context 'in RunQueries method' do
|
32
42
|
it 'should parse batch-query responce' do
|
43
|
+
mock_sphinx_response('run_queries')
|
33
44
|
@sphinx.AddQuery('wifi', 'test1')
|
34
45
|
@sphinx.AddQuery('gprs', 'test1')
|
35
46
|
results = @sphinx.RunQueries
|
@@ -39,6 +50,7 @@ describe Sphinx::Client, 'connected' do
|
|
39
50
|
end
|
40
51
|
|
41
52
|
it 'should process errors in RunQueries method' do
|
53
|
+
mock_sphinx_response('run_queries_error')
|
42
54
|
@sphinx.AddQuery('wifi', 'fakeindex')
|
43
55
|
r = @sphinx.RunQueries
|
44
56
|
r[0]['error'].should_not be_empty
|
@@ -47,132 +59,133 @@ describe Sphinx::Client, 'connected' do
|
|
47
59
|
|
48
60
|
context 'in BuildExcerpts method' do
|
49
61
|
it 'should parse response' do
|
62
|
+
mock_sphinx_response('build_excerpts')
|
50
63
|
result = @sphinx.BuildExcerpts(['what the world', 'London is the capital of Great Britain'], 'test1', 'the')
|
51
|
-
result.should
|
64
|
+
result.should eq(['what <b>the</b> world', 'London is <b>the</b> capital of Great Britain'])
|
52
65
|
end
|
53
66
|
end
|
54
67
|
|
55
68
|
context 'in BuildKeywords method' do
|
56
69
|
it 'should parse response' do
|
70
|
+
mock_sphinx_response('build_keywords')
|
57
71
|
result = @sphinx.BuildKeywords('wifi gprs', 'test1', true)
|
58
|
-
result.should
|
72
|
+
result.should eq([
|
59
73
|
{ 'normalized' => 'wifi', 'tokenized' => 'wifi', 'hits' => 6, 'docs' => 3 },
|
60
74
|
{ 'normalized' => 'gprs', 'tokenized' => 'gprs', 'hits' => 1, 'docs' => 1 }
|
61
|
-
]
|
75
|
+
])
|
62
76
|
end
|
63
77
|
end
|
64
78
|
|
65
79
|
context 'in UpdateAttributes method' do
|
66
80
|
it 'should parse response' do
|
67
|
-
|
68
|
-
|
69
|
-
result['matches'][0]['attrs']['group_id'].should == 1
|
70
|
-
@sphinx.UpdateAttributes('test1', ['group_id'], { 2 => [2] }).should == 1
|
71
|
-
result = @sphinx.Query('wifi', 'test1')
|
72
|
-
result['matches'][0]['attrs']['group_id'].should == 2
|
81
|
+
mock_sphinx_response('update_attributes')
|
82
|
+
@sphinx.UpdateAttributes('test1', ['group_id'], { 2 => [1] }).should eq(1)
|
73
83
|
end
|
74
84
|
|
75
85
|
it 'should parse response with MVA' do
|
76
|
-
|
77
|
-
|
78
|
-
result['matches'][0]['attrs']['tags'].should == [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
79
|
-
@sphinx.UpdateAttributes('test1', ['tags'], { 2 => [[5, 6, 7, 8]] }, true).should == 1
|
80
|
-
result = @sphinx.Query('wifi', 'test1')
|
81
|
-
result['matches'][0]['attrs']['tags'].should == [5, 6, 7, 8]
|
86
|
+
mock_sphinx_response('update_attributes_mva')
|
87
|
+
@sphinx.UpdateAttributes('test1', ['tags'], { 2 => [[1, 2, 3, 4, 5, 6, 7, 8, 9]] }, true).should eq(1)
|
82
88
|
end
|
83
89
|
end
|
84
90
|
|
85
91
|
context 'in Open method' do
|
86
92
|
it 'should open socket' do
|
93
|
+
mock_sphinx_response('open')
|
87
94
|
@sphinx.Open.should be_true
|
88
95
|
socket = @sphinx.servers.first.instance_variable_get(:@socket)
|
89
|
-
socket.
|
90
|
-
socket.should be_kind_of(Sphinx::BufferedIO)
|
96
|
+
socket.should eq(@sock)
|
91
97
|
socket.close
|
92
98
|
end
|
93
|
-
|
99
|
+
|
94
100
|
it 'should produce an error when opened twice' do
|
101
|
+
mock_sphinx_response('open')
|
102
|
+
sock = @sock
|
95
103
|
@sphinx.Open.should be_true
|
104
|
+
mock_sphinx_response('open_twice')
|
96
105
|
@sphinx.Open.should be_false
|
97
|
-
@sphinx.GetLastError.should
|
98
|
-
|
106
|
+
@sphinx.GetLastError.should eq('already connected')
|
107
|
+
|
99
108
|
socket = @sphinx.servers.first.instance_variable_get(:@socket)
|
100
|
-
socket.should
|
109
|
+
socket.should eq(sock)
|
101
110
|
socket.close
|
102
111
|
end
|
103
112
|
end
|
104
|
-
|
113
|
+
|
105
114
|
context 'in Close method' do
|
106
115
|
it 'should open socket' do
|
116
|
+
mock_sphinx_response('open')
|
107
117
|
@sphinx.Open.should be_true
|
108
118
|
@sphinx.Close.should be_true
|
109
119
|
@sphinx.servers.first.instance_variable_get(:@socket).should be_nil
|
110
120
|
end
|
111
|
-
|
121
|
+
|
112
122
|
it 'should produce socket is closed' do
|
113
123
|
@sphinx.Close.should be_false
|
114
|
-
@sphinx.GetLastError.should
|
124
|
+
@sphinx.GetLastError.should eq('not connected')
|
115
125
|
@sphinx.servers.first.instance_variable_get(:@socket).should be_nil
|
116
|
-
|
126
|
+
|
127
|
+
mock_sphinx_response('open')
|
117
128
|
@sphinx.Open.should be_true
|
118
129
|
@sphinx.Close.should be_true
|
119
130
|
@sphinx.Close.should be_false
|
120
|
-
@sphinx.GetLastError.should
|
131
|
+
@sphinx.GetLastError.should eq('not connected')
|
121
132
|
@sphinx.servers.first.instance_variable_get(:@socket).should be_nil
|
122
133
|
end
|
123
134
|
end
|
124
135
|
|
125
136
|
context 'in Status method' do
|
126
137
|
it 'should parse response' do
|
138
|
+
mock_sphinx_response('status')
|
127
139
|
response = @sphinx.Status
|
128
140
|
response.should be_an(Array)
|
129
141
|
response.size.should be > 10
|
130
142
|
end
|
131
143
|
end
|
132
144
|
|
133
|
-
context 'in
|
145
|
+
context 'in FlushAttributes method' do
|
134
146
|
it 'should not raise an error' do
|
147
|
+
mock_sphinx_response('flush_attributes')
|
135
148
|
expect {
|
136
|
-
@sphinx.
|
149
|
+
@sphinx.FlushAttributes
|
137
150
|
}.to_not raise_error
|
138
151
|
end
|
139
152
|
end
|
140
153
|
|
141
154
|
def validate_results_wifi(result)
|
142
|
-
result['total_found'].should
|
143
|
-
result['matches'].length.should
|
155
|
+
result['total_found'].should eq(3)
|
156
|
+
result['matches'].length.should eq(3)
|
144
157
|
result['time'].should_not be_nil
|
145
|
-
result['attrs'].should
|
158
|
+
result['attrs'].should eq({
|
146
159
|
'group_id' => Sphinx::SPH_ATTR_INTEGER,
|
147
160
|
'created_at' => Sphinx::SPH_ATTR_TIMESTAMP,
|
148
161
|
'rating' => Sphinx::SPH_ATTR_FLOAT,
|
149
162
|
'tags' => Sphinx::SPH_ATTR_MULTI | Sphinx::SPH_ATTR_INTEGER
|
150
|
-
}
|
151
|
-
result['fields'].should
|
152
|
-
result['total'].should
|
163
|
+
})
|
164
|
+
result['fields'].should eq([ 'name', 'description' ])
|
165
|
+
result['total'].should eq(3)
|
153
166
|
result['matches'].should be_an_instance_of(Array)
|
154
167
|
|
155
|
-
result['matches'][0]['id'].should
|
156
|
-
result['matches'][0]['weight'].should
|
157
|
-
result['matches'][0]['attrs']['group_id'].should
|
158
|
-
result['matches'][0]['attrs']['created_at'].should
|
159
|
-
result['matches'][0]['attrs']['tags'].should
|
160
|
-
('%0.2f' % result['matches'][0]['attrs']['rating']).should
|
161
|
-
|
162
|
-
result['matches'][1]['id'].should
|
163
|
-
result['matches'][1]['weight'].should
|
164
|
-
result['matches'][1]['attrs']['group_id'].should
|
165
|
-
result['matches'][1]['attrs']['created_at'].should
|
166
|
-
result['matches'][1]['attrs']['tags'].should
|
167
|
-
('%0.2f' % result['matches'][1]['attrs']['rating']).should
|
168
|
-
|
169
|
-
result['matches'][2]['id'].should
|
170
|
-
result['matches'][2]['weight'].should
|
171
|
-
result['matches'][2]['attrs']['group_id'].should
|
172
|
-
result['matches'][2]['attrs']['created_at'].should
|
173
|
-
result['matches'][2]['attrs']['tags'].should
|
174
|
-
('%0.2f' % result['matches'][2]['attrs']['rating']).should
|
175
|
-
|
176
|
-
result['words'].should
|
168
|
+
result['matches'][0]['id'].should eq(2)
|
169
|
+
result['matches'][0]['weight'].should eq(2)
|
170
|
+
result['matches'][0]['attrs']['group_id'].should eq(2)
|
171
|
+
result['matches'][0]['attrs']['created_at'].should eq(1175683755)
|
172
|
+
result['matches'][0]['attrs']['tags'].should eq([5, 6, 7, 8])
|
173
|
+
('%0.2f' % result['matches'][0]['attrs']['rating']).should eq('54.85')
|
174
|
+
|
175
|
+
result['matches'][1]['id'].should eq(3)
|
176
|
+
result['matches'][1]['weight'].should eq(2)
|
177
|
+
result['matches'][1]['attrs']['group_id'].should eq(1)
|
178
|
+
result['matches'][1]['attrs']['created_at'].should eq(1175683847)
|
179
|
+
result['matches'][1]['attrs']['tags'].should eq([1, 7, 9, 10])
|
180
|
+
('%0.2f' % result['matches'][1]['attrs']['rating']).should eq('16.25')
|
181
|
+
|
182
|
+
result['matches'][2]['id'].should eq(1)
|
183
|
+
result['matches'][2]['weight'].should eq(1)
|
184
|
+
result['matches'][2]['attrs']['group_id'].should eq(1)
|
185
|
+
result['matches'][2]['attrs']['created_at'].should eq(1175683690)
|
186
|
+
result['matches'][2]['attrs']['tags'].should eq([1, 2, 3, 4])
|
187
|
+
('%0.2f' % result['matches'][2]['attrs']['rating']).should eq('13.32')
|
188
|
+
|
189
|
+
result['words'].should eq({ 'wifi' => { 'hits' => 6, 'docs' => 3 } })
|
177
190
|
end
|
178
191
|
end
|
data/spec/client_spec.rb
CHANGED
@@ -20,7 +20,7 @@ describe Sphinx::Client, 'disconnected' do
|
|
20
20
|
2.times do
|
21
21
|
cnt = 0
|
22
22
|
expect {
|
23
|
-
@sphinx.send(:with_server) { |server| cnt += 1; server.should
|
23
|
+
@sphinx.send(:with_server) { |server| cnt += 1; server.should eq(@sphinx.servers[0]); raise Sphinx::SphinxConnectError }
|
24
24
|
}.to raise_error(Sphinx::SphinxConnectError)
|
25
25
|
cnt.should == 1
|
26
26
|
end
|
@@ -29,24 +29,24 @@ describe Sphinx::Client, 'disconnected' do
|
|
29
29
|
it 'should select server based on index' do
|
30
30
|
@sphinx.SetServers(@servers)
|
31
31
|
cnt = 0
|
32
|
-
@sphinx.send(:with_server, 0) { |server| cnt += 1; server.should
|
33
|
-
cnt.should
|
32
|
+
@sphinx.send(:with_server, 0) { |server| cnt += 1; server.should eq(@sphinx.servers[0]) }
|
33
|
+
cnt.should eq(1)
|
34
34
|
cnt = 0
|
35
|
-
@sphinx.send(:with_server, 1) { |server| cnt += 1; server.should
|
36
|
-
cnt.should
|
35
|
+
@sphinx.send(:with_server, 1) { |server| cnt += 1; server.should eq(@sphinx.servers[1]) }
|
36
|
+
cnt.should eq(1)
|
37
37
|
cnt = 0
|
38
|
-
@sphinx.send(:with_server, 2) { |server| cnt += 1; server.should
|
39
|
-
cnt.should
|
38
|
+
@sphinx.send(:with_server, 2) { |server| cnt += 1; server.should eq(@sphinx.servers[0]) }
|
39
|
+
cnt.should eq(1)
|
40
40
|
end
|
41
41
|
|
42
42
|
it 'should select given server' do
|
43
43
|
@sphinx.SetServers(@servers)
|
44
44
|
cnt = 0
|
45
45
|
@sphinx.send(:with_server, @sphinx.servers[0]) { |server| cnt += 1; server.should == @sphinx.servers[0] }
|
46
|
-
cnt.should
|
46
|
+
cnt.should eq(1)
|
47
47
|
cnt = 0
|
48
48
|
@sphinx.send(:with_server, @sphinx.servers[1]) { |server| cnt += 1; server.should == @sphinx.servers[1] }
|
49
|
-
cnt.should
|
49
|
+
cnt.should eq(1)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
@@ -58,36 +58,36 @@ describe Sphinx::Client, 'disconnected' do
|
|
58
58
|
it 'should raise an exception on error' do
|
59
59
|
cnt = 0
|
60
60
|
expect {
|
61
|
-
@sphinx.send(:with_server) { |server| cnt += 1; server.should
|
61
|
+
@sphinx.send(:with_server) { |server| cnt += 1; server.should eq(@sphinx.servers[0]); raise Sphinx::SphinxConnectError }
|
62
62
|
}.to raise_error(Sphinx::SphinxConnectError)
|
63
|
-
cnt.should
|
63
|
+
cnt.should eq(3)
|
64
64
|
end
|
65
65
|
|
66
66
|
it 'should round-robin servers and raise an exception on error' do
|
67
67
|
@sphinx.SetServers(@servers)
|
68
68
|
cnt = 0
|
69
69
|
expect {
|
70
|
-
@sphinx.send(:with_server) { |server| cnt += 1; server.should
|
70
|
+
@sphinx.send(:with_server) { |server| cnt += 1; server.should eq(@sphinx.servers[(cnt - 1) % 2]); raise Sphinx::SphinxConnectError }
|
71
71
|
}.to raise_error(Sphinx::SphinxConnectError)
|
72
|
-
cnt.should
|
72
|
+
cnt.should eq(3)
|
73
73
|
end
|
74
74
|
|
75
75
|
it 'should round-robin servers with respect to passed index and raise an exception on error' do
|
76
76
|
@sphinx.SetServers(@servers)
|
77
77
|
cnt = 0
|
78
78
|
expect {
|
79
|
-
@sphinx.send(:with_server, 1) { |server| cnt += 1; server.should
|
79
|
+
@sphinx.send(:with_server, 1) { |server| cnt += 1; server.should eq(@sphinx.servers[cnt % 2]); raise Sphinx::SphinxConnectError }
|
80
80
|
}.to raise_error(Sphinx::SphinxConnectError)
|
81
|
-
cnt.should
|
81
|
+
cnt.should eq(3)
|
82
82
|
end
|
83
83
|
|
84
84
|
it 'should round-robin with respect to attempts number passed' do
|
85
85
|
@sphinx.SetServers(@servers)
|
86
86
|
cnt = 0
|
87
87
|
expect {
|
88
|
-
@sphinx.send(:with_server, 0, 5) { |server| cnt += 1; server.should
|
88
|
+
@sphinx.send(:with_server, 0, 5) { |server| cnt += 1; server.should eq(@sphinx.servers[(cnt - 1) % 2]); raise Sphinx::SphinxConnectError }
|
89
89
|
}.to raise_error(Sphinx::SphinxConnectError)
|
90
|
-
cnt.should
|
90
|
+
cnt.should eq(5)
|
91
91
|
end
|
92
92
|
end
|
93
93
|
end
|
@@ -110,7 +110,7 @@ describe Sphinx::Client, 'disconnected' do
|
|
110
110
|
@socket.should_receive(:read).with(4).and_return([1].pack('N'))
|
111
111
|
cnt = 0
|
112
112
|
@sphinx.send(:with_socket, @server) { |socket| cnt += 1; socket.should == @socket }
|
113
|
-
cnt.should
|
113
|
+
cnt.should eq(1)
|
114
114
|
end
|
115
115
|
|
116
116
|
it 'should raise exception when searchd protocol is not 1+' do
|
@@ -120,7 +120,7 @@ describe Sphinx::Client, 'disconnected' do
|
|
120
120
|
expect {
|
121
121
|
@sphinx.send(:with_socket, @server) { cnt += 1; }
|
122
122
|
}.to raise_error(Sphinx::SphinxConnectError, 'expected searchd protocol version 1+, got version \'0\'')
|
123
|
-
cnt.should
|
123
|
+
cnt.should eq(0)
|
124
124
|
end
|
125
125
|
|
126
126
|
it 'should handle request timeouts' do
|
@@ -130,10 +130,10 @@ describe Sphinx::Client, 'disconnected' do
|
|
130
130
|
cnt = 0
|
131
131
|
expect {
|
132
132
|
@sphinx.send(:with_socket, @server) { cnt += 1; sleep 2 }
|
133
|
-
}.to raise_error(Sphinx::SphinxResponseError, 'failed to read searchd response (msg=
|
134
|
-
cnt.should
|
133
|
+
}.to raise_error(Sphinx::SphinxResponseError, 'failed to read searchd response (msg=execution expired)')
|
134
|
+
cnt.should eq(1)
|
135
135
|
|
136
|
-
@sphinx.GetLastError.should
|
136
|
+
@sphinx.GetLastError.should eq('failed to read searchd response (msg=execution expired)')
|
137
137
|
@sphinx.IsConnectError.should be_false
|
138
138
|
end
|
139
139
|
|
@@ -144,9 +144,9 @@ describe Sphinx::Client, 'disconnected' do
|
|
144
144
|
expect {
|
145
145
|
@sphinx.send(:with_socket, @server) { cnt += 1; raise Sphinx::SphinxInternalError, 'hello' }
|
146
146
|
}.to raise_error(Sphinx::SphinxInternalError, 'hello')
|
147
|
-
cnt.should
|
147
|
+
cnt.should eq(1)
|
148
148
|
|
149
|
-
@sphinx.GetLastError.should
|
149
|
+
@sphinx.GetLastError.should eq('hello')
|
150
150
|
@sphinx.IsConnectError.should be_false
|
151
151
|
end
|
152
152
|
end
|
@@ -167,9 +167,9 @@ describe Sphinx::Client, 'disconnected' do
|
|
167
167
|
expect {
|
168
168
|
@sphinx.send(:with_socket, @server) { cnt += 1; raise Sphinx::SphinxInternalError, 'hello' }
|
169
169
|
}.to raise_error(Sphinx::SphinxInternalError, 'hello')
|
170
|
-
cnt.should
|
170
|
+
cnt.should eq(3)
|
171
171
|
|
172
|
-
@sphinx.GetLastError.should
|
172
|
+
@sphinx.GetLastError.should eq('hello')
|
173
173
|
@sphinx.IsConnectError.should be_false
|
174
174
|
end
|
175
175
|
end
|
@@ -206,7 +206,7 @@ describe Sphinx::Client, 'disconnected' do
|
|
206
206
|
@socket.should_receive(:read).with(8).and_return([Sphinx::SEARCHD_WARNING, 1, 14].pack('n2N'))
|
207
207
|
@socket.should_receive(:read).with(14).and_return([5].pack('N') + 'helloworld')
|
208
208
|
@sphinx.send(:parse_response, @socket, 1).should == 'world'
|
209
|
-
@sphinx.GetLastWarning.should
|
209
|
+
@sphinx.GetLastWarning.should eq('hello')
|
210
210
|
end
|
211
211
|
|
212
212
|
it 'should raise exception when SEARCHD_ERROR received' do
|
@@ -313,24 +313,26 @@ describe Sphinx::Client, 'disconnected' do
|
|
313
313
|
|
314
314
|
describe 'with rank' do
|
315
315
|
[ :proximity_bm25, :bm25, :none, :wordcount, :proximity, :matchany, :fieldmask, :sph04 ].each do |rank|
|
316
|
+
expr = rank == :expr ? '' : 'sum(lcs*user_weight)*1000+bm25'
|
317
|
+
|
316
318
|
it "should generate valid request for SPH_RANK_#{rank.to_s.upcase}" do
|
317
319
|
expected = sphinx_fixture("ranking_#{rank}")
|
318
320
|
@sock.should_receive(:write).with(expected)
|
319
|
-
@sphinx.SetRankingMode(Sphinx::Client.const_get("SPH_RANK_#{rank.to_s.upcase}"))
|
321
|
+
@sphinx.SetRankingMode(Sphinx::Client.const_get("SPH_RANK_#{rank.to_s.upcase}"), expr)
|
320
322
|
sphinx_safe_call { @sphinx.Query('query') }
|
321
323
|
end
|
322
324
|
|
323
325
|
it "should generate valid request for \"#{rank}\"" do
|
324
326
|
expected = sphinx_fixture("ranking_#{rank}")
|
325
327
|
@sock.should_receive(:write).with(expected)
|
326
|
-
@sphinx.SetRankingMode(rank.to_s)
|
328
|
+
@sphinx.SetRankingMode(rank.to_s, expr)
|
327
329
|
sphinx_safe_call { @sphinx.Query('query') }
|
328
330
|
end
|
329
331
|
|
330
332
|
it "should generate valid request for :#{rank}" do
|
331
333
|
expected = sphinx_fixture("ranking_#{rank}")
|
332
334
|
@sock.should_receive(:write).with(expected)
|
333
|
-
@sphinx.SetRankingMode(rank)
|
335
|
+
@sphinx.SetRankingMode(rank, expr)
|
334
336
|
sphinx_safe_call { @sphinx.Query('query') }
|
335
337
|
end
|
336
338
|
end
|
@@ -535,7 +537,7 @@ describe Sphinx::Client, 'disconnected' do
|
|
535
537
|
end
|
536
538
|
|
537
539
|
it 'should generate valid request for SetOverride' do
|
538
|
-
expected = sphinx_fixture('
|
540
|
+
expected = sphinx_fixture('override')
|
539
541
|
@sock.should_receive(:write).with(expected)
|
540
542
|
@sphinx.SetOverride('attr1', Sphinx::SPH_ATTR_INTEGER, { 10 => 20 })
|
541
543
|
@sphinx.SetOverride('attr2', Sphinx::SPH_ATTR_FLOAT, { 11 => 30.3 })
|
@@ -549,6 +551,41 @@ describe Sphinx::Client, 'disconnected' do
|
|
549
551
|
@sphinx.SetSelect('attr1, attr2')
|
550
552
|
sphinx_safe_call { @sphinx.Query('query') }
|
551
553
|
end
|
554
|
+
|
555
|
+
it 'should generate valid request for SetOuterSelect' do
|
556
|
+
expected = sphinx_fixture('outer_select')
|
557
|
+
@sock.should_receive(:write).with(expected)
|
558
|
+
@sphinx.SetOuterSelect('attr', 10, 100)
|
559
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
560
|
+
end
|
561
|
+
|
562
|
+
it 'should generate valid request for SetQueryFlag' do
|
563
|
+
expected = sphinx_fixture('query_flag')
|
564
|
+
@sock.should_receive(:write).with(expected)
|
565
|
+
@sphinx.SetQueryFlag('reverse_scan', 1)
|
566
|
+
@sphinx.SetQueryFlag('sort_method', 'kbuffer')
|
567
|
+
@sphinx.SetQueryFlag('max_predicted_time', 15)
|
568
|
+
@sphinx.SetQueryFlag('boolean_simplify', true)
|
569
|
+
@sphinx.SetQueryFlag('idf', 'plain')
|
570
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
571
|
+
end
|
572
|
+
|
573
|
+
it 'should generate valid request for SetQueryFlag after flag reset' do
|
574
|
+
expected = sphinx_fixture('query_flag_after_reset')
|
575
|
+
@sock.should_receive(:write).with(expected)
|
576
|
+
@sphinx.SetQueryFlag('reverse_scan', 1)
|
577
|
+
@sphinx.SetQueryFlag('sort_method', 'kbuffer')
|
578
|
+
@sphinx.SetQueryFlag('max_predicted_time', 15)
|
579
|
+
@sphinx.SetQueryFlag('boolean_simplify', true)
|
580
|
+
@sphinx.SetQueryFlag('idf', 'plain')
|
581
|
+
|
582
|
+
@sphinx.SetQueryFlag('reverse_scan', 0)
|
583
|
+
@sphinx.SetQueryFlag('sort_method', 'pq')
|
584
|
+
@sphinx.SetQueryFlag('max_predicted_time', 0)
|
585
|
+
@sphinx.SetQueryFlag('boolean_simplify', false)
|
586
|
+
@sphinx.SetQueryFlag('idf', 'normalized')
|
587
|
+
sphinx_safe_call { @sphinx.Query('query') }
|
588
|
+
end
|
552
589
|
end
|
553
590
|
|
554
591
|
context 'in RunQueries method' do
|