[Spark共同好友查找]

本文介绍了一种在社交网络中查找共同好友的算法,并通过Spark实现了该算法。以QQ社交平台为例,展示了如何通过处理用户及其好友关系数据,计算出任意两个用户之间的共同好友。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

共同好友的概念

      在一个庞大的社交网络中,两个互相认识的朋友之间的也会存在共同好友。在这个庞大的社交网络总,对所有的用户对中找到”共同好友”,这是一个复杂及有趣的事情。假设,U为一个用户及其所有好友的一个集合:{U1,U2,U3,…Un},我们要从每组集合(Ui,Uj)(i != j)找出共同好友关系。

       在如今的大多数社交网络(Facebook,LinkedIn,QQ)都提供了有关的服务,可以帮助帮助你与好友共享消息,图片和视频。有些网站甚至还提供了视频聊天服务,帮助你和好友保持联系和分享生活中的乐趣。下图是QQ共同好友界面。

       根据定义,好友就是你认识的,喜欢的或信任的一个人。例如,你在QQ上有一个好友列表,这个社交网络中好友关系是双向的。如果你是我的好友,那么我也就是你的好友。一般情况下,社交网络会尽可能的预先完成计算来减少请求的处理时间,其中一个常见的请求处理就是共同好友特性。访问QQ的好友查找页面时,就可以看到两个好友之间的共同好友个数。这个列表的信息不会频繁改变,如果每次访问这个页面的信息时都要重新计算,这将会浪费时间和资源。

共同好友输入样本数据

       准备一组记录数据作为输入,每个记录的数据格式如下所示:

       <user>,<friend1> <friend2> … <friendn>

这里的<friend1> <friend2> … <friendn>就是用户<user>的好友,每个用户/好友有唯一用户ID标识。以下是一个简单且完整的测试输入数据实例:

A1,A2 A3 A4 A5 A6 A7
A2,A1 A3 A4
A3,A1 A2 A4 A5
A4,A1 A2 A3
A5,A1 A3 A7
A6,A1
A7,A2

共同好友处理流程

       为了帮助我们更好的理解共同好友的查找,假设每一个用户的好友作为一个键-值对,即用户ID作为一个键,用户好友作为一组值,那么将会有以下的一序列map信息。

map(A1,(A2 A3 A4 A5 A6 A7))将生成:

((A1,A2),List(A2, A3, A4, A5, A6, A7))
((A1,A3),List(A2, A3, A4, A5, A6, A7))
((A1,A4),List(A2, A3, A4, A5, A6, A7))
((A1,A5),List(A2, A3, A4, A5, A6, A7))
((A1,A6),List(A2, A3, A4, A5, A6, A7))
((A1,A7),List(A2, A3, A4, A5, A6, A7))

map(A2,(A1 A3 A4))将生成:

((A1,A2),List(A1, A3, A4))
((A2,A3),List(A1, A3, A4))
((A2,A4),List(A1, A3, A4))

map(A3,(A1 A2 A4 A5))将生成:

((A1,A3),List(A1, A2, A4, A5))
((A2,A3),List(A1, A2, A4, A5))
((A3,A4),List(A1, A2, A4, A5))
((A3,A5),List(A1, A2, A4, A5))

map(A4,(A1 A2 A3))将生成:

((A1,A4),List(A1, A2, A3))
((A2,A4),List(A1, A2, A3))
((A3,A4),List(A1, A2, A3))

map(A5,(A1 A3 A7))将生成:

((A1,A5),List(A1, A3, A7))
((A3,A5),List(A1, A3, A7))
((A5,A7),List(A1, A3, A7))

map(A6,(A1))将生成:

((A1,A6),List(A1))

map(A7,(A2))将生成:

((A2,A7),List(A2))

将上面的map信息按键进行分组,则有:

((A1,A3),(List(A2, A3, A4, A5, A6, A7), List(A1, A2, A4, A5)))
((A2,A3),(List(A1, A3, A4), List(A1, A2, A4, A5)))
((A5,A7),(List(A1, A3, A7)))
((A3,A5),(List(A1, A2, A4, A5), List(A1, A3, A7)))
((A1,A5),(List(A2, A3, A4, A5, A6, A7), List(A1, A3, A7)))
((A2,A7),(List(A2)))
((A3,A4),(List(A1, A2, A4, A5), List(A1, A2, A3)))
((A2,A4),(List(A1, A3, A4), List(A1, A2, A3)))
((A1,A2),(List(A2, A3, A4, A5, A6, A7), List(A1, A3, A4)))
((A1,A7),(List(A2, A3, A4, A5, A6, A7)))
((A1,A4),(List(A2, A3, A4, A5, A6, A7), List(A1, A2, A3)))
((A1,A6),(List(A2, A3, A4, A5, A6, A7), List(A1)))

最后,用户的共同好友将生成:

