二度人脉基础知识

二度人脉算法基本原理

参考:http://my.oschina.net/BreathL/blog/75112
完整java实现:https://github.com/intergret/snippet/blob/master/deg2friend.java

所谓六度人脉关系理论(Six Degrees of Separation),是指地球上所有的人都可以通过六层以内的熟人链和任何其他人联系起来。通俗地讲:“你和任何一个陌生人之间所间隔的人不会超过六个,也就是说,最多通过六个人你就能够认识任何一个陌生人。”

目标

社交网站上的各个用户以及用户之间的相互关注可以抽象为一个图。图算法里面的宽度优先搜索。我们以用户I为起点,在相互关注所构成的图上往外不退回地走N步所能到的顶点,就是用户I的N度好友。
二度人脉基础知识

  • 类似新浪微博的“你可能感兴趣的人” ,核心思想即寻找你关注的群体所关注最多的人,则此人可能你也想关注。
  • 在程序的实现上,其实我们要找的是:若A用户关注人的集合{User3,User4,User5,... ,User12...}记为集合UF1
  • UF1中的这些人,他们也有follow的集合,分别是记为: UF3(User3 follow的人),UF4,UF5,...,UF12
  • 求关注的人的关注的人集合的最大交集,就是我们要寻找的二度人脉

把逻辑简化称SQL:
select * from 用户关注人表
where 用户 in 我关注的用户表
最后求出现凭此最高的
当用户数据量大、关注关系复杂、动态更新频繁的情况,怎么设计能提高性能呢?

广度搜索算法来查找(深度2以内)

  • 算法,第一步找到你关注的人;第二步找到这些人关注的人,最后找出第二步结果中出现频率最高的一个或多个人,即完成。在海量数据的处理显得不合适,采用下一种方法

Map(映射)/Reduce(归纳)

  • 我们要数图书馆中的所有书。你数1号书架,我数2号书架。这就是“Map”。我们人越多,数书就更快。
  • 现在我们到一起,把所有人的统计数加在一起。这就是“Reduce”。

实现

  • Map/Reduce 1:找出任意一个用户的follow 集合与被follow的集合。如图所示:
    二度人脉基础知识

        public void map(Text key, IntWritable values, Context context) throws IOException,InterruptedException{
            int value = values.get();
            //切分出两个用户id
            String[] _key = Separator.CONNECTORS_Pattern.split(key.toString());
            if(_key.length ==2){
                //"f"前缀表示 follow;"b" 前缀表示 被follow
                context.write(new Text(_key[0]), new Text("f"+_key[1]));
                context.write(new Text(_key[1]), new Text("b"+_key[0]));
    
    
        }
    }
  • Reduce任务: 输出时key:用户A的ID , value为 两个String,第一个是他follow的所有人(用分割符分割),第二个为follow他的人(同样分割)。其中Separator.TABLE_String为自定义的分隔符;TextPair为自定义的 Writable 类,让一个key可以对应两个value,且这两个value可区分。

     protected void reduce(Text key, Iterable<TextPair> pairs, Context context)
         throws IOException,InterruptedException{
            StringBuilder first_follow = new StringBuilder();
            StringBuilder second_befollow = new StringBuilder();
    
        for(TextPair pair: pairs){
            String id = pair.getFirst().toString();
            String value = pair.getSecond().toString();
            if(id.startsWith("f")){
                first_follow.append(id.substring(1)).append(Separator.TABLE_String);
            } else if(id.startsWith("b")){
                second_befollow.append(id.substring(1)).append(Separator.TABLE_String);
            }
        }
    
        context.write(key, new TextPair(first_follow.toString(),second_befollow.toString()));
    }
  • Map/Reduce 2:在上一步关系中,若B follow A,而 A follow T ,则可以得出 T 为 B 的二度人脉,且 间接者为A ,于是找出 相同二度人脉的不同间接人。如图所示:
    二度人脉基础知识
    Map 任务:输出时 key 为 由两个String 记录的ID表示的 二度人脉关系,value 为 这个二度关系产生的间接人的ID

    public void map(Text key, TextPair values, Context context) throws IOException,InterruptedException{
           //Map<String, String> first_follow = new HashMap<String, String>();
           //Map<String, String> second_befollow = new HashMap<String, String>();
           //String _key = key.toString();
           String[] follow = values.getFirst().toString().split(Separator.TABLE_String);
    
       String[] befollow = values.getSecond().toString().split(Separator.TABLE_String);
    
       for(String f : follow){
           for(String b : befollow){
                //避免自己关注自己
               if(!f.equals(b)){
                   context.write(new TextPair(f.getKey() ,b.getKey()), new Text(key));
               }
           }
       }
     }

    Reduce任务:输出时 key 仍然为二度人脉关系, value 为所有间接人 的ID以逗号分割。

    protected void reduce(TextPair key, Iterable<Text> values, Context context)
    throws IOException, InterruptedException {
    
    StringBuilder resutl = new StringBuilder();
    for (Text text : values){
        resutl.append(text.toString()).append(",");
    }
    
    context.write(key, new Text(resutl.toString()));
    }

你可能感兴趣的:(基础)