Skip to content

Commit d58e93d

Browse files
committed
feat: VectorString helpers to build vector search queries
1 parent cebd383 commit d58e93d

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

binary.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package rueidis
22

33
import (
4+
"encoding/binary"
45
"encoding/json"
6+
"math"
57
"unsafe"
68
)
79

@@ -16,6 +18,54 @@ func BinaryString(bs []byte) string {
1618
return unsafe.String(unsafe.SliceData(bs), len(bs))
1719
}
1820

21+
// VectorString32 convert the provided []float32 into a string. Users can use this to build vector search queries:
22+
//
23+
// client.B().FtSearch().Index("idx").Query("*=>[KNN 5 @vec $V]").
24+
// Params().Nargs(2).NameValue().NameValue("V", rueidis.VectorString32([]float32{1})).
25+
// Dialect(2).Build()
26+
func VectorString32(v []float32) string {
27+
b := make([]byte, len(v)*4)
28+
for i, e := range v {
29+
i := i * 4
30+
binary.LittleEndian.PutUint32(b[i:i+4], math.Float32bits(e))
31+
}
32+
return BinaryString(b)
33+
}
34+
35+
// ToVector32 reverts VectorString32. User can use this to convert redis response back to []float32.
36+
func ToVector32(s string) []float32 {
37+
bs := unsafe.Slice(unsafe.StringData(s), len(s))
38+
vs := make([]float32, 0, len(bs)/4)
39+
for i := 0; i < len(bs); i += 4 {
40+
vs = append(vs, math.Float32frombits(binary.LittleEndian.Uint32(bs[i:i+4])))
41+
}
42+
return vs
43+
}
44+
45+
// VectorString64 convert the provided []float64 into a string. Users can use this to build vector search queries:
46+
//
47+
// client.B().FtSearch().Index("idx").Query("*=>[KNN 5 @vec $V]").
48+
// Params().Nargs(2).NameValue().NameValue("V", rueidis.VectorString64([]float64{1})).
49+
// Dialect(2).Build()
50+
func VectorString64(v []float64) string {
51+
b := make([]byte, len(v)*8)
52+
for i, e := range v {
53+
i := i * 8
54+
binary.LittleEndian.PutUint64(b[i:i+8], math.Float64bits(e))
55+
}
56+
return BinaryString(b)
57+
}
58+
59+
// ToVector64 reverts VectorString64. User can use this to convert redis response back to []float64.
60+
func ToVector64(s string) []float64 {
61+
bs := unsafe.Slice(unsafe.StringData(s), len(s))
62+
vs := make([]float64, 0, len(bs)/8)
63+
for i := 0; i < len(bs); i += 8 {
64+
vs = append(vs, math.Float64frombits(binary.LittleEndian.Uint64(bs[i:i+8])))
65+
}
66+
return vs
67+
}
68+
1969
// JSON convert the provided parameter into a JSON string. Users can use this JSON helper to work with RedisJSON commands.
2070
// For example:
2171
//

binary_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package rueidis
22

33
import (
44
"encoding/json"
5+
"reflect"
56
"strings"
67
"testing"
78
)
@@ -29,6 +30,32 @@ func TestJSONPanic(t *testing.T) {
2930
JSON(a)
3031
}
3132

33+
func TestVectorString32(t *testing.T) {
34+
for _, test := range [][]float32{
35+
{},
36+
{0, 0, 0, 0},
37+
{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9},
38+
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
39+
} {
40+
if !reflect.DeepEqual(test, ToVector32(VectorString32(test))) {
41+
t.Fatalf("fail to convert %v", test)
42+
}
43+
}
44+
}
45+
46+
func TestVectorString64(t *testing.T) {
47+
for _, test := range [][]float64{
48+
{},
49+
{0, 0, 0, 0},
50+
{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9},
51+
{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
52+
} {
53+
if !reflect.DeepEqual(test, ToVector64(VectorString64(test))) {
54+
t.Fatalf("fail to convert %v", test)
55+
}
56+
}
57+
}
58+
3259
type recursive struct {
3360
R *recursive
3461
}

0 commit comments

Comments
 (0)