Skip to content

Commit 0ca3698

Browse files
authored
Merge branch 'master' into NOSTOPWORDS
2 parents 20bcf2f + d1b07e7 commit 0ca3698

File tree

6 files changed

+156
-24
lines changed

6 files changed

+156
-24
lines changed

.circleci/config.yml

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ jobs:
5353
build: # test with redisearch:latest
5454
docker:
5555
- image: circleci/golang:1.16
56-
- image: redislabs/redisearch:latest
56+
- image: redislabs/redisearch:edge
5757

5858
working_directory: /go/src/github.com/RediSearch/redisearch-go
5959
steps:
@@ -65,34 +65,12 @@ jobs:
6565
- run: make coverage
6666
- run: bash <(curl -s https://raw.githubusercontent.com/codecov/codecov-bash/master/codecov) -t ${CODECOV_TOKEN}
6767

68-
build-v16:
69-
docker:
70-
- image: circleci/golang:1.16
71-
- image: redislabs/redisearch:edge
72-
73-
working_directory: /go/src/github.com/RediSearch/redisearch-go
74-
steps:
75-
- checkout
76-
- run: make test
77-
78-
build-edge: # test nightly with redisearch:edge
79-
docker:
80-
- image: circleci/golang:1.16
81-
- image: redislabs/redisearch:edge
82-
83-
working_directory: /go/src/github.com/RediSearch/redisearch-go
84-
steps:
85-
- checkout
86-
- run: make test
87-
8868
workflows:
8969
version: 2
9070
commit:
9171
jobs:
9272
- build-tls
9373
- build
94-
- build-edge
95-
- build-v16
9674
nightly:
9775
triggers:
9876
- schedule:
@@ -102,5 +80,5 @@ workflows:
10280
only:
10381
- master
10482
jobs:
105-
- build-edge
83+
- build
10684
- build-tls

redisearch/query.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ type Query struct {
9696
SortBy *SortingKey
9797
HighlightOpts *HighlightOptions
9898
SummarizeOpts *SummaryOptions
99+
Params map[string]interface{}
100+
Dialect int
99101
}
100102

101103
// Paging represents the offset paging of a search result
@@ -233,6 +235,18 @@ func (q Query) serialize() redis.Args {
233235
}
234236
}
235237
}
238+
239+
if q.Params != nil {
240+
args = args.Add("PARAMS", len(q.Params)*2)
241+
for name, value := range q.Params {
242+
args = args.Add(name, value)
243+
}
244+
}
245+
246+
if q.Dialect != 0 {
247+
args = args.Add("DIALECT", q.Dialect)
248+
}
249+
236250
return args
237251
}
238252

@@ -376,6 +390,29 @@ func (q *Query) SummarizeOptions(opts SummaryOptions) *Query {
376390
return q
377391
}
378392

