Redis按范围过滤,排序并先返回10
假设我们有一个带有字段的简单mysql表(用户):
idrating
salary
我想获得10个具有最高评级和指定范围(50-100)薪水的用户,即在mysql中
SELECT id from user WHERE salary>50 and salary<100 ORDER by rating limit 0, 10
此操作在100K用户表上运行20ms。
假设我的redis值相同:Zlist评分(rating => user_id)Zlist薪水(salary => user_id)
我使用redis看到的所有解决方案包括复制10万薪水Zlist,删除不需要的条目以及与10万评级列表合并,例如
zinterstore 1 search salary zremrange search -inf 50
zremrange search 100 +inf
zinterstore 2 search rating weights 0 1
zrange search 0 10
这绝对是慢的(为什么要复制100k元素以删除大多数元素?)。
有什么方法可以使用redis至少实现同等效率吗?
回答:
您描述的用例无法在NoSQL解决方案中完美建模。这不是Redis的限制。
让我解释一下。您正在一个字段上运行范围查询,而在另一个字段上进行排序。这不是NoSQL解决方案擅长的。例如,Google App
Engine禁止此类查询。查看GAE查询限制,并阅读“不等式过滤器中的属性必须在其他排序顺序之前进行排序”部分
为了获得与不等式过滤器匹配的所有结果,查询将在索引表中扫描第一条匹配的行,然后返回所有连续的结果,直到找到不匹配的行。为了使连续的行代表完整的结果集,必须先通过不等式过滤器对行进行排序,然后再进行其他排序。
话虽如此,您仍然可以有效地运行查询,但是解决方案并不完美。
- 创建薪资范围-0-5000、5000-10000、10000-15000等
- 创建类似的集
users_with_salary:10000-15000
。该集合将包含工资在给定范围内的用户ID。 - 同样,创建诸如`users_with_rating:1-2“之类的集合。该集合将包含评分在给定范围内的用户ID
- 现在,运行以下伪代码
String userids[]; for(rating = 10; rating > 0; rating--) {
for(salary = min_salary; salary < max_salary; salary += 5000) {
String salary_key = "users_with_salary:" + salary + "-" + (salary+5000);
String rating_key = "users_with_rating:" + rating + "-" + (rating+1);
userids.append(redis.sinter(salary_key, rating_key));
if(userids.length > 10) {
break;
}
}
}
使用redis 2.6和lua脚本,您甚至可以在lua服务器上运行它。
总之,如果要对数据运行复杂的查询,则最好在关系数据库中对其进行建模。
以上是 Redis按范围过滤,排序并先返回10 的全部内容, 来源链接: utcz.com/qa/402766.html