繁体   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