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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 989e86efdc440fc616ee1741256c81b829ca69b0
4
- data.tar.gz: 2f2d59a65e355750b045f317dc7e6619d120bb0b
2
+ SHA256:
3
+ metadata.gz: 99d803efbd160ce83d3cf58a50b2e739540f143666dc87f18b04c3ff10766577
4
+ data.tar.gz: d83a8a81049e5b6266130f351d2c82381b12abaf93c1f616e7d602b2503d5abb
5
5
  SHA512:
6
- metadata.gz: 3b61fc7f81b2d86c33142c3c01a3b2b79647b5d40c0f5cfdca094ac9710104c439e153f8c8ab68a29503c97cbedc64a7f440824e02521051f7b0a304a59c25e4
7
- data.tar.gz: 9208b2b791c07ce5a0dc7b700e9cefc99030a255444500a5bc99103a053b6af167baa17a14120cd7111c8b55a6804bb65ad81e393406a6e642a4a28a6f2f0253
6
+ metadata.gz: abf6a993f32a3c93979763b3cf22e72a959fffd3d14c8ccf2fa44031b5f1c65a30ddad8715c1226ff7467f2b3ad4146be3edc806248073ec5e6926f75fc233fe
7
+ data.tar.gz: 524ed525611003f0ef515d2eee40ab4a4fcdef851083fa75b053011c1219187f1c2d1ff22c7d3fb6e456b7c53e6a0af42d12f9f6b32701bd91f0ea9a4d8be568
@@ -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 origin 4.0.1
11
- - git checkout ae43e164d4b09d7753e27bb7cba6f7f4f85326b3
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/src
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
@@ -1,11 +1,11 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- ruby '2.4.1'
4
-
5
- gem 'redis', '~> 4.0.0.rc1'
3
+ ruby '>=2.4.1'
6
4
 
5
+ gem 'redis', '~> 4.0.1'
7
6
  group :development, :test do
8
7
  gem 'dotenv'
8
+ gem 'rake'
9
9
  gem 'subprocess'
10
10
  gem 'minitest', '~> 5.0'
11
11
  end
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) ![travis-ci](https://travis-ci.org/vruizext/redisearch-rb.svg?branch=master)
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',
@@ -12,14 +12,26 @@ class RediSearch
12
12
  #
13
13
  # { verbatim: true, withscores: true, withsortkey: false }
14
14
 
15
- CREATE_OPTIONS_FLAGS = [:nooffsets, :nofreqs, :noscoreidx, :nofields]
16
- ADD_OPTIONS_FLAGS = [:nosave, :replace]
17
- SEARCH_OPTIONS_FLAGS = [:nocontent, :verbatim, :nostopwords, :withscores, :withsortkeys]
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
- ADD_OPTIONS_PARAMS = [:language]
22
- SEARCH_OPTIONS_PARAMS = [:filter, :return, :infields, :inkeys, :slop, :scorer, :sortby, :limit]
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
- multi { docs.each { |doc_id, fields| @redis.call(ft_add(doc_id, fields, opts)) } }
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
- #@return [Array] documents matching the query
126
+ # @return [Array] documents matching the query
98
127
  def search(query, opts = {})
99
- results_to_hash(call(ft_search(query, opts)), opts)
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
- private
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
- def multi
112
- @redis.with_reconnect { @redis.multi { yield } }
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
- @redis.with_reconnect { @redis.call(command) }
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 , *create_options(opts), 'SCHEMA', *schema]
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, *add_options(opts), 'FIELDS', *fields]
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, *search_options(opts)].flatten
270
+ ['FT.SEARCH', @idx_name, *query, *serialize_options(opts, :search)].flatten
141
271
  end
142
272
 
143
- def create_options(opts = {})
144
- build_options(opts, CREATE_OPTIONS_FLAGS, [])
273
+ def ft_get(doc_id)
274
+ ['FT.GET', @idx_name , doc_id]
145
275
  end
146
276
 
147
- def add_options(opts = {})
148
- build_options(opts, ADD_OPTIONS_FLAGS, ADD_OPTIONS_PARAMS)
277
+ def ft_mget(doc_ids)
278
+ ['FT.MGET', @idx_name , *doc_ids]
149
279
  end
150
280
 
151
- def search_options(opts = {})
152
- build_options(opts, SEARCH_OPTIONS_FLAGS, SEARCH_OPTIONS_PARAMS)
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 build_options(opts, flags_keys, params_keys)
156
- flags_keys.map do |key|
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
- params_keys.map do |key|
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 results_to_hash(results, opts = {})
165
- return {} if results.nil? || results[0] == 0
325
+ def build_docs(results, opts = {})
326
+ return [] if results.nil? || results[0] == 0
166
327
  results.shift
167
- offset = opts[:withscores] ? 1 : 0
168
- rows_per_doc = 2 + offset
169
- nr_of_docs = results.size / (2 + offset)
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 + 1 + offset]]
172
- doc['score'] = results[rows_per_doc * n + offset] if offset > 0
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
@@ -1,3 +1,3 @@
1
1
  class RediSearch
2
- VERSION = '0.1.7'
2
+ VERSION = '1.1.0'
3
3
  end
@@ -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
@@ -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
- assert(@redisearch_client.drop_index)
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: 0.1.7
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: 2017-08-08 00:00:00.000000000 Z
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: '0'
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
- rubyforge_project:
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