redisearch-rb 0.2.0 → 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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/lib/redisearch.rb +116 -38
- data/lib/redisearch/version.rb +1 -1
- data/test/redisearch_test.rb +31 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea52a309430c3f6fbed50c64e43e8a6158606584
|
4
|
+
data.tar.gz: 0bcfe47c805b649f14cefed4772526f7004f2173
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3d38b1b71012fa9acd1bb7d14a7e71db16c7d840a3ec934f93f1167b5fb4e86440fc6be916ab17bfe77757b1f4617d2f25d92b490ef3eeed734177edf18605a
|
7
|
+
data.tar.gz: 2f80306e5c404618a47ed90aee72c42e77ee343559f2ce54539ef4f74e61d575f3a851761c22ef6520994bde9a04d9ff84269da2da0560efa4d98f0f23d26666
|
data/.travis.yml
CHANGED
data/lib/redisearch.rb
CHANGED
@@ -12,15 +12,24 @@ class RediSearch
|
|
12
12
|
#
|
13
13
|
# { verbatim: true, withscores: true, withsortkey: false }
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
OPTIONS_FLAGS = {
|
16
|
+
add: [:nosave, :replace, :partial],
|
17
|
+
create: [:nooffsets, :nofreqs, :nohl, :nofields],
|
18
|
+
del: [:dd],
|
19
|
+
drop: [:keepdocs],
|
20
|
+
search: [:nocontent, :verbatim, :nostopwords, :withscores, :withsortkeys],
|
21
|
+
sugadd: [:incr],
|
22
|
+
sugget: [:fuzzy, :withscores],
|
23
|
+
}
|
18
24
|
|
19
25
|
# Params options need an array with the values for the option
|
20
26
|
# { limit: ['0', '50'], sortby: ['year', 'desc'], return: ['2', 'title', 'year'] }
|
21
|
-
|
22
|
-
|
23
|
-
|
27
|
+
OPTIONS_PARAMS = {
|
28
|
+
add: [:language, :payload],
|
29
|
+
create: [:stopwords],
|
30
|
+
search: [:filter, :return, :infields, :inkeys, :slop, :scorer, :sortby, :limit, :payload],
|
31
|
+
sugget: [:max],
|
32
|
+
}
|
24
33
|
|
25
34
|
# Create RediSearch client instance
|
26
35
|
#
|
@@ -54,8 +63,8 @@ class RediSearch
|
|
54
63
|
#
|
55
64
|
# See http://redisearch.io/Commands/#ftdrop
|
56
65
|
# @return [String] "OK" on success
|
57
|
-
def drop_index
|
58
|
-
call(ft_drop)
|
66
|
+
def drop_index(opts = {})
|
67
|
+
call(ft_drop(opts))
|
59
68
|
end
|
60
69
|
|
61
70
|
# Add a single doc to the index, with the given `doc_id` and `fields`
|
@@ -122,27 +131,75 @@ class RediSearch
|
|
122
131
|
#
|
123
132
|
# @param [String] doc_id id assigned to the document
|
124
133
|
# @return [int] 1 if the document was in the index, or 0 if not.
|
125
|
-
def delete_by_id(doc_id)
|
126
|
-
call(ft_del(doc_id))
|
134
|
+
def delete_by_id(doc_id, opts = {})
|
135
|
+
call(ft_del(doc_id, opts))
|
127
136
|
end
|
128
137
|
|
129
|
-
# Deletes all documents
|
138
|
+
# Deletes all documents matching the query
|
130
139
|
#
|
131
140
|
# @param [String] query in the same format as used in `search`
|
132
141
|
# @param [Hash] opts options for the query, same as in `search`
|
133
142
|
# @return [int] count of documents deleted
|
134
143
|
def delete_by_query(query, opts = {})
|
135
144
|
call(ft_search(query, opts.merge(nocontent: true)))[1..-1].map do |doc_id|
|
136
|
-
call(ft_del(doc_id))
|
145
|
+
call(ft_del(doc_id, opts))
|
137
146
|
end.sum
|
138
147
|
end
|
139
148
|
|
140
|
-
#
|
149
|
+
# Adds a string to an auto-complete suggestion dictionary.
|
150
|
+
#
|
151
|
+
# See https://oss.redislabs.com/redisearch/Commands/#ftsugadd
|
152
|
+
#
|
153
|
+
# @param [String] dict_name the key used to store the dictionary
|
154
|
+
# @param [String] content the string that is going to be indexed
|
155
|
+
# @param [Hash] opts optional parameters
|
156
|
+
# @return [int] current size of the dictionary
|
157
|
+
def autocomplete_add(dict_name, content, score = 1.0, opts = {})
|
158
|
+
call(ft_sugadd(dict_name, content, score, opts))
|
159
|
+
end
|
160
|
+
|
161
|
+
# Gets completion suggestions for a prefix.
|
162
|
+
#
|
163
|
+
# See https://oss.redislabs.com/redisearch/Commands/#ftsugadd
|
164
|
+
#
|
165
|
+
# @param [String] dict_name the key used to store the dictionary
|
166
|
+
# @param [String] prefix the prefix to search / complete
|
167
|
+
# @param [Hash] opts optional parameters
|
168
|
+
# @return [Array] a list of the top suggestions matching the prefix,
|
169
|
+
# optionally with score after each entry
|
170
|
+
def autocomplete_get(dict_name, prefix, opts = {})
|
171
|
+
call(ft_sugget(dict_name, prefix, opts))
|
172
|
+
end
|
173
|
+
|
174
|
+
# Deletes a string from an auto-complete suggestion dictionary.
|
175
|
+
#
|
176
|
+
# See https://oss.redislabs.com/redisearch/Commands/#ftsugdel
|
177
|
+
#
|
178
|
+
# @param [String] dict_name the key used to store the dictionary
|
179
|
+
# @param [String] content the string that is going to be deleted
|
180
|
+
# @param [Hash] opts optional parameters
|
181
|
+
# @return [int] 1 if the string was found and deleted, 0 otherwise
|
182
|
+
def autocomplete_del(dict_name, content)
|
183
|
+
call(ft_sugdel(dict_name, content))
|
184
|
+
end
|
185
|
+
|
186
|
+
# Gets the current size of an auto-complete suggestion dictionary.
|
187
|
+
#
|
188
|
+
# See https://oss.redislabs.com/redisearch/Commands/#ftsugdel
|
189
|
+
#
|
190
|
+
# @param [String] dict_name the key used to store the dictionary
|
191
|
+
# @return [int] current size of the dictionary
|
192
|
+
def autocomplete_len(dict_name)
|
193
|
+
call(ft_suglen(dict_name))
|
194
|
+
end
|
195
|
+
|
196
|
+
# Execute arbitrary command in redisearch index
|
197
|
+
# Only RediSearch commands are allowed
|
141
198
|
#
|
142
199
|
# @param [Array] command
|
143
200
|
# @return [mixed] The output returned by redis
|
144
201
|
def call(command)
|
145
|
-
raise ArgumentError.new("#{command
|
202
|
+
raise ArgumentError.new("unknown/unsupported command '#{command.first}'") unless valid_command?(command.first)
|
146
203
|
@redis.with_reconnect { @redis.call(command.flatten) }
|
147
204
|
end
|
148
205
|
|
@@ -161,11 +218,11 @@ class RediSearch
|
|
161
218
|
end
|
162
219
|
|
163
220
|
def ft_create(schema, opts)
|
164
|
-
['FT.CREATE', @idx_name , *
|
221
|
+
['FT.CREATE', @idx_name , *serialize_options(opts, :create), 'SCHEMA', *schema]
|
165
222
|
end
|
166
223
|
|
167
|
-
def ft_drop
|
168
|
-
['FT.DROP', @idx_name]
|
224
|
+
def ft_drop(opts)
|
225
|
+
['FT.DROP', @idx_name, *serialize_options(opts, :drop)]
|
169
226
|
end
|
170
227
|
|
171
228
|
def ft_info
|
@@ -173,15 +230,15 @@ class RediSearch
|
|
173
230
|
end
|
174
231
|
|
175
232
|
def ft_add(doc_id, fields, opts = {}, weight = nil)
|
176
|
-
['FT.ADD', @idx_name , doc_id, weight || DEFAULT_WEIGHT, *
|
233
|
+
['FT.ADD', @idx_name , doc_id, weight || DEFAULT_WEIGHT, *serialize_options(opts, :add), 'FIELDS', *fields]
|
177
234
|
end
|
178
235
|
|
179
236
|
def ft_add_hash(doc_id, opts = {}, weight = nil)
|
180
|
-
['FT.ADDHASH', @idx_name , doc_id, weight || DEFAULT_WEIGHT, *
|
237
|
+
['FT.ADDHASH', @idx_name , doc_id, weight || DEFAULT_WEIGHT, *serialize_options(opts, :add)]
|
181
238
|
end
|
182
239
|
|
183
240
|
def ft_search(query, opts)
|
184
|
-
['FT.SEARCH', @idx_name, *query, *
|
241
|
+
['FT.SEARCH', @idx_name, *query, *serialize_options(opts, :search)].flatten
|
185
242
|
end
|
186
243
|
|
187
244
|
def ft_get(doc_id)
|
@@ -192,40 +249,59 @@ class RediSearch
|
|
192
249
|
['FT.MGET', @idx_name , *doc_ids]
|
193
250
|
end
|
194
251
|
|
195
|
-
def ft_del(doc_id)
|
196
|
-
['FT.DEL', @idx_name , doc_id]
|
252
|
+
def ft_del(doc_id, opts)
|
253
|
+
['FT.DEL', @idx_name , doc_id, *serialize_options(opts, :del)]
|
254
|
+
end
|
255
|
+
|
256
|
+
def ft_tagvals(field_name)
|
257
|
+
['FT.TAGVALS', @idx_name , field_name]
|
258
|
+
end
|
259
|
+
|
260
|
+
def ft_explain(query, opts)
|
261
|
+
['FT.EXPLAIN', @idx_name, *query, *serialize_options(opts, :search)].flatten
|
262
|
+
end
|
263
|
+
|
264
|
+
def ft_sugadd(dict_name, content, score, opts)
|
265
|
+
['FT.SUGADD', dict_name , content, score, *serialize_options(opts, :sugadd)]
|
197
266
|
end
|
198
267
|
|
199
|
-
def
|
200
|
-
|
268
|
+
def ft_sugdel(dict_name, content)
|
269
|
+
['FT.SUGDEL', dict_name , content]
|
201
270
|
end
|
202
271
|
|
203
|
-
def
|
204
|
-
|
272
|
+
def ft_suglen(dict_name)
|
273
|
+
['FT.SUGLEN', dict_name]
|
205
274
|
end
|
206
275
|
|
207
|
-
def
|
208
|
-
|
276
|
+
def ft_sugget(dict_name, prefix,opts)
|
277
|
+
['FT.SUGGET', dict_name , prefix, *serialize_options(opts, :sugget)]
|
209
278
|
end
|
210
279
|
|
211
|
-
def
|
212
|
-
|
280
|
+
def serialize_options(opts, method)
|
281
|
+
[flags_for_method(opts, method), params_for_method(opts, method)].flatten.compact
|
282
|
+
end
|
283
|
+
|
284
|
+
def flags_for_method(opts, method)
|
285
|
+
OPTIONS_FLAGS[method].to_a.map do |key|
|
213
286
|
key.to_s.upcase if opts[key]
|
214
|
-
end.compact
|
215
|
-
|
216
|
-
|
217
|
-
|
287
|
+
end.compact
|
288
|
+
end
|
289
|
+
|
290
|
+
def params_for_method(opts, method)
|
291
|
+
OPTIONS_PARAMS[method].to_a.map do |key|
|
292
|
+
[key.to_s.upcase, *opts[key]] unless opts[key].nil?
|
293
|
+
end.compact
|
218
294
|
end
|
219
295
|
|
220
296
|
def build_docs(results, opts = {})
|
221
297
|
return {} if results.nil? || results[0] == 0
|
222
298
|
results.shift
|
223
299
|
score_offset = opts[:withscores] ? 1 : 0
|
224
|
-
content_offset =
|
225
|
-
rows_per_doc = 1 + content_offset
|
300
|
+
content_offset = opts[:nocontent] ? 0 : 1
|
301
|
+
rows_per_doc = 1 + content_offset + score_offset
|
226
302
|
nr_of_docs = results.size / rows_per_doc
|
227
303
|
(0..nr_of_docs-1).map do |n|
|
228
|
-
doc = opts[:nocontent] ? {} : Hash[*results[rows_per_doc * n + content_offset]]
|
304
|
+
doc = opts[:nocontent] ? {} : Hash[*results[rows_per_doc * n + content_offset + score_offset]]
|
229
305
|
doc['score'] = results[rows_per_doc * n + score_offset] if opts[:withscores]
|
230
306
|
doc['id'] = results[rows_per_doc * n]
|
231
307
|
doc
|
@@ -233,6 +309,8 @@ class RediSearch
|
|
233
309
|
end
|
234
310
|
|
235
311
|
def valid_command?(command)
|
236
|
-
|
312
|
+
%w(FT.CREATE FT.ADD FT.ADDHASH FT.SEARCH FT.DEL FT.DROP FT.GET FT.MGET
|
313
|
+
FT.SUGADD FT.SUGGET FT.SUGDEL FT.SUGLEN FT.SYNADD FT.SYNUPDATE FT.SYNDUMP
|
314
|
+
FT.INFO FT.AGGREGATE FT.EXPLAIN FT.TAGVALS).include?(command)
|
237
315
|
end
|
238
316
|
end
|
data/lib/redisearch/version.rb
CHANGED
data/test/redisearch_test.rb
CHANGED
@@ -37,8 +37,19 @@ class RediSearchTest < Minitest::Test
|
|
37
37
|
|
38
38
|
def test_drop_idx
|
39
39
|
assert(@redisearch_client.create_index(@schema))
|
40
|
-
|
40
|
+
doc = ['title', 'Lost in translation', 'director', 'Sofia Coppola', 'year', '2004']
|
41
|
+
@redisearch_client.add_doc('id_1', doc)
|
42
|
+
@redisearch_client.drop_index
|
41
43
|
assert_raises(Redis::CommandError) { @redisearch_client.info }
|
44
|
+
assert(@redis_client.hgetall('id_1').empty?)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_drop_idx_keep_documents
|
48
|
+
@redisearch_client.create_index(@schema)
|
49
|
+
doc = ['title', 'Lost in translation', 'director', 'Sofia Coppola', 'year', '2004']
|
50
|
+
@redisearch_client.add_doc('id_1', doc)
|
51
|
+
@redisearch_client.drop_index({ keepdocs: true })
|
52
|
+
assert(@redis_client.hgetall('id_1').any?)
|
42
53
|
end
|
43
54
|
|
44
55
|
def test_add_doc
|
@@ -175,10 +186,28 @@ class RediSearchTest < Minitest::Test
|
|
175
186
|
['id_3', ['title', 'Terminator', 'director', 'James Cameron', 'year', '1984']],
|
176
187
|
['id_4', ['title', 'Blade Runner', 'director', 'Ridley Scott', 'year', '1982']]]
|
177
188
|
assert(@redisearch_client.add_docs(docs))
|
178
|
-
assert_equal(1, @redisearch_client.delete_by_id('id_1'))
|
189
|
+
assert_equal(1, @redisearch_client.delete_by_id('id_1', { dd: false }))
|
190
|
+
assert_equal(1, @redisearch_client.delete_by_id('id_2', { dd: true }))
|
179
191
|
assert_empty(@redisearch_client.search('@title:lost'))
|
180
192
|
assert(@redisearch_client.get_by_id('id_1').any?)
|
193
|
+
assert(@redisearch_client.get_by_id('id_2').empty?)
|
181
194
|
assert(@redis_client.del('id_1'))
|
182
195
|
assert(@redisearch_client.get_by_id('id_1').empty?)
|
183
196
|
end
|
197
|
+
|
198
|
+
def test_auto_complete_suggestions
|
199
|
+
dict_name = 'test_suggestions'
|
200
|
+
@redisearch_client.autocomplete_add(dict_name, 'foobar', 2.0)
|
201
|
+
@redisearch_client.autocomplete_add(dict_name, 'foowoz', 1.0)
|
202
|
+
@redisearch_client.autocomplete_add(dict_name, 'foomeh', 0.85)
|
203
|
+
@redisearch_client.autocomplete_add(dict_name, 'woowoz', 1.0)
|
204
|
+
assert_equal(4, @redisearch_client.autocomplete_len(dict_name))
|
205
|
+
results = @redisearch_client.autocomplete_get(dict_name, 'foo')
|
206
|
+
assert_equal(3, results.count)
|
207
|
+
assert_equal('foobar', results.first)
|
208
|
+
assert_equal(4, @redisearch_client.autocomplete_get(dict_name, 'foo', { fuzzy: true }).count)
|
209
|
+
assert @redisearch_client.autocomplete_del(dict_name, 'foobar').to_i > 0
|
210
|
+
refute @redisearch_client.autocomplete_del(dict_name, 'foozzz').to_i > 0
|
211
|
+
assert_equal('foowoz', @redisearch_client.autocomplete_get(dict_name, 'foo').first)
|
212
|
+
end
|
184
213
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redisearch-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Victor Ruiz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-11-27 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |-
|
14
14
|
A simple Ruby client library for RediSearch.
|