小白终于进入了职场,从事大数据方面的工作!

分到项目组了,搬砖的时候遇到了一个这样的问题。

要求:用spark实现oracle的存储过程中计算部分。

  坑:由于报表中包含了一个ID字段,其要求是不同的区域拥有不同的区域ID,且ID在数据库表中的属性为主键。Oracle的存储过程中采用的是自定义序列,采用发号的形式实现ID唯一且符合区域特性。

  填坑过程:

方法一:sql.functions 中monotonically_increasing_id

采用import org.apache.spark.sql.functions.中的
monotonically_increasing_id函数。
使用demo如下:
//从数据库中加载表TEST_EMP进入内存,并且取ENAME和EMPNO两列
val dfEmp=sqlContext.read.options(conUtil.con("TEST_EMP"))
.format("jdbc").load()
.select("ENAME","EMPNO")
val test =dfEmp
.withColumn("TEST_NO",monotonically_increasing_id)
//向oracle中写数据,这个函数的使用前提是需要确定表"EMP_TMP"存在。且向这张表写入数据的时候最好字段进行对应,如果列多余数据库中的列数则会出现参数过多的错误。
JdbcUtils.saveTable(test, url, "EMP_TMP", properties)

//代码结果如下所示,在数据库中生成了一个从0开始自增的列
ENAME EMPNO TEST_NO
SMITH  7369 0
ALLEN 7499 1
WARD 7521 2
JONES 7566 3
这个方法有一个缺点:序列是从0开始的,monotonically_increasing_id函数无法接受参数,所以我们无法用其根据我们的业务进行指定序列。
所以,有一个想法于是去看了一下该方法的源码,发下如下特点:
  首先看到函数的定义def monotonically_increasing_id(): Column = withExpr { MonotonicallyIncreasingID() }
  深入查看MonotonicallyIncreasingID() ,具体源码如下:
private[sql] case class MonotonicallyIncreasingID() extends LeafExpression with Nondeterministic {

  /**
* Record ID within each partition. By being transient, count's value is reset to 0 every time
* we serialize and deserialize and initialize it.
*/
@transient private[this] var count: Long = _ @transient private[this] var partitionMask: Long = _ override protected def initInternal(): Unit = {
count = 0L
partitionMask = TaskContext.getPartitionId().toLong << 33
} override def nullable: Boolean = false override def dataType: DataType = LongType override protected def evalInternal(input: InternalRow): Long = {
val currentCount = count
count += 1
partitionMask + currentCount
} override def genCode(ctx: CodeGenContext, ev: GeneratedExpressionCode): String = {
val countTerm = ctx.freshName("count")
val partitionMaskTerm = ctx.freshName("partitionMask")
ctx.addMutableState(ctx.JAVA_LONG, countTerm, s"$countTerm = 0L;")
ctx.addMutableState(ctx.JAVA_LONG, partitionMaskTerm,
s"$partitionMaskTerm = ((long) org.apache.spark.TaskContext.getPartitionId()) << 33;") ev.isNull = "false"
s"""
final ${ctx.javaType(dataType)} ${ev.value} = $partitionMaskTerm + $countTerm;
$countTerm++;
"""
}
}
我们可以发现这个类中重写了父类的initInternal()方法,指定了初始值count=0L,enmm这样子的话我们可不可以通过复写该类中的初始值来满足我们的业务需求
override protected def initInternal(): Unit = {
count = 0L
partitionMask = TaskContext.getPartitionId().toLong << 33
}
(别想太多,一个业务涉及那么多序列,总不能用一次改一次吧,当然如果技术过硬,自己写一套方法以及类,用来接收参数1:序列起始值,参数2:序列终止值。当前技术不够且加班 导致这个想法凉凉)
方法二:rdd算子中的zipWithIndex()方法
代码demo如下:
val dfEmp=sqlContext.read.options(conUtil.con("TEST_EMP"))
.format("jdbc").load()
.select("ENAME","EMPNO")
//对读取的dfEmp进行schema加列操作,增加一列且指定列数据类型
val schma=dfEmp.schema.add(StructField("TEST_NO",LongType))
val temp=dfEmp.rdd.zipWithIndex()
//可以在row中指定我们自己业务需求的序列初始值
val changed= temp.map(t => Row.merge(t._1, Row(t._2+340000000)))
val in=sqlContext.createDataFrame(changed,schma)
JdbcUtils.saveTable(in, url, "EMP_TMP", properties)
结果如下所示:
ENAME  EMPNO TEST_NO
 SMITH  7369  300000000
ALLEN   7499  300000001
 WARD  7521  300000002
 到此,入职的第一个坑填好了!貌似方法二还能够用zipWithUniqueId()方法进行实现,由于时间不够就没有一一的尝试了,如果各位小伙伴们有空可以尝试一下!
 同时,如果小伙伴们有更加好的方法,求分享!求指导!感谢!!!!!
  欢迎留言!!!!

