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.
Files changed (86) hide show
  1. data/.gitignore +4 -0
  2. data/README.rdoc +243 -0
  3. data/Rakefile +45 -0
  4. data/VERSION.yml +5 -0
  5. data/init.rb +1 -0
  6. data/lib/sphinx/buffered_io.rb +26 -0
  7. data/lib/sphinx/client.rb +2426 -0
  8. data/lib/sphinx/constants.rb +179 -0
  9. data/lib/sphinx/indifferent_access.rb +152 -0
  10. data/lib/sphinx/request.rb +121 -0
  11. data/lib/sphinx/response.rb +71 -0
  12. data/lib/sphinx/server.rb +170 -0
  13. data/lib/sphinx/timeout.rb +31 -0
  14. data/lib/sphinx.rb +51 -0
  15. data/spec/client_response_spec.rb +170 -0
  16. data/spec/client_spec.rb +669 -0
  17. data/spec/client_validations_spec.rb +859 -0
  18. data/spec/fixtures/default_search.php +8 -0
  19. data/spec/fixtures/default_search_index.php +8 -0
  20. data/spec/fixtures/excerpt_custom.php +11 -0
  21. data/spec/fixtures/excerpt_default.php +8 -0
  22. data/spec/fixtures/excerpt_flags.php +12 -0
  23. data/spec/fixtures/field_weights.php +9 -0
  24. data/spec/fixtures/filter.php +9 -0
  25. data/spec/fixtures/filter_exclude.php +9 -0
  26. data/spec/fixtures/filter_float_range.php +9 -0
  27. data/spec/fixtures/filter_float_range_exclude.php +9 -0
  28. data/spec/fixtures/filter_range.php +9 -0
  29. data/spec/fixtures/filter_range_exclude.php +9 -0
  30. data/spec/fixtures/filter_range_int64.php +10 -0
  31. data/spec/fixtures/filter_ranges.php +10 -0
  32. data/spec/fixtures/filters.php +10 -0
  33. data/spec/fixtures/filters_different.php +13 -0
  34. data/spec/fixtures/geo_anchor.php +9 -0
  35. data/spec/fixtures/group_by_attr.php +9 -0
  36. data/spec/fixtures/group_by_attrpair.php +9 -0
  37. data/spec/fixtures/group_by_day.php +9 -0
  38. data/spec/fixtures/group_by_day_sort.php +9 -0
  39. data/spec/fixtures/group_by_month.php +9 -0
  40. data/spec/fixtures/group_by_week.php +9 -0
  41. data/spec/fixtures/group_by_year.php +9 -0
  42. data/spec/fixtures/group_distinct.php +10 -0
  43. data/spec/fixtures/id_range.php +9 -0
  44. data/spec/fixtures/id_range64.php +9 -0
  45. data/spec/fixtures/index_weights.php +9 -0
  46. data/spec/fixtures/keywords.php +8 -0
  47. data/spec/fixtures/limits.php +9 -0
  48. data/spec/fixtures/limits_cutoff.php +9 -0
  49. data/spec/fixtures/limits_max.php +9 -0
  50. data/spec/fixtures/limits_max_cutoff.php +9 -0
  51. data/spec/fixtures/match_all.php +9 -0
  52. data/spec/fixtures/match_any.php +9 -0
  53. data/spec/fixtures/match_boolean.php +9 -0
  54. data/spec/fixtures/match_extended.php +9 -0
  55. data/spec/fixtures/match_extended2.php +9 -0
  56. data/spec/fixtures/match_fullscan.php +9 -0
  57. data/spec/fixtures/match_phrase.php +9 -0
  58. data/spec/fixtures/max_query_time.php +9 -0
  59. data/spec/fixtures/miltiple_queries.php +12 -0
  60. data/spec/fixtures/ranking_bm25.php +9 -0
  61. data/spec/fixtures/ranking_fieldmask.php +9 -0
  62. data/spec/fixtures/ranking_matchany.php +9 -0
  63. data/spec/fixtures/ranking_none.php +9 -0
  64. data/spec/fixtures/ranking_proximity.php +9 -0
  65. data/spec/fixtures/ranking_proximity_bm25.php +9 -0
  66. data/spec/fixtures/ranking_wordcount.php +9 -0
  67. data/spec/fixtures/retries.php +9 -0
  68. data/spec/fixtures/retries_delay.php +9 -0
  69. data/spec/fixtures/select.php +9 -0
  70. data/spec/fixtures/set_override.php +11 -0
  71. data/spec/fixtures/sort_attr_asc.php +9 -0
  72. data/spec/fixtures/sort_attr_desc.php +9 -0
  73. data/spec/fixtures/sort_expr.php +9 -0
  74. data/spec/fixtures/sort_extended.php +9 -0
  75. data/spec/fixtures/sort_relevance.php +9 -0
  76. data/spec/fixtures/sort_time_segments.php +9 -0
  77. data/spec/fixtures/sphinxapi.php +1633 -0
  78. data/spec/fixtures/update_attributes.php +8 -0
  79. data/spec/fixtures/update_attributes_mva.php +8 -0
  80. data/spec/fixtures/weights.php +9 -0
  81. data/spec/spec_helper.rb +24 -0
  82. data/spec/sphinx/sphinx-id64.conf +67 -0
  83. data/spec/sphinx/sphinx.conf +67 -0
  84. data/spec/sphinx/sphinx_test.sql +88 -0
  85. data/sphinx.gemspec +127 -0
  86. 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