Skip to content

ScanStruct function doesn't work with FT.INFO output from RediSearch module #691

Description

@nantiferov

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)
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions