Skip to content

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

@nantiferov

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions