redisearch-rb 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 223cca42fa38796e6abd0b5780b589dc2d0536bb
4
- data.tar.gz: ee5aa7e8e327dd933cf8079d02fdbca425abb3aa
3
+ metadata.gz: 38fdd275f958d4e5df2905efaca54d8d50d98c5b
4
+ data.tar.gz: f96e95211a060b7ba444be7d6edc8d264fd77f03
5
5
  SHA512:
6
- metadata.gz: 003b2d21b74b25530e9126028e416b003b690a05d29c7e9cee79abb46e5874ca1c9bbb2f4ae532f766897834f993729f3530785220ca66c1426385c8145b3619
7
- data.tar.gz: 5a9856724a08319139ad6ad9af814f77eca878a247db345248b59ec051afe2016810f5c58f8bce718ce6db62b666493f130eaca390dcbee22730f4c596bb849e
6
+ metadata.gz: a1e81b076d263436bbbf1586df2ad7397be0804bce9c0885f79e54d0cc5b43db735cf6e880656aff995d0bef0ae09df1d8cf8b28cd72c34014cc323dc9ccb76c
7
+ data.tar.gz: 5cc4a44605e1e420319d5daa68482e4c684321bdbcb2bb2af1401509b964b952781c4c2cd46fe285e9ccfebce7c2fba73b150aa7510823716e3d95d3b3b80de4
data/.gitignore CHANGED
@@ -11,3 +11,4 @@
11
11
  .idea/
12
12
  *.gem
13
13
  *.rdb
14
+ *.so
data/.travis.yml CHANGED
@@ -1,14 +1,18 @@
1
- sudo: false
1
+ sudo: required
2
+ dist: trusty
2
3
  language: ruby
3
4
  rvm:
4
- - 2.4.0
5
+ - 2.4.1
5
6
  before_install:
6
7
  - gem install bundler -v 1.14.6
7
- - git clone --depth 1 https://github.com/antirez/redis.git
8
+ - git clone --depth 10 https://github.com/antirez/redis.git
8
9
  - cd redis
10
+ - git fetch origin 4.0.1
11
+ - git checkout ae43e164d4b09d7753e27bb7cba6f7f4f85326b3
9
12
  - make
10
13
  - cd ..
11
14
  - git clone --depth 1 https://github.com/RedisLabsModules/RediSearch.git
12
15
  - cd RediSearch/src
13
16
  - make all
17
+ - ls -la *.so
14
18
  - cd ..
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- ruby '2.4.0'
3
+ ruby '2.4.1'
4
4
 
5
5
  gem 'redis', '~> 4.0.0.rc1'
6
6
 
data/TODO.md ADDED
@@ -0,0 +1,16 @@
1
+ ## TODO
2
+
3
+ - [ x ] Add options hash in `FT.CREATE` (`[NOOFFSETS] [NOFIELDS] [NOSCOREIDX]`) / Allow _raw_ options block
4
+
5
+ - [ x ] Add options hash in `FT.ADD` (`[NOSAVE] [REPLACE] [LANGUAGE {language}] [PAYLOAD {payload}]`) / Allow _raw_ options block
6
+
7
+ - [ x ] Add more options to options hash in `FT.SEARCH` / Allow _raw_ options block
8
+
9
+ - [ ] Add function `FT.DEL`
10
+
11
+ - [ ] Add function `FT.OPTIMIZE`
12
+
13
+ - [ ] Add autocomplete functions: `FT.SUGGADD`, `FT.SUGGET`, `FT.SUGGDEL`, `FT.SUGGLEN`
14
+
15
+ - [ ] Add function `FT.EXPLAIN`
16
+
data/lib/redisearch.rb CHANGED
@@ -5,6 +5,22 @@ require 'redis'
5
5
  # http://redisearch.io/
6
6
  #
7
7
  class RediSearch
8
+ DEFAULT_WEIGHT = '1.0'
9
+
10
+ # Supported options
11
+ # Flags options can be only true or false,
12
+ #
13
+ # { verbatim: true, withscores: true, withsortkey: false }
14
+
15
+ CREATE_OPTIONS_FLAGS = [:nooffsets, :nofreqs, :noscoreidx, :nofields]
16
+ ADD_OPTIONS_FLAGS = [:nosave, :replace]
17
+ SEARCH_OPTIONS_FLAGS = [:nocontent, :verbatim, :nostopwords, :withscores, :withsortkeys]
18
+
19
+ # Params options need an array with the values for the option
20
+ # { 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]
23
+
8
24
  # Create RediSearch client instance
9
25
  #
10
26
  # @param [String] idx_name name of the index
@@ -29,8 +45,8 @@ class RediSearch
29
45
  # See http://redisearch.io/Commands/#ftcreate
30
46
  #
