使用Spark发送统计数据邮件

问题

有些时候希望spark计算完的统计数据直接已邮件的形式发送。在这其中有一些点和技巧记录一下

1.拼接邮件HTML

调取公司发邮件接口的时候,传入的是html格式的字符传,一开始这个地方最繁琐麻烦的可能就是拼接html,但是scala支持直接写html,这个比较实用,写起来很方便。
包括标签,样式都可以直接写。

  /**
    * 拼接HTML Table
    * @param data
    * @return
    */
  def generateTable(columns:List[String],data: Array[Row]) = {
    <table cellpadding="4" style="border: 1px solid #000000; border-collapse: collapse;" border="1">
      {
      <TR style="background-color:#BDD6EE;">{
        columns.map(column =>
          <TH align="center" style="text-align:center; margin:0;border:solid #000 1px;">{column}</TH>)
        }</TR>
        <TR>{data.map{row=>
          <tr>{row.toSeq.toList.map(cell =>
            <th align="center" style="text-align:center; margin:0;border:solid #000 1px;">{cell}</th>)}</tr>}
          }</TR>
      }
    </table>
  }
  
    def generateTable(data: List[List[Any]]) = {
    <table cellpadding="4" style="border: 1px solid #000000; border-collapse: collapse;" border="1">
      {data.zipWithIndex.map{ case (row,rownum) =>
      if((rownum == 0)){
        <tr>
          {row.map(cell =>
          <th align="center" style="font-size:large">
            {cell}
          </th>)}
        </tr>
      }else{
        <tr>
          {row.map(cell =>
          <td>
            {cell}
          </td>)}
        </tr>}
    }
      }
    </table>
  }

2.日期处理

这个地方记录下这次使用的结果日期处理函数吧,省的下次到处找,找不到反复写工具类

   
    /**
     * 生成前N天
     */
    public static String getDateBeforeOrAfter(int num) {
        return genYmdFromTs(System.currentTimeMillis() + (num * DateTimeUtil.TIME_DAY_MILLISECOND));
    }
    
    public static String genLastDayStr() {
        return getDateBeforeOrAfter(-1);
    }
    
    /**
     * 获取当前日期对应的上周日
     */
    public static String getLastSunday(String yyyyMMdd) throws ParseException {
        return getAfterYymmdd(yyyyMMdd, -1);
    }

3.计算TopN

这个很常识,使用row_number() over ,但是使用的 时候经常写错,还得百度谷歌,这个地方记一下

// 各品牌销售top 15
select brand,marketName,row_number() over ( partition by brand order by cnt desc) rank  from ( select brand,marketName,count(*) as cnt from new_user_df_days where firstDate = '${yyyyMMdd}' and marketName!= ''  group by brand,marketName ) a having rank <= ${topN} 

4.dataframe的join

没啥说的 写两个示例,分别是on 一个字段和多个字段。

    // 默认inner join,可以参数选择leftjoin等
    val df_result = df_l.join(df_r,df_l("col1")===df_r("col2")).drop("col2")

    // 这个on两个字段,字段名要相同,join完后自动保留一列
    val df_result = df_l.join(df_r,Seq("colA","colB"))

5.dataframe 增加一列

增加一列,并写下增加的这一列的计算逻辑,可以用udf


    val df_result = df_1.withColumn("new_col_name",df_1("col_1") / (df_1("col_2") + 1))

6.计算月均

  //计算月均,这里是上月月均,头疼的是对分母的处理
    var (year, month) = (yyyyMMdd.substring(0, 4).toInt, yyyyMMdd.substring(4, 6).toInt)
    if (month == 12) year = year -1
    val last_month = if(month == 12) 1 else month -1
    val fds = if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) 29 else 28
    val month2Days: Map[Int, Int] = Map(1 -> 31, 2 -> fds, 3 -> 31, 4 -> 30, 5 -> 31, 6 -> 30,
      7 -> 31, 8 -> 31, 9 -> 30, 10 -> 31, 11 -> 30, 12 -> 31)

    println(month2Days(last_month))

7.显示百分比

需要显示成 99.8%的形式

    concat(cast(round(day_ratio * 100,1)  as string),'%') as d_ratio

8. repartition(1) 和 orderby

如果是存csv的话需要repartition(1),但是oderby的效果就没了,再orderby就又默认200分区,我还没找到好的办法。
不过确认的一点是orderby后collect是保留顺序的。返回一个array也相当于一个文件了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值