redisearch-rb 0.1.8 → 0.2.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
2
  SHA1:
3
- metadata.gz: '01498d9fe5aeb06096b245b7045bc558d66edfb7'
4
- data.tar.gz: 659c1c312134ec3acba593feaa8ab1597d21611f
3
+ metadata.gz: 1184cc3821b5bee90dcb18d41ad3b6ea9a93b750
4
+ data.tar.gz: 11ac50692f0cfc629e4283baa588e20cba18d854
5
5
  SHA512:
6
- metadata.gz: a672c99130602f2461208d94f50e659d77f4e9b38b9b2149ed5e28665b1a5a3283fe6217a4322cdfba4af990849f09bd51fa2b9791f889bdea570458c3d86205
7
- data.tar.gz: a283066a539ead576d84dd83265f911d090fbc86b340a1f9b26d033305c5943fece67a7fbd51374c59c2ae86984752341ae39a2d551dee7fbbb29d814ceb1baa
6
+ metadata.gz: c0e51193c7b3d7989f973472e5cdc4335f3ed428fa73c56ddbefa271023c053c85107639fc6f05bf0dee00820e4eb729cea3782ab7f0d62cb197d3587e7da624
7
+ data.tar.gz: ab05d37fe0469216d05dff6fa0223dd7530832b0a945226352a67a270a2e5239376111418793b7ccff8c2245b68916d46cc71fcba486c8a3f9b48c96d9b30904
@@ -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.0.4
16
18
  - make all
17
- - ls -la *.so
18
19
  - cd ..
20
+
data/Gemfile CHANGED
@@ -2,10 +2,11 @@ source 'https://rubygems.org'
2
2
 
3
3
  ruby '2.4.1'
4
4
 
5
- gem 'redis', '~> 4.0.0.rc1'
5
+ gem 'redis', '~> 4.0.1'
6
6
 
7
7
  group :development, :test do
8
8
  gem 'dotenv'
9
+ gem 'rake'
9
10
  gem 'subprocess'
10
11
  gem 'minitest', '~> 5.0'
11
12
  end
data/README.md CHANGED
@@ -10,8 +10,8 @@ http://redisearch.io/
10
10
 
11
11
  First of all, you need to install RediSearch, if you haven't yet:
12
12
 
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/
13
+ 1. Install Redis 4.0.1 or highger https://github.com/antirez/redis/releases/tag/4.0.1
14
+ 2. Install RediSearch 1.0.4 or higher http://redisearch.io/Quick_Start/
15
15
  3. Edit your `redis.conf` file and add a `loadmodule` directive to load the RediSearch module built in the step 2.
16
16
 
17
17
  To install this gem, add this line to your application's Gemfile:
@@ -12,12 +12,13 @@ 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]
15
+ CREATE_OPTIONS_FLAGS = [:nooffsets, :nofreqs, :nohl, :nofields]
16
+ ADD_OPTIONS_FLAGS = [:nosave, :replace, :partial]
17
17
  SEARCH_OPTIONS_FLAGS = [:nocontent, :verbatim, :nostopwords, :withscores, :withsortkeys]
18
18
 
19
19
  # Params options need an array with the values for the option
20
20
  # { limit: ['0', '50'], sortby: ['year', 'desc'], return: ['2', 'title', 'year'] }
21
+ CREATE_OPTIONS_PARAMS = [:stopwords]
21
22
  ADD_OPTIONS_PARAMS = [:language]
22
23
  SEARCH_OPTIONS_PARAMS = [:filter, :return, :infields, :inkeys, :slop, :scorer, :sortby, :limit]
23
24
 
@@ -36,11 +37,11 @@ class RediSearch
36
37
 
37
38
  # Create new index with the given `schema`
38
39
  # @param [Array] schema
39
- #
40
+ # @param [Hash] opts options
40
41
  # Example:
41
42
  #
42
43
  # redisearch = RediSearch.new('my_idx')