31
47
  # @return [String] "OK" on success
32
- def create_index(schema)
33
- call(ft_create(schema))
48
+ def create_index(schema, opts = {})
49
+ call(ft_create(schema, opts))
34
50
  end
35
51
 
36
52
  # Drop all the keys in the current index
@@ -45,7 +61,7 @@ class RediSearch
45
61
  #
46
62
  # @param [String] doc_id id assigned to the document
47
63
  # @param [Array] fields name-value pairs to be indexed
48
- #
64
+ # @param [Hash] opts optional parameters
49
65
  # Example:
50
66
  #
51
67
  # redisearch = RediSearch.new('my_idx')
@@ -53,8 +69,8 @@ class RediSearch
53
69
  #
54
70
  # See http://redisearch.io/Commands/#ftadd
55
71
  # @return [String] "OK" on success
56
- def add_doc(doc_id, fields)
57
- call(ft_add(doc_id, fields))
72
+ def add_doc(doc_id, fields, opts = {})
73
+ call(ft_add(doc_id, fields, opts))
58
74
  end
59
75
 
60
76
  # Add a set of docs to the index. Uses redis `multi` to make a single bulk insert.
@@ -70,8 +86,8 @@ class RediSearch
70
86
  #
71
87
  # See http://redisearch.io/Commands/#ftadd
72
88
  # @return [String] "OK" on success
73
- def add_docs(docs)
74
- multi { docs.each { |doc_id, fields| @redis.call(ft_add(doc_id, fields)) } }
89
+ def add_docs(docs, opts = {})
90
+ multi { docs.each { |doc_id, fields| @redis.call(ft_add(doc_id, fields, opts)) } }
75
91
  end
76
92
 
77
93
  # Search the index with the given `query`
@@ -80,7 +96,7 @@ class RediSearch
80
96
  #
81
97
  #@return [Array] documents matching the query
82
98
  def search(query, opts = {})
83
- results_to_hash(call(ft_search(query, opts)))
99
+ results_to_hash(call(ft_search(query, opts)), opts)
84
100
  end
85
101
 
86
102
  # Return information and statistics on the index.
@@ -104,8 +120,8 @@ class RediSearch
104
120
  @redis.call(ft_add(doc_id, fields))
105
121
  end
106
122
 
107
- def ft_create(schema)
108
- ['FT.CREATE', @idx_name , 'SCHEMA', *schema]
123
+ def ft_create(schema, opts)
124
+ ['FT.CREATE', @idx_name , *create_options(opts), 'SCHEMA', *schema]
109
125
  end
110
126
 
111
127
  def ft_drop
@@ -116,28 +132,39 @@ class RediSearch
116
132
  ['FT.INFO', @idx_name]
117
133
  end
118
134
 
119
- def ft_add(doc_id, fields)
120
- ['FT.ADD', @idx_name , doc_id, '1.0', 'REPLACE', 'FIELDS', *fields]
135
+ def ft_add(doc_id, fields, opts = {}, weight = nil)
136
+ ['FT.ADD', @idx_name , doc_id, weight || DEFAULT_WEIGHT, *add_options(opts), 'FIELDS', *fields]
121
137
  end
122
138
 
123
139
  def ft_search(query, opts)
124
- command = ['FT.SEARCH', @idx_name, *query]
125
- command << 'NOSTOPWORDS' if opts[:nostopwords]
126
- command << 'VERBATIM' if opts[:verbatim]
127
- if opts[:offset] || opts[:limit]
128
- limit = opts[:limit].to_i > 0 ? opts[:limit].to_i : -1
129
- command << ["LIMIT", opts[:offset], limit]
130
- end
131
- command << 'WITHSCORES' if opts[:withscores]
132
- command << ["SCORER", opts[:scorer]] unless opts[:scorer].to_s.empty?
133
- command << ["SLOP", opts[:slop]] if opts[:slop].to_i > 0
134
- command.flatten
140
+ ['FT.SEARCH', @idx_name, *query, *search_options(opts)].flatten
141
+ end
142
+
143
+ def create_options(opts = {})
144
+ build_options(opts, CREATE_OPTIONS_FLAGS, [])
145
+ end
146
+
147
+ def add_options(opts = {})
148
+ build_options(opts, ADD_OPTIONS_FLAGS, ADD_OPTIONS_PARAMS)
149
+ end
150
+
151
+ def search_options(opts = {})
152
+ build_options(opts, SEARCH_OPTIONS_FLAGS, SEARCH_OPTIONS_PARAMS)
153
+ end
154
+
155
+ def build_options(opts, flags_keys, params_keys)
156
+ flags_keys.map do |key|
157
+ key.to_s.upcase if opts[key]
158
+ end.compact +
159
+ params_keys.map do |key|
160
+ [key.to_s.upcase, *opts[key]] unless opts[key].nil?
161
+ end.compact
135
162
  end
