递归发生时Scala堆栈溢出

递归发生时Scala堆栈溢出,scala,graph-algorithm,Scala,Graph Algorithm,Hi I有一个BronKerbosch算法用于检测社区,该算法使用scala实现。它有一个超过100000个节点的数据集。当我运行代码时,它会给出一个错误,称为stackoverflows。我也添加了@tailrec注释。下面我添加了代码和错误 import org.apache.spark.SparkContext import org.apache.spark.graphx.Graph.graphToGraphOps import org.slf4j.{Logger, LoggerFacto

Hi I有一个BronKerbosch算法用于检测社区,该算法使用scala实现。它有一个超过100000个节点的数据集。当我运行代码时,它会给出一个错误,称为stackoverflows。我也添加了@tailrec注释。下面我添加了代码和错误

import org.apache.spark.SparkContext
import org.apache.spark.graphx.Graph.graphToGraphOps
import org.slf4j.{Logger, LoggerFactory}
import scala.annotation.tailrec
import scala.collection.mutable.{ArrayBuffer, Set => MutableSet}
import scala.reflect.ClassTag

class BronKerbosch[VD: ClassTag, ED: ClassTag](sc: SparkContext,
                                           inputGraph: Graph[VD, ED])  {



  private val logger: Logger = 
  LoggerFactory.getLogger(classOf[BronKerbosch[VD, ED]]);

  private val sparkContext: SparkContext = sc;

  private var graph: Graph[VD, ED] = inputGraph;

  private var neighbourVerticesMap = 
  graph.collectNeighborIds(EdgeDirection.Either)
  .collect().map(vertex => (vertex._1.asInstanceOf[Long], vertex._2))
  .toMap;

  def runAlgorithm = {

    logger.info("Starting BronKerbosch Algorithm");
    var potentialClique = Array[Long]()
    var candidates = graph.vertices.map(vertex => 
    vertex._1.asInstanceOf[Long]).collect().to[ArrayBuffer];

    var alreadyFound = ArrayBuffer[Long]();

    var cliques = ArrayBuffer[Array[Long]]()

    findCliques(potentialClique, candidates, alreadyFound, cliques);

    cliques;
  }


  private def findCliques(potentialClique: Array[Long],candidates: ArrayBuffer[Long], alreadyFound: ArrayBuffer[Long],cliques: ArrayBuffer[Array[Long]]): Unit = {

    if (candidates.isEmpty && alreadyFound.isEmpty) {
      cliques.append(potentialClique)

    }
    @tailrec
    var originalCandidates = candidates
    candidates.foreach { candidateVertex =>
    {
     var neighbourVertices = neighbourVerticesMap.getOrElse(candidateVertex, Array[Long]())

     findCliques((potentialClique :+ candidateVertex).distinct,candidates.intersect(neighbourVertices),alreadyFound.intersect(neighbourVertices), cliques)
  }


  }
 }
 }
Exception in thread "main" java.lang.StackOverflowError
at 
scala.collection.mutable.HashTable$class.findEntry(HashTable.scala:132)
at scala.collection.mutable.HashMap.findEntry(HashMap.scala:40)
at scala.collection.mutable.HashMap.apply(HashMap.scala:64)
at scala.collection.SeqLike$$anonfun$occCounts$1.apply(SeqLike.scala:481)
at scala.collection.SeqLike$$anonfun$occCounts$1.apply(SeqLike.scala:481)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
at scala.collection.mutable.WrappedArray.foreach(WrappedArray.scala:35)
at scala.collection.SeqLike$class.occCounts(SeqLike.scala:481)
at scala.collection.SeqLike$class.intersect(SeqLike.scala:469)
at scala.collection.AbstractSeq.intersect(Seq.scala:41)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply$mcVJ$sp(BronKerbosch.scala:57)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at com.creative.graphx.BronKerbosch.com$creative$graphx$BronKerbosch$$findCliques(BronKerbosch.scala:53)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply$mcVJ$sp(BronKerbosch.scala:57)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at com.creative.graphx.BronKerbosch.com$creative$graphx$BronKerbosch$$findCliques(BronKerbosch.scala:53)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply$mcVJ$sp(BronKerbosch.scala:57)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at com.creative.graphx.BronKerbosch.com$creative$graphx$BronKerbosch$$findCliques(BronKerbosch.scala:53)
下面是错误

import org.apache.spark.SparkContext
import org.apache.spark.graphx.Graph.graphToGraphOps
import org.slf4j.{Logger, LoggerFactory}
import scala.annotation.tailrec
import scala.collection.mutable.{ArrayBuffer, Set => MutableSet}
import scala.reflect.ClassTag

class BronKerbosch[VD: ClassTag, ED: ClassTag](sc: SparkContext,
                                           inputGraph: Graph[VD, ED])  {



  private val logger: Logger = 
  LoggerFactory.getLogger(classOf[BronKerbosch[VD, ED]]);

  private val sparkContext: SparkContext = sc;

  private var graph: Graph[VD, ED] = inputGraph;

  private var neighbourVerticesMap = 
  graph.collectNeighborIds(EdgeDirection.Either)
  .collect().map(vertex => (vertex._1.asInstanceOf[Long], vertex._2))
  .toMap;

  def runAlgorithm = {

    logger.info("Starting BronKerbosch Algorithm");
    var potentialClique = Array[Long]()
    var candidates = graph.vertices.map(vertex => 
    vertex._1.asInstanceOf[Long]).collect().to[ArrayBuffer];

    var alreadyFound = ArrayBuffer[Long]();

    var cliques = ArrayBuffer[Array[Long]]()

    findCliques(potentialClique, candidates, alreadyFound, cliques);

    cliques;
  }


  private def findCliques(potentialClique: Array[Long],candidates: ArrayBuffer[Long], alreadyFound: ArrayBuffer[Long],cliques: ArrayBuffer[Array[Long]]): Unit = {

    if (candidates.isEmpty && alreadyFound.isEmpty) {
      cliques.append(potentialClique)

    }
    @tailrec
    var originalCandidates = candidates
    candidates.foreach { candidateVertex =>
    {
     var neighbourVertices = neighbourVerticesMap.getOrElse(candidateVertex, Array[Long]())

     findCliques((potentialClique :+ candidateVertex).distinct,candidates.intersect(neighbourVertices),alreadyFound.intersect(neighbourVertices), cliques)
  }


  }
 }
 }
Exception in thread "main" java.lang.StackOverflowError
at 
scala.collection.mutable.HashTable$class.findEntry(HashTable.scala:132)
at scala.collection.mutable.HashMap.findEntry(HashMap.scala:40)
at scala.collection.mutable.HashMap.apply(HashMap.scala:64)
at scala.collection.SeqLike$$anonfun$occCounts$1.apply(SeqLike.scala:481)
at scala.collection.SeqLike$$anonfun$occCounts$1.apply(SeqLike.scala:481)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
at scala.collection.mutable.WrappedArray.foreach(WrappedArray.scala:35)
at scala.collection.SeqLike$class.occCounts(SeqLike.scala:481)
at scala.collection.SeqLike$class.intersect(SeqLike.scala:469)
at scala.collection.AbstractSeq.intersect(Seq.scala:41)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply$mcVJ$sp(BronKerbosch.scala:57)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at com.creative.graphx.BronKerbosch.com$creative$graphx$BronKerbosch$$findCliques(BronKerbosch.scala:53)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply$mcVJ$sp(BronKerbosch.scala:57)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at com.creative.graphx.BronKerbosch.com$creative$graphx$BronKerbosch$$findCliques(BronKerbosch.scala:53)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply$mcVJ$sp(BronKerbosch.scala:57)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at com.creative.graphx.BronKerbosch$$anonfun$com$creative$graphx$BronKerbosch$$findCliques$1.apply(BronKerbosch.scala:53)
at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at com.creative.graphx.BronKerbosch.com$creative$graphx$BronKerbosch$$findCliques(BronKerbosch.scala:53)

解决这个问题的最佳方法是什么?

这段代码有很多问题,但肯定不是尾部递归的

尾部递归要求函数只执行一个递归调用,并且该调用必须是函数中的最后一个操作。代码中可能有多个调用,但对于代码中的任何给定路径,只能调用一个

在您的代码中,对findCliques的递归调用位于foreach循环中,因此它可能会被多次调用,每个候选循环调用一次。这可能就是堆栈溢出的原因

您的@ TreReC注释不起作用,因为它需要在函数定义之前,而不是在函数的中间。


代码的其他问题包括格式错误、不必要地使用var、未使用的原始值和太多可变数据结构。

如果代码正确对齐,将非常有帮助MCV也很好我已经格式化了代码,但出于某种原因,当我在此处复制代码时,格式化的代码不正确aligned@Ethan不不不不不不!带有这样的错误报告的代码是无法按预期工作的代码。不按预期工作的代码是根据定义的,用于代码审查!嗨,蒂姆,谢谢你的回答,我使用了var而没有使用val来生成每个变量mutable@Supun如果要重新分配变量,只需使用var。也就是说,如果你要把它放在作业的左边。您的代码不会重新分配任何内容,因此您可以始终使用val。如果您的val包含一个可变对象,则可以更改该对象,但不能使变量引用其他对象。值得补充的是,许多经典算法无法处理大数据。东西并不是都存储在同一个地方,范围也变得太大了。Spark/GraphX集团查找算法可能涉及多轮消息传递,可能是pregel。