43
- # redisearch.create_idx(['title', 'TEXT', 'WEIGHT', '2.0', 'director', 'TEXT', 'WEIGHT', '1.0'])
44
+ # redisearch.create_idx(['title', 'TEXT', 'WEIGHT', '2.0', 'director', 'TEXT', 'WEIGHT', '1.0', 'year', 'NUMERIC', 'SORTABLE'])
44
45
  #
45
46
  # See http://redisearch.io/Commands/#ftcreate
46
47
  #
@@ -87,22 +88,25 @@ class RediSearch
87
88
  # See http://redisearch.io/Commands/#ftadd
88
89
  # @return [String] "OK" on success
89
90
  def add_docs(docs, opts = {})
90
- multi { docs.each { |doc_id, fields| @redis.call(ft_add(doc_id, fields, opts)) } }
91
+ docs.each { |doc_id, fields| call(ft_add(doc_id, fields, opts))}
91
92
  end
92
93
 
93
94
  # Search the index with the given `query`
94
95
  # @param [String] query text query, see syntax here http://redisearch.io/Query_Syntax/
95
96
  # @param [Hash] opts options for the query
96
97
  #
97
- #@return [Array] documents matching the query
98
+ # @return [Array] documents matching the query
98
99
  def search(query, opts = {})
99
- results_to_hash(call(ft_search(query, opts)), opts)
100
+ build_docs(call(ft_search(query, opts)), opts)
100
101
  end
101
102
 
102
103
  # Fetch a document by id
103
- def get_by_id(id)
104
- Hash[with_reconnect { @redis.hgetall(id) } || []]
105
- .tap { |doc| doc['id'] = id unless doc.empty? }
104
+ #
105
+ # @param [String] doc_id id assigned to the document
106
+ # @return [Hash] Hash containing document
107
+ def get_by_id(doc_id)
108
+ Hash[*call(ft_get(doc_id))]
109
+ .tap { |doc| doc['id'] = doc_id unless doc.empty? } || {}
106
110
  end
107
111
 
108
112
  # Return information and statistics on the index.
@@ -112,6 +116,36 @@ class RediSearch
112
116
  Hash[*call(ft_info)]
113
117
  end
114
118
 
119
+ # Deletes a document from the index
120
+ #
121
+ # See http://redisearch.io/Commands/#ftdel
122
+ #
123
+ # @param [String] doc_id id assigned to the document
124
+ # @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))
127
+ end
128
+
129
+ # Deletes all documents returned by the query
130
+ #
131
+ # @param [String] query in the same format as used in `search`
132
+ # @param [Hash] opts options for the query, same as in `search`
133
+ # @return [int] count of documents deleted
134
+ def delete_by_query(query, opts = {})
135
+ call(ft_search(query, opts.merge(nocontent: true)))[1..-1].map do |doc_id|
136
+ call(ft_del(doc_id))
137
+ end.sum
138
+ end
139
+
140
+ # Execute arbitrary command. Only RediSearch commands are allowed
141
+ #
142
+ # @param [Array] command
143
+ # @return [mixed] The output returned by redis
144
+ def call(command)
145
+ raise ArgumentError.new("#{command&.first} is not a RediSearch command") unless valid_command?(command)
146
+ @redis.with_reconnect { @redis.call(command.flatten) }
147
+ end
148
+
115
149
  private
116
150
 
117
151
  def with_reconnect
@@ -122,10 +156,6 @@ class RediSearch
122
156
  @redis.with_reconnect { @redis.multi { yield } }
123
157
  end
124
158
 
125
- def call(command)
126
- @redis.with_reconnect { @redis.call(command) }
127
- end
128
-
129
159
  def add(doc_id, fields)
130
160
  @redis.call(ft_add(doc_id, fields))
131
161
  end
@@ -146,10 +176,26 @@ class RediSearch
146
176
  ['FT.ADD', @idx_name , doc_id, weight || DEFAULT_WEIGHT, *add_options(opts), 'FIELDS', *fields]
147
177
  end
148
178
 
179
+ def ft_add_hash(doc_id, opts = {}, weight = nil)
180
+ ['FT.ADDHASH', @idx_name , doc_id, weight || DEFAULT_WEIGHT, *add_options(opts)]
181
+ end
182
+
149
183
  def ft_search(query, opts)