136
163
 
137
- def results_to_hash(results)
164
+ def results_to_hash(results, opts = {})
138
165
  return {} if results.nil? || results[0] == 0
139
166
  results.shift
140
- offset = results.size % 3 == 0 ? 1 : 0
167
+ offset = opts[:withscores] ? 1 : 0
141
168
  rows_per_doc = 2 + offset
142
169
  nr_of_docs = results.size / (2 + offset)
143
170
  (0..nr_of_docs-1).map do |n|
@@ -1,3 +1,3 @@
1
1
  class RediSearch
2
- VERSION = '0.1.5'
2
+ VERSION = '0.1.6'
3
3
  end
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.email = ["vruizext@gmail.com"]
9
9
 
10
10
  spec.summary = "A simple Ruby client library for RediSearch"
11
- spec.description = "A simple Ruby client library for RediSearc. RediSearch is a Full-Text search index over Redis,
12
- developed by RedisLabs. http://redisearch.io/"
11
+ spec.description = "A simple Ruby client library for RediSearch.
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
 
@@ -2,15 +2,15 @@ require 'test_helper'
2
2
 
3
3
  class RediSearchTest < Minitest::Test
4
4
  def setup
5
- @redis_server = RedisTestServer.new
5
+ @redis_server = RedisTestServer.new(6388)
6
6
  fail('error starting redis-server') unless @redis_server.start
7
7
  sleep(0.25)
8
- @redis_client = Redis.new(url: ENV['REDIS_URL'])
8
+ @redis_client = Redis.new(url: @redis_server.url)
9
9
  @redis_client.flushdb
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
- 'year', 'NUMERIC']
13
+ 'year', 'NUMERIC', 'SORTABLE']
14
14
 
15
15
  end
16
16
 
@@ -47,6 +47,21 @@ class RediSearchTest < Minitest::Test
47
47
  assert_includes(@redis_client.call(['FT.SEARCH', 'test_idx', 'lost']).to_s, 'Lost in translation')
48
48
  end
49
49
 
50
+ def test_add_doc_replace
51
+ assert(@redisearch_client.create_index(@schema))
52
+ doc = ['title', 'Lost in translation', 'director', 'Sofia Coppola', 'year', '2004']
53
+ assert(@redisearch_client.add_doc('id_1', doc))
54
+
55
+ doc = ['title', 'Lost in translation', 'director', 'SC', 'year', '2005']
56
+ assert_raises(Redis::CommandError) { @redisearch_client.add_doc('id_1', doc) }
57
+ assert(@redisearch_client.add_doc('id_1', doc, { replace: true }))
58
+
59
+ result = @redis_client.call(['FT.SEARCH', 'test_idx', 'SC'])
60
+ assert result.any?
61
+ assert result.to_s.include?('2005')
62
+ assert result.to_s.include?('id_1')
63
+ end
64
+
50
65
  def test_add_docs
51
66
  assert(@redisearch_client.create_index(@schema))
