我在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集?
感谢您的帮助。
答案 0 :(得分:2)
您的代码速度很慢主要是因为您将大量数据从Redis移动到PHP过滤器。这里的一般动机应该是在服务器上执行尽可能多的过滤。要做到这一点,你需要在CPU和CPU中支付某种代价。 RAM。
有很多方法可以做到这一点,这里有一个:
要仅允许有效地查找doc
,请保持doc.pos
对不变,但使用得分= 0的排序集,例如:
ZADD type_in_docs.1 0 2805.2339 0 2410.14208 0 3516.1810
这样您就可以使用以下内容模仿SISMEMBER
集合中的doc
:
ZRANGEBYLEX type_in_docs.1 [<$typeID> (<$typeID + "\xff">
您现在可以{(1}}在(通常)较小的SMEMBERS
集上,然后在每个filterDocs
上调用ZRANGEBYLEX
以获得即时收益。
如果你想做得更好 - 在极端情况下(即大filterDocs
,小type_in_docs
)你应该反过来。
如果你想做得更好,可以使用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