当前位置: 首页 > 面试题库 >

Redis按范围过滤,排序并先返回10

暨修洁
2023-03-14
问题内容

假设我们有一个带有字段的简单mysql表(用户):

id
rating
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查询限制,并阅读“不等式过滤器中的属性必须在其他排序顺序之前进行排序”部分

为了获得与不等式过滤器匹配的所有结果,查询将在索引表中扫描第一条匹配的行,然后返回所有连续的结果,直到找到不匹配的行。为了使连续的行代表完整的结果集,必须先通过不等式过滤器对行进行排序,然后再进行其他排序。

话虽如此,您仍然可以有效地运行查询,但是解决方案并不完美。

  1. 创建薪资范围-0-5000、5000-10000、10000-15000等
  2. 创建类似的集users_with_salary:10000-15000。该集合将包含工资在给定范围内的用户ID。
  3. 同样,创建诸如`users_with_rating:1-2“之类的集合。该集合将包含评分在给定范围内的用户ID
  4. 现在,运行以下伪代码
    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服务器上运行它。

总之,如果要对数据运行复杂的查询,则最好在关系数据库中对其进行建模。



 类似资料:
  • 问题内容: 我正在尝试通过键入日期范围来过滤包含时间戳的列表 例如: JSFIDDLE html javascript 我希望能够用值填充“发件人”字段:27-05-2010 并且“ To”字段的值为:29-07-2015 并仅获取该范围内的记录。 (示例中的第一条记录)。 谢谢分配阿维 问题答案: 您可以创建一个自定义过滤器来实现此目的。 JSFIDDLE html javascript 此外,

  • 我对mongodb有意见。有人能解释一下为什么这样做(给出了一些结果): 这不起作用(返回零): 非常感谢。

  • 我正在使用弹性搜索。我以前从未使用过的网络NEST客户端。我想做的是在得分前按日期范围过滤结果。 我使用对象初始值设定项语法,因为它最适合我。 我已经完成了我想要的: 这给了我一个JSON请求,就像我期望的那样: 但留档过滤查询说"弃用在2.0.0-beta1.改为使用bool查询,查询的必须子句和筛选器子句”。 因为这是我发现的唯一包含过滤器的方法,有没有更好的方法来使用嵌套对象初始值设定项语法

  • 问题内容: 我设置了一个范围滑块,范围为0-2hr,时间以分钟为单位计算,然后像这样转换为hh:mm:10min,20min,1hr 20min,2hr。 但是现在我正在尝试使用范围滑块指定的范围来过滤一堆项目,而我很难做到这一点。 这是我所做的http://cdpn.io/LDusa 我正在使用http://danielcrisp.github.io/angular- rangeslider/d

  • 如何使用java8流过滤列表,如果找到的元素是过滤列表中唯一的元素,则返回该元素,否则(如果有更多的元素满足条件,或者没有满足条件的结果)返回例如 我需要这样的东西: 但我想知道我是否可以在一个单一的流中做到这一点? 有单一的流解决方案吗?

  • 是否可以在elasticsearch中更改范围聚合结果的排序?我在elasticsearch中有一个键控范围查询,并希望根据键而不是doc_count进行排序。 我的文件是: 和聚合查询: 此查询的结果是: 我想根据关键字对结果进行排序,而不是根据范围值。根据elasticsearch文档,无法指定排序顺序,当指定排序顺序时,我得到以下异常: 你有什么办法吗?谢谢!