neighbor-redis 0.1.0 → 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 +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +9 -3
- data/lib/neighbor/redis/index.rb +39 -19
- data/lib/neighbor/redis/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 15f6a05f33831afcb282262440f8a4ccd73264c109ada3d5de1383af76cab304
|
4
|
+
data.tar.gz: 977b93e67d4b62db75837bf72dff4959a5b6aae8c940828273bee22563f172ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6148b2717ddbb7cef8e9d762866b3c0d981be8e57e6a9e7c8a28f3a37b8402b5add0383e2676bc21b1c93dd687e10ae2fdaf9bfb31969adc80d7fb43def01a4
|
7
|
+
data.tar.gz: e7bc98f4436a8e48c84215e837461312bf0d610e9f5103a8d6f0ce39aa800970f5adb4c341ff691e21a059d30e4540eda4ef1df3d17f7d313923e6799860beb3
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
|
3
3
|
Nearest neighbor search for Ruby and Redis
|
4
4
|
|
5
|
-
[](https://github.com/ankane/neighbor-redis/actions)
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
9
9
|
First, [install RediSearch](https://redis.io/docs/stack/search/quick_start/). With Docker, use:
|
10
10
|
|
11
11
|
```sh
|
12
|
-
docker run -p 6379:6379 redis/redis-stack-server
|
12
|
+
docker run -p 6379:6379 redis/redis-stack-server
|
13
13
|
```
|
14
14
|
|
15
15
|
Add this line to your application’s Gemfile:
|
@@ -41,7 +41,7 @@ index.add(2, [2, 2, 2])
|
|
41
41
|
index.add(3, [1, 1, 2])
|
42
42
|
```
|
43
43
|
|
44
|
-
Note: IDs are stored and returned as strings (uses less total
|
44
|
+
Note: IDs are stored and returned as strings (uses less total memory)
|
45
45
|
|
46
46
|
Get the nearest neighbors to an item
|
47
47
|
|
@@ -118,6 +118,12 @@ Add multiple items
|
|
118
118
|
index.add_all(ids, embeddings)
|
119
119
|
```
|
120
120
|
|
121
|
+
Get an item
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
index.find(id)
|
125
|
+
```
|
126
|
+
|
121
127
|
Remove an item
|
122
128
|
|
123
129
|
```ruby
|
data/lib/neighbor/redis/index.rb
CHANGED
@@ -52,7 +52,7 @@ module Neighbor
|
|
52
52
|
params = {
|
53
53
|
"TYPE" => @float64 ? "FLOAT64" : "FLOAT32",
|
54
54
|
"DIM" => @dimensions,
|
55
|
-
"DISTANCE_METRIC" => @distance_metric
|
55
|
+
"DISTANCE_METRIC" => @distance_metric
|
56
56
|
}.merge(create_params)
|
57
57
|
|
58
58
|
command = ["FT.CREATE", @index_name]
|
@@ -70,7 +70,7 @@ module Neighbor
|
|
70
70
|
# fix for invalid value for Float(): "-nan"
|
71
71
|
true
|
72
72
|
rescue => e
|
73
|
-
raise unless e.message.include?("
|
73
|
+
raise unless e.message.downcase.include?("unknown index name")
|
74
74
|
false
|
75
75
|
end
|
76
76
|
|
@@ -167,31 +167,51 @@ module Neighbor
|
|
167
167
|
|
168
168
|
def search_by_blob(blob, count)
|
169
169
|
resp = redis.call("FT.SEARCH", @index_name, "*=>[KNN #{count.to_i} @v $BLOB]", "PARAMS", "2", "BLOB", blob, "SORTBY", "__v_score", "DIALECT", "2")
|
170
|
-
|
170
|
+
resp.is_a?(Hash) ? parse_results_hash(resp) : parse_results_array(resp)
|
171
|
+
end
|
172
|
+
|
173
|
+
def parse_results_hash(resp)
|
174
|
+
prefix_length = nil
|
175
|
+
resp["results"].map do |result|
|
176
|
+
key = result["id"]
|
177
|
+
info = result["extra_attributes"]
|
178
|
+
prefix_length ||= find_prefix_length(key)
|
179
|
+
search_result(key, info, prefix_length)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def parse_results_array(resp)
|
171
184
|
prefix_length = nil
|
172
|
-
|
185
|
+
resp.shift.times.map do |i|
|
173
186
|
key, info = resp.shift(2)
|
174
187
|
info = info.each_slice(2).to_h
|
175
|
-
score = info["__v_score"].to_f
|
176
|
-
distance =
|
177
|
-
case @distance_metric
|
178
|
-
when "L2"
|
179
|
-
Math.sqrt(score)
|
180
|
-
when "IP"
|
181
|
-
(score * -1) + 1
|
182
|
-
else
|
183
|
-
score
|
184
|
-
end
|
185
|
-
|
186
188
|
prefix_length ||= find_prefix_length(key)
|
189
|
+
search_result(key, info, prefix_length)
|
190
|
+
end
|
191
|
+
end
|
187
192
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
193
|
+
def search_result(key, info, prefix_length)
|
194
|
+
score = info["__v_score"].to_f
|
195
|
+
distance = calculate_distance(score)
|
196
|
+
|
197
|
+
{
|
198
|
+
id: key[prefix_length..-1],
|
199
|
+
distance: distance
|
200
|
+
}
|
201
|
+
end
|
202
|
+
|
203
|
+
def calculate_distance(score)
|
204
|
+
case @distance_metric
|
205
|
+
when "L2"
|
206
|
+
Math.sqrt(score)
|
207
|
+
when "IP"
|
208
|
+
(score * -1) + 1
|
209
|
+
else
|
210
|
+
score
|
192
211
|
end
|
193
212
|
end
|
194
213
|
|
214
|
+
# can't just remove @prefix since may be an alias
|
195
215
|
def find_prefix_length(key)
|
196
216
|
key[@global_prefix.length..-1].index(":") + @global_prefix.length + 1
|
197
217
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: neighbor-redis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-10-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis-client
|
@@ -51,14 +51,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '3.1'
|
55
55
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
56
|
requirements:
|
57
57
|
- - ">="
|
58
58
|
- !ruby/object:Gem::Version
|
59
59
|
version: '0'
|
60
60
|
requirements: []
|
61
|
-
rubygems_version: 3.
|
61
|
+
rubygems_version: 3.5.16
|
62
62
|
signing_key:
|
63
63
|
specification_version: 4
|
64
64
|
summary: Nearest neighbor search for Ruby and Redis
|