(A1, A3)  [A4, A5, A2]
(A2, A3)  [A4, A1]
(A5, A7)  []
(A3, A5)  [A1]
(A1, A5)  [A3, A7]
(A2, A7)  []
(A3, A4)  [A2, A1]
(A2, A4)  [A3, A1]
(A1, A2)  [A4, A3]
(A1, A7)  []
(A1, A4)  [A2, A3]
(A1, A6)  []

Spark代码实现

/**
  * Spark共同好友查找
  **/
object FindCommonFriends {
    def main(args: Array[String]): Unit = {
        if (args.size < 2) {
            println("Usage: FindCommonFriends <input-dir> <output-dir>")
            sys.exit(1)
        }
        //输入路径
        val inputPath = args(0)
        //输出路径
        val outputPath = args(1)
        //测试环境使用1个内核处理即可,生产环境中进行修改
        val sparkConf: SparkConf = new SparkConf()
            .setMaster("local[1]")
            .setAppName("FindCommonFriends")
        val sc: SparkContext = SparkContext.getOrCreate(sparkConf)

        val records: RDD[String] = sc.textFile(inputPath)
        //映射两两组合键值对
        val pairs: RDD[((String, String), Seq[String])] = records.flatMap(s => {
            val tokens: Array[String] = s.split(",")
            val person: String = tokens(0)
            val friends: Seq[String] = tokens(1).split("\\s+").toList
            val result: Seq[((String, String), Seq[String])] = for {
                i <- 0 until friends.size
                friend = friends(i)
            } yield {
                if (person < friend)
                    ((person, friend), friends)
                else
                    ((friend, person), friends)
            }
            result
        })

        //共同好友计算
        val commonFriends: RDD[((String, String), immutable.Iterable[String])] = pairs
            .groupByKey()
            .mapValues(iter => {
                val friendCount = for {
                    list <- iter
                    if !list.isEmpty
                    friend <- list
                } yield ((friend, 1))
                friendCount.groupBy(_._1).mapValues(_.unzip._2.sum).filter(_._2 > 1).map(_._1)
            })

        //保存结果
        //commonFriends.saveAsTextFile(outputPath)

        //打印共同好友结果
        val formatedResult = commonFriends.map(
            f => s"(${f._1._1}, ${f._1._2})\t${f._2.mkString("[", ", ", "]")}"
        )

        formatedResult.foreach(println)
        sc.stop()
    }
}

运行结果

(A1, A3)	[A4, A5, A2]
(A2, A3)	[A4, A1]
(A5, A7)	[]
(A3, A5)	[A1]
(A1, A5)	[A3, A7]
(A2, A7)	[]
(A3, A4)	[A2, A1]
(A2, A4)	[A3, A1]
(A1, A2)	[A4, A3]
(A1, A7)	[]
(A1, A4)	[A2, A3]
(A1, A6)	[]

结论

     通过共同好友查找算法,我们可以很方便的计算出一个社交网络中用户的共同好友关系。在上面的测试运行结果中,我们可以看到,用户两两之间的共同好友。其中(A5, A7),(A2, A7),(A1, A7),(A1, A6)之间没有共同好友。

ubuntu编写 PySpark,实现“你可能认识的人”社交网络推荐算法。主要思想是,如果两个人有很多共同好友, 那么系统应该推荐再这两个人之间建立联系。 数据 • 作业附带data目录下的soc-LiveJournal1Adj.txt文件 • 文件包含多行邻接列表,格式如下: <User><TAB><Friends> 其中<User>代表用户的唯一整数 ID;<Friends>代表用户的朋友,为逗号隔开的整数列表。注意朋 友关系是相互的 (即朋友之间的边是无向的):如果 A 是 B 的朋友,那么 B 也是 A 的朋友。提供的 数据中保证如果 A 在 B 的朋友列表中出现,B 也会在 A 的朋友列表里。 算法 使用一个简单的算法:对于每个用户 U,算法会推荐 N=10 个还不是 U 的朋友的用户,但他们与 U 有最多的共同好友。 输出 • 输出应该为每个用户包含一行如下格式 <User><TAB><Recommendations> 其中<User>代表用户的唯一整数 ID;<Recommendations>是逗号隔开的整数 ID 列表,代表算法推 荐的 User 可能认识的人,按照共同好友数量的降序排列。 • 如果用户的 2 度好友 (即上述通过中间好友建立关联的朋友) 少于 10 个,也请将这些推荐按结果按 共同好友数量的降序悉数列出。如果用户没有好友,你可以输出一个空的列表。如果在推荐的结果中 共同好友的数量相同,请将被推荐好友按他们的 ID 数值升序排列。 流程简述 请用简明的几句话描述你是如何使用 PySpark 解决这个问题的。 提示 • 复用环境初始化代码 • 逐行检查你每个步骤的输出。比如使用.take(X)方法查看 RDD 的前X个元素 • 为了便于验证,用户 ID 11 的推荐结果应该是: 27552,7785,27573,27574,27589,27590,27600,27617,27620,276
最新发布
03-15
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值