393+
// SetParams sets parameters that can be referenced in the query string by a $ , followed by the parameter name,
394+
// e.g., $user , and each such reference in the search query to a parameter name is substituted
395+
// by the corresponding parameter value.
396+
func (q *Query) SetParams(params map[string]interface{}) *Query {
397+
q.Params = params
398+
return q
399+
}
400+
401+
// AddParam adds a new param to the parameters list
402+
func (q *Query) AddParam(name string, value interface{}) *Query {
403+
if q.Params == nil {
404+
q.Params = make(map[string]interface{})
405+
}
406+
q.Params[name] = value
407+
return q
408+
}
409+
410+
// SetDialect can have one of 2 options: 1 or 2
411+
func (q *Query) SetDialect(dialect int) *Query {
412+
q.Dialect = dialect
413+
return q
414+
}
415+
379416
// IndexOptions indexes multiple documents on the index, with optional Options passed to options
380417
func (i *Client) IndexOptions(opts IndexingOptions, docs ...Document) error {
381418

redisearch/query_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ func TestQuery_serialize(t *testing.T) {
7979
SortBy *SortingKey
8080
HighlightOpts *HighlightOptions
8181
SummarizeOpts *SummaryOptions
82+
Params map[string]interface{}
83+
Dialect int
8284
}
8385
tests := []struct {
8486
name string
@@ -112,6 +114,8 @@ func TestQuery_serialize(t *testing.T) {
112114
NumFragments: 3,
113115
Separator: "...",
114116
}}, redis.Args{raw, "LIMIT", 0, 0, "SUMMARIZE", "FIELDS", 1, "test_field", "LEN", 20, "FRAGS", 3, "SEPARATOR", "..."}},
117+
{"Params", fields{Raw: raw, Params: map[string]interface{}{"min": 1}}, redis.Args{raw, "LIMIT", 0, 0, "PARAMS", 2, "min", 1}},
118+
{"Dialect", fields{Raw: raw, Dialect: 2}, redis.Args{raw, "LIMIT", 0, 0, "DIALECT", 2}},
115119
}
116120
for _, tt := range tests {
117121
t.Run(tt.name, func(t *testing.T) {
@@ -127,6 +131,8 @@ func TestQuery_serialize(t *testing.T) {
127131
SortBy: tt.fields.SortBy,
128132
HighlightOpts: tt.fields.HighlightOpts,
129133
SummarizeOpts: tt.fields.SummarizeOpts,
134+
Params: tt.fields.Params,
135+
Dialect: tt.fields.Dialect,
130136
}
131137
if g := q.serialize(); !reflect.DeepEqual(g, tt.want) {
132138
t.Errorf("serialize() = %v, want %v", g, tt.want)

redisearch/redisearch_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,3 +533,67 @@ func TestNoStopWords(t *testing.T) {
533533
assert.Nil(t, err)
534534
assert.Equal(t, 0, total)
535535
}
536+
537+
func TestParams(t *testing.T) {
538+
c := createClient("TestParams")
539+
version, _ := c.getRediSearchVersion()
540+
if version < 20430 {
541+
// VectorSimilarity is available for RediSearch 2.2+
542+
return
543+
}
544+
545+
// Create a schema
546+
sc := NewSchema(DefaultOptions).AddField(NewNumericField("numval"))
547+
c.Drop()
548+
assert.Nil(t, c.CreateIndex(sc))
549+
// Create data
550+
_, err := c.pool.Get().Do("HSET", "1", "numval", "1")
551+
assert.Nil(t, err)
552+
_, err = c.pool.Get().Do("HSET", "2", "numval", "2")
553+
assert.Nil(t, err)
554+
_, err = c.pool.Get().Do("HSET", "3", "numval", "3")
555+
assert.Nil(t, err)
556+
// Searching with parameters
557+
_, total, err := c.Search(NewQuery("@numval:[$min $max]").
558+
SetParams(map[string]interface{}{"min": "1", "max": "2"}).
559+
SetDialect(2))
560+
assert.Nil(t, err)
561+
assert.Equal(t, 2, total)
562+
}
563+
564+
func TestVectorField(t *testing.T) {
565+
c := createClient("TestVectorField")
566+
version, _ := c.getRediSearchVersion()
567+
if version < 20430 {
568+
// VectorSimilarity is available for RediSearch 2.2+
569+
return
570+
}
571+
572+
// Create a schema
573+
sc := NewSchema(DefaultOptions).AddField(
574+
NewVectorFieldOptions("v", VectorFieldOptions{Algorithm: Flat, Attributes: map[string]interface{}{
575+
"TYPE": "FLOAT32",
576+
"DIM": 2,
577+
"DISTANCE_METRIC": "L2",
578+
}}),
579+
)
580+
c.Drop()
581+
assert.Nil(t, c.CreateIndex(sc))
582+
// Create data
583+
_, err := c.pool.Get().Do("HSET", "a", "v", "aaaaaaaa")
584+
assert.Nil(t, err)
585+
_, err = c.pool.Get().Do("HSET", "b", "v", "aaaabaaa")
586+
assert.Nil(t, err)
587+
_, err = c.pool.Get().Do("HSET", "c", "v", "aaaaabaa")
588+
assert.Nil(t, err)
589+
// Searching with parameters
590+
docs, total, err := c.Search(NewQuery("*=>[KNN 2 @v $vec]").
591+
AddParam("vec", "aaaaaaaa").
592+
SetSortBy("__v_score", true).
593+
AddReturnFields("__v_score").
594+
SetDialect(2))
595+
assert.Nil(t, err)
596+
assert.Equal(t, 2, total)
597+
assert.Equal(t, "a", docs[0].Id)
598+
assert.Equal(t, "0", docs[0].Properties["__v_score"])
599+
}

redisearch/schema.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ const (
135135

136136
// TagField is a field used for compact indexing of comma separated values
137137
TagField
138+
139+
//VectorField allows vector similarity queries against the value in this attribute.
140+
VectorField
138141
)
139142

140143
// Phonetic Matchers
@@ -185,6 +188,20 @@ type GeoFieldOptions struct {
185188
As string
186189
}
187190

191+
type algorithm string
192+
193+
// Supported algorithms for Vector field
194+
const (
195+
Flat algorithm = "FLAT"
196+
HNSW algorithm = "HNSW"
197+
)
198+
199+
// VectorFieldOptions Options for vector fields
200+
type VectorFieldOptions struct {
201+
Algorithm algorithm
202+
Attributes map[string]interface{}
203+
}
204+
188205
// NewTextField creates a new text field with the given weight
189206
func NewTextField(name string) Field {
190207
return Field{
@@ -268,6 +285,15 @@ func NewGeoFieldOptions(name string, options GeoFieldOptions) Field {
268285
return f
269286
}
270287

288+
// NewVectorFieldOptions creates a new geo field with the given name and additional options
289+
func NewVectorFieldOptions(name string, options VectorFieldOptions) Field {
290+
return Field{
291+
Name: name,
292+
Type: VectorField,
293+
Options: options,
294+
}
295+
}
296+
271297
// Schema represents an index schema Schema, or how the index would
272298
// treat documents sent to it.
273299
type Schema struct {
@@ -417,6 +443,26 @@ func serializeField(f Field, args redis.Args) (argsOut redis.Args, err error) {
417443
argsOut = append(argsOut, "NOINDEX")
418444
}
419445
}
446+
case VectorField:
447+
argsOut = append(argsOut, f.Name, "VECTOR")
448+
if f.Options != nil {
449+
opts, ok := f.Options.(VectorFieldOptions)
450+
if !ok {
451+
err = fmt.Errorf("Error on VectorField serialization")
452+
return
453+
}
454+
if opts.Algorithm != "" {
455+
argsOut = append(argsOut, opts.Algorithm)
456+
}
457+
if opts.Attributes != nil {
458+
var flat []interface{}
459+
for attrName, attrValue := range opts.Attributes {
460+
flat = append(flat, attrName, attrValue)
461+
}
462+
argsOut = append(argsOut, len(flat))
463+
argsOut = append(argsOut, flat...)
464+
}
465+
}
420466
default:
421467
err = fmt.Errorf("Unrecognized field type %v serialization", f.Type)
422468
return

redisearch/schema_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ func TestSerializeSchema(t *testing.T) {
7474
{"default-and-tag", args{NewSchema(DefaultOptions).AddField(NewTagField("tag-field")), redis.Args{}}, redis.Args{"SCHEMA", "tag-field", "TAG", "SEPARATOR", ","}, false},
7575
{"default-and-tag-with-options", args{NewSchema(DefaultOptions).AddField(NewTagFieldOptions("tag-field", TagFieldOptions{Sortable: true, NoIndex: false, Separator: byte(','), As: "field"})), redis.Args{}}, redis.Args{"SCHEMA", "tag-field", "AS", "field", "TAG", "SEPARATOR", ",", "SORTABLE"}, false},
7676
{"default-geo-with-options", args{NewSchema(DefaultOptions).AddField(NewGeoFieldOptions("location", GeoFieldOptions{As: "loc"})), redis.Args{}}, redis.Args{"SCHEMA", "location", "AS", "loc", "GEO"}, false},
77+
{"default-vector", args{NewSchema(DefaultOptions).AddField(NewVectorFieldOptions("vec", VectorFieldOptions{Algorithm: Flat, Attributes: map[string]interface{}{"DIM": 128}})), redis.Args{}}, redis.Args{"SCHEMA", "vec", "VECTOR", Flat, 2, "DIM", 128}, false},
7778
{"error-unsupported", args{NewSchema(DefaultOptions).AddField(Field{Type: 10}), redis.Args{}}, nil, true},
7879
}
7980
for _, tt := range tests {

0 commit comments

Comments
 (0)