#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-файлами.