riddle 0.9.8.1533.10 → 1.0.0
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 +1 -0
- data/lib/riddle.rb +9 -15
- data/lib/riddle/0.9.8.rb +0 -0
- data/lib/riddle/0.9.9.rb +5 -0
- data/lib/riddle/0.9.9/client.rb +49 -0
- data/lib/riddle/0.9.9/client/filter.rb +22 -0
- data/lib/riddle/0.9.9/configuration/searchd.rb +28 -0
- data/lib/riddle/client.rb +110 -18
- data/lib/riddle/client/filter.rb +29 -20
- data/lib/riddle/client/message.rb +4 -0
- data/lib/riddle/client/response.rb +10 -0
- data/lib/riddle/configuration/distributed_index.rb +8 -7
- data/lib/riddle/configuration/index.rb +15 -11
- data/lib/riddle/configuration/searchd.rb +6 -4
- data/lib/riddle/configuration/sql_source.rb +9 -4
- data/lib/riddle/controller.rb +5 -3
- data/spec/fixtures/data_generator.0.9.8.php +208 -0
- data/spec/fixtures/data_generator.0.9.9.php +225 -0
- data/spec/fixtures/sphinx/configuration.erb +38 -0
- data/spec/fixtures/sphinx/people.spa +0 -0
- data/spec/fixtures/sphinx/people.spd +0 -0
- data/spec/fixtures/sphinx/people.sph +0 -0
- data/spec/fixtures/sphinx/people.spi +0 -0
- data/spec/fixtures/sphinx/people.spk +0 -0
- data/spec/fixtures/sphinx/people.spm +0 -0
- data/spec/fixtures/sphinx/people.spp +0 -0
- data/spec/fixtures/sphinx/searchd.log +3731 -0
- data/spec/fixtures/sphinx/searchd.query.log +1032 -0
- data/spec/fixtures/sphinx/spec.conf +38 -0
- data/spec/fixtures/sphinxapi.0.9.8.php +1228 -0
- data/spec/fixtures/sphinxapi.0.9.9.php +1646 -0
- data/spec/fixtures/sql/conf.example.yml +3 -0
- data/spec/fixtures/sql/conf.yml +3 -0
- data/spec/fixtures/sql/data.sql +25000 -0
- data/spec/fixtures/sql/structure.sql +16 -0
- data/spec/functional/excerpt_spec.rb +37 -10
- data/spec/functional/persistance_spec.rb +17 -0
- data/spec/functional/status_spec.rb +21 -0
- data/spec/functional/update_spec.rb +3 -3
- data/spec/spec_helper.rb +30 -0
- data/spec/sphinx_helper.rb +93 -0
- data/spec/unit/client_spec.rb +20 -3
- data/spec/unit/configuration/distributed_index_spec.rb +2 -0
- data/spec/unit/configuration/index_spec.rb +16 -0
- data/spec/unit/configuration/searchd_spec.rb +46 -13
- data/spec/unit/configuration/sql_source_spec.rb +15 -0
- metadata +61 -37
- data/MIT-LICENCE +0 -20
- data/lib/tabtab_definitions.rb +0 -15
data/README.textile
CHANGED
data/lib/riddle.rb
CHANGED
@@ -7,24 +7,18 @@ require 'riddle/controller'
|
|
7
7
|
|
8
8
|
module Riddle #:nodoc:
|
9
9
|
class ConnectionError < StandardError #:nodoc:
|
10
|
+
#
|
10
11
|
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
Rev = 1533
|
19
|
-
# Release number to mark my own fixes, beyond feature parity with
|
20
|
-
# Sphinx itself.
|
21
|
-
Release = 10
|
22
|
-
|
23
|
-
String = [Major, Minor, Tiny].join('.')
|
24
|
-
GemVersion = [Major, Minor, Tiny, Rev, Release].join('.')
|
13
|
+
def self.escape_pattern
|
14
|
+
Thread.current[:riddle_escape_pattern] ||= /[\(\)\|\-!@~"&\/]/
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.escape_pattern=(pattern)
|
18
|
+
Thread.current[:riddle_escape_pattern] = pattern
|
25
19
|
end
|
26
20
|
|
27
21
|
def self.escape(string)
|
28
|
-
string.gsub(
|
22
|
+
string.gsub(escape_pattern) { |char| "\\#{char}" }
|
29
23
|
end
|
30
|
-
end
|
24
|
+
end
|
data/lib/riddle/0.9.8.rb
ADDED
File without changes
|
data/lib/riddle/0.9.9.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
Riddle::Client::Versions[:search] = 0x116
|
2
|
+
Riddle::Client::Versions[:update] = 0x102
|
3
|
+
|
4
|
+
class Riddle::Client
|
5
|
+
private
|
6
|
+
|
7
|
+
def initialise_connection
|
8
|
+
socket = initialise_socket
|
9
|
+
|
10
|
+
# Send version
|
11
|
+
socket.send [1].pack('N'), 0
|
12
|
+
|
13
|
+
# Checking version
|
14
|
+
version = socket.recv(4).unpack('N*').first
|
15
|
+
if version < 1
|
16
|
+
socket.close
|
17
|
+
raise VersionError, "Can only connect to searchd version 1.0 or better, not version #{version}"
|
18
|
+
end
|
19
|
+
|
20
|
+
socket
|
21
|
+
end
|
22
|
+
|
23
|
+
def update_message(index, attributes, values_by_doc)
|
24
|
+
message = Message.new
|
25
|
+
|
26
|
+
message.append_string index
|
27
|
+
message.append_int attributes.length
|
28
|
+
attributes.each_with_index do |attribute, index|
|
29
|
+
message.append_string attribute
|
30
|
+
message.append_boolean values_by_doc.values.first[index].is_a?(Array)
|
31
|
+
end
|
32
|
+
|
33
|
+
message.append_int values_by_doc.length
|
34
|
+
values_by_doc.each do |key,values|
|
35
|
+
message.append_64bit_int key # document ID
|
36
|
+
values.each do |value|
|
37
|
+
case value
|
38
|
+
when Array
|
39
|
+
message.append_int value.length
|
40
|
+
message.append_ints *value
|
41
|
+
else
|
42
|
+
message.append_int value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
message.to_s
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Riddle::Client::Filter
|
2
|
+
#
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def append_integer_range(message, range)
|
7
|
+
message.append_64bit_ints self.values.first, self.values.last
|
8
|
+
end
|
9
|
+
|
10
|
+
def append_array(message, array)
|
11
|
+
message.append_64bit_ints *array.collect { |val|
|
12
|
+
case val
|
13
|
+
when TrueClass
|
14
|
+
1
|
15
|
+
when FalseClass
|
16
|
+
0
|
17
|
+
else
|
18
|
+
val
|
19
|
+
end
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Riddle
|
2
|
+
class Configuration
|
3
|
+
class Searchd
|
4
|
+
def valid?
|
5
|
+
set_listen
|
6
|
+
clear_deprecated
|
7
|
+
|
8
|
+
!( @listen.nil? || @pid_file.nil? )
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def set_listen
|
14
|
+
return unless @listen.nil?
|
15
|
+
|
16
|
+
@listen = @port.to_s if @port && @address.nil?
|
17
|
+
@listen = "#{@address}:#{@port}" if @address && @port
|
18
|
+
end
|
19
|
+
|
20
|
+
def clear_deprecated
|
21
|
+
return if @listen.nil?
|
22
|
+
|
23
|
+
@address = nil
|
24
|
+
@port = nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/riddle/client.rb
CHANGED
@@ -33,14 +33,19 @@ module Riddle
|
|
33
33
|
:search => 0, # SEARCHD_COMMAND_SEARCH
|
34
34
|
:excerpt => 1, # SEARCHD_COMMAND_EXCERPT
|
35
35
|
:update => 2, # SEARCHD_COMMAND_UPDATE
|
36
|
-
:keywords => 3
|
36
|
+
:keywords => 3, # SEARCHD_COMMAND_KEYWORDS
|
37
|
+
:persist => 4, # SEARCHD_COMMAND_PERSIST
|
38
|
+
:status => 5, # SEARCHD_COMMAND_STATUS
|
39
|
+
:query => 6 # SEARCHD_COMMAND_QUERY
|
37
40
|
}
|
38
41
|
|
39
42
|
Versions = {
|
40
43
|
:search => 0x113, # VER_COMMAND_SEARCH
|
41
44
|
:excerpt => 0x100, # VER_COMMAND_EXCERPT
|
42
45
|
:update => 0x101, # VER_COMMAND_UPDATE
|
43
|
-
:keywords => 0x100
|
46
|
+
:keywords => 0x100, # VER_COMMAND_KEYWORDS
|
47
|
+
:status => 0x100, # VER_COMMAND_STATUS
|
48
|
+
:query => 0x100 # VER_COMMAND_QUERY
|
44
49
|
}
|
45
50
|
|
46
51
|
Statuses = {
|
@@ -64,7 +69,10 @@ module Riddle
|
|
64
69
|
:proximity_bm25 => 0, # SPH_RANK_PROXIMITY_BM25
|
65
70
|
:bm25 => 1, # SPH_RANK_BM25
|
66
71
|
:none => 2, # SPH_RANK_NONE
|
67
|
-
:wordcount => 3
|
72
|
+
:wordcount => 3, # SPH_RANK_WORDCOUNT
|
73
|
+
:proximity => 4, # SPH_RANK_PROXIMITY
|
74
|
+
:match_any => 5, # SPH_RANK_MATCHANY
|
75
|
+
:fieldmask => 6 # SPH_RANK_FIELDMASK
|
68
76
|
}
|
69
77
|
|
70
78
|
SortModes = {
|
@@ -82,6 +90,7 @@ module Riddle
|
|
82
90
|
:ordinal => 3, # SPH_ATTR_ORDINAL
|
83
91
|
:bool => 4, # SPH_ATTR_BOOL
|
84
92
|
:float => 5, # SPH_ATTR_FLOAT
|
93
|
+
:bigint => 6, # SPH_ATTR_BIGINT
|
85
94
|
:multi => 0x40000000 # SPH_ATTR_MULTI
|
86
95
|
}
|
87
96
|
|
@@ -104,7 +113,7 @@ module Riddle
|
|
104
113
|
:match_mode, :sort_mode, :sort_by, :weights, :id_range, :filters,
|
105
114
|
:group_by, :group_function, :group_clause, :group_distinct, :cut_off,
|
106
115
|
:retry_count, :retry_delay, :anchor, :index_weights, :rank_mode,
|
107
|
-
:max_query_time, :field_weights, :timeout
|
116
|
+
:max_query_time, :field_weights, :timeout, :overrides, :select
|
108
117
|
attr_reader :queue
|
109
118
|
|
110
119
|
# Can instantiate with a specific server and port - otherwise it assumes
|
@@ -113,6 +122,7 @@ module Riddle
|
|
113
122
|
def initialize(server=nil, port=nil)
|
114
123
|
@server = server || "localhost"
|
115
124
|
@port = port || 3312
|
125
|
+
@socket = nil
|
116
126
|
|
117
127
|
reset
|
118
128
|
|
@@ -146,6 +156,8 @@ module Riddle
|
|
146
156
|
# string keys are field names, integer values are weightings
|
147
157
|
@field_weights = {}
|
148
158
|
@timeout = 0
|
159
|
+
@overrides = {}
|
160
|
+
@select = "*"
|
149
161
|
end
|
150
162
|
|
151
163
|
# Set the geo-anchor point - with the names of the attributes that contain
|
@@ -389,27 +401,77 @@ module Riddle
|
|
389
401
|
end
|
390
402
|
end
|
391
403
|
|
404
|
+
def status
|
405
|
+
response = Response.new request(
|
406
|
+
:status, Message.new
|
407
|
+
)
|
408
|
+
|
409
|
+
rows, cols = response.next_int, response.next_int
|
410
|
+
|
411
|
+
(0...rows).inject({}) do |hash, row|
|
412
|
+
hash[response.next.to_sym] = response.next
|
413
|
+
hash
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
def add_override(attribute, type, values)
|
418
|
+
@overrides[attribute] = {:type => type, :values => values}
|
419
|
+
end
|
420
|
+
|
421
|
+
def open
|
422
|
+
open_socket
|
423
|
+
|
424
|
+
return if Versions[:search] < 0x116
|
425
|
+
|
426
|
+
@socket.send [
|
427
|
+
Commands[:persist], 0, 4, 1
|
428
|
+
].pack("nnNN"), 0
|
429
|
+
end
|
430
|
+
|
431
|
+
def close
|
432
|
+
close_socket
|
433
|
+
end
|
434
|
+
|
392
435
|
private
|
393
436
|
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
socket = nil
|
437
|
+
def open_socket
|
438
|
+
raise "Already Connected" unless @socket.nil?
|
439
|
+
|
398
440
|
if @timeout == 0
|
399
|
-
socket = initialise_connection
|
441
|
+
@socket = initialise_connection
|
400
442
|
else
|
401
443
|
begin
|
402
|
-
Timeout.timeout(@timeout) { socket = initialise_connection }
|
444
|
+
Timeout.timeout(@timeout) { @socket = initialise_connection }
|
403
445
|
rescue Timeout::Error
|
404
446
|
raise Riddle::ConnectionError,
|
405
447
|
"Connection to #{@server} on #{@port} timed out after #{@timeout} seconds"
|
406
448
|
end
|
407
449
|
end
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
450
|
+
|
451
|
+
true
|
452
|
+
end
|
453
|
+
|
454
|
+
def close_socket
|
455
|
+
raise "Not Connected" if @socket.nil?
|
456
|
+
|
457
|
+
@socket.close
|
458
|
+
@socket = nil
|
459
|
+
|
460
|
+
true
|
461
|
+
end
|
462
|
+
|
463
|
+
# Connects to the Sphinx daemon, and yields a socket to use. The socket is
|
464
|
+
# closed at the end of the block.
|
465
|
+
def connect(&block)
|
466
|
+
unless @socket.nil?
|
467
|
+
yield @socket
|
468
|
+
else
|
469
|
+
open_socket
|
470
|
+
begin
|
471
|
+
yield @socket
|
472
|
+
ensure
|
473
|
+
close_socket
|
474
|
+
end
|
413
475
|
end
|
414
476
|
end
|
415
477
|
|
@@ -453,7 +515,7 @@ module Riddle
|
|
453
515
|
if message.respond_to?(:force_encoding)
|
454
516
|
message = message.force_encoding('ASCII-8BIT')
|
455
517
|
end
|
456
|
-
|
518
|
+
|
457
519
|
connect do |socket|
|
458
520
|
case command
|
459
521
|
when :search
|
@@ -463,6 +525,10 @@ module Riddle
|
|
463
525
|
Commands[command], Versions[command],
|
464
526
|
4+message.length, messages.length
|
465
527
|
].pack("nnNN") + message, 0
|
528
|
+
when :status
|
529
|
+
socket.send [
|
530
|
+
Commands[command], Versions[command], 4, 1
|
531
|
+
].pack("nnNN"), 0
|
466
532
|
else
|
467
533
|
socket.send [
|
468
534
|
Commands[command], Versions[command], message.length
|
@@ -565,6 +631,30 @@ module Riddle
|
|
565
631
|
|
566
632
|
message.append_string comments
|
567
633
|
|
634
|
+
return message.to_s if Versions[:search] < 0x116
|
635
|
+
|
636
|
+
# Overrides
|
637
|
+
message.append_int @overrides.length
|
638
|
+
@overrides.each do |key,val|
|
639
|
+
message.append_string key.to_s
|
640
|
+
message.append_int AttributeTypes[val[:type]]
|
641
|
+
message.append_int val[:values].length
|
642
|
+
val[:values].each do |id,map|
|
643
|
+
message.append_64bit_int id
|
644
|
+
method = case val[:type]
|
645
|
+
when :float
|
646
|
+
:append_float
|
647
|
+
when :bigint
|
648
|
+
:append_64bit_int
|
649
|
+
else
|
650
|
+
:append_int
|
651
|
+
end
|
652
|
+
message.send method, map
|
653
|
+
end
|
654
|
+
end
|
655
|
+
|
656
|
+
message.append_string @select
|
657
|
+
|
568
658
|
message.to_s
|
569
659
|
end
|
570
660
|
|
@@ -626,9 +716,11 @@ module Riddle
|
|
626
716
|
|
627
717
|
case type
|
628
718
|
when AttributeTypes[:float]
|
629
|
-
is_multi ? response.next_float_array
|
719
|
+
is_multi ? response.next_float_array : response.next_float
|
720
|
+
when AttributeTypes[:bigint]
|
721
|
+
is_multi ? response.next_64bit_int_arry : response.next_64bit_int
|
630
722
|
else
|
631
|
-
is_multi ? response.next_int_array
|
723
|
+
is_multi ? response.next_int_array : response.next_int
|
632
724
|
end
|
633
725
|
end
|
634
726
|
end
|
data/lib/riddle/client/filter.rb
CHANGED
@@ -1,23 +1,22 @@
|
|
1
1
|
module Riddle
|
2
2
|
class Client
|
3
|
-
# Used for querying Sphinx.
|
4
3
|
class Filter
|
5
4
|
attr_accessor :attribute, :values, :exclude
|
6
|
-
|
5
|
+
|
7
6
|
# Attribute name, values (which can be an array or a range), and whether
|
8
7
|
# the filter should be exclusive.
|
9
8
|
def initialize(attribute, values, exclude=false)
|
10
9
|
@attribute, @values, @exclude = attribute, values, exclude
|
11
10
|
end
|
12
|
-
|
11
|
+
|
13
12
|
def exclude?
|
14
13
|
self.exclude
|
15
14
|
end
|
16
|
-
|
15
|
+
|
17
16
|
# Returns the message for this filter to send to the Sphinx service
|
18
17
|
def query_message
|
19
18
|
message = Message.new
|
20
|
-
|
19
|
+
|
21
20
|
message.append_string self.attribute.to_s
|
22
21
|
case self.values
|
23
22
|
when Range
|
@@ -26,28 +25,38 @@ module Riddle
|
|
26
25
|
message.append_floats self.values.first, self.values.last
|
27
26
|
else
|
28
27
|
message.append_int FilterTypes[:range]
|
29
|
-
message
|
28
|
+
append_integer_range message, self.values
|
30
29
|
end
|
31
30
|
when Array
|
32
31
|
message.append_int FilterTypes[:values]
|
33
32
|
message.append_int self.values.length
|
34
|
-
|
35
|
-
# signed ints on x32 platforms
|
36
|
-
message.append_ints *self.values.collect { |val|
|
37
|
-
case val
|
38
|
-
when TrueClass
|
39
|
-
1.0
|
40
|
-
when FalseClass
|
41
|
-
0.0
|
42
|
-
else
|
43
|
-
val.to_f
|
44
|
-
end
|
45
|
-
}
|
33
|
+
append_array message, self.values
|
46
34
|
end
|
47
35
|
message.append_int self.exclude? ? 1 : 0
|
48
|
-
|
36
|
+
|
49
37
|
message.to_s
|
50
38
|
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def append_integer_range(message, range)
|
43
|
+
message.append_ints self.values.first, self.values.last
|
44
|
+
end
|
45
|
+
|
46
|
+
# Using to_f is a hack from the PHP client - to workaround 32bit signed
|
47
|
+
# ints on x32 platforms
|
48
|
+
def append_array(message, array)
|
49
|
+
message.append_ints *array.collect { |val|
|
50
|
+
case val
|
51
|
+
when TrueClass
|
52
|
+
1.0
|
53
|
+
when FalseClass
|
54
|
+
0.0
|
55
|
+
else
|
56
|
+
val.to_f
|
57
|
+
end
|
58
|
+
}
|
59
|
+
end
|
51
60
|
end
|
52
61
|
end
|
53
|
-
end
|
62
|
+
end
|