从赌钱游戏看PageRank算法
谈到并行计算应用,会有人想到PageRank算法,我们有成千上万的网页分析链接关系确定排名先后,借助并行计算完成是一个很好的场景。长期以来,google的创始发明PageRank算法吸引了很多人学习研究,据说当年google创始者兴奋的找到yahoo公司,说他们找到一种更好的搜索引擎算法,但是被yahoo公司技术人员泼了冷水,说他们关心的不是更好的技术,而是搜索的盈利。后来google包装成了“更先进技术的新一代搜索引擎”的身份,逐渐取代了市场,并实现了盈利。
由于PageRank算法有非常高的知名度和普及度,我们接下来以PageRank算法为例讲述“并行计算+数据算法”的经典搭配,并且这种“海量数据并行处理、迭代多轮后收敛”的分析过程也跟其他的数据挖掘或者机器学习算法应用类似,能起到很好的参考作用。
下面是PageRank算法的公式:
我们其实可以直接阐述该公式本身,并介绍如何使用并行计算套用上面公式得到各网页的PageRank值,这样虽然通过并行计算方式完成了PageRank计算,但是大家仍然不明白上面的PageRank公式是怎么来的。
我们把这个PageRank算法公式先放在一边,看看一个赌钱的游戏:
有甲、乙、丙三个人赌钱,他们的输赢关系如下:
甲的钱输给乙和丙
乙的钱输给丙
丙的钱输给甲
例如,甲、乙、丙各有本钱100元,按照以上输赢关系,玩一把下来:
甲输给乙50元、输给丙50元
乙输给丙100元
丙输给甲100元
如果仅是玩一把的话很容易算出谁输谁赢
但如果他们几个维持这样的输赢关系,赢的钱又投进去继续赌,这样一轮一轮赌下去的话,最后会是什么样子呢?
我们可以写个单机程序看看,为了方便计算,初始本钱都设为1块钱,用x1,x2,x3代表甲、乙、丙:
double x1=1.0,x2=1.0,x3=1.0;
用x1_income,x2_income,x3_income代表每赌一把后各人赢的钱,根据输赢关系:
double x2_ income =x1/2.0;
double x3_ income =x1/2.0+x2;
double x1_ income =x3;
最后再把各人赢的钱覆盖掉本钱,继续往下算。完整程序如下:
// Gamble单机程序
public class Gamble{public static double x1=1.0,x2=1.0,x3=1.0;public static void playgame(){double x2_income=x1/2.0;double x3_income=x1/2.0+x2;double x1_income=x3;x1=x1_income;x2=x2_income;x3=x3_income;System.out.println("x1:"+x1+", x2:"+x2+", x3:"+x3);}public static void main(String[] args){for(int i=0;i<500;i++){System.out.print("第"+i+"轮 ");playgame();}}}




import com.fourinone.BeanContext;public class ParkServerDemo{public static void main(String[] args){BeanContext.startPark();}}import com.fourinone.MigrantWorker;import com.fourinone.WareHouse;import com.fourinone.Workman;public class PageRankWorker extends MigrantWorker{public String page = null;public String[] links = null;public PageRankWorker(String page, String[] links){this.page = page;this.links = links;}public WareHouse doTask(WareHouse inhouse){Double pr = (Double)inhouse.getObj(page);System.out.println(pr);WareHouse outhouse = new WareHouse();for(String p:links)outhouse.setObj(p, pr/links.length);//对包括的链接PR投票return outhouse;}public static void main(String[] args){String[] links = null;if(args[2].equals("A"))links = new String[]{"B","C"};//A页面包括的链接else if(args[2].equals("B"))links = new String[]{"C"};else if(args[2].equals("C"))links = new String[]{"A"};PageRankWorker mw = new PageRankWorker(args[2],links);mw.waitWorking(args[0],Integer.parseInt(args[1]),"pagerankworker");}}import com.fourinone.Contractor;import com.fourinone.WareHouse;import com.fourinone.WorkerLocal;import java.util.Iterator;public class PageRankCtor extends Contractor{public WareHouse giveTask(WareHouse inhouse){WorkerLocal[] wks = getWaitingWorkers("pagerankworker");System.out.println("wks.length:"+wks.length);for(int i=0;i<500;i++){//500轮WareHouse[] hmarr = doTaskBatch(wks, inhouse);WareHouse prwh = new WareHouse();for(WareHouse result:hmarr){for(Iterator iter=result.keySet().iterator();iter.hasNext();){String page = (String)iter.next();Double pagepr = (Double)result.getObj(page);if(prwh.containsKey(page))pagepr = pagepr+(Double)prwh.getObj(page);prwh.setObj(page,pagepr);}}inhouse = prwh;//迭代System.out.println("No."+i+":"+inhouse);}return inhouse;}public static void main(String[] args){PageRankCtor a = new PageRankCtor();WareHouse inhouse = new WareHouse();inhouse.setObj("A",1.00d);//A的pr初始值inhouse.setObj("B",1.00d);//B的pr初始值inhouse.setObj("C",1.00d);//C的pr初始值a.giveTask(inhouse);a.exit();}}