mahout里面的关联规则是用FP-tree实现的,上次简单分析了下实现的第一步,一共有三步,如下:
现简要分析下第二步:
假如原始数据如下:
牛奶,鸡蛋,面包,薯片 鸡蛋,爆米花,薯片,啤酒 鸡蛋,面包,薯片 牛奶,鸡蛋,面包,爆米花,薯片,啤酒 牛奶,面包,啤酒 鸡蛋,面包,啤酒 牛奶,面包,薯片 牛奶,鸡蛋,面包,黄油,薯片 牛奶,鸡蛋,黄油,薯片那么生成的fList如下:
薯片 7 鸡蛋 7 面包 7 牛奶 6 啤酒 4
根据上面的两个输入(当然fList是放入内存的),ParallelFPGrowthMapper的作用就是完成每条记录的转化和输出,和Part1的截图一样,比如:
首先是转化:薯片-->0, 鸡蛋-->1,面包-->2,牛奶-->3,啤酒-->4;接着是针对每一条记录进行输出比如针对第一条记录:
牛奶,鸡蛋,面包,薯片输出如下:
groupId transactionTree
3 [0, 1, 2, 3] 2 [0, 1, 2] 1 [0, 1] 0 [0]接着到ParallelFPGrowthReducer的reduce方法,(在这之前有个combiner,但是个人没有看,而是在源码中直接注释了,反正也不影响结果,应该是只影响性能的吧),此Reducer的setup方法是读取fList的,暂时没有用到。此Reducer把所有groupID相同的transactionTree通过TransactionTree.addPattern()把这些transactionTrees加入到一个TransactionTree中,然后通过这个TransactionTree构建本地的fList,即localFList(要按照出现次数由大到小排序)。
比如当groupId为3的时候,所有的transactionTree如下:
[([0, 1, 2, 3],1)] [([0, 1, 2, 3],1)] [([1, 3],1)] [([0, 1, 3],1)] [([0, 1, 2, 3],1)] [([0, 2, 3],1)]通过上面的TransactionTree得到localFList如下:
[(3,6), (0,5), (1,5), (2,4)]接着调用了FPGrowth.generateTopKFrequentPatterns()方法,该方法有下面的参数:
Iterator<Pair<List<A>,Long>> transactionStream,
Collection<Pair<A, Long>> frequencyList,
long minSupport,
int k,Collection<A> returnableFeatures,
OutputCollector<A,List<Pair<List<A>,Long>>> output,
StatusUpdater updater
其实这个方法我看了好久但是还是不知道它是如何运作的,transactoinStream应该是TransactionTree的遍历输出,frequencyList是本地的fList,output应该就是输出最后的结果;这个方法刚开始是一些转化工作,接着递归调用自己,不过这时的参数有变:
generateTopKFrequentPatterns(new TransactionIterator<A>(transactionStream,
attributeIdMapping), attributeFrequency, minSupport, k, reverseMapping
.size(), returnFeatures, new TopKPatternsOutputConverter<A>(output,
reverseMapping), updater);
其中的输出的类变为了TopKPatternOutputConverter,然后我测试到这个类输出如下,同时这个方法只递归了一次:
0 [([0],7)] 1 [([1],7), ([0, 1],5)] 2 [([2],7), ([0, 2],6), ([1, 2],5), ([0, 1, 2],4)] 3 [([3],6), ([1, 3],5), ([0, 3],5), ([0, 2, 3],4), ([0, 1, 3],4), ([0, 1, 2, 3],3)] 4 [([4],4), ([2, 4],3), ([1, 4],3)]而整个parallelFPGrowth的输出如下,也就是第二个阶段的输出:
key:薯片,value:([薯片],7) key:面包,value:([面包],7), ([薯片, 面包],5) key:鸡蛋,value:([鸡蛋],7), ([薯片, 鸡蛋],6), ([面包, 鸡蛋],5), ([薯片, 面包, 鸡蛋],4) key:牛奶,value:([牛奶],6), ([面包, 牛奶],5), ([薯片, 牛奶],5), ([薯片, 鸡蛋, 牛奶],4), ([薯片, 面包, 牛奶],4), ([薯片, 面包, 鸡蛋, 牛奶],3) key:啤酒,value:([啤酒],4), ([鸡蛋, 啤酒],3), ([面包, 啤酒],3)上面的两个结果其实是一样的,只要转化一下就可以了,但是转化的过程在哪里?returnFeatures即是转化的关键,但是是在哪个地方什么时候实现的?还有既然是用的FP-tree实现的,那么建立的FP-tree是哪个类?TransactionTree是这个么?。。。
其实,我已经看了关联规则第二部分好长时间了,但是一直还是没有看的明白。只能说:源码艰晦涩,入读需谨慎。
以上仅代表个人观点,难免有误,望指正。
分享,成长,快乐