Выполните итерацию по XML на основе count и создайте ArrayString с помощью spark scala

#scala #apache-spark #apache-spark-sql

#scala #apache-spark #apache-spark-sql

Вопрос:

проанализируйте XML, выполнив итерацию по циклу, и создайте массив строк, используя циклы

 <USR_ORD><OrderResponse>
<OrderCount1>3</OrderCount1>
<OrderResult><orders>
<order>
<name>A</name><address>AAA</address><number>A1</number><status></status>
</order>
<order>
<name>B</name><number>B1</number>
</order>
<order>
<name>C</name><address>CCC</address><number>C1</number><status></status>
</order>
</orders></OrderResult>
</OrderResponse></USR_ORD>
 

Мой код выглядит следующим образом

 //creating list
val myList=List((100,1,"<USR_ORD><OrderResponse><OrderCount1>3</OrderCount1><OrderResult><orders><order><name>A</name><address>AAA</address><number>A1</number><status></status></order><order><name>B</name><number>B1</number></order><order><name>C</name><address>CCC</address><number>C1</number><status></status></order></orders></OrderResult></OrderResponse></USR_ORD>"))

//creating dataframe and temp table
val rdd = spark.sparkContext.parallelize(myList);
val DF1 = rdd.toDF("customer_id","response_id","response_output")
DF1.createOrReplaceTempView("ord_tbl");

spark.sql("""select * from ord_tbl""").show(10,false)
 ----------- ----------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
|customer_id|response_id|response_output                                                                                                                                                                                                                                                                                                                                         |
 ----------- ----------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
|100        |1          |<USR_ORD><OrderResponse><OrderCount1>3</OrderCount1><OrderResult><orders><order><name>A</name><address>AAA</address><number>A1</number><status></status></order><order><name>B</name><number>B1</number></order><order><name>C</name><address>CCC</address><number>C1</number><status></status></order></orders></OrderResult></OrderResponse></USR_ORD>|
 ----------- ----------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
 

используя стандартную функцию xpath

 spark.sql("""select xpath(response_output, '/USR_ORD/OrderResponse/OrderResult/orders/order/name/text()') as name
      ,xpath(response_output, '/USR_ORD/OrderResponse/OrderResult/orders/order/address/text()') as address
      , xpath(response_output, '/USR_ORD/OrderResponse/OrderResult/orders/order/status/text()') as status from ord_tbl""").show(10,false)
 --------- ---------- ------ 
|name     |address   |status|
 --------- ---------- ------ 
|[A, B, C]|[AAA, CCC]|[]    |
 --------- ---------- ------ 
 

но ожидаемый фрейм данных должен быть таким, как показано ниже

  --------- ---------- ------ 
|name     |address   |status|
 --------- ---------- ------ 
|[A, B, C]|[AAA,,CCC]|[,,]  |
 --------- ---------- ------ 
 

Что-то, что я пытался использовать для ссылки, что, я уверен, неправильно и не компилируется

 def (inorders:Int,inOrderCount:int,partxpathstring1:String,partxpathstring2:String,)
val orders=inorders
val OrderCount=inOrderCount
var i=0
var j=0
for (i <- 1 to orders){
    for(j <- 1 to OrderCount){
    fullxpath=xpath_string(response_output,'$partxpathstring1 [i] $partxpathstring2 [j]')
    fullxpath =fullxpath
    )
j =1
    }
i 1
}
 

Ответ №1:

xpath Функция Spark, похоже, фильтрует пустые значения в узлах XML. Возможно, вам придется использовать UDF для решения этой проблемы. Вот пример использования scala.xml.XML для анализа столбца response_output :

 val parse_orders = udf((response: String) => {
  val xml = scala.xml.XML.loadString(response)

  val orderCount = (xml \ "USR_ORD"  "OrderResponse"  "OrderCount1").text
  val orders = xml \ "USR_ORD"  "OrderResponse"  "OrderResult"  "orders"  "order"

  val orderInfo = Seq("name", "address", "number", "status").map { node =>
    (node -> (orders  node).map(_.text))
  }.toMap

  (orderCount, orderInfo)
})


val df1 = df.withColumn("parsed", parse_orders(col("response_output")))
  .select(
    col("customer_id"),
    col("response_id"),
    col("parsed._1").as("orderCount"),
    col("parsed._2.name").as("name"),
    col("parsed._2.address").as("address"),
    col("parsed._2.number").as("number"),
    col("parsed._2.status").as("status")
  )  

df1.show(false)
// ----------- ----------- ---------- --------- ------------ ------------ ------ 
//|customer_id|response_id|orderCount|name     |address     |number      |status|
// ----------- ----------- ---------- --------- ------------ ------------ ------ 
//|100        |1          |3         |[A, B, C]|[AAA, , CCC]|[A1, B1, C1]|[, , ]|
// ----------- ----------- ---------- --------- ------------ ------------ ------ 
 

Комментарии:

1. Привет @blackbishop Я принимаю это решение, но это также не работает в моем случае, поскольку вышеупомянутое решение работает, только если длина xml меньше 28544, и это прерывается, как только мы превышаем эту длину xml, к сожалению, в моем случае xml, с которым я имею дело, имеет длину 319989. любой другой способ решить эту проблему.

2. Привет @pythonsparkscala, это для синтаксического анализа небольших строк XML. Я советую вам использовать spark-xml , если вы имеете дело с большими XML-файлами.