J'ai un exemple de code
[BNK,c1@v1,c2@v2,c3@v3,c5@20181106]
Sortie réelle:
[BNK,c1@v1,c2@v2,c3@v3] [BNK,c1@v1,c2@v2,c3@v3] [BNK,c1@v1,c2@v2,c3@v3] [BNK,c1@v1,c2@v2,c3@v3,c5@20181106]
Ce que j'attends, c'est de n'obtenir qu'une seule ligne comme résultat.
import org.apache.spark.sql.Row import scala.xml._ object reading_xml { def main(args: Array[String]): Unit = { //I have 42 Millions of records val records = List( "<root><c1>v1</c1><c2>v2</c2><c3>v3</c3><c4>v4</c4><c5>20181104</c5></root>", "<root><c1>v1</c1><c2>v2</c2><c3>v3</c3><c4>v4</c4><c5>20181102</c5></root>", "<root><c1>v1</c1><c2>v2</c2><c3>v3</c3><c4>v4</c4><c5>20181102</c5></root>", "<root><c1>v1</c1><c2>v2</c2><c3>v3</c3><c4>v4</c4><c5>20181106</c5><c6>v6</c6></root>" ) import org.apache.spark.sql.SparkSession val spark = SparkSession.builder().master("local").getOrCreate() import spark.implicits._ val df = records.toDF() df.show() val rdd = df.rdd.map(line => Row.fromSeq( "BNK" :: scala.xml.XML.loadString("<?xml version='1.0' encoding='utf-8'?>" + line(0)).child .filter(elem => elem.label == "c1" || elem.label == "c2" || elem.label == "c3" || (elem.label == "c5" && elem.text =="20181106") ).map(elem => elem.label+"@"+elem.text).toList) ) rdd.take(100).foreach(println)
Quel est le problème avec mon état ou tout ce que j'ai oublié de comprendre sur scala_xml, et comment obtenir le résultat attendu?
3 Réponses :
En fonction de ce que vous essayez de faire. Si vous recherchez si l'une des balises c1, c2, c3, c5 a une valeur de 20181106, vous pouvez le faire.
(elem.label == "c1" || elem.label == "c2" || elem.label == "c3" || elem.label == "c5") && elem.text =="20181106"
Je veux un retour de sortie comme [BNK, c1 @ v1, c2 @ v2, c3 @ v3, c5 @ 20181106]
vous pouvez tester mon code ci-dessus, vous conduisez seulement comme ceci [BANK] [BANK] [BANK] [BANK, c5 @ 20181106]
Votre carte externe attend 4 enregistrements et elle renvoie 4 enregistrements comme prévu. Vous voudrez peut-être ajouter un filtre à la fin.
[BNK,c1@v1,c2@v2,c3@v3,c5@20181106]
Op:
val rdd = df.rdd.map(line => Row.fromSeq( "BNK" :: scala.xml.XML.loadString("<?xml version='1.0' encoding='utf-8'?>" + line(0)).child .filter(elem => elem.label == "c1" || elem.label == "c2" || elem.label == "c3" || (elem.label == "c5" && elem.text =="20181106") ).map(elem => elem.label+"@"+elem.text).toList) ).filter(line => line.mkString.contains("c1") && line.mkString.contains("c2") && line.mkString.contains("c3")&& line.mkString.contains("c5") && line.mkString.contains("20181106")) rdd.take(100).foreach(println)
@ kn3l - Veuillez me faire savoir si cela est utile ou non?
Le XML peut être analysé, puis les nœuds requis à gauche, puis le nœud avec la valeur requise à gauche:
val rdd = df.rdd.map(line => scala.xml.XML.loadString("<?xml version='1.0' encoding='utf-8'?>" + line(0)).child) // left only required nodes .map(nodeList => nodeList.filter(elem => Seq("c1", "c2", "c3", "c5").contains(elem.label))) // find element where "c5" == "20181106" .filter(nodeList => nodeList.find(elem => elem.label == "c5" && elem.text == "20181106").isDefined) .map(s => Row.fromSeq("BNK" :: s.map(elem => elem.label + "@" + elem.text).toList))