Indexing 使用占位符快速查找树?

Indexing 使用占位符快速查找树?,indexing,data-structures,tree,s-expression,Indexing,Data Structures,Tree,S Expression,对于我正在考虑的一个应用程序,将有一个大型(100000+)树“数据库”(想想编程语言中的表达式,或S表达式),我需要查询该数据库中与特定给定表达式匹配的表达式 在给出我想要的详细信息之前,请注意,我希望了解有关索引一大组树以优化子树查找的任何信息 在我的特定情况下(即后台将由证明助手使用),表达式具有以下结构(类似于Haskell的表示法): data Expression=Placeholder Id | VarName Id | ConstName Id[表达式] 或作为S表达式形式的B

对于我正在考虑的一个应用程序,将有一个大型(100000+)树“数据库”(想想编程语言中的表达式,或S表达式),我需要查询该数据库中与特定给定表达式匹配的表达式

在给出我想要的详细信息之前,请注意,我希望了解有关索引一大组树以优化子树查找的任何信息

在我的特定情况下(即后台将由证明助手使用),表达式具有以下结构(类似于Haskell的表示法):

data Expression=Placeholder Id | VarName Id | ConstName Id[表达式]
或作为S表达式形式的BNF:

Expression='?'Id | Id |'('Id Expression*')”
其中,
Id
是某种标识符

例如,我可以有一个包含以下表达式的数据库

(相当于ph-ps)
(不在(应用(sqrt)(2))中)
(当量(方程式A-B)(对于所有x(当量(in?x?A)(in?x?B)))
在此上下文中,如果可以用表达式替换占位符使两个表达式相等,则两个表达式匹配。因此,在上述迷你数据库中查找
(eq(eq A(emptyset))?ph)
将得到第一个和最后一个表达式


那么,我该如何在一大组带有占位符的(表达式)树中实现快速查找呢?我可以使用什么样的索引数据结构?

我将使用。每个钥匙将由以下部件之一组成:

  • 常量名称标识符
  • 变量w/上下文信息
  • 常量值
  • 占位符
它们应该以某种方式排序——可能是占位符,然后是所有常量名(字母顺序),然后是变量(范围顺序,然后是参数顺序),然后是常量值(数字顺序)。只要在trie中有具体的使用顺序,您就可以了

遍历表达式的树,在遇到相应的键时将它们注入trie。对要插入到数据结构中的所有表达式执行此操作。当需要查询时,您可以以类似的方式遍历trie,但需要使用一些新规则

  • 所有内容都与占位符节点匹配。如果它也匹配其他一些键,那么您需要探索这两个分支(通过类似于DFS的递归方法很容易完成)
  • 占位符匹配所有内容。这与前一点不同——我们在这里讨论的是查询中的占位符,前一个项目符号将占位符视为trie键
现在,这确实意味着当您遇到占位符时,搜索空间可能会有点“爆炸”,但有一件事您可以尝试在实践中缓解这种情况。以广度优先的方式遍历表达式的树(在trie的构造和查询中)。这意味着,如果其中一个参数是占位符,则不必对到目前为止匹配该表达式的每一子树进行全深度搜索,而是跳转到下一个参数,该参数可能不是占位符,因此将大大缩减搜索空间(与匹配“所有内容”相比)

为了完整起见,让我们举一个例子

(not (in (appl (sqrt) (2)) (Q)))
并从中创建一个trie条目-

not -> in -> apply -> "Q" -> sqrt -> 2
添加
(非(在?ph E中))
将导致-

not -> in -> apply -> "Q" -> sqrt -> 2
         \-> ?ph   -> "E"
继续以这种方式将表达式注入trie。也以这种方式遍历以进行查询,直到到达trie中搜索的末尾,并返回匹配的结果

注意-这些条目的唯一性基于您不必支持可变函数的假设。如果这样做,请在每个键上附加一些上下文信息(阅读下面的段落了解如何执行此操作),以区分哪些参数指向哪些函数

我忽略了一个细节——变量。如果您只希望它们是完全相同的变量名时匹配,则无需进行任何工作。但这可能不是你想要的;您可能希望它匹配通用变量,只要它们彼此“一致”。实现这一点的方法是为每个变量分配一个标识符,该标识符表示它最初定义的范围


实现这一点最简单的方法就是从其祖先的参数顺序的串联中合成一个标识符。也就是说,如果一个变量首先被定义为一个函数的第二个参数,它是根函数的第五个参数,那么我们可以将它标记为
(5,2)
(2,5)
,以直观上更合理的为准。无论哪种方式,这都将确保为变量提供一致的标识符,而不考虑其他地方的其他变量/函数。然后像往常一样使用这个新变量名。

我找不到像“reference request”这样的标记,但当然我也很欣赏指向文献的指针。(就像CS中的大多数事情一样,这可能在70年代就已经完成了。:-(Prolog pun的意思)你能再解释一下为什么第一个和第三个表达式匹配吗?谢谢。@Primusa在第一个例子中,用
(eq A(emptyset))
替换
?ph
,用
替换
?ps
(forall?x(equal(In?x A)(In?x(emptyset)))
。在第三种情况下,(一致地)用
A
替换
?A
,用
(清空)
替换
?B
(和
?x本身)。这使得两者都等于
(eq(eq A(emptyset))(forall?x(eq(in?x A)(in?x(emptyset))
@Primusa对不起,前面的评论解释了第一个和第三个如何相互匹配。