52
67
  docs = [['id_1', ['title', 'Lost in translation', 'director', 'Sofia Coppola', 'year', '2004']],
@@ -80,6 +95,57 @@ class RediSearchTest < Minitest::Test
80
95
  assert_equal 1, @redisearch_client.search('@year:[2004 2005]').count
81
96
  end
82
97
 
98
+ def test_search_inkeys
99
+ @redisearch_client.create_index(@schema)
100
+ docs = [['id_1', ['title', 'Lost in translation', 'director', 'Sofia Coppola', 'year', '2004']],
101
+ ['id_2', ['title', 'Ex Machina', 'director', 'Alex Garland', 'year', '2014']]]
102
+ assert(@redisearch_client.add_docs(docs))
103
+ matches = @redisearch_client.search('(lost|garland)', { infields: ['1', 'title'] })
104
+ assert_equal 1, matches.count
105
+ matches = @redisearch_client.search('(lost|garland)', { infields: ['2', 'director', 'title'] })
106
+ assert_equal 2, matches.count
107
+ end
108
+
109
+ def test_search_return_keys
110
+ assert(@redisearch_client.create_index(@schema))
111
+ doc = ['id_1', ['title', 'Lost in translation', 'director', 'Sofia Coppola', 'year', '2004']]
112
+ assert(@redisearch_client.add_doc(*doc))
113
+ matches = @redisearch_client.search('@title:lost', { return: ['2', 'title', 'year'] })
114
+ assert_equal 1, matches.count
115
+ assert_nil matches[0]['director']
116
+ assert_equal 'Lost in translation', matches[0]['title']
117
+ assert_equal '2004', matches[0]['year']
118
+ end
119
+
120
+ def test_search_sort_by
121
+ @redisearch_client.create_index(@schema)
122
+ docs = [['id_1', ['title', 'Lost in translation', 'director', 'Sofia Coppola', 'year', '2004']],
123
+ ['id_2', ['title', 'Ex Machina', 'director', 'Alex Garland', 'year', '2014']]]
124
+ assert(@redisearch_client.add_docs(docs))
125
+ matches = @redisearch_client.search('@year:[2000 2017]', { sortby: ['year', 'asc'] })
126
+ assert_equal 2, matches.count
127
+ assert_equal 'id_1', matches[0]['id']
128
+ matches = @redisearch_client.search('@year:[2000 2017]', { sortby: ['year', 'desc'] })
129
+ assert_equal 'id_2', matches[0]['id']
130
+ end
131
+
132
+ def test_search_limit
133
+ assert(@redisearch_client.create_index(@schema))
134
+ docs = [['id_1', ['title', 'Lost in translation', 'director', 'Sofia Coppola', 'year', '2004']],
135
+ ['id_2', ['title', 'Ex Machina', 'director', 'Alex Garland', 'year', '2014']],
136
+ ['id_3', ['title', 'Terminator', 'director', 'James Cameron', 'year', '1984']],
137
+ ['id_4', ['title', 'Blade Runner', 'director', 'Ridley Scott', 'year', '1982']]]
138
+ assert(@redisearch_client.add_docs(docs))
139
+ matches = @redisearch_client.search('@year:[1980 2017]', { limit: ['0', '3'], sortby: ['year', 'asc'] })
140
+ assert_equal 3, matches.count
141
+ assert_equal 'id_4', matches[0]['id']
142
+ assert_equal 'id_3', matches[1]['id']
143
+ assert_equal 'id_1', matches[2]['id']
144
+ matches = @redisearch_client.search('@year:[1980 2017]', { limit: ['3', '3'], sortby: ['year', 'asc'] })
145
+ assert_equal 1, matches.count
146
+ assert_equal 'id_2', matches[0]['id']
147
+ end
148
+
83
149
  def test_index_info
84
150
  assert(@redisearch_client.create_index(@schema))
85
151
  doc = ['id_1', ['title', 'Lost in translation', 'director', 'Sofia Coppola', 'year', '2004']]
data/test/test_helper.rb CHANGED
@@ -10,17 +10,19 @@ require './lib/redisearch-rb'
10
10
  Dotenv.load('./.env')
11
11
 
12
12
  class RedisTestServer
13
- DEFAULT_REDIS_PATH = ''#'redis-server'
13
+ DEFAULT_REDIS_PATH = 'redis-server'
14
14
 
15
- attr_reader :process
15
+ attr_reader :process, :url
16
16
 
17
- def initialize
17
+ def initialize(default_port = nil)
18
18
  @command = [ENV['REDIS_SERVER_PATH'] || DEFAULT_REDIS_PATH]
19
+ @port = ENV['REDIS_PORT'] || default_port
19
20
  end
20
21
 
21
22
  def start
22
23
  build_args
23
24
  @process = Subprocess.popen(@command)
25
+ @url = "redis://127.0.0.1:#{@port}"
24
26
  rescue => error
25
27
  Logger.new(STDERR).error(error.message)
26
28
  @process = nil
@@ -36,7 +38,7 @@ class RedisTestServer
36
38
 
37
39
  def build_args
38
40
  if ENV['REDIS_CONF_PATH'].to_s.empty?
39
- @command << "--port #{ENV['REDIS_PORT']}" unless ENV['REDIS_PORT'].to_s.empty?
41
+ @command << "--port #{@port}" unless @port.to_s.empty?
40
42
  @command << "--loadmodule #{ENV['REDIS_MODULE_PATH']}" unless ENV['REDIS_MODULE_PATH'].to_s.empty?
41
43
  else
42
44
  @command << ENV['REDIS_CONF_PATH']
metadata CHANGED
@@ -1,18 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redisearch-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
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-06-08 00:00:00.000000000 Z
11
+ date: 2017-08-08 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |-
14
- A simple Ruby client library for RediSearc. RediSearch is a Full-Text search index over Redis,
15
- developed by RedisLabs. http://redisearch.io/
14
+ A simple Ruby client library for RediSearch.
15
+ RediSearch is a Redis powered search engine, developed by RedisLabs. http://redisearch.io/
16
16
  email:
17
17
  - vruizext@gmail.com
18
18
  executables: []
@@ -26,6 +26,7 @@ files:
26
26
  - LICENSE.txt
27
27
  - README.md
28
28
  - Rakefile
29
+ - TODO.md
29
30
  - lib/redisearch-rb.rb
30
31
  - lib/redisearch.rb
31
32
  - lib/redisearch/version.rb