2017-05-27 2 views
1

Ich habe eine Scala-Klasse, die das Maximum eines Eingabetyps IN mit einem MR-Job in Apache Spark zurückgibt. Diese Klasse funktioniert gut, wenn ich es von Scala nennen und es funktioniert wie folgt:Aufruf des primären Konstruktors mit mehreren impliziten Parametern Aufruf von Java

// Class 
class TypedMax[IN, T](val f: IN => T)(implicit ev$1: T => Ordered[T], ev$2: TypeTag[T]) 
    extends Aggregator[IN, T, T] { 

    override def zero: T = null.asInstanceOf[T] 
    override def reduce(b: T, a: IN): T = if (b > f(a)) b else f(a) 
    override def merge(b1: T, b2: T): T = if (b1 > b2) b1 else b2 
    override def finish(reduction: T): T = reduction 
} 

// Call function 
def max[IN, T](f: IN => T)(implicit ev$1: T => Ordered[T], ev$2: TypeTag[T]): TypedColumn[IN, T] = 
    new TypedMax[IN, T](f).toColumn 

Nun möchte Ich mag diese auch von Java aufrufbar machen, aber ich einige Schwierigkeiten, die mit der impliziten Parameter. Ich weiß, dass implizite Parameter übergeben werden können, indem sie an die Argumentliste in Java angehängt werden, aber die impliziten Parameter sind in Scala. Deshalb versuche ich folgendes zu tun:

class TypedMax[IN, T](val f: IN => T)(implicit ev$1: T => Ordered[T], ev$2: TypeTag[T]) 
    extends Aggregator[IN, T, T] { 

    override def zero: T = null.asInstanceOf[T] 
    override def reduce(b: T, a: IN): T = if (b > f(a)) b else f(a) 
    override def merge(b1: T, b2: T): T = if (b1 > b2) b1 else b2 
    override def finish(reduction: T): T = reduction 

    // Java api support 
    def this(f: MapFunction[IN, java.lang.Double]) = 
    this(x => f.call(x).asInstanceOf[T])(ev$1: T => Ordered[T], ev$2: TypeTag[T]) 

die dann von Java aufgerufen werden kann:

public static <T> TypedColumn<T, Double> max(MapFunction<T, Double> f) { 
    return new TypedMax<T, Double>(f).toColumn(); 
} 

ich viele Permutationen vorbei in den implicits aus dem Hilfs Konstruktor versucht haben, mit implicityimplicit und herumspielen mit Kommas und Klammern. Allerdings beschwert es sich immer, dass ev $ 1 und ev $ 2 nicht gefunden werden. Ich habe aber in den Parameter zu übergeben, da sonst Fehler es:

Error:(135, 5) No implicit view available from T => Ordered[T]. 
    this(x => f.call(x).asInstanceOf[T]) 
Error:(135, 5) not enough arguments for constructor TypedMax: (implicit ev$1: T => Ordered[T], implicit ev$2: reflect.runtime.universe.TypeTag[T])org.apache.spark.sql.execution.aggregate.TypedMax[IN,T]. 
Unspecified value parameters ev$1, ev$2. 
    this(x => f.call(x).asInstanceOf[T]) 

Und wenn ich versuche:

def this(f: MapFunction[IN, T]) = 
    this(x => f.call(x))(T => Ordered[T], TypeTag[T]) 

Das Ergebnis ist:

Error:(135, 38) value Ordered of type scala.math.Ordered.type does not take type parameters. 
    this(x => f.call(x))(T => Ordered[T], TypeTag[T]) 
Error:(135, 50) missing argument list for method apply in object TypeTag 
Unapplied methods are only converted to functions when a function type is expected. 
You can make this conversion explicit by writing `apply _` or `apply(_,_)` instead of `apply`. 
    this(x => f.call(x))(T => Ordered[T], TypeTag[T]) 

Was bin ich fehlt/Missverständnis? Danke!

Antwort

1

T => Ordered[T] bedeutet nicht, was Sie denken, es bedeutet, dies erstellt Function1 mit einem Argument T und Körper scala.math.Ordered.apply[T]. Versuchen Sie Folgendes statt:

def this(f: MapFunction[IN, T], e: MapFunction[T, Ordered[T]], tt: TypeTag[T]) = 
    this(x => f.call(x))(x => e.call(x), tt) 

(Ich bin nicht wirklich sicher, ob Sie eine TypeTag[T] von Java zu materialisieren in der Lage sein werden)

+0

Dank Olivier. Sie haben Recht: Ich kann TypeTag nicht realisieren. Ich versuche gerade, einen Wrapper darum zu schreiben, um das ganze Problem zu umgehen, aber selbst das funktioniert nicht. Hast du Vorschläge dazu? Klasse TypedMaxJava [IN, T] (f: MapFunction [IN, T]) { def typedMax: TypedColumn [IN, T] = { neu TypedMax [IN, T] (x => f.call (x))) (Bestellung [T], TypeTag [T]). ToColumn } } reicht leider nicht – ScrubS

+0

Es gibt keinen sauberen Weg herum, 'TypeTags' werden materialisiert von scalac ... Wenn Sie im Voraus die Untermenge von kennen Unterstützte Typen, die Sie haben könnten ein 'Objekt TypeTagForJava {def ttInt = TypeTag [Int]; ...} '. Andernfalls müssen Sie zur Reflexion zurückfallen, die Spark sowieso https://github.com/apache/spark/blob/master/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst verwendet/ScalaReflection.scala – OlivierBlanvillain

Verwandte Themen