redisearch-rb 0.1.7 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![Gem Version](https://badge.fury.io/rb/redisearch-rb.svg)](https://badge.fury.io/rb/redisearch-rb)
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/redisearch-rb.svg)](https://badge.fury.io/rb/redisearch-rb)
|
2
|
+
[![travis-ci](https://travis-ci.org/vruizext/redisearch-rb.svg?branch=master)](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
|