scala не является членом параметра типа

Я пытаюсь использовать Spark GraphX ​​и сталкиваюсь с тем, что я считаю проблемой в том, как я использую Scala. Я новичок в Scala и Spark.

Я создаю график, вызывая собственную функцию:

val initialGraph: Graph[VertexAttributes, Int] = sim.createGraph

VertexAttributes — это класс, который я определил:

class VertexAttributes(var pages: List[Page], var ads: List[Ad], var step: Long, val inDegree: Int, val outDegree: Int)
extends java.io.Serializable
{
  // Define alternative methods to be used as the score
  def averageScore() =
  {
    this.ads.map(_.score).sum / this.ads.length
  }

  def maxScore() =
  {
    if(this.ads.length == 0) None else Some(this.ads.map(_.score).max)
  }

  // Select averageScore as the function to be used
  val score = averageScore _
}

После некоторых вычислений я использую функцию GraphX ​​vertices(), чтобы получить оценки для каждой вершины:

val nodeRdd = g.vertices.map(v => if(v._2.score() == 0)(v._1 + ",'0,0,255'") else (v._1 + ",'255,0,0'"))

Но это не скомпилируется, сообщение sbt:

value score is not a member of type parameter VertexAttributes

Я погуглил это сообщение об ошибке, но, честно говоря, не могу следить за разговором. Может ли кто-нибудь объяснить причину ошибки и как я могу ее исправить?

Спасибо.

P.S. Ниже приведен мой код для метода createGraph:

// Define a class to run the simulation
class Butterflies() extends java.io.Serializable
{
  // A boolean flag to enable debug statements
  var debug = true

  // A boolean flag to read an edgelist file rather than compute the edges
  val readEdgelistFile = true;

  // Create a graph from a page file and an ad file
  def createGraph(): Graph[VertexAttributes, Int] =
  {
    // Just needed for textFile() method to load an RDD from a textfile
    // Cannot use the global Spark context because SparkContext cannot be serialized from master to worker
    val sc = new SparkContext

    // Parse a text file with the vertex information
    val pages = sc.textFile("hdfs://ip-172-31-4-59:9000/user/butterflies/data/1K_nodes.txt")
      .map { l =>
        val tokens = l.split("\\s+")     // split("\\s") will split on whitespace
        val id = tokens(0).trim.toLong
        val tokenList = tokens.last.split('|').toList
        (id, tokenList)
      }
    println("********** NUMBER OF PAGES: " + pages.count + " **********")

    // Parse a text file with the ad information
    val ads = sc.textFile("hdfs://ip-172-31-4-59:9000/user/butterflies/data/1K_ads.txt")
      .map { l =>
        val tokens = l.split("\\s+")     // split("\\s") will split on whitespace
        val id = tokens(0).trim.toLong
        val tokenList = tokens.last.split('|').toList
        val next: VertexId = 0
        val score = 0
        //val vertexId: VertexId = id % 1000
        val vertexId: VertexId = id
        (vertexId, Ad(id, tokenList, next, score))
      }
    println("********** NUMBER OF ADS: " + ads.count + " **********")

    // Check if we should simply read an edgelist file, or compute the edges from scratch
    val edgeGraph =
    if (readEdgelistFile)
    {
      // Create a graph from an edgelist file
      GraphLoader.edgeListFile(sc, "hdfs://ip-172-31-4-59:9000/user/butterflies/data/1K_edges.txt")
    }
    else
    {
      // Create the edges between similar pages
      //   Create of list of all possible pairs of pages
      //   Check if any pair shares at least one token
      //   We only need the pair id's for the edgelist
      val allPairs = pages.cartesian(pages).filter{ case (a, b) => a._1 < b._1 }
      val similarPairs = allPairs.filter{ case (page1, page2) => page1._2.intersect(page2._2).length >= 1 }
      val idOnly = similarPairs.map{ case (page1, page2) => Edge(page1._1, page2._1, 1)}
      println("********** NUMBER OF EDGES: " + idOnly.count + " **********")

      // Save the list of edges as a file, to be used instead of recomputing the edges every time
      //idOnly.saveAsTextFile("hdfs://ip-172-31-4-59:9000/user/butterflies/data/saved_edges")

      // Create a graph from an edge list RDD
      Graph.fromEdges[Int, Int](idOnly, 1);
    }

    // Copy into a graph with nodes that have vertexAttributes
    //val attributeGraph: Graph[VertexAttributes, Int] =
    val attributeGraph = 
      edgeGraph.mapVertices{ (id, v) => new VertexAttributes(Nil, Nil, 0, 0, 0) }

    // Add the node information into the graph
    val nodeGraph = attributeGraph.outerJoinVertices(pages) {
      (vertexId, attr, pageTokenList) =>
        new VertexAttributes(List(Page(vertexId, pageTokenList.getOrElse(List.empty), 0)),
                         attr.ads, attr.step, attr.inDegree, attr.outDegree)
    }

    // Add the node degree information into the graph
    val degreeGraph = nodeGraph
    .outerJoinVertices(nodeGraph.inDegrees)
    {
      case (id, attr, inDegree) => new VertexAttributes(attr.pages, attr.ads, attr.step, inDegree.getOrElse(0), attr.outDegree)
    }
    .outerJoinVertices(nodeGraph.outDegrees)
    {
      case (id, attr, outDegree) =>
        new VertexAttributes(attr.pages, attr.ads, attr.step, attr.inDegree, outDegree.getOrElse(0))
    }

    // Add the ads to the nodes
    val adGraph = degreeGraph.outerJoinVertices(ads)
    {
      (vertexId, attr, ad) =>
      {
        if (ad.isEmpty)
        {
          new VertexAttributes(attr.pages, List.empty, attr.step, attr.inDegree, attr.outDegree)
        }
        else
        {
          new VertexAttributes(attr.pages, List(Ad(ad.get.id, ad.get.tokens, ad.get.next, ad.get.score)),           
                               attr.step, attr.inDegree, attr.outDegree)
        }
      }
    }

    // Display the graph for debug only
    if (debug)
    {
      println("********** GRAPH **********")
      //printVertices(adGraph)
    }

    // return the generated graph
    return adGraph
  }
}

