Search code examples
redisstackexchange.redisredisearch

Usage of RediSearch for simple string and integer indexing on entities


I need to store simple entity objects (C#) in Redis. I need also to search for them using secondary indexing and exact matching. After struggling with Redis natvie data types, I chose to try RediSearch for this task.

However I can't find how to use it the way I need.

My goal is very simple. Entity data structures are very straightforward. For example I have a Device class which sounds like this (I have omitted most string/int fields which must not be indexed, thus are not relevant for the example):

public class Device 
{
    public int Id { get; set; } // primary key
    public string Name { get; set; } // no indexing on this
    public string SerialNumber { get; set; } // this is indexed and unique
    public string ServerNode { get; set; } // this is indexed
    public int Status { get; set; } // this is indexed, possible values 0..4
    public string Info { get; set; } // no indexing on this
}

I need to store instances of the Device class and retrieve them:

  • individually, by SerialNumber
  • as a list by ServerNode and/or Status

I'm switching from MySQL to Redis, and just to make a sql-equivalent, I'm trying to replicate any of these sql-where clauses:

  • WHERE SerialNumber = 'RK01:"12345678"'
  • WHERE ServerNode = 'Node-US-01'
  • WHERE Status BETWEEN 1 AND 3
  • WHERE ServerNode = 'Node-IT-04' AND Status = 4

My project is written in C#, and I've begun using StackExchange.Redis and NRediSearch packages.

I cannot figure out how to create the correct schema indices (via redis-cli), nor I can understand how to properly store entities using NRediSearch Client class.

I don't need any of the full-text or tokenization/stopwords/etc. features of RediSearch, just "simple plain" text and integer indexing.

My first problem is the presence of punctuation characters (mostly hyphens, but in some cases also double quotes) in the strings.

I've created a schema based on TAG and NUMERIC field types:

FT.CREATE Device NOHL NOOFFSETS NOFREQS STOPWORDS 0 SCHEMA Id NUMERIC SORTABLE SerialNumber TAG SORTABLE ServerNode TAG SORTABLE Status NUMERIC SORTABLE

I've tried to add then "documents" via NRediSearch (but also via redis-cli for testing purposes) in the following way:

via redis-cli:

FT.ADD Device obj:Device:1 1.0 FIELDS Id 1 Name "FoobarDevice" SerialNumber "RK01:\"12345678\"" ServerNode "Node-US-01" Status 1 Info "this and that"

via NRediSearch

var rsc = new Client("Device", redis_database);
var doc = new Document("obj:Device:1");
doc.Set("Id", 1);
doc.Set("Name", "FoobarDevice");
doc.Set("SerialNumber", "RK01:\"12345678\"");
doc.Set("ServerNode", "Node-US-01");
doc.Set("Status", 1);
doc.Set("Info", "this and that");
rsc.AddDocument(doc);

if I type any of these commands in redis-cli, I get the right Device entity dumped on screen: > FT.GET Device obj:Device:1 or > HGETALL obj:Device:1

Now the problem: I am not able to perform any query on these indexes. First of all, it's not clear to me the proper query syntax on the command line; here are some non working examples:

>FT.SEARCH Device @ServerNode:{Node-US-01}

>FT.SEARCH Device "@ServerNode:{Node-US-01}"

>FT.SEARCH Device @ServerNode:"{Node-US-01}"

>FT.SEARCH Device @ServerNode:{"Node-US-01"}

>FT.SEARCH Device @SerialNumber:{RK01:\"12345678\"}

I either get a syntax error or no results.

I know the serial number string is a little bit odd but I cannot change its format.

Should I store escaped version of string values in the document? Which is the right syntax for reproducing the same results as the sql-like where clauses? And how can I deal with string search on field values that include double quotes (") in the value itself?

Last but not least, I could not find any clarifying example or documentation about using NRediSearch Query class and QueryBuilder namespace (but this will maybe be a little less obscure after I understand how RediSaerch "thinks").


Solution

  • You indexed the data just fine, the only problem is with your search query. Your data contains chars that RediSearch tokenize automatically (like - and :). In order to avoid tokanization you need to escape them in the query. Notice that when using redis-cli you must do double escaping so the escape char (\) will actually be sent to the redis. With " its more problematic, you must escape it in the query and in the redis-cli so you will need three escapes (two so the escape char will be sent to redis and one to escape it in the cli). It will look something like this:

    127.0.0.1:6379> FT.SEARCH Device "@ServerNode:{Node\\-US\\-01}"
    1) (integer) 1
    2) "obj:Device:1"
    3)  1) Id
        2) "1"
        3) Name
        4) "FoobarDevice"
        5) SerialNumber
        6) "RK01:\"12345678\""
        7) ServerNode
        8) "Node-US-01"
        9) Status
       10) "1"
       11) Info
       12) "this and that"
    
    127.0.0.1:6379> FT.SEARCH Device "@SerialNumber:{RK01\\:\\\"12345678\\\"}"
    1) (integer) 1
    2) "obj:Device:1"
    3)  1) Id
        2) "1"
        3) Name
        4) "FoobarDevice"
        5) SerialNumber
        6) "RK01:\"12345678\""
        7) ServerNode
        8) "Node-US-01"
        9) Status
       10) "1"
       11) Info
       12) "this and that"
    

    You can read more about tokanization and escaping here: https://oss.redislabs.com/redisearch/Escaping/