Dans mon projet, une fonction est fournie pour Autocomplete, et la quantité de données est probablement de plusieurs dizaines de milliers. Dans cet article, j'utilise l'exemple de récupération de nom pour illustrer. Pour la liste, veuillez cliquer sur la démo de l'auteur de Redis.
Autocomplete的功能,数据量大概在几万。这篇文章里我用姓名检索的例子来说明,列表请戳来自Redis作者的Demo。
在这样的列表里全是用户名,例如我们的系统里有一个用户对象:
public Class User { public string Id{get; set;} public string Name {get; set;} .... public string UserHead {get; set;} }
系统里需要一个用户的下拉列表,由于数据量大不能一次显示完,于是就加上了一个AutoComplete功能。缓存可以在本地内存中直接存储,不必使用像Redis这样的集中式缓存,这样缓存结构会更加简单
var users = new List<User>{...};//读到一个用户列表MemoryCache.Set("capqueen:users", users);//放入内存//读取var users = MemoryCache.Get<List<User>>("capqueen:users");
因为都是在内存里,所以直接存List就可以了,搜索的时候也可以直接的如下:
var findUsers = users.Where(user => user.Name.StartWith("A")).ToList();例如输入的字符是 “A“
相当简单,完全不用考虑如何存储,存储的数据结构。然而,一旦转向使用Redis这样的集中式缓存服务,我们需要重新考虑如何存储。
方案一:类似内存式的缓存实现。
本文里使用的Redis链接库是StactkExchange.Redis,出自StackOverFlow的开源产品。
var db = redis.GetDataBase();//获取0数据库var usersJson = JsonConvert.SerializeObject(users)//序列化db.StringSet("capqueen:users", usersJson);//存储var usersString = db.StringGet("capqueen:users"); var userList = JsonConvert.DeserializeObject<List<User>>(users);//反序列化
上面的方式逻辑上是没有问题的,编译也可以通过。但是仔细想一想,Redis作为独立的缓存服务和appSever是分开来的,这样的读取方式对redis服务器的IO是个负担,甚至这样的读取比本地内存缓存慢了太多了。
那如何解决呢?试想key-value的精髓是在于Key,那么对于List来说应该要把item分开来存储。
方案二:Keys模糊匹配。
在翻阅Redis的命令文档(见参考资料4)后,他惊奇地发现了Keys命令,这让他立刻修改了自己的方案。首先我们需要把要搜索的关键词建立为key,这里我把key定义为 "capqueen:user:{id}:{name}",其中{}内的是要用item对应属性替换的。代码如下:
var redis = ConnectionMultiplexer.Connect("localhost");var db = redis.GetDatabase(); var users = new List<User> { new User{Id = 6, Name = "aaren", Age=10}, new User{Id = 7, Name = "issy", Age=11}, new User{Id = 8, Name = "janina", Age=13}, new User{Id = 9, Name = "karena", Age=14} }; users.ForEach(item => { var key = string.Format("capqueen:user:{0}:{1}", item.Id, item.Name); var value = JsonConvert.SerializeObject(item); db.StringSet(key, value); });
所有的user都以单独的Key-Value方式存储,那么如何利用Keys搜索呢?我们来看下Redis的Keys命令:
KEYS pattern 查找所有符合给定模式 pattern 的 key 。 KEYS * 匹配数据库中所有 key 。 KEYS h?llo 匹配 hello , hallo 和 hxllo 等。 KEYS h*llo 匹配 hllo 和 heeeeello 等。 KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo 。 特殊符号用 \ 隔开
也就是说Keys能够进行简单的模糊匹配,那么我们这里的搜索就可以换成如下的方式:
var redis = ConnectionMultiplexer.Connect("192.168.10.178");var db = redis.GetDatabase();var server = redis.GetServer("192.168.10.178", 6379);var keys = server.Keys(pattern: "capqueen:user:*:a*");var values = db.StringGet(keys.ToArray());//反序列化var jsonValues = new StringBuilder("["); values.ToList().ForEach(item => jsonValues.Append(item).Append(",")); jsonValues.Append("]");var userList = JsonConvert.DeserializeObject<List<User>>(jsonValues.ToString());
注意以上的代码里,因为每个value是一个json,为了增加转化时的效率,我先处理成json arry再进行反序列化。
这种方案,确实是解决了我目前的问题,然而我注意到了Redis文档里的一段话:
KEYS 的速度非常快,但在一个大的数据库中使用它仍然可能造成性能问题,如果你需要从一个数据集中查找特定的 key
clé
à partir d'un ensemble de données, vous feriez mieux d'utiliser la structure de collection (ensemble) de Redis à la place. 🎜Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!