Застрял в написании полиморфной функции транспонирования, которая принимает и возвращает RDD-массивы либо массивов, либо секвенций / векторов. - PullRequest
0 голосов
/ 23 мая 2019

Я занимаюсь рефакторингом библиотеки Scala, которая взаимодействует со Spark, чтобы использовать Векторы там, где это имеет смысл. Я хотел бы предоставить функции, которые напрямую взаимодействуют со Spark, с возможностью работы с массивами или векторами. Одной из этих функций является функция транспонирования. И все же я не могу понять, как правильно подписать тип, чтобы сделать вывод типа.

Я попытался определить сигнатуру функции следующим образом, но, похоже, это не сработало, вместо этого я получил следующее сообщение о выводе типа, когда я запускаю тест с RDD String Vector в качестве примера.

 def transpose[T, Abs <: IndexedSeq[T] : ClassTag](rdd: RDD[Abs]): RDD[Abs] = {
​
  rdd
   .zipWithIndex // give the columns an index
   .flatMap{
    case (row, row_idx) => row.zipWithIndex.map{ // give the rows an index
     case (el, col_idx) => (col_idx, (row_idx, el)) // each element now has a column and row index
    }
   }
   .groupBy(_._1)
   .sortBy(_._1)
   .map{ case (_, els) => els.map(_._2).toIndexedSeq.sortBy(_._1) }
   .map( row => row.map(_._2))
   .map(_.asInstanceOf[Abs])
 }
Error:(26, 5) inferred type arguments [Nothing,scala.collection.immutable.Vector[String]] do not conform to method transpose's type parameter bounds [T,Abs <: IndexedSeq[T]]
    transpose(subset)
Error:(26, 15) type mismatch;
 found   : org.apache.spark.rdd.RDD[scala.collection.immutable.Vector[String]]
 required: org.apache.spark.rdd.RDD[Abs]
    transpose(subset)

1 Ответ

0 голосов
/ 06 июня 2019

Компилятору удается только определить параметры типа, которые появляются в списке параметров-значений (или тип возвращаемого значения, в некоторых случаях). Уловка, которая обычно работает в подобных случаях:

def transpose[T, Abs <: IndexedSeq[T] : ClassTag](rdd: RDD[Abs with IndexedSeq[T]]): RDD[Abs] = {
  rdd
   .zipWithIndex // give the columns an index
   .flatMap{
    case (row, row_idx) => row.zipWithIndex.map{ // give the rows an index
     case (el, col_idx) => (col_idx, (row_idx, el)) // each element now has a column and row index
    }
   }
   .groupBy(_._1)
   .sortBy(_._1)
   .map{ case (_, els) => els.map(_._2).toIndexedSeq.sortBy(_._1) }
   .map( row => row.map(_._2))
   .map(_.asInstanceOf[Abs])
 }

Поскольку Abs является подтипом IndexedSeq[T], Abs with IndexedSeq[T] и Abs более или менее эквивалентны (*), только теперь компилятор может сделать вывод, что Abs равно Vector[String], а T равно String.

* Вы можете убедиться в этом:

scala> implicitly[Vector[String] =:= (Vector[String] with IndexedSeq[String])]
res3: =:=[Vector[String],Vector[String] with scala.collection.immutable.IndexedSeq[String]] = <function1>
...