-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Hi,
I noticed that it seems ScanStruct function doesn't work with FT.INFO output from RediSearch module due to difference in string types.
I tried to use redis.ScanStruct() from redigo to parse search index parameters from RediSearch module and got error: redigo.ScanStruct: key 0 not a bulk string value from this part of code in redis/scan.go:
name, ok := src[i].([]byte)
if !ok {
return fmt.Errorf("redigo.ScanStruct: key %d not a bulk string value", i)
}I checked my code for issues and after some time found this in Redis RESP protocol description:
In the RESP documentation, it is explained how to represent each data type. There are a bunch of data types supported by Redis, but we will only care about 3 types: bulk strings, arrays, and nulls.
Bulk string will be represented like this: $\r\n\r\n
Simple string will be represented like this: +<the_string>\r\n
And indeed by comparing raw output from XINFO STREAM <stream> and FT.INFO <index> it's visible that first one uses bulk strings, while second - simple strings, logs:
# XINFO STREAM
Connection to localhost port 32770 [tcp/*] succeeded!
*20
$6
length
:50000
$15
radix-tree-keys
:25000
$16
radix-tree-nodes
:42546
# FT.INFO
Connection to localhost port 32770 [tcp/*] succeeded!
*68
+index_name
+idx:bicycle
+index_options
*0
+index_definition
*8
+key_type
+JSON
I tried changing ScanStruct() function to accept simple string with name, ok := src[i].(string) change and it successfully transformed output of FT.INFO to provided struct.
I'm wondering what could be the next steps:
- Is it possible somehow to adapt ScanStruct to this output without changing library? (seems unlikely to me)
- Maybe I can prepare PR with allowing ScanStruct work with simple string as key name?
- Should I open issue in https://github.com/RediSearch/RediSearch to check why output is in simple strings instead of bulk ones?
As last resort I sure can parse output of FT.INFO without ScanStruct(), but that wouldn't look as nice.
Code snippet:
type searchIndexInfo struct {
IndexName string `redis:"index_name"`
NumDocs int64 `redis:"num_docs"`
NumRecords int64 `redis:"num_records"`
}
values, err := redis.Values(doRedisCmd(c, "FT.INFO", "some-index"))
if err != nil {
log.Errorf("err: %s", err)
return
}
// Scan slice to struct
var indexInfo searchIndexInfo
if err := redis.ScanStruct(values, &indexInfo); err != nil {
log.Errorf("Couldn't scan search index '%s': %s", index, err)
}