150
184
  ['FT.SEARCH', @idx_name, *query, *search_options(opts)].flatten
151
185
  end
152
186
 
187
+ def ft_get(doc_id)
188
+ ['FT.GET', @idx_name , doc_id]
189
+ end
190
+
191
+ def ft_mget(doc_ids)
192
+ ['FT.MGET', @idx_name , *doc_ids]
193
+ end
194
+
195
+ def ft_del(doc_id)
196
+ ['FT.DEL', @idx_name , doc_id]
197
+ end
198
+
153
199
  def create_options(opts = {})
154
200
  build_options(opts, CREATE_OPTIONS_FLAGS, [])
155
201
  end
@@ -166,22 +212,27 @@ class RediSearch
166
212
  flags_keys.map do |key|
167
213
  key.to_s.upcase if opts[key]
168
214
  end.compact +
169
- params_keys.map do |key|
170
- [key.to_s.upcase, *opts[key]] unless opts[key].nil?
171
- end.compact
215
+ params_keys.map do |key|
216
+ [key.to_s.upcase, *opts[key]] unless opts[key].nil?
217
+ end.compact
172
218
  end
173
219
 
174
- def results_to_hash(results, opts = {})
220
+ def build_docs(results, opts = {})
175
221
  return {} if results.nil? || results[0] == 0
176
222
  results.shift
177
- offset = opts[:withscores] ? 1 : 0
178
- rows_per_doc = 2 + offset
179
- nr_of_docs = results.size / (2 + offset)
223
+ score_offset = opts[:withscores] ? 1 : 0
224
+ content_offset = score_offset + 1
225
+ rows_per_doc = 1 + content_offset
226
+ nr_of_docs = results.size / rows_per_doc
180
227
  (0..nr_of_docs-1).map do |n|
181
- doc = Hash[*results[rows_per_doc * n + 1 + offset]]
182
- doc['score'] = results[rows_per_doc * n + offset] if offset > 0
228
+ doc = opts[:nocontent] ? {} : Hash[*results[rows_per_doc * n + content_offset]]
229
+ doc['score'] = results[rows_per_doc * n + score_offset] if opts[:withscores]
183
230
  doc['id'] = results[rows_per_doc * n]
184
231
  doc
185
232
  end
186
233
  end
234
+
235
+ def valid_command?(command)
236
+ command[0] =~ /^ft\./i
237
+ end
187
238
  end
@@ -1,3 +1,3 @@
1
1
  class RediSearch
2
- VERSION = '0.1.8'
2
+ VERSION = '0.2.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
@@ -166,4 +167,18 @@ class RediSearchTest < Minitest::Test
166
167
  assert_equal 1, info['max_doc_id'].to_i
167
168
  assert_equal 5, info['num_terms'].to_i
168
169
  end
170
+
171
+ def test_delete_by_id
172
+ assert(@redisearch_client.create_index(@schema))
173
+ docs = [['id_1', ['title', 'Lost in translation', 'director', 'Sofia Coppola', 'year', '2004']],
174
+ ['id_2', ['title', 'Ex Machina', 'director', 'Alex Garland', 'year', '2014']],
175
+ ['id_3', ['title', 'Terminator', 'director', 'James Cameron', 'year', '1984']],
176
+ ['id_4', ['title', 'Blade Runner', 'director', 'Ridley Scott', 'year', '1982']]]
177
+ assert(@redisearch_client.add_docs(docs))
178
+ assert_equal(1, @redisearch_client.delete_by_id('id_1'))
179
+ assert_empty(@redisearch_client.search('@title:lost'))
180
+ assert(@redisearch_client.get_by_id('id_1').any?)
181
+ assert(@redis_client.del('id_1'))
182
+ assert(@redisearch_client.get_by_id('id_1').empty?)
183
+ end
169
184
  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.8
4
+ version: 0.2.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-09-16 00:00:00.000000000 Z
11
+ date: 2018-01-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |-
14
14
  A simple Ruby client library for RediSearch.
@@ -43,9 +43,9 @@ 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
  - - ">="