redisearch-rb 0.1.7 → 1.1.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 +5 -5
- data/.travis.yml +6 -4
- data/Gemfile +3 -3
- data/README.md +5 -4
- data/lib/redisearch.rb +210 -42
- data/lib/redisearch/version.rb +1 -1
- data/redisearch-rb.gemspec +1 -1
- data/test/redisearch_test.rb +110 -1
- metadata +5 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 99d803efbd160ce83d3cf58a50b2e739540f143666dc87f18b04c3ff10766577
|
4
|
+
data.tar.gz: d83a8a81049e5b6266130f351d2c82381b12abaf93c1f616e7d602b2503d5abb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: abf6a993f32a3c93979763b3cf22e72a959fffd3d14c8ccf2fa44031b5f1c65a30ddad8715c1226ff7467f2b3ad4146be3edc806248073ec5e6926f75fc233fe
|
7
|
+
data.tar.gz: 524ed525611003f0ef515d2eee40ab4a4fcdef851083fa75b053011c1219187f1c2d1ff22c7d3fb6e456b7c53e6a0af42d12f9f6b32701bd91f0ea9a4d8be568
|
data/.travis.yml
CHANGED
@@ -7,12 +7,14 @@ before_install:
|
|
7
7
|
- gem install bundler -v 1.14.6
|
8
8
|
- git clone --depth 10 https://github.com/antirez/redis.git
|
9
9
|
- cd redis
|
10
|
-
- git fetch
|
11
|
-
- git checkout
|
10
|
+
- git fetch && git fetch --tags
|
11
|
+
- git checkout 4.0.6
|
12
12
|
- make
|
13
13
|
- cd ..
|
14
14
|
- git clone --depth 1 https://github.com/RedisLabsModules/RediSearch.git
|
15
|
-
- cd RediSearch
|
15
|
+
- cd RediSearch
|
16
|
+
- git fetch && git fetch --tags
|
17
|
+
- git checkout v1.2.0
|
16
18
|
- make all
|
17
|
-
- ls -la *.so
|
18
19
|
- cd ..
|
20
|
+
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
[](https://badge.fury.io/rb/redisearch-rb)
|
1
|
+
[](https://badge.fury.io/rb/redisearch-rb)
|
2
|
+
[](https://travis-ci.org/vruizext/redisearch-rb)
|
2
3
|
|
3
4
|
# redisearch-rb
|
4
5
|
|
@@ -10,8 +11,8 @@ http://redisearch.io/
|
|
10
11
|
|
11
12
|
First of all, you need to install RediSearch, if you haven't yet:
|
12
13
|
|
13
|
-
1. Install Redis 4.0.1 https://github.com/antirez/redis/releases/tag/4.0.1
|
14
|
-
2. Install RediSearch http://redisearch.io/Quick_Start/
|
14
|
+
1. Install Redis 4.0.1 or highger https://github.com/antirez/redis/releases/tag/4.0.1
|
15
|
+
2. Install RediSearch 1.2.0 or higher http://redisearch.io/Quick_Start/
|
15
16
|
3. Edit your `redis.conf` file and add a `loadmodule` directive to load the RediSearch module built in the step 2.
|
16
17
|
|
17
18
|
To install this gem, add this line to your application's Gemfile:
|
@@ -43,7 +44,7 @@ In order to run the tests, it's necessary to set some env variables (see .env.ex
|
|
43
44
|
```ruby
|
44
45
|
require 'redisearch-rb'
|
45
46
|
|
46
|
-
redis = Redis.new(REDIS_URL)
|
47
|
+
redis = Redis.new(url: REDIS_URL)
|
47
48
|
redisearch_client = RediSearch.new('test_idx', redis)
|
48
49
|
|
49
50
|
schema = ['title', 'TEXT', 'WEIGHT', '2.0',
|
data/lib/redisearch.rb
CHANGED
@@ -12,14 +12,26 @@ 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
|
+
addhash: [:replace],
|
18
|
+
create: [:nooffsets, :nofreqs, :nohl, :nofields],
|
19
|
+
del: [:dd],
|
20
|
+
drop: [:keepdocs],
|
21
|
+
search: [:nocontent, :verbatim, :nostopwords, :withscores, :withsortkeys, :highlight, :summarize],
|
22
|
+
sugadd: [:incr],
|
23
|
+
sugget: [:fuzzy, :withscores],
|
24
|
+
}
|
18
25
|
|
19
26
|
# Params options need an array with the values for the option
|
20
27
|
# { limit: ['0', '50'], sortby: ['year', 'desc'], return: ['2', 'title', 'year'] }
|
21
|
-
|
22
|
-
|
28
|
+
OPTIONS_PARAMS = {
|
29
|
+
add: [:language, :payload],
|
30
|
+
addhash: [:language],
|
31
|
+
create: [:stopwords],
|
32
|
+
search: [:filter, :return, :infields, :inkeys, :slop, :scorer, :sortby, :limit, :payload],
|
33
|
+
sugget: [:max],
|
34
|
+
}
|
23
35
|
|
24
36
|
# Create RediSearch client instance
|
25
37
|
#
|
@@ -36,11 +48,11 @@ class RediSearch
|
|
36
48
|
|
37
49
|
# Create new index with the given `schema`
|
38
50
|
# @param [Array] schema
|
39
|
-
#
|
51
|
+
# @param [Hash] opts options
|
40
52
|
# Example:
|
41
53
|
#
|
42
54
|
# redisearch = RediSearch.new('my_idx')
|
43
|
-
# redisearch.create_idx(['title', 'TEXT', 'WEIGHT', '2.0', 'director', 'TEXT', 'WEIGHT', '1.0'])
|
55
|
+
# redisearch.create_idx(['title', 'TEXT', 'WEIGHT', '2.0', 'director', 'TEXT', 'WEIGHT', '1.0', 'year', 'NUMERIC', 'SORTABLE'])
|
44
56
|
#
|
45
57
|
# See http://redisearch.io/Commands/#ftcreate
|
46
58
|
#
|
@@ -53,14 +65,15 @@ class RediSearch
|
|
53
65
|
#
|
54
66
|
# See http://redisearch.io/Commands/#ftdrop
|
55
67
|
# @return [String] "OK" on success
|
56
|
-
def drop_index
|
57
|
-
call(ft_drop)
|
68
|
+
def drop_index(opts = {})
|
69
|
+
call(ft_drop(opts))
|
58
70
|
end
|
59
71
|
|
60
72
|
# Add a single doc to the index, with the given `doc_id` and `fields`
|
61
73
|
#
|
62
74
|
# @param [String] doc_id id assigned to the document
|
63
75
|
# @param [Array] fields name-value pairs to be indexed
|
76
|
+
# @param [Float] weight asigned by the user to the document
|
64
77
|
# @param [Hash] opts optional parameters
|
65
78
|
# Example:
|
66
79
|
#
|
@@ -69,8 +82,8 @@ class RediSearch
|
|
69
82
|
#
|
70
83
|
# See http://redisearch.io/Commands/#ftadd
|
71
84
|
# @return [String] "OK" on success
|
72
|
-
def add_doc(doc_id, fields, opts = {})
|
73
|
-
call(ft_add(doc_id, fields, opts))
|
85
|
+
def add_doc(doc_id, fields, opts = {}, weight = nil)
|
86
|
+
call(ft_add(doc_id, fields, opts, weight))
|
74
87
|
end
|
75
88
|
|
76
89
|
# Add a set of docs to the index. Uses redis `multi` to make a single bulk insert.
|
@@ -80,23 +93,58 @@ class RediSearch
|
|
80
93
|
# Example:
|
81
94
|
#
|
82
95
|
# redisearch = RediSearch.new('my_idx')
|
83
|
-
# docs = [['id_1', ['title', 'Lost in translation', 'director', 'Sofia Coppola'],
|
84
|
-
# ['id_2', ['title', 'Ex Machina', 'director', 'Alex Garland']]
|
96
|
+
# docs = [['id_1', ['title', 'Lost in translation', 'director', 'Sofia Coppola'], 0.75],
|
97
|
+
# ['id_2', ['title', 'Ex Machina', 'director', 'Alex Garland'], 0.95]
|
85
98
|
# redisearch.add_docs(docs)
|
86
99
|
#
|
87
100
|
# See http://redisearch.io/Commands/#ftadd
|
88
101
|
# @return [String] "OK" on success
|
89
102
|
def add_docs(docs, opts = {})
|
90
|
-
|
103
|
+
docs.map { |doc_id, fields, weight| call(ft_add(doc_id, fields, opts, weight))}
|
104
|
+
end
|
105
|
+
|
106
|
+
# Adds a document to the index from an existing HASH key `doc_id` in Redis.
|
107
|
+
#
|
108
|
+
# @param [String] doc_id HASH key holding the fields that need to be indexed
|
109
|
+
# @param [Hash] opts optional parameters
|
110
|
+
# @param [Float]weight asigned by the user to the document
|
111
|
+
# Example:
|
112
|
+
#
|
113
|
+
# redisearch = RediSearch.new('my_idx')
|
114
|
+
# redisearch.add_hash('id_1', { weight: true })
|
115
|
+
#
|
116
|
+
# See http://redisearch.io/Commands/#ftadd
|
117
|
+
# @return [String] "OK" on success
|
118
|
+
def add_hash(doc_id, opts = {}, weight = nil)
|
119
|
+
call(ft_addhash(doc_id, opts, weight))
|
91
120
|
end
|
92
121
|
|
93
122
|
# Search the index with the given `query`
|
94
123
|
# @param [String] query text query, see syntax here http://redisearch.io/Query_Syntax/
|
95
124
|
# @param [Hash] opts options for the query
|
96
125
|
#
|
97
|
-
|
126
|
+
# @return [Array] documents matching the query
|
98
127
|
def search(query, opts = {})
|
99
|
-
|
128
|
+
build_docs(call(ft_search(query, opts)), opts)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Fetch the contents of multiple documents
|
132
|
+
#
|
133
|
+
# @param [Array] doc_ids ids assigned to the document
|
134
|
+
# @return [Array] documents found for the ids given
|
135
|
+
def get_by_ids(doc_ids)
|
136
|
+
call(ft_mget(doc_ids)).map.with_index do |doc, i|
|
137
|
+
{ 'id' => doc_ids[i] }.merge(Hash[*doc]) unless doc.empty?
|
138
|
+
end.compact
|
139
|
+
end
|
140
|
+
|
141
|
+
# Fetch a document by id
|
142
|
+
#
|
143
|
+
# @param [String] doc_id id assigned to the document
|
144
|
+
# @return [Hash] Hash containing document
|
145
|
+
def get_by_id(doc_id)
|
146
|
+
Hash[*call(ft_get(doc_id))]
|
147
|
+
.tap { |doc| doc['id'] = doc_id unless doc.empty? } || {}
|
100
148
|
end
|
101
149
|
|
102
150
|
# Return information and statistics on the index.
|
@@ -106,14 +154,92 @@ class RediSearch
|
|
106
154
|
Hash[*call(ft_info)]
|
107
155
|
end
|
108
156
|
|
109
|
-
|
157
|
+
# Deletes a document from the index
|
158
|
+
#
|
159
|
+
# See http://redisearch.io/Commands/#ftdel
|
160
|
+
#
|
161
|
+
# @param [String] doc_id id assigned to the document
|
162
|
+
# @return [int] 1 if the document was in the index, or 0 if not.
|
163
|
+
def delete_by_id(doc_id, opts = {})
|
164
|
+
call(ft_del(doc_id, opts))
|
165
|
+
end
|
110
166
|
|
111
|
-
|
112
|
-
|
167
|
+
# Deletes all documents matching the query
|
168
|
+
#
|
169
|
+
# @param [String] query in the same format as used in `search`
|
170
|
+
# @param [Hash] opts options for the query, same as in `search`
|
171
|
+
# @return [int] count of documents deleted
|
172
|
+
def delete_by_query(query, opts = {})
|
173
|
+
call(ft_search(query, opts.merge(nocontent: true)))[1..-1].map do |doc_id|
|
174
|
+
call(ft_del(doc_id, opts))
|
175
|
+
end.sum
|
176
|
+
end
|
177
|
+
|
178
|
+
# Adds a string to an auto-complete suggestion dictionary.
|
179
|
+
#
|
180
|
+
# See https://oss.redislabs.com/redisearch/Commands/#ftsugadd
|
181
|
+
#
|
182
|
+
# @param [String] dict_name the key used to store the dictionary
|
183
|
+
# @param [String] content the string that is going to be indexed
|
184
|
+
# @param [Hash] opts optional parameters
|
185
|
+
# @return [int] current size of the dictionary
|
186
|
+
def autocomplete_add(dict_name, content, score = 1.0, opts = {})
|
187
|
+
call(ft_sugadd(dict_name, content, score, opts))
|
188
|
+
end
|
189
|
+
|
190
|
+
# Gets completion suggestions for a prefix.
|
191
|
+
#
|
192
|
+
# See https://oss.redislabs.com/redisearch/Commands/#ftsugadd
|
193
|
+
#
|
194
|
+
# @param [String] dict_name the key used to store the dictionary
|
195
|
+
# @param [String] prefix the prefix to search / complete
|
196
|
+
# @param [Hash] opts optional parameters
|
197
|
+
# @return [Array] a list of the top suggestions matching the prefix,
|
198
|
+
# optionally with score after each entry
|
199
|
+
def autocomplete_get(dict_name, prefix, opts = {})
|
200
|
+
call(ft_sugget(dict_name, prefix, opts))
|
201
|
+
end
|
202
|
+
|
203
|
+
# Deletes a string from an auto-complete suggestion dictionary.
|
204
|
+
#
|
205
|
+
# See https://oss.redislabs.com/redisearch/Commands/#ftsugdel
|
206
|
+
#
|
207
|
+
# @param [String] dict_name the key used to store the dictionary
|
208
|
+
# @param [String] content the string that is going to be deleted
|
209
|
+
# @param [Hash] opts optional parameters
|
210
|
+
# @return [int] 1 if the string was found and deleted, 0 otherwise
|
211
|
+
def autocomplete_del(dict_name, content)
|
212
|
+
call(ft_sugdel(dict_name, content))
|
213
|
+
end
|
214
|
+
|
215
|
+
# Gets the current size of an auto-complete suggestion dictionary.
|
216
|
+
#
|
217
|
+
# See https://oss.redislabs.com/redisearch/Commands/#ftsugdel
|
218
|
+
#
|
219
|
+
# @param [String] dict_name the key used to store the dictionary
|
220
|
+
# @return [int] current size of the dictionary
|
221
|
+
def autocomplete_len(dict_name)
|
222
|
+
call(ft_suglen(dict_name))
|
113
223
|
end
|
114
224
|
|
225
|
+
# Execute arbitrary command in redisearch index
|
226
|
+
# Only RediSearch commands are allowed
|
227
|
+
#
|
228
|
+
# @param [Array] command
|
229
|
+
# @return [mixed] The output returned by redis
|
115
230
|
def call(command)
|
116
|
-
|
231
|
+
raise ArgumentError.new("unknown/unsupported command '#{command.first}'") unless valid_command?(command.first)
|
232
|
+
@redis.with_reconnect { @redis.call(command.flatten) }
|
233
|
+
end
|
234
|
+
|
235
|
+
private
|
236
|
+
|
237
|
+
def with_reconnect
|
238
|
+
@redis.with_reconnect { yield }
|
239
|
+
end
|
240
|
+
|
241
|
+
def multi
|
242
|
+
@redis.with_reconnect { @redis.multi { yield } }
|
117
243
|
end
|
118
244
|
|
119
245
|
def add(doc_id, fields)
|
@@ -121,11 +247,11 @@ class RediSearch
|
|
121
247
|
end
|
122
248
|
|
123
249
|
def ft_create(schema, opts)
|
124
|
-
['FT.CREATE', @idx_name , *
|
250
|
+
['FT.CREATE', @idx_name , *serialize_options(opts, :create), 'SCHEMA', *schema]
|
125
251
|
end
|
126
252
|
|
127
|
-
def ft_drop
|
128
|
-
['FT.DROP', @idx_name]
|
253
|
+
def ft_drop(opts)
|
254
|
+
['FT.DROP', @idx_name, *serialize_options(opts, :drop)]
|
129
255
|
end
|
130
256
|
|
131
257
|
def ft_info
|
@@ -133,45 +259,87 @@ class RediSearch
|
|
133
259
|
end
|
134
260
|
|
135
261
|
def ft_add(doc_id, fields, opts = {}, weight = nil)
|
136
|
-
['FT.ADD', @idx_name , doc_id, weight || DEFAULT_WEIGHT, *
|
262
|
+
['FT.ADD', @idx_name , doc_id, weight || DEFAULT_WEIGHT, *serialize_options(opts, :add), 'FIELDS', *fields]
|
263
|
+
end
|
264
|
+
|
265
|
+
def ft_addhash(doc_id, opts = {}, weight = nil)
|
266
|
+
['FT.ADDHASH', @idx_name , doc_id, weight || DEFAULT_WEIGHT, *serialize_options(opts, :add)]
|
137
267
|
end
|
138
268
|
|
139
269
|
def ft_search(query, opts)
|
140
|
-
['FT.SEARCH', @idx_name, *query, *
|
270
|
+
['FT.SEARCH', @idx_name, *query, *serialize_options(opts, :search)].flatten
|
141
271
|
end
|
142
272
|
|
143
|
-
def
|
144
|
-
|
273
|
+
def ft_get(doc_id)
|
274
|
+
['FT.GET', @idx_name , doc_id]
|
145
275
|
end
|
146
276
|
|
147
|
-
def
|
148
|
-
|
277
|
+
def ft_mget(doc_ids)
|
278
|
+
['FT.MGET', @idx_name , *doc_ids]
|
149
279
|
end
|
150
280
|
|
151
|
-
def
|
152
|
-
|
281
|
+
def ft_del(doc_id, opts)
|
282
|
+
['FT.DEL', @idx_name , doc_id, *serialize_options(opts, :del)]
|
153
283
|
end
|
154
284
|
|
155
|
-
def
|
156
|
-
|
285
|
+
def ft_tagvals(field_name)
|
286
|
+
['FT.TAGVALS', @idx_name , field_name]
|
287
|
+
end
|
288
|
+
|
289
|
+
def ft_explain(query, opts)
|
290
|
+
['FT.EXPLAIN', @idx_name, *query, *serialize_options(opts, :search)].flatten
|
291
|
+
end
|
292
|
+
|
293
|
+
def ft_sugadd(dict_name, content, score, opts)
|
294
|
+
['FT.SUGADD', dict_name , content, score, *serialize_options(opts, :sugadd)]
|
295
|
+
end
|
296
|
+
|
297
|
+
def ft_sugdel(dict_name, content)
|
298
|
+
['FT.SUGDEL', dict_name , content]
|
299
|
+
end
|
300
|
+
|
301
|
+
def ft_suglen(dict_name)
|
302
|
+
['FT.SUGLEN', dict_name]
|
303
|
+
end
|
304
|
+
|
305
|
+
def ft_sugget(dict_name, prefix,opts)
|
306
|
+
['FT.SUGGET', dict_name , prefix, *serialize_options(opts, :sugget)]
|
307
|
+
end
|
308
|
+
|
309
|
+
def serialize_options(opts, method)
|
310
|
+
[flags_for_method(opts, method), params_for_method(opts, method)].flatten.compact
|
311
|
+
end
|
312
|
+
|
313
|
+
def flags_for_method(opts, method)
|
314
|
+
OPTIONS_FLAGS[method].to_a.map do |key|
|
157
315
|
key.to_s.upcase if opts[key]
|
158
|
-
end.compact
|
159
|
-
|
316
|
+
end.compact
|
317
|
+
end
|
318
|
+
|
319
|
+
def params_for_method(opts, method)
|
320
|
+
OPTIONS_PARAMS[method].to_a.map do |key|
|
160
321
|
[key.to_s.upcase, *opts[key]] unless opts[key].nil?
|
161
322
|
end.compact
|
162
323
|
end
|
163
324
|
|
164
|
-
def
|
165
|
-
return
|
325
|
+
def build_docs(results, opts = {})
|
326
|
+
return [] if results.nil? || results[0] == 0
|
166
327
|
results.shift
|
167
|
-
|
168
|
-
|
169
|
-
|
328
|
+
score_offset = opts[:withscores] ? 1 : 0
|
329
|
+
content_offset = opts[:nocontent] ? 0 : 1
|
330
|
+
rows_per_doc = 1 + content_offset + score_offset
|
331
|
+
nr_of_docs = results.size / rows_per_doc
|
170
332
|
(0..nr_of_docs-1).map do |n|
|
171
|
-
doc = Hash[*results[rows_per_doc * n +
|
172
|
-
doc['score'] = results[rows_per_doc * n +
|
333
|
+
doc = opts[:nocontent] ? {} : Hash[*results[rows_per_doc * n + content_offset + score_offset]]
|
334
|
+
doc['score'] = results[rows_per_doc * n + score_offset] if opts[:withscores]
|
173
335
|
doc['id'] = results[rows_per_doc * n]
|
174
336
|
doc
|
175
337
|
end
|
176
338
|
end
|
339
|
+
|
340
|
+
def valid_command?(command)
|
341
|
+
%w(FT.CREATE FT.ADD FT.ADDHASH FT.SEARCH FT.DEL FT.DROP FT.GET FT.MGET
|
342
|
+
FT.SUGADD FT.SUGGET FT.SUGDEL FT.SUGLEN FT.SYNADD FT.SYNUPDATE FT.SYNDUMP
|
343
|
+
FT.INFO FT.AGGREGATE FT.EXPLAIN FT.TAGVALS).include?(command)
|
344
|
+
end
|
177
345
|
end
|
data/lib/redisearch/version.rb
CHANGED
data/redisearch-rb.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
RediSearch is a Redis powered search engine, developed by RedisLabs. http://redisearch.io/"
|
13
13
|
spec.homepage = "https://github.com/vruizext/redisearch-rb"
|
14
14
|
spec.license = "MIT"
|
15
|
-
|
15
|
+
spec.required_ruby_version = '> 2.4.0'
|
16
16
|
spec.files = `git ls-files`.split("\n")
|
17
17
|
spec.test_files = `git ls-files -- {test}/*`.split("\n")
|
18
18
|
end
|
data/test/redisearch_test.rb
CHANGED
@@ -10,6 +10,7 @@ class RediSearchTest < Minitest::Test
|
|
10
10
|
@redisearch_client = RediSearch.new('test_idx', @redis_client)
|
11
11
|
@schema = ['title', 'TEXT', 'WEIGHT', '2.0',
|
12
12
|
'director', 'TEXT', 'WEIGHT', '1.0',
|
13
|
+
'genre', 'TAG',
|
13
14
|
'year', 'NUMERIC', 'SORTABLE']
|
14
15
|
|
15
16
|
end
|
@@ -36,8 +37,19 @@ class RediSearchTest < Minitest::Test
|
|
36
37
|
|
37
38
|
def test_drop_idx
|
38
39
|
assert(@redisearch_client.create_index(@schema))
|
39
|
-
|
40
|
+
doc = ['title', 'Lost in translation', 'director', 'Sofia Coppola', 'year', '2004']
|
41
|
+
@redisearch_client.add_doc('id_1', doc)
|
42
|
+
@redisearch_client.drop_index
|
40
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?)
|
41
53
|
end
|
42
54
|
|
43
55
|
def test_add_doc
|
@@ -72,6 +84,36 @@ class RediSearchTest < Minitest::Test
|
|
72
84
|
assert_includes(search_result.to_s, 'Ex Machina')
|
73
85
|
end
|
74
86
|
|
87
|
+
def test_add_hash
|
88
|
+
assert(@redisearch_client.create_index(@schema))
|
89
|
+
doc = ['title', 'Lost in translation', 'director', 'Sofia Coppola', 'year', '2004']
|
90
|
+
@redis_client.hmset('id_1', *doc)
|
91
|
+
assert(@redisearch_client.add_hash('id_1'))
|
92
|
+
assert_includes(@redis_client.call(['FT.SEARCH', 'test_idx', '@title:lost']).to_s, 'Lost in translation')
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_get_by_id
|
96
|
+
assert(@redisearch_client.create_index(@schema))
|
97
|
+
docs = [['id_1', ['title', 'Lost in translation', 'director', 'Sofia Coppola', 'year', '2004']],
|
98
|
+
['id_2', ['title', 'Ex Machina', 'director', 'Alex Garland', 'year', '2014']]]
|
99
|
+
assert(@redisearch_client.add_docs(docs))
|
100
|
+
doc = @redisearch_client.get_by_id('id_1')
|
101
|
+
assert_equal('id_1', doc['id'])
|
102
|
+
assert_equal('Lost in translation', doc['title'])
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_get_by_ids
|
106
|
+
assert(@redisearch_client.create_index(@schema))
|
107
|
+
docs = [['id_1', ['title', 'Lost in translation', 'director', 'Sofia Coppola', 'year', '2004']],
|
108
|
+
['id_2', ['title', 'Ex Machina', 'director', 'Alex Garland', 'year', '2014']]]
|
109
|
+
assert(@redisearch_client.add_docs(docs))
|
110
|
+
docs = @redisearch_client.get_by_ids(['id_1', 'id_2'])
|
111
|
+
assert_equal('id_1', docs[0]['id'])
|
112
|
+
assert_equal('Lost in translation', docs[0]['title'])
|
113
|
+
assert_equal('id_2', docs[1]['id'])
|
114
|
+
assert_equal('Ex Machina', docs[1]['title'])
|
115
|
+
end
|
116
|
+
|
75
117
|
def test_search_simple_query
|
76
118
|
assert(@redisearch_client.create_index(@schema))
|
77
119
|
docs = [['id_1', ['title', 'Lost in translation', 'director', 'Sofia Coppola', 'year', '2004']],
|
@@ -82,6 +124,7 @@ class RediSearchTest < Minitest::Test
|
|
82
124
|
assert matches.any? { |doc| 'Lost in translation' == doc['title'] }
|
83
125
|
assert matches.any? { |doc| 'Ex Machina' == doc['title'] }
|
84
126
|
matches.each { |doc| assert doc['score'].to_i > 0 }
|
127
|
+
assert_equal([], @redisearch_client.search('foobarwozzz'))
|
85
128
|
end
|
86
129
|
|
87
130
|
def test_search_field_selector
|
@@ -146,6 +189,40 @@ class RediSearchTest < Minitest::Test
|
|
146
189
|
assert_equal 'id_2', matches[0]['id']
|
147
190
|
end
|
148
191
|
|
192
|
+
def test_search_summarize
|
193
|
+
assert(@redisearch_client.create_index(@schema))
|
194
|
+
long_director = 'Steven ' * 80 + 'Sofia Coppola' + ' ' + 'Steven ' * 80
|
195
|
+
docs = [['id_1', ['title', 'Lost in translation', 'director', long_director, 'year', '2004']],
|
196
|
+
['id_2', ['title', 'Ex Machina', 'director', 'Alex Garland', 'year', '2014']],
|
197
|
+
['id_3', ['title', 'Terminator', 'director', 'James Cameron', 'year', '1984']],
|
198
|
+
['id_4', ['title', 'Blade Runner', 'director', 'Ridley Scott', 'year', '1982']]]
|
199
|
+
assert(@redisearch_client.add_docs(docs))
|
200
|
+
matches = @redisearch_client.search('Sofia', summarize: false)
|
201
|
+
assert_equal 1, matches.count
|
202
|
+
assert_equal long_director.size, matches[0]['director'].size
|
203
|
+
|
204
|
+
matches = @redisearch_client.search('Sofia', summarize: true)
|
205
|
+
assert_equal 1, matches.count
|
206
|
+
assert_in_epsilon 122, matches[0]['director'].size, 20
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_search_highlight
|
210
|
+
assert(@redisearch_client.create_index(@schema))
|
211
|
+
long_director = 'Steven ' * 80 + 'Sofia Coppola' + ' ' + 'Steven ' * 80
|
212
|
+
docs = [['id_1', ['title', 'Lost in translation', 'director', long_director, 'year', '2004']],
|
213
|
+
['id_2', ['title', 'Ex Machina', 'director', 'Alex Garland', 'year', '2014']],
|
214
|
+
['id_3', ['title', 'Terminator', 'director', 'James Cameron', 'year', '1984']],
|
215
|
+
['id_4', ['title', 'Blade Runner', 'director', 'Ridley Scott', 'year', '1982']]]
|
216
|
+
assert(@redisearch_client.add_docs(docs))
|
217
|
+
matches = @redisearch_client.search('Sofia', highlight: false)
|
218
|
+
assert_equal 1, matches.count
|
219
|
+
assert_match(/^[^<]+$/, matches[0]['director'])
|
220
|
+
|
221
|
+
matches = @redisearch_client.search('Sofia', highlight: true)
|
222
|
+
assert_equal 1, matches.count
|
223
|
+
assert_match(/<b>/, matches[0]['director'])
|
224
|
+
end
|
225
|
+
|
149
226
|
def test_index_info
|
150
227
|
assert(@redisearch_client.create_index(@schema))
|
151
228
|
doc = ['id_1', ['title', 'Lost in translation', 'director', 'Sofia Coppola', 'year', '2004']]
|
@@ -156,4 +233,36 @@ class RediSearchTest < Minitest::Test
|
|
156
233
|
assert_equal 1, info['max_doc_id'].to_i
|
157
234
|
assert_equal 5, info['num_terms'].to_i
|
158
235
|
end
|
236
|
+
|
237
|
+
def test_delete_by_id
|
238
|
+
assert(@redisearch_client.create_index(@schema))
|
239
|
+
docs = [['id_1', ['title', 'Lost in translation', 'director', 'Sofia Coppola', 'year', '2004']],
|
240
|
+
['id_2', ['title', 'Ex Machina', 'director', 'Alex Garland', 'year', '2014']],
|
241
|
+
['id_3', ['title', 'Terminator', 'director', 'James Cameron', 'year', '1984']],
|
242
|
+
['id_4', ['title', 'Blade Runner', 'director', 'Ridley Scott', 'year', '1982']]]
|
243
|
+
assert(@redisearch_client.add_docs(docs))
|
244
|
+
assert_equal(1, @redisearch_client.delete_by_id('id_1', { dd: false }))
|
245
|
+
assert_equal(1, @redisearch_client.delete_by_id('id_2', { dd: true }))
|
246
|
+
assert_empty(@redisearch_client.search('@title:lost'))
|
247
|
+
assert(@redisearch_client.get_by_id('id_1').any?)
|
248
|
+
assert(@redisearch_client.get_by_id('id_2').empty?)
|
249
|
+
assert(@redis_client.del('id_1'))
|
250
|
+
assert(@redisearch_client.get_by_id('id_1').empty?)
|
251
|
+
end
|
252
|
+
|
253
|
+
def test_auto_complete_suggestions
|
254
|
+
dict_name = 'test_suggestions'
|
255
|
+
@redisearch_client.autocomplete_add(dict_name, 'foobar', 2.0)
|
256
|
+
@redisearch_client.autocomplete_add(dict_name, 'foowoz', 1.0)
|
257
|
+
@redisearch_client.autocomplete_add(dict_name, 'foomeh', 0.85)
|
258
|
+
@redisearch_client.autocomplete_add(dict_name, 'woowoz', 1.0)
|
259
|
+
assert_equal(4, @redisearch_client.autocomplete_len(dict_name))
|
260
|
+
results = @redisearch_client.autocomplete_get(dict_name, 'foo')
|
261
|
+
assert_equal(3, results.count)
|
262
|
+
assert_equal('foobar', results.first)
|
263
|
+
assert_equal(4, @redisearch_client.autocomplete_get(dict_name, 'foo', { fuzzy: true }).count)
|
264
|
+
assert @redisearch_client.autocomplete_del(dict_name, 'foobar').to_i > 0
|
265
|
+
refute @redisearch_client.autocomplete_del(dict_name, 'foozzz').to_i > 0
|
266
|
+
assert_equal('foowoz', @redisearch_client.autocomplete_get(dict_name, 'foo').first)
|
267
|
+
end
|
159
268
|
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:
|
4
|
+
version: 1.1.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:
|
11
|
+
date: 2020-11-15 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |-
|
14
14
|
A simple Ruby client library for RediSearch.
|
@@ -43,17 +43,16 @@ require_paths:
|
|
43
43
|
- lib
|
44
44
|
required_ruby_version: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
- - "
|
46
|
+
- - ">"
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version:
|
48
|
+
version: 2.4.0
|
49
49
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
51
|
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '0'
|
54
54
|
requirements: []
|
55
|
-
|
56
|
-
rubygems_version: 2.6.8
|
55
|
+
rubygems_version: 3.0.3
|
57
56
|
signing_key:
|
58
57
|
specification_version: 4
|
59
58
|
summary: A simple Ruby client library for RediSearch
|