作者:Catharine Wyss,Chris Giannella,Edward Robertson
会议/期刊:DBLP 2001
FastFDs算法
定义和例子
是关系模式,是的一个实例。是属性数量,是元组数。
定义1
函数依赖:是关系的一个函数依赖当且仅当对任意元组,。写作
平凡函数依赖:是平凡的当且仅当
最小函数依赖:是最小的当且仅当,
定义2
函数依赖集合的规范覆盖:关系上的函数依赖集合的规范覆盖为。
定义3
差集:对于,元组和的差集为。
关系的差集:
关系的差集在上的投影:
例2:
表1 关系表r0
表1是关系表,有
定义4
覆盖:设为的幂集(即所有属性组合的集合),且。则覆盖当且仅当。
最小覆盖:是的覆盖且不存在覆盖,则:是的最小覆盖。
考虑,覆盖。设,则。在上值不同的任意两个元组在上的值一定也不同,也就是说,可以区分任意两个在上值不同的元组,也就意味着。因此,有:
引理1
设,则当且仅当覆盖。
定理1
设,是上的一个关系实例。是上的一个最小函数依赖当且仅当是的一个最小覆盖。
定理1把原问题计算转化为寻找的问题。令。的覆盖一定也是的覆盖。因此,我们可以只保留最小差集并计算的最小覆盖即可。
例3:在例2的关系表中,,。的最小覆盖有。因此RHS为的最小函数依赖有:。
更进一步优化,如果有两个元组只在上值不同,即,则一定是平凡的。在这种情况下,算法可以直接终止。
通过计算的最小覆盖来计算的思路最早在Dependency Inference (vldb.org)里被提出。作者发现里的元组组成了超图里的边。因此,计算的问题转化为计算超图的最小覆盖问题。SIAM95里对许多超图问题的时间复杂度进行了系统的研究。PODS97里研究了数据挖掘问题大框架(包括函数依赖发现问题)与超图遍历问题的关系。
这个方法也是Dep-Miner算法的基础。FastFDs算法和Dep-Miner算法的主要区别是:Dep-Miner采用层次搜索策略计算覆盖,FastFDs采用一种启发式的深度优先搜索策略。
计算差集
FastFDs首先计算基于关系和模式的差集,计算过程如图1所示。然后,对于每一个属性,利用计算并计算的最小覆盖,计算过程如图4所示。在这一部分,我们描述genDiffSets,下一部分我们描述findCovers。在计算
TANE算法的复杂度与成线性关系。另一方面,最多有个可能的差集(元组对的个数),所以计算这些差集的时间复杂度为。在中,提出了一个在某些情况下减少计算差集的时间复杂度的方法。该方法计算一致集。一致集与差集互补。因此,差集可以定义在一致集上。
定义5
- 给定,和的一致集为。
- 关系的一致集为。
引理2将和联系起来了。给定,我们定义。
引理2
给定模式上的关系实例且,。
证明:设,根据定义,对于所有有,因此 ,。设,则。所以存在使得。因此根据定义,对于所有有,。
为了计算,我们首先计算关系的一致集。然后计算里每个成员的补集以得到。这个看似拐弯抹角的方法的好处在于里的成员不是从原始关系的元组对中产生,而是从精简划分里的元组对中产生。对于随机整数值关系表(?),精简划分中的元组对数量与原始关系中的元组对数量相比大大减少,加速了计算。
定义6
给定,定义:
- 关于属性等价,当且仅当。
- 对于,令为关于属性的等价类,则的精简划分为
- 的精简划分为
- 的最大精简划分为
引理3
设,如果和没有出现在任意,则和在所有属性上的值都不同。
因此,只需要处理每一个中的元组对来计算。图1展示了计算的程序genDiffSets。
图1 genDiffSets:从一个关系实例中计算差集
发现的最小覆盖
FastFDs使用图4中的findCovers程序寻找的最小覆盖。每一个不包含的的子集都可能是的最小覆盖。考虑一个简单的搜索树,暴力产生不包含的的子集。如图2所示,对于,从根节点到每个节点的路径代表了的子集。共有个节点。深度优先、从左到右的搜索过程可以无重复地按照字典序产生的子集。注意,在图2中的字典序为。
图2 生成R-{A}的子集
优化后的搜索方法findCovers构建一棵搜索树,同样地,属性是有序的,但是不像图2中的单纯按照字典序,这个属性顺序随着深度搜索的进行不断变化。如图3所示,是寻找的最小覆盖的过程。树中的每个节点,我们对剩余的属性按照它们覆盖的差集(这些差集在处理当前节点之前还未被覆盖)的数量排序。当两个属性覆盖的差集数量相同时,则按照字典序排序。在每个节点,我们不断更新剩余的差集以及剩余属性的顺序。
图3所示的方法是findCovers所使用的搜索策略,支撑了FastFDs算法(图4)。图3中的叶子节点分为以下两种情况:
-
如果某个叶子节点还有剩余差集未被覆盖,但是已经没有剩余属性了,则为失败状态(此叶子节点不存在函数依赖)。如图3中的叶子⑤,⑦,⑧,⑨。
-
如果某个节点不存在还未被覆盖的差集,又分为两种情况:
(a) 该叶子节点表示的函数依赖不是最小的(叶子①)。合法性检测包括测试当前叶子节点代表的LHS的直接子集是否能构成合法的LHS。
(b) 否则,输出从根节点到当前叶子节点的路径作为当前属性的一个函数依赖的LHS。(叶子②,③,④,⑥)。 在每个节点,我们使用的是贪婪搜索策略:我们优先搜索覆盖剩余差集最多的属性(因为我们的目标是找到覆盖所有差集的属性组)。这个贪婪搜索策略表现良好(见实验部分),但是也会做一些无用功。如图3中的叶子①,函数依赖不是最小的,因为也是合法的函数依赖(叶子⑥)。这种情况的出现是由于当两个属性覆盖的差集数量相同时,我们按照字典序对它们排序,造成了多余的分支。多余的分支很难辨别,因此算法在输出它生成的函数依赖前必须进行最小性检测。
图3 搜索子集格以寻找最小覆盖
我们正式定义属性的顺序。为一些属性组合的集合。对于,为中包含的成员个数。对于:
图3这个启发式的,深度优先搜索过程可以用递归方法findCovers表示(图4)。为了计算,我们对于每个属性搜索类似图3的树。注意若(例如),则不存在任意两个元组在上的值不同,即所有元组在上的取值相同,此时作为RHS的最小函数依赖只有。上文提到过,若,则不存在属性作为RHS的非平凡函数依赖。图5所示的FastFDs算法先检查上述两种情况是否发生,未发生的情况下迭代地对执行findCovers。
图4 findCovers:寻找$\underline{D_r^A}$的最小覆盖
FastFDs的复杂度
前文定义过,这里设,让我们复盘一下FastFDs的执行过程。
图5 FastFDs:计算一个关系实例的最小函数依赖
-
首先,我们必须计算关系的差集,花费时间;为了从计算,我们需要最小化包含的集合。设,则最小化过程花费时间(why?);因此计算的时间为。
-
给定,则findCovers的复杂度为,其中是我们不完美的启发式搜素过程造成的多余的工作。
-
由于我们对每个属性调用findCovers函数,因此FastFDs中的主循环(2-8行)花费时间。 总的来说,我们算法的最差时间复杂度为
然而,FastFDs的空间复杂度比层级搜索的Dep-Miner和TANE降低了指数级。FastFDs只需要空间。的上限是。TANE和Dep-Miner消耗了大量空间在候选集上。因此,当很大时,FastFDs显著快于层级搜索方法,因为的大小是的指数级。这个趋势在伯努利关系实例中更为明显,因为其函数依赖的平均长度为或更大。
实验结果
FastFDs已经用C++实现。测试环境:700MHz Athlon系统(128MV RAM),Red Hat Linux6.1。我们同样实现了我们自己版本的Dep-Miner,其使用和FastFDs相同的代码读取输入关系表并计算。我们自己版本的Dep-Miner和FastFDs都完全在内存中运行。我们使用的TANE版本可以在网页上运行。
整数值关系实例
我们的第一个实验集包括一些随机生成的整数关系实例。表2展示了TANE,Dep-Miner,FastFDs在这些关系实例上的性能。每个关系实例根据相关系数(CF)生成。CF越高,每列中出现的不同值个数越少(每列的不同值个数范围为)。随着CF增加,精简划分的长度也增加,差集计算消耗时间增加。
表2 随机整数值关系实例的结果;|R|=20
表2的定性分析
表2中的结果揭示了以下结论:
- Dep-Miner和FastFDs中少于0.1%的计算时间花费在搜索函数依赖上;超过99.9%的时间用于计算差集。
- 随着CF增加,TANE的性能不断接近Dep-Miner和FastFDs的性能(图6)。
表2中的结果表明了差集计算的最好情况(与成线性关系,每个实例只出现了一次)和TANE在计算过程的每个阶段都必须计算一个线性的划分的差别。
总而言之,在随机生成的有20个属性的整数实例上,当CF范围为0.0-0.9,Dep-Miner和FastFDs比TANE快2-3倍。
图6 随机整数值关系实例(表2)
表3的定量分析
表三对比了FastFDs和Dep-Miner在固定元组数(10,000),属性数量从10到60时的性能。注意到随着CF增加,FstFDs逐渐变得比Dep-Miner更高效。当CF为0.0时,Dep-Miner用时是FastFDs的倍,当CF为0.9时,Dep-Miner用时是FastFDs的2倍。注意到随着CF增加,计算的最小函数依赖的平均长度从2(CF=0.0)增加到3(CF=0.9)。这个趋势可以帮忙解释当CF增加时,为什么FastFDs更高效,且这个现象在伯努利关系实例中更明显,当最小函数依赖的平均长度增加到时,Dep-Miner变得非常低效。
表3 随机整数值关系实例的结果;|r|固定为10,000;删除了计算差集的时间
下一节中可以看出,低CF的随机整数关系实例不能很好地预测现实生活中的关系实例。伯努利关系实例在恰好这方面表现良好。伯努利关系实例
我们的第二个实验集包括随机生成的伯努利关系实例。伯努利关系实例只包含两个值(通常是0和1)。在这方面,伯努利关系很像频繁项集问题中的“购物篮”关系。
随机伯努利关系实例是发现最小函数依赖的很好的测试。尽管随机整数值实例似乎很适合FastFDs,Dep-Miner,Tane这些搜索方法,但最小函数依赖数量很少,而在伯努利实例中则不同。随机伯努利实例中的最小函数依赖的平均长度已经被量化。对于个属性的伯努利实例,最小函数依赖的平均期望长度是,当元组数是。这个长度代表了n个属性的幂集格中任意一层的可能的最大子集的数量,在实践中,当随n呈指数增长时,表示返回的最小FDs的数量。
当小于30时,平均长度为的最小函数依赖涉及到相对小的数据库,Dep-Miner和FastFDs计算差集的时间被最小化。在随机整数数据库中,Dep-Miner和FastFDs在搜索函数依赖的时间少于0.1%,然而在的伯努利关系实例中,超过99%的时间花费在搜索函数依赖上(而不是计算差集)。
另外一个有趣的地方在于,由于有许多大小为的子集,层级算法需要指数级的空间去存储中间层的候选集合。因此,需要查看层级搜索算法的指数级空间使用和FastFDs的的空间使用的影响。
表4阐述了TANE,Dep-Miner和FastFDs在伯努利数据库上的相对性能,当,且范围为20至28。
表4 伯努利关系实例上的结果
表4的定量分析
三种算法的函数依赖的数量都随着成指数增长。然而,我们可以看到TANE和Dep-Miner的指数级空间使用的影响。当时,TANE的时间大约是FastFDs的两倍。在,由于大量使用磁盘交换空间,TANE的执行时间迅速增加。当,TANE运行超出内存大小。Dep-Miner的结果类似,尽管Dep-Miner的空间使用情况略好于TANE,其时间性能比FastFDs差了两个数量级。
FastFDs不会出现内存用尽的问题。这很重要,因为内存是比CPU更为稀缺的资源并且当内存交换被避免时,CPU会被使用的更高效。
备注1 在伯努利实验上的一个重要结论是,当越大时,相比随机整数值实例,伯努利实例上的差集计算效率越低。事实上,对于伯努利实例,计算差集的暴力搜索算法比优化算法更高效。因此,可能有更好的优化算法来计算个值的关系实例(k比较小)。
图7 表4的结果:右边y轴单位是对数
机器学习库关系实例
我们的第三个实验集涉及从机器学习仓库里提取的非合成的关系。表5展示了FastFDs,TANE,Dep-Miner三种算法在9个关系表上的性能。表6展示了在删除差集计算时间后Dep-Miner和FastFDs的性能。
表5 在机器学习关系实例上的结果
表6 表5中结果删除了差集计算时间
表5和表6的定量分析
首先比较FastFDs和Dep-Miner的运行时间。在所有情况下,FastFDs性能都不次于Dep-Miner。随着的增长,FastFDs比Dep-Miner快的越来越多。
接下来比较FastFDs和TANE的运行时间。注意当很大时,FastFDs的时间很长,这是由于的差集计算时间。另一方面,随着增加,TANE的内存消耗迅速增加。对于Horse-Colic数据库()FastFDs快速发现了最小函数依赖;而TANE超出内存限制。在现实情况中,发现函数依赖的最好方法可能是TANE(小和大)和FastFDs(小和大)的平衡。
结论和未来方向
本文提出了一个新的函数依赖发现方法FastFDs,在差集上利用启发式,深度优先搜索发现最小函数依赖。
我们的实验结果表明FastFDs在以下每种基准关系实例上都很有竞争力:(1)不同相关系数的随机整数实例,(2)随机伯努利实例,(3)现实生活中的机器学习库关系实例。事实上,我们的实验表明,对于宽的关系(大),在任何类型的关系实例上,FastFDs都表现非常好,原因在于深度优先搜索算法固有的空间高效性。对比较窄的关系,TANE可能更适用于种类(3)的关系实例。
有趣的是通常用来解决AI问题的启发式深度优先算法经常被数据挖掘界回避,因为它们不能处理数据挖掘程序需要的大量数据。然而,我们的实验表明,在计算的覆盖这一问题上,AI搜索策略比规范的层级搜索更好。事实上,在伯努利数据库中,当计算的函数依赖的平均长度,启发式搜索方法惊人得高效。
FastFDs的空间高效性使得它自然而然具有并行性。FastFDs的一个明显的多线程版本就是同时计算不同的属性作为RHS的函数依赖。
FastFDs的性能依赖于用以计算最小超图覆盖的简单的,贪婪的启发式算法。我们的启发式算法用来在一般的超图上发现最小覆盖;然而,并不是所有的超图都可以由关系实例产生。关系实例中蕴含着额外的限制还未被当前的启发式算法反映出来。在未来对这些限制进一步研究,以设计更好的启发式算法是一条有趣的道路。
另外一个有用的方向是考虑增量依赖推理问题:给定,函数依赖集合的规范覆盖,和一个元组,发现或的规范覆盖。据我们所了解,这个问题目前还未被解决,并且看起来极具挑战性。
最后,非常合理的一点是,所有的函数依赖推理问题的应用都不需要所有的函数依赖,只需要“有趣的”函数依赖。举个例子,LHS比较小的函数依赖可能比LHS大的函数依赖更有用。刻画函数依赖的趣味性并设计算法发现这些依赖是未来的一个好的研究方向。