初学spark碰到的一些问题

本文介绍了Spark使用中遇到的问题,包括topByKey操作、Spark调试、Scala Map排序、日志输出、RDD转换为Map、正则匹配、字符串split、flatMap操作、HiveContext读取JDBC、sample操作、时间戳转换、函数柯里化、Top操作、RDD嵌套问题、通过Key找Value的方法、Spark写数据库、监控、函数作用域、资源配置、分区器以及错误处理等,提供了相应的解决方案和最佳实践。
摘要由CSDN通过智能技术生成

Spark and Scala

  1. topbykey:
    Returns the top k (largest) elements for each key from this RDD as defined by the specified implicit Ordering[T]. If the number of elements for a certain key is less than k, all of them will be returned.
  2. spark的调试问题
    spark运行过程中的数据总是以RDD的方式存储,使用Logger等日志模块时,对RDD内数据无法识别,应先使用行为操作转化为scala数据结构然后输出。
  3. scala Map 排序
    对于scala Map数据的排序,使用 scala.collection.immutable.ListMap 和 sortWiht(sortBy),具体用法如下

    val sortedScore = ListMap(outScore.toSeq.sortWith(_._2._5>_._2._5):_*)
    

    即, 使用outScore value的第5个值按降序排列

  4. spark Logger 的输出
    spark rdd数据为惰性数据,在map的过程中无法打印中间数据,需要通过行为操作将其转化为scala数据格式,然后遍历打印。

  5. spark rdd 转换为map
    contenttypeHit是一个spark pair RDD,需要转化为一个Map,maxHit = contenttypeHit.collect()执行后获取的是一个Array,不能通过key值获取value,因此先定义一个可变映射val score = new scala.collection.mutable.HashMap[Int, Long],然后对maxHit执行map操作更新score的值,maxHit.map(x => if(x._2==0) score(x._1)=1L else score(x._1)=x._2),缺点是maxHit得到的是一个unit值。 这是一个蠢方法,正确的方法是 val maxHit = contenttypeHit.map(x=>(x._1, x._2)).collectAsMap()

  6. 转换操作中不要掺杂行为操作
    正则匹配貌似在转化操作中也无法正常执行,会抛出空指针的异常,暂时还未确定 更正:正则表达式可以在转化操作中进行,空指针是因为读数据返回的空值不是“”而是Null

  7. scala 字符串 split 对于字符串s =”11010002|11010003|11019999”,如果想按照竖线分割,需要val lst = s.split(“//|”),如果直接s.split(“|”),会分割成 Array(1, 1, 0, 1, 0, 0, 0, 2, |, 1, 1, 0, 1, 0, 0, 0, 3, |, 1, 1, 0, 1, 9, 9, 9, 9)
  8. spark flatmap

    val subtype_pid_score = sub_type.filter(v => v._4.isInstanceOf[String])
                             .flatMap(vv => vv._4.split("|")
                             .filter(vvf => vvf.length==8)
                             .map(vvv => (vvv.toLong,(vv._1, pid_score.getOrElse(vv._1, 0.0))))
                              )
    

    flatMap操作后产生了[[“12112”, “343434”], [“8787”, “77987”]]并展开成[“12112”, “343434”,”8787”, “77987”, vvv] 然后进行map操作是对所有展开后的元素,并且可对应到vv。

  9. HiveContext 读取 JDBC

    Jdbc的读取分为两种方法,一种是使用sqlContext,一种是使用HiveContext,前种方法返回的是一个rdd,后种方法返回的是dataFrame

    1. JDBCsqlContext读取

      def getNewsDataRankInfo(sqlContext: SQLContext) = {
      sqlContext.read.jdbc(JDBCUrl, "t_news_info", Prop).registerTempTable("t_news_info")
      sqlContext.sql("select f_news_id as f_pid, UNIX_TIMESTAMP(f_release_time) as f_time, f_sub_type from t_news_info where f_status = 65002")
          }
      

      sqlContext.read.jdbc相当于将JDBC的配置读取到sqlContext中,然后使用sqlContext类提供了一个sql方法,使用sql语句select需要的数据。返回值是一个DataFrame类实例。

    2. JDBChiveContext读取

      val hiveCtx = new HiveContext(sc)
      val url = "jdbc:mysql://192.168.36.94/homed_spider"
      val tableName = "t_spider_program_final"
      import java.util.Properties
      val connProperties = new java.util.Properties
      connProperties.setProperty("user", "root")
      connProperties.setProperty("password", "123456")
      val jdbcDF = hiveContext.read.jdbc(url, tableName, connProperties)
      

    返回的值jdbcDF即整个表,类型为DataFrame

  10. Map的更新

    scala中映射分为两种

    • 可变映射 import scala.collection.mutable.HashMap
    • 不变映射 val score = Map((“a”,1))

    对于可变映射,值的更新可以直接通过key赋值,对于不变映射你无法更新它的值,但是你 可以得到一个新的

    val newScore = score + ("v"->12, "a"->13)
    

    新赋的值将覆盖原来的值,如果想通过Map来更新Map,使用++运算符

    val nScore = score ++ newScore
    
  11. groupBy

    对于rdd使用groupBy,可以生成以指定项为key的Map

    val exp =Array((都市,0.3), (爱情,0.3), (纪录,0.28),(都市, 0.4))

    val expMap =exp.groupBy(x=>x._1).map(v=>(v._1, v._2.map(x=>x._2)))  
    

    生成的数据格式为 Map(都市->(0.3,0,4),爱情->(0.3),记录->(0.28))

  12. sample

    sample对RDD采样,以及是否替换,调用方法为

    rdd.sample(false,0.5)
    
    • true 表示有放回的取样,即该次抽样所得样本有重复
    • false 表示无放回的取样,抽样无重复
  13. scala 时间戳与时间互转

    依赖包:

    import java.util.Date
    import java.text.SimpleDateFormat
    

    1.时间戳转时间字符串

    def tmiestampTostr(ts :Long) = {
        val  SimpleDateFormat  = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
        SimpleDateFormat.format(new Date(ts*1000L))
    }
    

    2.时间转时间戳

    def getTimestamp(t: String):Long = {
    val date1 = """(\d\d\d\d)(\d\d)(\d\d)""".r
    val date2 = """(\d\d\d\d)-(\d\d)-(\d\d).*""".r      
    
    val fm1 = new SimpleDateFormat("yyyyMMdd")
    val fm2 = new SimpleDateFormat("y-M-d")
    
    t match {
    case date1(y, m, d) => fm1.parse(t).getTime / 1000
    case date2(y, m, d) => fm2.parse(t).getTime / 1000
    case _ => {
    //Logger.info(s"can't parse time from this string:$t")
    //curTime.set(1970, 0, 0)
        0L
            }
        }
    }
    
  14. scala 函数柯里化

    scala> def sum(x:Int)(y:Int)=x+y  
    sum: (x: Int)(y: Int)Int  
    
    scala> val second = sum(1)_  
    second: Int => Int = <function1>  
    
    scala> second(2)  
    res1: Int = 3
    

    柯里化函数执行时,分解为两个函数执行,步骤与下面的方法调用过程类似

    scala> def first(x:Int) = (y:Int)=>x+y  
    first: (x: Int)Int => Int  
    
    scala> val second = first(1)  
    second: Int => Int = <function1>  
    
    scala> second(2)  
    res4: Int = 3  
    

    curry化最大的意义在于把多个参数的function等价转化成多个单参数function的级联,这样所有的函数就都统一了,方便做lambda演算。 在scala里,curry化对类型推演也有帮助,scala的类型推演是局部的,在同一个参数列表中后面的参数不能借助前面的参数类型进行推演,curry化以后,放在两个参数列表里,后面一个参数列表里的参数可以借助前面一个参数列表里的参数类型进行推演。这就是为什么 foldLeft这种函数的定义都是curry的形式

  15. Top操作取前几项

    top方法返回一个由原RDD中前N大的元素构成的RDD,并且可以指定由哪个数据排序

    val 
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值