sphinx 0.9.9.2117
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 +4 -0
- data/README.rdoc +243 -0
- data/Rakefile +45 -0
- data/VERSION.yml +5 -0
- data/init.rb +1 -0
- data/lib/sphinx/buffered_io.rb +26 -0
- data/lib/sphinx/client.rb +2426 -0
- data/lib/sphinx/constants.rb +179 -0
- data/lib/sphinx/indifferent_access.rb +152 -0
- data/lib/sphinx/request.rb +121 -0
- data/lib/sphinx/response.rb +71 -0
- data/lib/sphinx/server.rb +170 -0
- data/lib/sphinx/timeout.rb +31 -0
- data/lib/sphinx.rb +51 -0
- data/spec/client_response_spec.rb +170 -0
- data/spec/client_spec.rb +669 -0
- data/spec/client_validations_spec.rb +859 -0
- data/spec/fixtures/default_search.php +8 -0
- data/spec/fixtures/default_search_index.php +8 -0
- data/spec/fixtures/excerpt_custom.php +11 -0
- data/spec/fixtures/excerpt_default.php +8 -0
- data/spec/fixtures/excerpt_flags.php +12 -0
- data/spec/fixtures/field_weights.php +9 -0
- data/spec/fixtures/filter.php +9 -0
- data/spec/fixtures/filter_exclude.php +9 -0
- data/spec/fixtures/filter_float_range.php +9 -0
- data/spec/fixtures/filter_float_range_exclude.php +9 -0
- data/spec/fixtures/filter_range.php +9 -0
- data/spec/fixtures/filter_range_exclude.php +9 -0
- data/spec/fixtures/filter_range_int64.php +10 -0
- data/spec/fixtures/filter_ranges.php +10 -0
- data/spec/fixtures/filters.php +10 -0
- data/spec/fixtures/filters_different.php +13 -0
- data/spec/fixtures/geo_anchor.php +9 -0
- data/spec/fixtures/group_by_attr.php +9 -0
- data/spec/fixtures/group_by_attrpair.php +9 -0
- data/spec/fixtures/group_by_day.php +9 -0
- data/spec/fixtures/group_by_day_sort.php +9 -0
- data/spec/fixtures/group_by_month.php +9 -0
- data/spec/fixtures/group_by_week.php +9 -0
- data/spec/fixtures/group_by_year.php +9 -0
- data/spec/fixtures/group_distinct.php +10 -0
- data/spec/fixtures/id_range.php +9 -0
- data/spec/fixtures/id_range64.php +9 -0
- data/spec/fixtures/index_weights.php +9 -0
- data/spec/fixtures/keywords.php +8 -0
- data/spec/fixtures/limits.php +9 -0
- data/spec/fixtures/limits_cutoff.php +9 -0
- data/spec/fixtures/limits_max.php +9 -0
- data/spec/fixtures/limits_max_cutoff.php +9 -0
- data/spec/fixtures/match_all.php +9 -0
- data/spec/fixtures/match_any.php +9 -0
- data/spec/fixtures/match_boolean.php +9 -0
- data/spec/fixtures/match_extended.php +9 -0
- data/spec/fixtures/match_extended2.php +9 -0
- data/spec/fixtures/match_fullscan.php +9 -0
- data/spec/fixtures/match_phrase.php +9 -0
- data/spec/fixtures/max_query_time.php +9 -0
- data/spec/fixtures/miltiple_queries.php +12 -0
- data/spec/fixtures/ranking_bm25.php +9 -0
- data/spec/fixtures/ranking_fieldmask.php +9 -0
- data/spec/fixtures/ranking_matchany.php +9 -0
- data/spec/fixtures/ranking_none.php +9 -0
- data/spec/fixtures/ranking_proximity.php +9 -0
- data/spec/fixtures/ranking_proximity_bm25.php +9 -0
- data/spec/fixtures/ranking_wordcount.php +9 -0
- data/spec/fixtures/retries.php +9 -0
- data/spec/fixtures/retries_delay.php +9 -0
- data/spec/fixtures/select.php +9 -0
- data/spec/fixtures/set_override.php +11 -0
- data/spec/fixtures/sort_attr_asc.php +9 -0
- data/spec/fixtures/sort_attr_desc.php +9 -0
- data/spec/fixtures/sort_expr.php +9 -0
- data/spec/fixtures/sort_extended.php +9 -0
- data/spec/fixtures/sort_relevance.php +9 -0
- data/spec/fixtures/sort_time_segments.php +9 -0
- data/spec/fixtures/sphinxapi.php +1633 -0
- data/spec/fixtures/update_attributes.php +8 -0
- data/spec/fixtures/update_attributes_mva.php +8 -0
- data/spec/fixtures/weights.php +9 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/sphinx/sphinx-id64.conf +67 -0
- data/spec/sphinx/sphinx.conf +67 -0
- data/spec/sphinx/sphinx_test.sql +88 -0
- data/sphinx.gemspec +127 -0
- metadata +142 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
module Sphinx
|
2
|
+
begin
|
3
|
+
# Try to use the SystemTimer gem instead of Ruby's timeout library
|
4
|
+
# when running on something that looks like Ruby 1.8.x. See:
|
5
|
+
# http://ph7spot.com/articles/system_timer
|
6
|
+
# We don't want to bother trying to load SystemTimer on jruby and
|
7
|
+
# ruby 1.9+
|
8
|
+
if defined?(JRUBY_VERSION) || (RUBY_VERSION >= '1.9')
|
9
|
+
require 'timeout'
|
10
|
+
Timeout = ::Timeout
|
11
|
+
else
|
12
|
+
require 'system_timer'
|
13
|
+
Timeout = ::SystemTimer
|
14
|
+
end
|
15
|
+
rescue LoadError => e
|
16
|
+
puts "[sphinx] Could not load SystemTimer gem, falling back to Ruby's slower/unsafe timeout library: #{e.message}"
|
17
|
+
require 'timeout'
|
18
|
+
Timeout = ::Timeout
|
19
|
+
end
|
20
|
+
|
21
|
+
# Executes specified block respecting timeout passed.
|
22
|
+
#
|
23
|
+
# @private
|
24
|
+
def self.safe_execute(timeout = 5, &block)
|
25
|
+
if timeout > 0
|
26
|
+
Sphinx::Timeout.timeout(timeout, &block)
|
27
|
+
else
|
28
|
+
yield
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/sphinx.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Sphinx Client API
|
2
|
+
#
|
3
|
+
# Author:: Dmytro Shteflyuk <mailto:kpumuk@kpumuk.info>.
|
4
|
+
# Copyright:: Copyright (c) 2006 — 2009 Dmytro Shteflyuk
|
5
|
+
# License:: Distributes under the same terms as Ruby
|
6
|
+
# Version:: 0.9.9-r2117
|
7
|
+
# Website:: http://kpumuk.info/projects/ror-plugins/sphinx
|
8
|
+
# Sources:: http://github.com/kpumuk/sphinx
|
9
|
+
#
|
10
|
+
# This library is distributed under the terms of the Ruby license.
|
11
|
+
# You can freely distribute/modify this library.
|
12
|
+
#
|
13
|
+
module Sphinx
|
14
|
+
VERSION = begin
|
15
|
+
require 'yaml'
|
16
|
+
config = YAML.load(File.read(File.dirname(__FILE__) + '/../VERSION.yml'))
|
17
|
+
"#{config[:major]}.#{config[:minor]}.#{config[:patch]}.#{config[:build]}"
|
18
|
+
end
|
19
|
+
|
20
|
+
# Base class for all Sphinx errors
|
21
|
+
class SphinxError < StandardError; end
|
22
|
+
|
23
|
+
# Connect error occurred on the API side.
|
24
|
+
class SphinxConnectError < SphinxError; end
|
25
|
+
|
26
|
+
# Request error occurred on the API side.
|
27
|
+
class SphinxResponseError < SphinxError; end
|
28
|
+
|
29
|
+
# Internal error occurred inside searchd.
|
30
|
+
class SphinxInternalError < SphinxError; end
|
31
|
+
|
32
|
+
# Temporary error occurred inside searchd.
|
33
|
+
class SphinxTemporaryError < SphinxError; end
|
34
|
+
|
35
|
+
# Unknown error occurred inside searchd.
|
36
|
+
class SphinxUnknownError < SphinxError; end
|
37
|
+
end
|
38
|
+
|
39
|
+
require 'net/protocol'
|
40
|
+
require 'socket'
|
41
|
+
require 'zlib'
|
42
|
+
|
43
|
+
path = File.dirname(__FILE__)
|
44
|
+
require "#{path}/sphinx/constants"
|
45
|
+
require "#{path}/sphinx/indifferent_access"
|
46
|
+
require "#{path}/sphinx/request"
|
47
|
+
require "#{path}/sphinx/response"
|
48
|
+
require "#{path}/sphinx/timeout"
|
49
|
+
require "#{path}/sphinx/buffered_io"
|
50
|
+
require "#{path}/sphinx/server"
|
51
|
+
require "#{path}/sphinx/client"
|
@@ -0,0 +1,170 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
# To execute these tests you need to execute sphinx_test.sql and configure sphinx using sphinx.conf
|
4
|
+
# (both files are placed under sphinx directory)
|
5
|
+
describe Sphinx::Client, 'connected' do
|
6
|
+
before :each do
|
7
|
+
@sphinx = Sphinx::Client.new
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'in Query method' do
|
11
|
+
it 'should parse response' do
|
12
|
+
result = @sphinx.Query('wifi', 'test1')
|
13
|
+
validate_results_wifi(result)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should process 64-bit keys' do
|
17
|
+
result = @sphinx.Query('wifi', 'test2')
|
18
|
+
result['total_found'].should == 3
|
19
|
+
result['matches'].length.should == 3
|
20
|
+
result['matches'][0]['id'].should == 4294967298
|
21
|
+
result['matches'][1]['id'].should == 4294967299
|
22
|
+
result['matches'][2]['id'].should == 4294967297
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should process errors in Query method' do
|
26
|
+
@sphinx.Query('wifi', 'fakeindex').should be_false
|
27
|
+
@sphinx.GetLastError.should_not be_empty
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'in RunQueries method' do
|
32
|
+
it 'should parse batch-query responce' do
|
33
|
+
@sphinx.AddQuery('wifi', 'test1')
|
34
|
+
@sphinx.AddQuery('gprs', 'test1')
|
35
|
+
results = @sphinx.RunQueries
|
36
|
+
results.should be_an_instance_of(Array)
|
37
|
+
results.should have(2).items
|
38
|
+
validate_results_wifi(results[0])
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should process errors in RunQueries method' do
|
42
|
+
@sphinx.AddQuery('wifi', 'fakeindex')
|
43
|
+
r = @sphinx.RunQueries
|
44
|
+
r[0]['error'].should_not be_empty
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'in BuildExcerpts method' do
|
49
|
+
it 'should parse response' do
|
50
|
+
result = @sphinx.BuildExcerpts(['what the world', 'London is the capital of Great Britain'], 'test1', 'the')
|
51
|
+
result.should == ['what <b>the</b> world', 'London is <b>the</b> capital of Great Britain']
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'in BuildKeywords method' do
|
56
|
+
it 'should parse response' do
|
57
|
+
result = @sphinx.BuildKeywords('wifi gprs', 'test1', true)
|
58
|
+
result.should == [
|
59
|
+
{ 'normalized' => 'wifi', 'tokenized' => 'wifi', 'hits' => 6, 'docs' => 3 },
|
60
|
+
{ 'normalized' => 'gprs', 'tokenized' => 'gprs', 'hits' => 1, 'docs' => 1 }
|
61
|
+
]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'in UpdateAttributes method' do
|
66
|
+
it 'should parse response' do
|
67
|
+
@sphinx.UpdateAttributes('test1', ['group_id'], { 2 => [1] }).should == 1
|
68
|
+
result = @sphinx.Query('wifi', 'test1')
|
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
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should parse response with MVA' do
|
76
|
+
@sphinx.UpdateAttributes('test1', ['tags'], { 2 => [[1, 2, 3, 4, 5, 6, 7, 8, 9]] }, true).should == 1
|
77
|
+
result = @sphinx.Query('wifi', 'test1')
|
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]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'in Open method' do
|
86
|
+
it 'should open socket' do
|
87
|
+
@sphinx.Open.should be_true
|
88
|
+
socket = @sphinx.servers.first.instance_variable_get(:@socket)
|
89
|
+
socket.should_not be_nil
|
90
|
+
socket.should be_kind_of(Sphinx::BufferedIO)
|
91
|
+
socket.close
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should produce an error when opened twice' do
|
95
|
+
@sphinx.Open.should be_true
|
96
|
+
@sphinx.Open.should be_false
|
97
|
+
@sphinx.GetLastError.should == 'already connected'
|
98
|
+
|
99
|
+
socket = @sphinx.servers.first.instance_variable_get(:@socket)
|
100
|
+
socket.should be_kind_of(Sphinx::BufferedIO)
|
101
|
+
socket.close
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'in Close method' do
|
106
|
+
it 'should open socket' do
|
107
|
+
@sphinx.Open.should be_true
|
108
|
+
@sphinx.Close.should be_true
|
109
|
+
@sphinx.servers.first.instance_variable_get(:@socket).should be_nil
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should produce socket is closed' do
|
113
|
+
@sphinx.Close.should be_false
|
114
|
+
@sphinx.GetLastError.should == 'not connected'
|
115
|
+
@sphinx.servers.first.instance_variable_get(:@socket).should be_nil
|
116
|
+
|
117
|
+
@sphinx.Open.should be_true
|
118
|
+
@sphinx.Close.should be_true
|
119
|
+
@sphinx.Close.should be_false
|
120
|
+
@sphinx.GetLastError.should == 'not connected'
|
121
|
+
@sphinx.servers.first.instance_variable_get(:@socket).should be_nil
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'in Status method' do
|
126
|
+
it 'should parse response' do
|
127
|
+
response = @sphinx.Status
|
128
|
+
response.should be_an(Array)
|
129
|
+
response.size.should be > 10
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def validate_results_wifi(result)
|
134
|
+
result['total_found'].should == 3
|
135
|
+
result['matches'].length.should == 3
|
136
|
+
result['time'].should_not be_nil
|
137
|
+
result['attrs'].should == {
|
138
|
+
'group_id' => Sphinx::SPH_ATTR_INTEGER,
|
139
|
+
'created_at' => Sphinx::SPH_ATTR_TIMESTAMP,
|
140
|
+
'rating' => Sphinx::SPH_ATTR_FLOAT,
|
141
|
+
'tags' => Sphinx::SPH_ATTR_MULTI | Sphinx::SPH_ATTR_INTEGER
|
142
|
+
}
|
143
|
+
result['fields'].should == [ 'name', 'description' ]
|
144
|
+
result['total'].should == 3
|
145
|
+
result['matches'].should be_an_instance_of(Array)
|
146
|
+
|
147
|
+
result['matches'][0]['id'].should == 2
|
148
|
+
result['matches'][0]['weight'].should == 2
|
149
|
+
result['matches'][0]['attrs']['group_id'].should == 2
|
150
|
+
result['matches'][0]['attrs']['created_at'].should == 1175658555
|
151
|
+
result['matches'][0]['attrs']['tags'].should == [5, 6, 7, 8]
|
152
|
+
('%0.2f' % result['matches'][0]['attrs']['rating']).should == '54.85'
|
153
|
+
|
154
|
+
result['matches'][1]['id'].should == 3
|
155
|
+
result['matches'][1]['weight'].should == 2
|
156
|
+
result['matches'][1]['attrs']['group_id'].should == 1
|
157
|
+
result['matches'][1]['attrs']['created_at'].should == 1175658647
|
158
|
+
result['matches'][1]['attrs']['tags'].should == [1, 7, 9, 10]
|
159
|
+
('%0.2f' % result['matches'][1]['attrs']['rating']).should == '16.25'
|
160
|
+
|
161
|
+
result['matches'][2]['id'].should == 1
|
162
|
+
result['matches'][2]['weight'].should == 1
|
163
|
+
result['matches'][2]['attrs']['group_id'].should == 1
|
164
|
+
result['matches'][2]['attrs']['created_at'].should == 1175658490
|
165
|
+
result['matches'][2]['attrs']['tags'].should == [1, 2, 3, 4]
|
166
|
+
('%0.2f' % result['matches'][2]['attrs']['rating']).should == '13.32'
|
167
|
+
|
168
|
+
result['words'].should == { 'wifi' => { 'hits' => 6, 'docs' => 3 } }
|
169
|
+
end
|
170
|
+
end
|