redisearch-rb 0.1.5 → 0.1.6
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 +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +7 -3
- data/Gemfile +1 -1
- data/TODO.md +16 -0
- data/lib/redisearch.rb +52 -25
- data/lib/redisearch/version.rb +1 -1
- data/redisearch-rb.gemspec +2 -2
- data/test/redisearch_test.rb +69 -3
- data/test/test_helper.rb +6 -4
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38fdd275f958d4e5df2905efaca54d8d50d98c5b
|
4
|
+
data.tar.gz: f96e95211a060b7ba444be7d6edc8d264fd77f03
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1e81b076d263436bbbf1586df2ad7397be0804bce9c0885f79e54d0cc5b43db735cf6e880656aff995d0bef0ae09df1d8cf8b28cd72c34014cc323dc9ccb76c
|
7
|
+
data.tar.gz: 5cc4a44605e1e420319d5daa68482e4c684321bdbcb2bb2af1401509b964b952781c4c2cd46fe285e9ccfebce7c2fba73b150aa7510823716e3d95d3b3b80de4
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,14 +1,18 @@
|
|
1
|
-
sudo:
|
1
|
+
sudo: required
|
2
|
+
dist: trusty
|
2
3
|
language: ruby
|
3
4
|
rvm:
|
4
|
-
- 2.4.
|
5
|
+
- 2.4.1
|
5
6
|
before_install:
|
6
7
|
- gem install bundler -v 1.14.6
|
7
|
-
- git clone --depth
|
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
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,
|
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
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
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 =
|
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|
|
data/lib/redisearch/version.rb
CHANGED
data/redisearch-rb.gemspec
CHANGED
@@ -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
|
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
|
|
data/test/redisearch_test.rb
CHANGED
@@ -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:
|
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 = '
|
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 #{
|
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.
|
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-
|
11
|
+
date: 2017-08-08 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |-
|
14
|
-
A simple Ruby client library for
|
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
|