一、数据集准备:空格后面网址为前面网页中链接到的url
二、思路梳理
一个网页链接了几个url,就相当于给几个url进行的投票,那么它给其他url投票的分数就为:自己的得分/自己链接的url个数----(目前暂时不考虑给每个url投票的权重,默认都为1),所以我们需要按照每个url聚合,将它投票的网页聚合在一起,然后展开聚合后的多个url,每个url的得分就为:投票url/聚合url个数,这样每个url都能得到其他url给他的投票得分,最后按照key值求和就得出各个url被投票得分的总和。再根据修正后的pageRank公式计算出相关得分。
三、代码实现
object pageRank extends App{
val spark = SparkSession
.builder
.appName("SparkPageRank")
.master("local[*]")
.getOrCreate()
val path="file:///C:\\Users\\91BGJK2\\Desktop\\pageRank.txt"
//val iters = if (args.length > 1) args(1).toInt else 10
val iters = 10// 迭代10次
val lines = spark.read.textFile(path).rdd
//获取每个页面的关联页面----去除重复投票
val links = lines.map{ s =>
val parts = s.split("\\s+")
(parts(0), parts(1))
}.distinct()
//按照每个页面聚合自己投票的url
val link_group=links.groupByKey().cache()
var ranks: RDD[(String, Double)] = link_group.mapValues(v => 1.0)//给每个页面初始得分都为1
//迭代计算每个页面的得分值
for (i <- 1 to iters) {
val contribs= link_group.join(ranks).flatMap{ case (id,(urls, rank)) =>
val size = urls.size
urls.map(url => (url, rank / size))//计算出每个url被投票的得分
}
//计算每个url被投票了得多少分---key值聚合
ranks = contribs.reduceByKey(_ + _).mapValues(0.15 + 0.85 * _)
}
ranks.collect().sortWith(_._2>_._2).foreach(urls=>println(urls._1+"==>"+urls._2))
spark.stop()
}
四、文本摘要提取
本次提取文本摘要主要是通过比较句子间的相似度,类似pageRank中url之前的投票机制,只不过这个是每个句子间都会有交集会产生相似度,因此本次就借鉴pageRank的算法实现筛选出的分最高的句子,作为文本中的keySentence(提取关键词也可以用类似的方法)。
本次采用:spark+jieba+Word2vec实现
通过Word2vec得分句子间的向量,利用欧式距离求相似度,构建相邻矩阵(如图)
例:计算第一句的得分:
=1-0.85+0.85*(与第二句的相似度/第二句投给其他句子的相似度之和+与第三句的相似度/第三句投给其他句子的相似度之和)
最后通过迭代计算最终得分
代码:(备注,由于本次spark训练的word2vec模型不能加载,所有直接采用简单的计算句子间的相似度算法)
Similarity(S1,S2) = s1s2相同词的个数 / ( log(s1的词个数) + log(s2的词个数) )
object 文本摘要提取textRank extends App{
val spark = SparkSession
.builder
.appName("SparkPageRank")
.master("local[*]")
.getOrCreate()
val path="file:///C:\\Users\\91BGJK2\\Desktop\\人民的名义.txt"
val text="朝鲜外相今抵新加坡,穿黑西装打紫色领带,将与多国外长会谈。朝鲜外相李勇浩今抵新加坡。朝中社英文版2日的报道称,李勇浩率领朝鲜代表团于当天启程,除了新加坡,他还将访问伊朗。"
//分句拆词
val sent:Map[Int, List[String]]=splitSentence(text)
val metric=createMat(sent)
for(i<-metric)println(i.mkString(" "))
val ranks=Array.ofDim[Double](metric.length).map(str=>1.0)
//循环迭代结算得分
for(i<-0 until 5){
val res:Map[Int, Double]=sent.keys.map{ line=>
val score=pageRank(metric,ranks,line)
line->score
}.toMap
res.foreach(str=>println("句子"+str._1+"=="+str._2))
//更新第一次循环后的得分
res.map(str=>ranks.update(str._1,str._2))
}
//使用pageRand算法计算句子排名----计算单个句子的得分
def pageRank(board:Array[Array[Double]],ranks:Array[Double],num:Int): Double ={
val len=board.length
val d = 0.85
var added_score = 0.0
for(j<-0 until len){
var fraction = 0.0
var denominator:Double = 0.0
// 先计算分子
fraction= board(j)(num) * ranks(j)
// 计算分母
for(k<-0 until len){
denominator = denominator + board(j)(k)
}
added_score += fraction / denominator
}
val weighted_score = (1 - d) + d * added_score
return weighted_score
}
//构建句子间的相邻矩阵
def createMat(document:Map[Int, List[String]]): Array[Array[Double]] ={
val num = document.size
// 初始化表
val board=Array.ofDim[Double](num,num)
for(i<-0 until num){
for(j<-0 until num){
if(i!=j){
board(i)(j) = similar_cal(document.get(i).get, document.get(j).get)._2
}
}
}
return board
}
//句子间的相似度计算:共同词个数/log(len1)+log(len2)
def similar_cal(sent1:List[String],sent2:List[String]): ((String, String), Double) ={
val same_word=sent1.intersect(sent2)
val sim=same_word.size/(math.log(sent1.size)+math.log(sent2.size))
(sent1.toString(),sent2.toString())->sim
}
//中文分词
def cutWord(sentense:String): List[String] ={
val jieba = new JiebaSegmenter
val sent_split:List[String]= jieba.sentenceProcess(sentense).asScala.toList.filterNot(str=>str.matches(",|“|”|:|、"))
return sent_split
}
//拆分句子
def splitSentence(document:String ): Map[Int, List[String]] ={
val pattern="(。|!|?|\\.|\\!|\\?)".r
val res=pattern.split(document).toList.zipWithIndex.map(str=>str._2->cutWord(str._1)).toMap
return res
}
//两个list中的交集
def getUnio(): Unit ={
val list1=List("方向","既明","举措","频出")
val list2=List("方向","既明","好","频出")
val res=list1.intersect(list2)
res.foreach(println(_))
}
//训练词向量
def getWord2Vec(): Unit ={
val jieba = new JiebaSegmenter
val sc=spark.sparkContext
val input= sc.textFile("file:///C:\\Users\\91BGJK2\\Desktop\\人民的名义.txt").map(line => cutWord(line).toSeq)
val word2vec = new Word2Vec()
val model = word2vec.fit(input)
val vectors:Map[String, Array[Float]] = model.getVectors
vectors.foreach(str=>println(str._1+"==>"+str._2.toString))
//println(model.transform("平"))
// vectors.foreach(println(_))
//model.save(sc,"file:///C:\\U'sers\\91BGJK2\\Desktop\\word.model")
spark.stop()
}
}
参考博客:
https://blog.youkuaiyun.com/oxuzhenyi/article/details/54981372