[英]Extracting data from RDD in Scala/Spark
所以我有一個很大的數據集,它是一個stackoverflow用戶群的示例。 該數據集中的一行如下:
<row Id="42" Reputation="11849" CreationDate="2008-08-01T13:00:11.640" DisplayName="Coincoin" LastAccessDate="2014-01-18T20:32:32.443" WebsiteUrl="" Location="Montreal, Canada" AboutMe="A guy with the attention span of a dead goldfish who has been having a blast in the industry for more than 10 years.

Mostly specialized in game and graphics programming, from custom software 3D renderers to accelerated hardware pipeline programming." Views="648" UpVotes="337" DownVotes="40" Age="35" AccountId="33" />
我想從信譽中提取數字,在這種情況下為“ 11849”,從年齡中提取數字,在本示例中為“ 35”,我想將它們作為浮點數。
該文件位於HDFS中,因此格式為RDD
val linesWithAge = lines.filter(line => line.contains("Age=")) //This is filtering data which doesnt have age
val repSplit = linesWithAge.flatMap(line => line.split("\"")) //Here I am trying to split the data where there is a "
因此,當我用引號將其拆分時,信譽位於索引3中,年齡位於索引23中,但是如何將它們分配給地圖或變量,以便可以將它們用作浮動對象。 我還需要它對RDD上的每一行執行此操作。
編輯:
val linesWithAge = lines.filter(line => line.contains("Age=")) //transformations from the original input data
val repSplit = linesWithAge.flatMap(line => line.split("\""))
val withIndex = repSplit.zipWithIndex
val indexKey = withIndex.map{case (k,v) => (v,k)}
val b = indexKey.lookup(3)
println(b)
因此,如果將索引添加到數組中,現在我已經成功地將其分配給變量,但是我只能將其分配給RDD中的一項,那么有人知道如何對所有項進行處理嗎?
我們要做的是將原始數據集中的每個元素(表示為RDD)轉換為包含(Reputation, Age)
作為數值的元組。
一種可能的方法是使用String操作轉換RDD的每個元素,以便提取元素“ Age”和“ Reputation”的值,如下所示:
// define a function to extract the value of an element, given the name
def findElement(src: Array[String], name:String):Option[String] = {
for {
entry <- src.find(_.startsWith(name))
value <- entry.split("\"").lift(1)
} yield value
}
然后,我們使用該函數從每條記錄中提取有趣的值:
val reputationByAge = lines.flatMap{line =>
val elements = line.split(" ")
for {
age <- findElement(elements, "Age")
rep <- findElement(elements, "Reputation")
} yield (rep.toInt, age.toInt)
}
請注意,在執行此操作之前,我們不需要篩選“年齡”。 如果我們處理沒有“年齡”或“信譽”的記錄,則findElement
將返回None
。 此后, for-comprehension
的結果將為“ None
,並且記錄將通過flatMap
操作進行展平 。
解決此問題的更好方法是意識到我們正在處理結構化XML數據。 Scala為XML提供了內置支持,因此我們可以這樣做:
import scala.xml.XML
import scala.xml.XML._
// help function to map Strings to Option where empty strings become None
def emptyStrToNone(str:String):Option[String] = if (str.isEmpty) None else Some(str)
val xmlReputationByAge = lines.flatMap{line =>
val record = XML.loadString(line)
for {
rep <- emptyStrToNone((record \ "@Reputation").text)
age <- emptyStrToNone((record \ "@Age").text)
} yield (rep.toInt, age.toInt)
}
此方法依賴於XML記錄的結構來提取正確的屬性。 和以前一樣,我們結合使用Option
值和flatMap
來刪除不包含我們所需全部信息的記錄。
首先,您需要一個函數來提取行中給定鍵( getValueForKeyAs[T]
)的值,然后執行以下操作:
val rdd = linesWithAge.map(line => (getValueForKeyAs[Float](line,"Age"), getValueForKeyAs[Float](line,"Reputation")))
這應該給你一個RDD[(Float,Float)]
類型的RDD[(Float,Float)]
getValueForKeyAs
可以這樣實現:
def getValueForKeyAs[A](line:String, key:String) : A = {
val res = line.split(key+"=")
if(res.size==1) throw new RuntimeException(s"no value for key $key")
val value = res(1).split("\"")(1)
return value.asInstanceOf[A]
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.