簡體   English   中英

從Scala / Spark中的RDD中提取數據

[英]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.&#xD;&#xA;&#xD;&#xA;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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM