首页 >数据库 >Redis >Redis分词索引法怎么用

Redis分词索引法怎么用

王林
王林转载
2023-05-26 17:28:521038浏览

分词索引法

这种方式是我实践过后,结合上篇的前辈给的观点觉得唯一比较可行且符合redis特性的方式,不过最终效率上还是比不过内存。

详细的实现思路清看Redis作者博客(参考资料1),这里的例子还是基于UserName,英文,并且只针对词组做了长度为3的分词,其他场景请自行扩展。

首先基于AutoComplete的字母搜索,那么我们需要对所有的Name做一个分词,即:

abc => (a, ab, abc)

当输入a时,我们会直接获取集合a中的内容;当输入ab时,我们会直接获取集合ab中的内容。那么我们开始转换,首先我们需要对User表的姓名进行分词:

var redis = ConnectionMultiplexer.Connect("localhost");var db = redis.GetDatabase();for (var i = 1; i < 4; i++)
{    var data = dbCon.Lookup<string, int>(string.Format(@"select words, id from (
                                    select Row_number() over (partition by words order by name) as rn,id,words from (
                                        select  id, SUBSTRING(name, 1, {0}) as words, name from User 
                                    ) as t
                                    ) t2 where rn <= {1} and words != &#39;&#39; and words is not null", i, 20));

    data.ForEach((key, item) =>  {
         db.SetAdd("capqueen:Cache:user:" + key.ToLower(), item.Select<int, RedisValue>(j => j).ToArray());
      });
}

第一步:采用SQL,分组排序筛选出每个分词的前20条数据,这里使用的是OrmLite的语法。

第二部:存入RedisSet,注意这里其实只是做了一个索引,并不保存具体的User内容

接着搜索的时候我们可以实现如下:

public List<User> SearchWords(string keywords)
{            var redis = ConnectionMultiplexer.Connect("localhost");            var db = redis.GetDatabase();            var result = db.SetMembers("capqueen:Cache:user:" + keywords.ToLower());            var users = new List<User>();            if (result.Any())
            {                //转换成ids                var ids = result.ToList().Select<RedisValue, RedisKey>(i => i.ToString());                //按照keys获取value ,事先已经存好了Usersvar values = db.StringGet(ids.ToArray());                //构造List Json以加速解析var portsJson = new StringBuilder("[");

                values.ToList().ForEach(item =>{                    if (!string.IsNullOrWhiteSpace(item))
                    {
                        portsJson.Append(item).Append(",");
                    }
                });

                portsJson.Append("]");

                users = JsonConvert.DeserializeObject<List<User>>(portsJson.ToString());
            }
}

经过实际的测试,这样的写法比前面的Keys确实好了不少,但是性能还是差强人意的。

Scan搜索法

这种方法是我在查阅了Redis的文档之后,发现的,但是也就是试验一下,估计也不能用做生产环境大规模查询。

根据数据结构的不同,Scan分为了SCAN、HSCAN、SSCAN和ZSCAN。更详细的信息请参阅文档。我们这里采用了ZSCAN:

ZSCAN key cursor [MATCH pattern] [COUNT count]

这里cursor是搜索的迭代的一个游标,具体还没弄明白,pattern就是匹配规则 count就是记录条数

由于我使用的是StackExchange.Redis,它提供的zscan方法是:

IEnumerable SortedSetScan(RedisKey key, RedisValue pattern = null, int pageSize = 10, long cursor = 0, int pageOffset = 0, CommandFlags flags = CommandFlags.None);

public void CreateTerminalCache(List<User> users)
{            if (users == null) return;            var db = ConnectionMultiplexer.GetDatabase();            var sourceData = new List<KeyValuePair<RedisKey, RedisValue>>();            //构造集合数据var list = users.Select(item =>{                var value = JsonConvert.SerializeObject(item);                //构造原始数据sourceData.Add(new KeyValuePair<RedisKey, RedisValue>("capqueen:users:" + item.Id, value));                //构造数据    return new SortedSetEntry(item.Name, item.Id);
            });            //添加进有序集合,采用name - id db.SortedSetAdd("capqueen:users:index", list.ToArray());            //添加港口数据key-value            db.StringSet(sourceData.ToArray(), When.Always, CommandFlags.None);
}

然后搜索的时候如下:

public List<User> GetUserByWord(string words)
{            var db = ConnectionMultiplexer.GetDatabase();            //搜索var result = db.SortedSetScan("capqueen:users:index", words + "*", 10, 1, 30, CommandFlags.None).Take(30).ToList();           var users = new List<User>();            if (result.Any())
            {                //转换成ids                var ids = result.ToList().Select<SortedSetEntry, RedisKey>(i => i.ToString());                //按照keys获取valuevar values = db.StringGet(ids.ToArray());                //构造List Json以加速解析var portsJson = new StringBuilder("[");

                values.ToList().ForEach(item =>{                    if (!string.IsNullOrWhiteSpace(item))
                    {
                        portsJson.Append(item).Append(",");
                    }
                });

                portsJson.Append("]");

                users = JsonConvert.DeserializeObject<List<User>>(portsJson.ToString());
            }            return users;
}

以上是Redis分词索引法怎么用的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文转载于:yisu.com。如有侵权,请联系admin@php.cn删除