StackExchange Redis 集合搜索

StackExchange Redis Search on Collection

我们正在考虑使用托管在 Azure 中的 Redis。使用 StackExchange nuget,我们的第一个用例是针对我们的客户群进行搜索。最初大约有 10,000 名客户,但会随着时间的推移而增加。

客户会是一个特定的搜索模型,像这样:

    {
     "Id": 123,
     "Name": "Bob Smith",
     "Age": 72,
     "Postcode": "AB123EF",
     "Email": "bobsmith@anon.com",
     "Telephones": [
        "07710123456", 
        "01453123456"
      ]
    }

我的理解是,您应该避免将大型 blob 对象输入到 Redis 中,因此将列表存储为一个对象并不是一个好主意。所以我们使用 List* 函数将每个项目存储在一个键下并序列化数据。

初始工作看起来像这样:

    var tasks = new List<Task>();

    foreach (var customer in customers)
    {
     tasks.Add(db.ListLeftPushAsync(_key, JsonConvert.SerializeObject(customer)));
    }

    await Task.WhenAll(tasks).ConfigureAwait(true);

一切如我们所料,我确信有一些优化,但看起来还不错。

这从根本上给我们留下了查询信息的问题。我知道 Redis 将所有内容都存储为字符串,但我不明白如何搜索列表,因为它是 Redis 对象而不是字符串。所以我们不能使用 ListRange(_key).Where(c => c.Contains("Bob")) 例如。

如果我们的方法在这方面有误,或者我只是缺少一种方法,请告诉我。

完全同意@GuyKorland的说法,应该使用RediSearch这样的成熟产品,而不是基于redis实现自定义搜索引擎。

不过,我还是很高兴简单的介绍一下如何利用redis的数据结构实现一个简单的搜索引擎,仅凭我对redis的了解。

首先,如何将像您的示例客户这样的客户数据存储到 redis 中。你知道,redis 是内存上的 K-V 数据库,所以你可以将一个对象或一个 json 数据平存储为一个 redis Hash 结构,其键使用唯一的 Id & 前缀,如下。

CUSTOM#123 => 
  Id => 123
  Name => Bob Smith
  Age => 72,
  Postcode => AB123EF
  Email => bobsmith@anon.com
  Telephones#0 => 07710123456
  Telephones#1 => 01453123456

其次,使用redisListSorted Set结构为对象class的所有属性建立索引,如下

例如,对 NameAge 属性使用 List。这个想法是使用像NAME这样的前缀连接一个像Bob这样的对象的Name值和一个符号#来构建一个redis键并存储Id 值作为 redis List 元素。

\ To build `NAME` index for all objects contains `Bob`, `Smith` and `Bob Smith` in the `Name` propertory
NAME#Bob => 123, ... 
NAME#Smith => 123, ...
NAME#Bob Smith => 123, ...
\ Do the same operation above to build `AGE` index
AGE#72 => 123, ...

最后,您可以使用命令GET NAME#Bob在前缀为NAME#的redis键中搜索Bob,以准确获取客户Id的列表或命令keys NAME#Bob*模糊获取客户Id的列表,然后可以连续获取这些包含Name属性和Bob值的客户数据。如果要对客户 Id 的列表进行排序,则应该使用 Sorted Set 而不是 List 来对 Id 列表的结果进行排序。

我还是建议你使用基于redis的成熟产品,比如RediSearch,它会帮助你快速实现你的需求。