关于sparksql中设置自定义自增列的相关要点(工作共踩过的坑-1)的更多相关文章

  1. SpringBoot中设置自定义拦截器

    SpringBoot中设置自动以拦截器需要写一个类继承HandlerInterceptorAdapter并重写preHandle方法 例子 public class AuthorityIntercep ...

  2. SparkSQL中的自定义函数UDF

    在Spark中,也支持Hive中的自定义函数.自定义函数大致可以分为三种: UDF(User-Defined-Function),即最基本的自定义函数,类似to_char,to_date等 UDAF( ...

  3. 在python脚本中设置环境变量,并运行相关应用

    1. 问题 在自动化应用的时候 ,有时候环境变量与运行需要不一致.这时候有两种选择: 改变节点环境变量,使得其和运行需求保持一致: 在自动化脚本中设置环境变量,其范围只在脚本运行环境中有效. 显然,当 ...

  4. 在ListCtrl控件中设置自定义光标

    ::SetCursor(::LoadCursor   (::AfxGetInstanceHandle(),   MAKEINTRESOURCE(IDB_BMP_MOUSE))); void   CMy ...

  5. eclipse中设置自定义文档签名(工具)

    今天第一次认真学习eclipse的使用,看到自定义文档签名,步骤如下:  1.点击window->preferences->java->Code Style->Code Tem ...

  6. Eclipse中设置自定义文档签名

    今天第一次认真学习eclipse的使用,看到自定义文档签名,步骤如下: 1.点击window->preferences->java->Code Style->Code Temp ...

  7. Linux系统入门学习:在curl中设置自定义的HTTP头

    http://www.linuxidc.com/Linux/2015-02/114220.htm

  8. (转)Repeater中增加序号自增列

    <%# Convert.ToString(Container.ItemIndex+)%> 当Repeater空为时,提示没有数据... <FooterTemplate> < ...

  9. PowerDesigner中如何生成主键和自增列

    1.SQL Server版本: 第一步,首先要建立与数据库的连接,方法较多,这里举个例子: http://www.cnblogs.com/netsql/archive/2010/05/17/17375 ...

随机推荐

  1. 文件传输——TCP/IP协议介绍总结

    一.链路层 数据链路层的工作特性: 1.为IP模块发送和接收IP数据报2.为ARP模块发送ARP请求和接收ARP应答(ARP:地址解析协议,将IP地址转换成MAC地址)3.为RARP发送RARP请求和 ...

  2. [转载]linux下清除Squid缓存的方法记录

    在日常运维工作中,只要用到squid缓存服务,就会常常被要求清理squid缓存. 比如公司领导要求删一篇新闻,新闻是生成的静态.运维人员把服务器上静态的新闻页面删除了后,不料代理服务器上缓存还有.缓存 ...

  3. [原创]OpenvSwitch安装

    一.安装环境: ubuntu-12.04-64bit 二.使用root权限,安装所需软件: apt-get install build-essential apt-get install openss ...

  4. 最大公约数GCD学习笔记

    引理 已知:k|a,k|b 求证:k|(m*a+n*b) 证明:∵ k|a ∴ 有p*k=a 同理可得q*k=b ∴ p*k*m=m*a,q*k*n=n*b ∴ k(p*m+q*n)=m*a+n*b ...

  5. 个人永久性免费-Excel催化剂功能第19波-Excel与Sqlserver零门槛交互-查询篇

    对频繁使用Excel的高级应用的尝试用户来说,绕不过的一个问题Excel的性能问题,对于几万条数据还说得过去,上了10万行的数据量,随便一个函数公式的运算都是一个不小的负荷,有些上进一点的用户会往Ac ...

  6. HDU-1576 A/B 基础数论+解题报告

    HDU-1576 A/B 基础数论+解题报告 题意 求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973) (我们给定的A必能被B整除,且gcd(B,9973) = 1). 输入 数据 ...

  7. SpringMvc返回JSON出现"$.result.currentLevel"

    "$.result.currentLevel" 问题描述 使用SpringMvc返回一个json数据的时候,会在产生的结果中出现如下的问题:"$.result.curre ...

  8. [leetcode] 264. Ugly Number II (medium)

    263. Ugly Number的子母题 题目要求输出从1开始数,第n个ugly number是什么并且输出. 一开始想着1遍历到n直接判断,超时了. class Solution { public: ...

  9. vue.js 中组件的使用

    Vue中组件的使用 方式一 1.使用Vue.extend创建组件 var com1 = Vue.extend({ template: '<h3>这是使用 Vue.extend 创建的组件& ...

  10. Quartus ii调试技巧_01

    前几天李主任跟我分享了一些特别好用的调试技巧: 1)System Sources and Probes Editor---类似于人为设置触发条件,创建虚拟按键等功能,这段时间一直在做一个电机的驱动,板 ...