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
其次,使用redisList
或Sorted Set
结构为对象class的所有属性建立索引,如下
例如,对 Name
和 Age
属性使用 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
,它会帮助你快速实现你的需求。
我们正在考虑使用托管在 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
其次,使用redisList
或Sorted Set
结构为对象class的所有属性建立索引,如下
例如,对 Name
和 Age
属性使用 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
,它会帮助你快速实现你的需求。