Почему я не могу отфильтровать это условие при чтении XML и фильтра - PullRequest
3 голосов
/ 27 марта 2019

У меня есть пример кода

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)

Фактический объем производства:

[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]

Я ожидаю получить только одну строку.

[BNK,c1@v1,c2@v2,c3@v3,c5@20181106]

Что не так с моим состоянием или какими-либо пропущенными мною знаниями о scala_xml и как получить ожидаемый результат?

Ответы [ 3 ]

0 голосов
/ 30 марта 2019

Ваша внешняя карта ожидает 4 записи и возвращает 4 записи, как и ожидалось. Возможно, вы захотите добавить фильтр в конце.

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)

Оп:

[BNK,c1@v1,c2@v2,c3@v3,c5@20181106] 
0 голосов
/ 31 марта 2019

XML можно проанализировать, затем оставить необходимые узлы, а затем оставить узел с необходимым значением:

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))
0 голосов
/ 28 марта 2019

В зависимости от того, что вы пытаетесь сделать. Если вы ищете, имеет ли какой-либо из тегов c1, c2, c3, c5 значение 20181106, вы можете сделать это.

    (elem.label == "c1" || elem.label == "c2" || elem.label == "c3" || elem.label == "c5")
    && elem.text =="20181106"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...