2017-12-15 3 views
1

Daten: DataFrame, die 15 String-Spalten hat.Spark, DataFrame: Alle eindeutigen Zeichenfolgen aus vielen Spalten

Ziel: Erstellen einer Liste, die die verschiedenen Zeichenfolgen in allen 15 Spalten enthält.

Beispiel: Wenn das Wort "Gitarre" einmal oder mehrmals in der ersten Spalte sowie in der vierten Spalte erscheint, muss es einmal in der endgültigen Liste erscheinen.

vorgeschlagene Lösung aber nicht ideal: Eine UDF eine Option ist, alle Spalten verketten in einer neuen Spalt, dann kann ich diese Spalte mit einem CountVectorizer verarbeiten, die das Vokabular extrahieren. Aber die UDFs sind begrenzt, da sie maximal 10 Eingabeparameter akzeptieren (dh ich kann nicht mehr als 10 Spalten an eine UDF übergeben), also muss diese Lösung zwei UDFs implementieren, die ersten 10 Spalten zu verketten, die zweite die Ausgabe der ersten UDF mit den nächsten 5 Spalten.

Ich bin auf der Suche nach einer effizienteren kompakten Lösung für dieses Problem und allgemeiner eine Lösung für das Problem der begrenzten Anzahl von Eingabeparametern für UDFs.

+0

A Wenige Präzisionen, wenn ich fragen darf: Willst du zu einer Liste (zB Fahrerseite) oder zu einem Datenrahmen sammeln? Ist die Umstellung auf RDD eine Option für Ihren Fall? (Randbemerkung: array_concat + count vectorizer bieten eine gute Lösung für Ihre Frage ich denke, aber das ist, weil Ihr Anwendungsfall von Strings ist, nicht beliebige Typen) – GPI

+0

Kein Problem bei der Arbeit mit DataFrames und RDDs, akzeptiert Array_concat mehr als diese Zahl Säulen? – Rami

+0

Appart, dass es nicht 'array_concat' ist, nur' array', sorry dafür, ja, kann es. Siehe https://stackoverflow.com/questions/35419307/create-array-of-literals-and-columns-from-list-of-strings-in-spark-sql für etwas Ähnliches. Ich suche nach etwas Besserem. – GPI

Antwort

3

Die spark-sql-Funktion array kann eine beliebige Anzahl von Doppelpunkten (des gleichen Typs) einer Array-Spalte dieses Typs zuordnen.

Von da an können Sie eine UDF für den Array-Typ erstellen oder für Ihren Fall den CountVectorizer wie vorgeschlagen verwenden.

scala> val data = spark.sparkContext.parallelize(Seq(("a1", "b1", "c1"), ("a2", "b2", "c2"))).toDF("a", "b", "c") 
data: org.apache.spark.sql.DataFrame = [a: string, b: string ... 1 more field] 

scala> data.show 
+---+---+---+ 
| a| b| c| 
+---+---+---+ 
| a1| b1| c1| 
| a2| b2| c2| 
+---+---+---+ 

scala> data.select(array("a", "b", "c")).show 
+--------------+ 
|array(a, b, c)| 
+--------------+ 
| [a1, b1, c1]| 
| [a2, b2, c2]| 
+--------------+ 

Es ist einfacher, aber als ein CountVectorizer:

scala> data.select(explode(array("a", "b", "c"))).distinct.show 
+---+ 
|col| 
+---+ 
| b2| 
| c1| 
| a2| 
| b1| 
| a1| 
| c2| 
+---+ 

Wenn gehen RDD direkt in Ordnung ist mit Ihnen, es noch einfacher ist (und wahrscheinlich schneller):

scala> data.rdd.flatMap(r=>r.toSeq).distinct.collect 
res4: Array[Any] = Array(b2, a1, a2, c1, c2, b1) 
Verwandte Themen