person Big Data Newbie    schedule 28.06.2015    source источник
comment
Добро пожаловать в СО! Можете ли вы дать короткую самодостаточную программу наподобие sscce.org? В нынешнем виде эта ошибка довольно очевидна — g.vertices возвращает список кортежей (и я предполагаю здесь) — первый элемент в кортеже — это VertexAttribute, а второй — index позиция. Вероятно, вы захотите сделать: v._1.score, а не v._2.score.   -  person S.R.I    schedule 28.06.2015
comment
Спасибо за ответ. Сигнатура для вершин: val vertices: VertexRDD[VD] Сигнатура для графа: class Graph[VD, ED] Итак, vertices возвращает RDD атрибутов VertexAttributes.   -  person Big Data Newbie    schedule 28.06.2015
comment
Это примерно работает для меня. Можете ли вы опубликовать более полный пример? Кажется, что вы устанавливаете тип VertexAttribute где-то, который затеняет ваш класс.   -  person Justin Pihony    schedule 28.06.2015
comment
Спасибо за ответ. Я не могу опубликовать более полный пример, потому что большая часть работы выполняется внутри стандартной библиотеки GraphX ​​(которая предоставляет класс Graph и его функцию vertices()). Но гугление этой проблемы, похоже, сильно подняло эту слежку за вашим классом. Можете ли вы объяснить это новичку в Scala? Я не использую трейты, абстрактные классы или что-то необычное. Я думаю, что это что-то основное с интерфейсом класса или с тем, как нужно использовать map(). Я не знаю, что такое параметр типа. Я родом из C.   -  person Big Data Newbie    schedule 28.06.2015
comment
Я должен добавить, что я могу println v._2, и это выглядит как дамп экземпляра VertexAttributes (например, со списками объявлений). Но когда я пытаюсь получить доступ к любому полю VertexAttributes (например, v._2.score() или v._2.step) внутри карты, я получаю аналогичные ошибки компилятора VertexAttributes, не входящие в параметр типа.   -  person Big Data Newbie    schedule 28.06.2015


Ответы (1)


VertexAttributes в вашем коде относится к параметру типа, а не к классу VertexAttributes. Ошибка, вероятно, в вашей функции createGraph. Например, это может быть так:

class Sim {
  def createGraph[VertexAttributes]: Graph[VertexAttributes, Int]
}

or:

class Sim[VertexAttributes] {
  def createGraph: Graph[VertexAttributes, Int]
}

В обоих случаях у вас есть параметр типа с именем VertexAttributes. Это то же самое, как если бы вы написали:

class Sim[T] {
  def createGraph: Graph[T, Int]
}

Компилятор не знает, что у T есть метод score (потому что это не так). Вам не нужен этот параметр типа. Просто пиши:

class Sim {
  def createGraph: Graph[VertexAttributes, Int]
}

Теперь VertexAttributes будет ссылаться на класс, а не на параметр локального типа.

person Daniel Darabos    schedule 28.06.2015
comment
Спасибо за объяснение того, как параметр типа может непреднамеренно появиться. Однако я проверил свой код, думал, что нашел конструкцию, подобную той, что вы описываете, но все равно получаю ту же ошибку компилятора. Может быть, я допустил ошибку параметра типа в менее очевидной форме? Я добавил свой код createGraph в свой исходный вопрос. Если бы вы взглянули на него, я был бы очень признателен за помощь. Спасибо. - person Big Data Newbie; 28.06.2015
comment
Я не вижу ничего плохого в коде. Я бы порекомендовал удалить кучу вещей, пока у вас не останется несколько строк, воспроизводящих проблему. В этот момент вы, вероятно, сами увидите, в чем проблема! По крайней мере, это подход, который я бы выбрал, если бы у меня было время. Удачи! - person Daniel Darabos; 28.06.2015
comment
В очередной раз благодарим за помощь. По крайней мере, теперь у меня есть некоторое представление о том, что искать. - person Big Data Newbie; 29.06.2015