我正在将一些伪智能缓存构建到LINQ 查询提供程序中。我想做的(理想情况下)是在某些情况下使用给定查询的表达式树作为缓存键。但是,我不想存储整个对象图本身,那么从表达式树中获取类似哈希和的值的快速方法是什么?或者如果我走错了方向,还有更好的选择吗?
3 回答
让我们考虑一下。大概您想将(表达式树的哈希,结果)存储在地图中。
如果不存储整个树,则无法区分相同的树和哈希冲突。
根据定义,哈希将较大的集合映射到较小的集合(这就是哈希有用的原因),因此根据定义,您将(至少有可能发生)冲突。
当您获得表达式树时,您将对它进行哈希处理,然后在您的地图中查找结果,这会导致两种可能性:
这是地图中没有的散列,您以前从未见过的散列。你必须让这个运行,因为你没有缓存的结果。
它是映射中的哈希,但由于您没有将产生哈希的旧表达式树存储在映射中,因此无法将新传递的表达式与旧表达式进行比较。您可能有匹配或可能有碰撞,但没有办法区分这两种可能性。您无法返回缓存的结果,因为它可能是冲突。
此外,即使它不是冲突,即使它与您上次看到的表达式树完全相同,我们如何知道支持对象 - 数据库,列表,任何*没有添加元素或删除或修改,使得表达式返回的结果可能与缓存的结果不同?
也就是说,您可以递归地散列一棵树:
hashATree:
if leaf node
return hash(node)
else
return hash(node) *OP* hashATree(left.child) *OP* hashATree(right.child)
其中OP是一些操作(可能是乘法),或者更一般地说hash(node) *OP* accumulate( children.begin(), children.end(), *OP* );
当然,这与我们用来评估表达式树的递归相同(期望我们调用node.eval( children);
)
您可能可以使用此处提供的代码来完成。 http://petemontgomery.wordpress.com/2008/08/07/caching-the-results-of-linq-queries/
这显示了如何解决闭包问题并支持本地集合。
嗯,其实我觉得这可能很简单。
Expression 对象的 ToString() 方法将为您提供 Expression 的文本表示,如果您只想评估键的等效性,您可以对其进行散列。