如何根据Redis中的另一个SET按其concat值过滤任何SET

时间:2015-02-05 13:09:26

标签: lua redis

我在Redis中有一个过滤器优化问题。

我有一个Redis SET,用于保存语料库中类型的doc和pos对。

示例:

smembers type_in_docs.1

结果:doc.pos对

array (size=216627)
0 => string '2805.2339' (length=9)
1 => string '2410.14208' (length=10)
2 => string '3516.1810' (length=9)
...

我根据用户选择创建了另一个redis set 它包含选定的文档。

smembers filteredDocs

我想根据用户文档ID选项过滤 doc.pos " type_in_docs" 。 事实上,如果我没有在集合中使用concat值,那么 SINTER 很容易。

所以我实现了一个php过滤器代码,如下所示。 它工作但需要优化。 在大型doc.pairs中设置太多时间需要。 (几乎在150000名成员之后!)

$concordance= $this->redis->smembers('types_in_docs.'.$typeID);
$filteredDocs= $this->redis->smembers('filteredDocs');

$filtered = array_filter($concordance, function($pairs) use ($filteredDocs) {
    if( in_array(substr($pairs, 0, strpos($pairs, '.')), $filteredDocs) ) return true;
   });

我尝试将分数设为docId的排序集。 Bu无法找到得分值的交叉或过滤选项。

我正在考虑并使用支持的密钥,集合或Lua脚本搜索基于Redis的解决方案以进行时间优化。 但没有找到。

如何使用concat值过滤Redis集?

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

您的代码速度很慢主要是因为您将大量数据从Redis移动到PHP过滤器。这里的一般动机应该是在服务器上执行尽可能多的过滤。要做到这一点,你需要在CPU和CPU中支付某种代价。 RAM。

有很多方法可以做到这一点,这里有一个:

  1. 确保您使用的是Redis v2.8.9或更高版本。
  2. 要仅允许有效地查找doc,请保持doc.pos对不变,但使用得分= 0的排序集,例如:

    ZADD type_in_docs.1 0 2805.2339 0 2410.14208 0 3516.1810
    
  3. 这样您就可以使用以下内容模仿SISMEMBER集合中的doc

        ZRANGEBYLEX type_in_docs.1 [<$typeID> (<$typeID + "\xff">
    
    1. 您现在可以{(1}}在(通常)较小的SMEMBERS集上,然后在每个filterDocs上调用ZRANGEBYLEX以获得即时收益。

    2. 如果你想做得更好 - 在极端情况下(即大filterDocs,小type_in_docs)你应该反过来。

    3. 如果你想做得更好,可以使用Lua来结束过滤逻辑 - 例如:

      -- @usage:  redis-cli --filter_doc_pos.lua <filter set keyname> <type pairs keyname> 
      -- @returns: list of matching doc.pos pairs 
      
      local r = {}
      
      for _, fv in pairs(redis.call("SMEMBERS", KEYS[1])) do
          local t = redis.call("ZRANGEBYLEX", KEYS[2], "[" .. fv , "(" .. fv .. "\xff")
          for _, tv in pairs(t) do
              r[#r+1] = tv
          end
      end
      
      return r