通过一系列Redis的筛选,排序和第10回(Redis filter by range, sort

2019-07-29 01:29发布

假设我们有一个简单的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用户表20毫秒。

假设我在redis的相同:Zlist等级(等级=> USER_ID)Zlist薪水(工资=> 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的至少同等效率?

Answer 1:

您所描述的情况下使用,不能在NoSQL的解决方案优雅建模。 这不是一个Redis的限制。

让我多一点解释。 你在一个领域的运行范围查询,并在另一个排序。 这是不是NoSQL的解决方案所擅长的。 例如,谷歌应用程序引擎禁止此类查询。 看看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服务器上运行此。

总之,如果你想对你的数据进行复杂的查询,最好是它在一个关系数据库模型。



Answer 2:

使用脚本,你可以使用“ZRANGEBYSCORE工资50 100”来获得,其中工资是50和100之间的用户并将结果存储到TMP组。 假设你在哈希在关键存储用户的评级为“用户:[ID]”,然后你可以做的“排序TMP按用户名:* - >评级LIMIT 0 10”。

不幸的是,你目前不能SORT通过在zset的条目相关联,所以你就需要存储或者只或附加在一个单独的哈希使用这种方法,您的评价值的分数。

当然,你也可以使用“ZINTERSTORE TMP2 2评级TMP平衡重1 0”,然后“ZRANGE TMP 2 0 10”,但会比使用排序效率较低,因为它需要排序的所有TMP2的开销(因为它是被创建),而与SORT LIMIT使用局部快速排序算法有效地仅排序10个结果实际返回。 你可能想保持周围的TMP,因此您可以在范围在这种情况下存储用户的薪金在50和100之间的临时zset按评分排序可能是有意义的迅速恢复其他用户虽然。

我觉得那种方法我描述实际上是作为算法SQL数据库能达到那样好。 一旦你使用索引由一系列在一个字段筛选,我知道没有办法,在另一个领域中的指数可以用来改善分拣小结果集的效率。 我相信一个SQL数据库将只使用部分快速排序或相当于仅排序的结果返回。



文章来源: Redis filter by range, sort and return 10 first