redi_search_rails 0.1.2 → 0.1.3

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: 53fd6d815f84aaacba7a129c7e5bd574124b1937
4
- data.tar.gz: 6e00184db536350ce5e3d30e9c25f182b7fb8ea1
3
+ metadata.gz: 8bac86f5f0acbceaf4952a150531ddedc0c59e72
4
+ data.tar.gz: 1dbe06379bff95b1ef9d81e328871e808f693a47
5
5
  SHA512:
6
- metadata.gz: 914e17adff80e11950a6b63af883ef90b9e1bd97f2884e07b6ceea8d3d7f177d46e5411dcee5c879100d2a353943b5b506fab71dc4b411d362400060f2e6130b
7
- data.tar.gz: 730fb0ee494f8c79c7d5ffd6f28edc59b720737f5ae1d8855c8e522487ccb1816e24011030e1250a03055f496709965ffeadae642d3db355081abb3b9f638a0c
6
+ metadata.gz: fe54ebbd8202130643d8cedc40158faf6edd830f7ad524c4fdbf7864c734ca4f8738559cfee67a65580387fd4501052396337e654195f9722c1621f3f721ea19
7
+ data.tar.gz: a0c895f524468aa0f5777eff292f82512f148cbe7db3488fd951dd639010d559b28e5e3814e5e9d83d1856048ed4a149b4e15387b29237e8646b69f693aeb9fa
@@ -0,0 +1,37 @@
1
+ # Change Log
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](http://keepachangelog.com/)
5
+ and this project adheres to [Semantic Versioning](http://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Added
10
+
11
+ ### Changed
12
+
13
+ ### Removed
14
+
15
+ ### Fixed
16
+
17
+ ## 0.1.3 - 2017-05-19
18
+
19
+ ### Added
20
+ - ft_search_format and ft_search_count methods
21
+ - ft_search_format returns array of objects
22
+ - ft_add_hash and ft_del_all methods
23
+ - ft_sug* methods
24
+
25
+ ### Changed
26
+ - ft_search returns raw FT.SEARCH results
27
+ - switched to keyword arguments
28
+ - passing offset and num to FT.SEARCH
29
+
30
+ ## 0.1.2 - 2017-04-23
31
+
32
+ ### Fixed
33
+ - variable scope with redi_search_schema
34
+
35
+ ### Changed
36
+ - changed ft_search output to be an array of hashes
37
+ - changed dependencies to > Rails 4.2.8
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # RediSearchRails
2
2
 
3
+ [![Code Climate](https://codeclimate.com/github/dmitrypol/redi_search_rails.svg)](https://codeclimate.com/github/dmitrypol/redi_search_rails)
4
+ [![Inline docs](http://inch-ci.org/github/dmitrypol/redi_search_rails.svg?branch=master)](http://inch-ci.org/github/dmitrypol/redi_search_rails)
5
+ [![Gem Version](https://badge.fury.io/rb/redi_search_rails.svg)](http://badge.fury.io/rb/redi_search_rails)
6
+
3
7
  This gems simplifies integration with RediSearch module (http://redisearch.io/). This software is of Alpha quality and is provided with no warranties whatsoever. Additionally RediSearch is still not officially released so major features may change.
4
8
 
5
9
  ## Installation
@@ -42,7 +46,11 @@ User.ft_add_all
42
46
  # => or you can do it for specific record
43
47
  User.ft_add(User.where(id: 1))
44
48
  # => search
45
- User.ft_search('keyword here')
49
+ User.ft_search(keyword: 'keyword here', offset: 0, num: 10)
50
+ # => output
51
+ [1, "gid://application_name/User/unique_id", ["name", "Bob", "age", "100"]]
52
+ # => format results as array of objects
53
+ User.ft_search_format(keyword: 'keyword here', offset: 0, num: 10)
46
54
  # => output
47
55
  [{"id": "gid://application_name/User/unique_id", "name": "Bob", "age": "100"}, {...}]
48
56
  ```
@@ -63,9 +71,9 @@ Testing this gem requires having local Redis with RediSearch module. This makes
63
71
 
64
72
  * ActiveModel callbacks to index records on saving and remove from Redis on delete
65
73
  * Rake tasks to manage indexes
66
- * Support additional RediSearch API calls (SUGGADD, SUGGET, ...)
67
74
  * Support configuring SCORE, WEIGHT and other options
68
75
  * Support indexing fields from related models (index group name if user belongs to a group)
76
+ * Support GEO filters
69
77
  * Stopwords configuration
70
78
  * Minimum keyword length to index
71
79
  * Configurable method for doc_id, not just default to_global_id
@@ -1,5 +1,6 @@
1
1
  require "redi_search_rails/version"
2
2
  require "active_support/concern"
3
+ require "ostruct"
3
4
 
4
5
  module RediSearchRails
5
6
  extend ActiveSupport::Concern
@@ -24,15 +25,37 @@ module RediSearchRails
24
25
  # search the index for specific keyword(s)
25
26
  #
26
27
  # @param keyword [String] 'some keyword'
27
- # @return [Array] [{"id": "gid://application_name/User/unique_id", "name": "Bob", "age": "100"}, ...]
28
+ # @param offset [Integer] default 0
29
+ # @param keyword [Integer] default 10
30
+ # @return [Array] [1, "gid://application_name/User/unique_id", ["name", "Bob", "age", "100"]]
28
31
  # @raise [RuntimeError]
29
- def ft_search keyword
30
- results = REDI_SEARCH.call('FT.SEARCH', @index_name, keyword,
31
- #'LIMIT', 0, 1000,
32
- #'NOCONTENT', #'VERBATIM', #'WITHSCORES', #'NOSTOPWORDS', #'WITHPAYLOADS',
33
- )
34
- # => [1, "gid://application_name/User/unique_id", ["name", "Bob", "age", "100"]]
35
- # => transform into array of hashes
32
+ def ft_search keyword:, offset: 0, num: 10, filter: {}
33
+ if filter[:numeric_field].blank?
34
+ results = REDI_SEARCH.call('FT.SEARCH', @index_name, keyword.strip,
35
+ 'LIMIT', offset, num)
36
+ else
37
+ results = REDI_SEARCH.call('FT.SEARCH', @index_name, keyword.strip,
38
+ 'LIMIT', offset, num,
39
+ 'FILTER', filter[:numeric_field], filter[:min], filter[:max]
40
+ )
41
+ end
42
+ #'NOCONTENT', 'VERBATIM', 'WITHSCORES', 'NOSTOPWORDS', 'WITHPAYLOADS',
43
+ #'INKEYS', 'INFIELDS', 'SLOP', 'LANGUAGE', 'EXPANDER', 'SCORER', 'PAYLOAD', 'SORTBY'
44
+ return results
45
+ rescue Exception => e
46
+ Rails.logger.error e if defined? Rails
47
+ return e.message
48
+ end
49
+
50
+ # search the index for specific keyword(s) and return output as array of objects
51
+ #
52
+ # @param keyword [String] 'some keyword'
53
+ # @param offset [Integer] default 0
54
+ # @param keyword [Integer] default 10
55
+ # @return [Array] [{"id": "gid://application_name/User/unique_id", "name": "Bob", "age": "100"}, ...]
56
+ def ft_search_format(args)
57
+ results = ft_search(args)
58
+ # => transform into array of objects
36
59
  output = []
37
60
  results.shift # => remove count
38
61
  results.each_slice(2) do |result|
@@ -40,7 +63,8 @@ module RediSearchRails
40
63
  result[1].each_slice(2) do |attribute|
41
64
  attributes[attribute[0]] = attribute[1]
42
65
  end
43
- output << {id: result[0]}.merge(attributes)
66
+ hash = {id: result[0]}.merge(attributes)
67
+ output << OpenStruct.new(hash)
44
68
  end
45
69
  return output
46
70
  rescue Exception => e
@@ -48,13 +72,24 @@ module RediSearchRails
48
72
  return e.message
49
73
  end
50
74
 
75
+ # number of records found for keywords
76
+ #
77
+ # @param keyword [Hash] keyword that gets passed to ft_search
78
+ # @return [Integer] number of results matching the search
79
+ def ft_search_count(args)
80
+ ft_search(args).first
81
+ rescue Exception => e
82
+ Rails.logger.error e if defined? Rails
83
+ return e.message
84
+ end
85
+
51
86
  # create index for specific model
52
87
  #
53
88
  # @return [String]
54
89
  def ft_create
55
90
  REDI_SEARCH.call('FT.CREATE', @index_name,
56
- #'NOFIELDS', 'NOSCOREIDX', 'NOOFFSETS',
57
91
  'SCHEMA', @schema
92
+ #'NOFIELDS', 'NOSCOREIDX', 'NOOFFSETS',
58
93
  )
59
94
  ft_optimize
60
95
  rescue Exception => e
@@ -66,7 +101,8 @@ module RediSearchRails
66
101
  #
67
102
  # @return [String]
68
103
  def ft_add_all
69
- @model.all.each {|record| ft_add(record) }
104
+ @model.all.each {|record| ft_add(record: record) }
105
+ ft_optimize
70
106
  rescue Exception => e
71
107
  Rails.logger.error e if defined? Rails
72
108
  return e.message
@@ -76,24 +112,46 @@ module RediSearchRails
76
112
  #
77
113
  # @param record [Object] Object to index
78
114
  # @return [String]
79
- def ft_add record
115
+ def ft_add record:
80
116
  fields = []
81
117
  @fields.each { |field| fields.push(field, record.send(field)) }
82
118
  REDI_SEARCH.call('FT.ADD', @index_name, record.to_global_id.to_s, @score,
83
119
  'REPLACE',
84
- #'NOSAVE', 'PAYLOAD', record.name,
85
120
  'FIELDS', fields
121
+ #'NOSAVE', 'PAYLOAD', 'LANGUAGE'
86
122
  )
87
123
  rescue Exception => e
88
124
  Rails.logger.error e if defined? Rails
89
125
  return e.message
90
126
  end
91
127
 
128
+ # index existing Hash
129
+ #
130
+ # @param record [string] key of existing HASH key in Redis that will hold the fields the index needs.
131
+ # @return [String]
132
+ def ft_addhash redis_key:
133
+ REDI_SEARCH.call('FT.ADDHASH', @index_name, redis_key, @score, 'REPLACE')
134
+ rescue Exception => e
135
+ Rails.logger.error e if defined? Rails
136
+ return e.message
137
+ end
138
+
139
+ # delete all records in specific model
140
+ #
141
+ # @return [String]
142
+ def ft_del_all
143
+ @model.all.each {|record| ft_del(record: record) }
144
+ ft_optimize
145
+ rescue Exception => e
146
+ Rails.logger.error e if defined? Rails
147
+ return e.message
148
+ end
149
+
92
150
  # delete specific document from index
93
151
  #
94
152
  # @param record [Object] Object to delete
95
153
  # @return [String]
96
- def ft_del record
154
+ def ft_del record:
97
155
  doc_id = record.to_global_id
98
156
  REDI_SEARCH.call('FT.DEL', @index_name, doc_id)
99
157
  rescue Exception => e
@@ -131,6 +189,82 @@ module RediSearchRails
131
189
  return e.message
132
190
  end
133
191
 
192
+ # add all values for a model attribute to autocomplete
193
+ #
194
+ # @param attribute [String] - name, email, etc
195
+ def ft_sugadd_all (attribute:)
196
+ @model.all.each {|record| ft_sugadd(record: record, attribute: attribute) }
197
+ rescue Exception => e
198
+ Rails.logger.error e if defined? Rails
199
+ return e.message
200
+ end
201
+
202
+ # add string to autocomplete dictionary
203
+ #
204
+ # @param record [Object] object
205
+ # @param attribute [String] - name, email, etc
206
+ # @param score [Integer] - score
207
+ # @return [Integer] - current size of the dictionary
208
+ def ft_sugadd (record:, attribute:, score: 1)
209
+ # => combine model with attribute to create unique key like user_name
210
+ key = "#{@model.to_s}:#{attribute}"
211
+ string = record.send(attribute)
212
+ REDI_SEARCH.call('FT.SUGADD', key, string, score)
213
+ # => INCR
214
+ rescue Exception => e
215
+ Rails.logger.error e if defined? Rails
216
+ return e.message
217
+ end
218
+
219
+ # query dictionary for suggestion
220
+ #
221
+ # @param attribute [String] - name, email, etc
222
+ # @param prefix [String] - prefix to query dictionary
223
+ # @return [Array] - suggestions for prefix
224
+ def ft_sugget (attribute:, prefix:)
225
+ key = "#{@model}:#{attribute}"
226
+ REDI_SEARCH.call('FT.SUGGET', key, prefix)
227
+ rescue Exception => e
228
+ Rails.logger.error e if defined? Rails
229
+ return e.message
230
+ end
231
+
232
+ # delete all values for a model attribute to autocomplete
233
+ #
234
+ # @param attribute [String] - name, email, etc
235
+ def ft_sugdel_all (attribute:)
236
+ @model.all.each {|record| ft_sugdel(record: record, attribute: attribute) }
237
+ rescue Exception => e
238
+ Rails.logger.error e if defined? Rails
239
+ return e.message
240
+ end
241
+
242
+ # delete a string from a suggestion index.
243
+ #
244
+ # @param attribute [String]
245
+ # @param value [String] - string to delete
246
+ # @return [Integer] - 1 if found, 0 if not
247
+ def ft_sugdel (record:, attribute:)
248
+ key = "#{@model}:#{attribute}"
249
+ string = record.send(attribute)
250
+ REDI_SEARCH.call('FT.SUGDEL', key, string)
251
+ rescue Exception => e
252
+ Rails.logger.error e if defined? Rails
253
+ return e.message
254
+ end
255
+
256
+ # size of dictionary
257
+ #
258
+ # @param attribute [String]
259
+ # @return [Integer] - number of possible suggestions
260
+ def ft_suglen (attribute:)
261
+ key = "#{@model}:#{attribute}"
262
+ REDI_SEARCH.call('FT.SUGLEN', key)
263
+ rescue Exception => e
264
+ Rails.logger.error e if defined? Rails
265
+ return e.message
266
+ end
267
+
134
268
  end
135
269
 
136
270
  end
@@ -1,3 +1,3 @@
1
1
  module RediSearchRails
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redi_search_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Polyakovsky
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-04-23 00:00:00.000000000 Z
11
+ date: 2017-05-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -118,6 +118,7 @@ files:
118
118
  - ".gitignore"
119
119
  - ".rspec"
120
120
  - ".travis.yml"
121
+ - CHANGELOG.md
121
122
  - CODE_OF_CONDUCT.md
122
123
  - Gemfile
123
124
  - LICENSE.txt
@@ -149,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
150
  version: '0'
150
151
  requirements: []
151
152
  rubyforge_project:
152
- rubygems_version: 2.5.2
153
+ rubygems_version: 2.6.11
153
154
  signing_key:
154
155
  specification_version: 4
155
156
  summary: Simplifies integration with http://redisearch.io/.