Spark LDA 主题预测

本文主要对使用Spark MLlib LDA进行主题预测时遇到的工程问题做一总结,列出其中的一些小坑,或可供读者借鉴。关于LDA模型训练可以参考:Spark LDA 主题抽取

开发环境:spark-1.5.2,hadoop-2.6.0,spark-1.5.2要求jdk7+。语料有大概70万篇博客,十亿+词汇量,词典大概有五万左右的词。

模型准备

利用spark mllib LDA进行主题预测需要训练好的LDAModel以及词典,注意词典需要是训练LDAModel时所对应的词典,索引与词需要一一对应。使用时只需LocalLDAModel.load(sc, trained_model)即可。

预测代码

注意,此处是将SparkContext嵌入一个独立的java程序中使用(on windows),而不是直接spark-submit。

// 加载模型
System.setProperty("hadoop.home.dir", hadoop_home_dir);
val conf = new SparkConf().
                      setAppName("Spark LDA Model").
                      setMaster(spark_master).
                      setJars(Array("target/xxx.jar")).
                      set("spark.driver.maxResultSize", "8g").
                      set("spark.executor.memory", "16g")
sc = new SparkContext(conf)
ldaModel = LocalLDAModel.load(sc, trained_model)
vocabArray = sc.textFile(lda_vocabulary).collect()
vocabArrayMap = vocabArray.zipWithIndex.toMap

// 预测新文档
/* 函数直接返回若干个权重最大的关键词
*  输入已经分词为链表,返回关键词个数。输出是关键词及其权重
*/
def getKeyWords(docInWords: java.util.List[String],maxWordsTopic:Integer):JMap[String, Double] = {
    val results  = new util.HashMap[String, Double]()

    // 将输入文档转化为词频索引向量
    val wc = new mutable.HashMap[Int, Int]()
    docInWords.foreach { term =>
      if (vocabArrayMap.contains(term)) {
        val termIndex = vocabArrayMap(term)
        wc(termIndex) = wc.getOrElse(termIndex, 0) + 1
      }
    }
    // 与词典长度相同
    val indices = wc.keys.toArray.sorted
    val values = indices.map(i => wc(i).toDouble)
    val docVector = Vectors.sparse(vocabArrayMap.size, indices, values)
    // 转换为RDD
    val list = new ArrayBuffer[Vector]()
    list += docVector
    val documents = sc.parallelize(list).zipWithIndex.map(e => (e._2, e._1))

    // 预测文档在topic上的分布
    val topicDists = ldaModel.topicDistributions(documents).collect

    // 叠乘累加,得到文档到词的权重分布
    topicDists.foreach{ case (t,vec) => {
      val wordArray = ldaModel.topics.multiply(vec).toArray
      // 降序排列
      val wordRdd = wordArray.zipWithIndex.sortBy(-_._1).take(maxWordsTopic)
      // 从词典索引到实际词映射
      val topWords = wordRdd.map { case (weight, index) => (vocabArray(index.toInt), weight) }
      topWords.foreach(e => results.put(e._1, e._2))
    }}

    results
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

遇到的坑

System.setProperty(“hadoop.home.dir”, “c:\hadoop_home”)
下载winutils.exe,放于”c:\hadoop_home”。否则会有下列错误:“ERROR Shell: Failed to locate the winutils binary in the hadoop binary path 
java.io.IOException: Could not locate executable null\bin\winutils.exe in the  Hadoop binaries.
-XX:-UseSplitVerifier -Xmx3g -XX:MaxPermSize=128m
(intellj idea)设置”run-edit configuration-vm options”,对于jdk7可能需要”-XX:-UseSplitVerifier”。”-XX:MaxPermSize=128m”是为了预编译时设置固定不回收的内存,如果过小则有内存溢出错误,笔者误以为是spark内存不够,浪费了不少时间修改spark.executor.memory,然并卵。
–spark.driver.maxResultSize
根据模型大小灵活设置,小则内存溢出。
–spark.executor.memory
根据模型大小灵活设置,小则内存溢出。
setJars(Array(“target/xxx.jar”))
尽管是java独立程序,但是spark部分需远程执行,因此必须需要相关依赖文件,需要指定java程序jar包路径。否则”org.apache.spark.SparkException: Job aborted due to stage failure: Task from application”。注意在ide中调试执行的时候setJars(SparkContext.jarOfClass(this.getClass).toList)是不能解决此问题的。有时还可能需要fat jar,将所有依赖打进一个包,可以用maven-shade-plugin。此处问题具体见参考。
–预测结果
预测新文档主题分布:ldaModel.topicDistributions(newDocument) 
新文档主题分布与各主题在词上分布叠乘相加: 
ldaModel.topics.multiply(newDocument) 
最后得到新文档在词典上的权重分布,排序输出即可找到新文档的top 关键词

小结

推测新文档的时候,spark还需要一定时间计算,耗时可能达到10秒,感觉在线上实用还有距离,当然也有可能是训练模型问题。

不知道我的理解对不对,LDA最开始用来对大量文本聚类,现在也有用来主题词抽取。聚类实际上是一个粗粒度的分类,而关键词抽取则是个性化(具体到一篇文章),所以效果稍差,应该是有很多理解和实践不到位的地方,所以还要进一步研究,也欢迎大家给些建议。

参考

1.http://stackoverflow.com/questions/26892389/org-apache-spark-sparkexception-job-aborted-due-to-stage-failure-task-from-app 
2.http://stackoverflow.com/questions/24052899/how-to-make-it-easier-to-deploy-my-jar-to-spark-cluster-in-standalone-mode 
3.http://stackoverflow.com/questions/1832853/is-it-possible-to-create-an-uber-jar-containing-the-project-classes-and-the-pr 
4.http://www.mkyong.com/maven/create-a-fat-jar-file-maven-shade-plugin/

猜你喜欢

转载自blog.csdn.net/u012879957/article/details/81051835
今日推荐