webservice接口开发 java-webservice接口wsdl java
基于JVM的开源数据处理语言主要有Kotlin、Scala、SPL。 下面对三者进行横向比较,找出开发效率最高的数据处理语言。 本文适用场景设置为项目开发中常见的数据处理和业务逻辑,主要是结构化数据,大数据和高性能不是重点,不涉及消息流、科学计算等特殊场景。
基本特征
自适应表面
Kotlin的初衷是为了让Java开发效率更高。 可以适用于任何涉及Java的应用场景。 除了常用的信息管理系统外,还可以用于WebServer、Android项目、游戏开发等。 它具有良好的通用性。 Scala 最初被设计为一种集成了现代编程范式的通用开发语言。 在实践中主要用于后端大数据处理。 它很少出现在其他类型的项目中,通用性也不如Kotlin。 SPL设计的初衷是专业的数据处理语言,实践与初衷一致。 适用于前后端数据处理,大小数据处理。 应用场景比较集中,通用性不如Kotlin。
编程范式
Kotlin主要是面向对象编程,但也支持函数式编程。 Scala 支持这两种范式,面向对象编程比 Koltin 更彻底,函数式编程比 Koltin 更方便。 可以说SPL不支持面向对象编程。 它有对象的概念,但并没有继承和重载这些内容。 函数式编程比 Kotlin 更方便。
操作模式
Kotlin 和 Scala 是编译型语言,SPL 是解释型语言。 解释型语言更灵活,但对于同样的代码,性能却较差。 但是SPL拥有丰富高效的库函数,综合性能也不弱,在面对大数据的时候往往更有优势。
外部图书馆
Kotlin可以使用所有的Java类库,但是缺少专业的数据处理类库。 Scala还可以使用所有的Java类库,并且内置专业的大数据处理类库(Spark)。 SPL内置专业的数据处理功能,提供大量时间复杂度较低的基础运算。 通常不需要外部Java类库,特殊情况可以在自定义函数中调用。
IDE 和调试
这三个都具有图形化 IDE 和完整的调试功能。 SPL的IDE专为数据处理而设计。 结构化数据对象以表格形式呈现,观察更方便。 Kotlin 和 Scala 的 IDE 是通用的,没有针对数据处理进行优化,不能轻易观察结构化数据对象。
学习困难
Kotlin 比 Java 稍微难学一点,精通 Java 的人也能轻松上手。 Scala的目标是超越Java,而且比Java难学多了。 SPL的目标是简化Java甚至SQL的编码,刻意简化了很多概念,学习难度很低。
代码量
Kotlin的初衷是为了提高Java的开发效率。 官方宣称综合代码量仅为Java的20%。 这可能是由于数据处理库不专业,这块的实际代码量并没有减少多少。 Scala有很多语法糖,大数据处理库更专业,但代码量比Kotlin低很多。 SPL只做数据处理,是最专业的。 再加上解释型语言强大的表达能力,完成同样任务的代码量远低于前两者(后面会给出对比例子)。 可以说明它的学习难度比较低。
语法
数据类型
原子数据类型:三种都支持,例如 Short、Int、Long、Float、Double、Boolean
日期和时间类型:Kotlin 缺少一种易于使用的日期和时间类型,这种类型通常在 Java 中使用。 Scala 和 SPL 都有专门且方便的日期时间类型。
独特的数据类型:Kotlin 支持非数字字符 Char 和可空类型 Any?。 Scala 支持元组(定长泛型集合),内置 BigDecimal。 SPL支持高性能多层序列号密钥,内置BigDecimal。
集合类型:Kotlin 和 Scala 支持 Set、List、Map。 SPL 支持序列(有序的泛型集合,类似于 List)。
结构化数据类型:Kotlin有记录集合List,但缺少元数据,不够专业。 Scala有专业的结构化数据类型,包括Row、RDD、DataSet、DataFrame(本文以此为例说明)等。SPL有专业的结构化数据类型,包括record、table sequence(本文以此为例说明) illustrate),内表压缩表,外存惰性游标等。
Scala 具有独特的隐式转换能力,理论上可以在任何数据类型(包括参数、变量、函数、类)之间进行转换,并且可以很容易地改变或增强原有的功能。
工艺加工
三者都支持基本的顺序执行、判断分支和循环。 理论上可以进行任意的复杂工艺处理。 这方面的讨论不多。 下面重点对比一下循环结构对于采集数据的便利性。 以上一期的计算为例,Kotlin代码:
mData.forEachIndexed{index,it->
if(index>0) it.Mom= it.Amount/mData[index-1].Amount-1
}
Kotlin的forEachIndexed函数自带序号变量和成员变量,更方便集合循环,支持下标取记录,可以轻松进行跨行计算。 Kotlin 的缺点是对数组越界的额外处理。
斯卡拉代码:
val w = Window.orderBy(mData("SellerId"))
mData.withColumn("Mom", mData ("Amount")/lag(mData ("Amount"),1).over(w)-1)
Scala跨行计算不用处理数组越界,比Kotlin方便。 但是Scala的结构化数据对象不支持下标检索记录,只能使用lag函数整体迁移,对结构化数据不方便。 lag函数不能用于通用性强的forEach,而是withColumn等函数单一的循环函数。 为了保持函数式编程风格和SQL风格的底层统一,滞后函数还必须配合窗口函数(Python的转换函数没有这个要求),整体代码看起来比Kotlin复杂。
声压级代码:
mData.(Mom=Amount/Amount[-1]-1)
SPL对结构化数据对象的流控做了很多优化。 类似于forEach这个最常见最常用的循环函数,SPL可以直接用括号表示webservice接口开发 java,简化到了极致。 SPL也有shift功能,不过这里用的是更直观的“[relative position]”语法,在进行跨行计算时比Kotlin的绝对定位更强大,比Scala的shift功能更方便。 除了上述代码外,SPL还有更多针对结构化数据的process处理函数,例如:每次循环取一批而不是取一条记录; 当字段值更改时循环一次。
Lambda 表达式
Lambda表达式是匿名函数的简单实现,目的是简化函数的定义,尤其是各类集合计算的函数。 Kotlin 支持 Lambda 表达式,但由于编译语言的关系,很难方便地将参数表达式指定为值参数或函数参数,只能设计复杂的接口规则来区分。 甚至还有所谓的high-order function-specific interfaces,导致Kotin的Lambda表达式写起来有难度,在数据处理上缺乏专业性。 几个例子:
"abcd".substring( 1,2) //值参数
"abcd".sumBy{ it.toInt()} //函数参数
mData.forEachIndexed{ index,it-> if(index>0) it.Mom=…} //函数参数的函数带多个参数
Koltin的Lambda表达式不够专业,还说明了在使用字段时必须带上结构化数据对象的变量名(it),而像SQL那样计算单表时不能省略表名。
作为一种编译型语言,Scala 的 Lambda 表达式与 Kotlin 没有太大区别。 它们还需要设计复杂的接口规则,编写起来也比较困难,这里就不举例了。 计算与上期比较时,结构化数据对象的变量名或col函数要带在字段前,如mData("Amount")或col("Amount"),虽然可以补加了句法糖,写成$”Amount”或'Amount,但是很多函数不支持这种写法,试图弥补导致风格不一致。
SPL的Lambda表达式比前两者好用、专业,这与其解释型语言的特点有关。 解释型语言可以很容易地推断出值参数和函数参数。 没有所谓复杂的高阶函数专用接口,所有的函数接口都同样简单。 几个例子:
mid("abcd",2,1) //值参数
Orders.sum(Amount*Amount) //函数参数
mData.(Mom=Amount/Amount[-1]-1) //函数参数的函数带多个参数
SPL可以直接使用字段名而不用结构化数据对象变量名,例如:
Orders.select(Amount>1000 && Amount<=3000 && like(Client,"*S*"))
SPL的大部分循环函数都有默认的成员变量~和序号变量#,可以显着提高代码编写的便利性,特别适用于结构化数据的计算。 例如,获取偶数位置的记录:
Students.select(# % 2==0)
找出每组中排名前 3 的名字:
Orders.group(SellerId;~.top(3;Amount))
SPL 功能选项和层次结构参数
值得一提的是,为了进一步提高开发效率,SPL还提供了独特的函数语法。
当有大量功能相似的函数时,大多数编程语言只能用不同的名称或参数来区分,使用起来不是很方便。 但是SPL提供了一个非常独特的函数选项,让功能相似的函数可以共用一个函数名,只用函数选项来区分区别。 比如select函数的基本功能就是过滤。 如果只过滤掉符合条件的第一条记录,可以使用选项@1:
T.select@1(Amount>1000)
要使用二分法快速过滤有序数据,请使用@b:
T.select@b(Amount>1000)
功能选项也可以组合搭配,例如:
Orders.select@1b(Amount>1000)
有些函数的参数比较复杂,可能会分成多层。 常规的编程语言对此没有专门的语法方案,只能生成多层结构的数据对象,然后传入,非常麻烦。 SQL使用关键字将参数分成多组,比较直观简单,但是这样会使用很多关键字,使得语句结构不一致。 但是,SPL创造性地发明了分层参数来简化复杂参数的表达。 参数通过分号、逗号、冒号从高到低分为三层:
join(Orders:o,SellerId ; Employees:e,EId)
数据源
数据源类型
Kotlin原则上可以支持所有Java数据源,但代码繁琐,类型转换麻烦,稳定性差。 这是因为 Kotlin 没有内置数据源访问接口,没有针对结构化数据处理进行优化(JDBC 接口除外)。 从这个意义上说,也可以说它不直接支持任何数据源,只能使用Java第三方类库。 好在第三方类库的数量足够多。
Scala支持多种类型的数据源,内置六大数据源接口并针对结构化数据处理进行了优化,包括:JDBC、CSV、TXT、JSON、Parquet列存储格式、ORC列存储,虽然其他数据源接口没有可以使用由社区团体开发的内置第三方库。 Scala 提供数据源接口规范,需要第三方库输出结构化数据对象。 常见的第三方接口包括 XML、Cassandra、HBase 和 MongoDB。
SPL 拥有最多的内置数据源接口,并针对结构化数据处理进行了优化,包括:
这些数据源可以直接使用,非常方便。 对于其他未列出的数据源,SPL也提供了接口规范,只要按照规范输出为SPL结构化数据对象,即可进行后续计算。
代码比较
以规范的CSV文件为例,比较三种语言的解析代码。 科特林:
val file = File("D:\\data\\Orders.txt")
data class Order(var OrderID: Int,var Client: String,var SellerId: Int, var Amount: Double, var OrderDate: Date)
var sdf = SimpleDateFormat("yyyy-MM-dd")
var Orders=file.readLines().drop(1).map{
var l=it.split("\t")
var r=Order(l[0].toInt(),l[1],l[2].toInt(),l[3].toDouble(),sdf.parse(l[4]))
r
}var resutl=Orders.filter{
it.Amount>= 1000 && it.Amount < 3000}
Koltin不够专业。 读取CSV通常需要硬写代码,包括提前定义好数据结构,在循环函数中手动解析数据类型。 整体代码相当繁琐。 它也可以被 OpenCSV 等库读取。 虽然数据类型不需要在代码中解析,但是必须在配置文件中定义。 实现过程不一定简单。
Scala 非常专业,内置了解析 CSV 的接口。 代码比 Koltin 短得多:
val spark = SparkSession.builder().master("local").getOrCreate()
val Orders = spark.read.option("header", "true").option("sep","\t").option("inferSchema", "true").csv("D:/data/orders.csv").withColumn("OrderDate", col("OrderDate").cast(DateType))
Orders.filter("Amount>1000 and Amount<=3000")
Scala在解析数据类型的时候比较麻烦,其他方面没有明显的缺点。
SPL比较专业,分析计算只有一行:
T("D:/data/orders.csv").select(Amount>1000 && Amount<=3000)
跨源计算
JVM数据处理语言的开放性很强,能够对不同的数据源进行关联、合并、集合操作,但数据处理专业知识的差异导致不同语言在使用方便性上存在较大差异。
Kotlin不够专业。 不仅没有内置数据源接口,也没有跨源计算功能,只能硬写代码实现。 假设已经从不同的数据源获取了员工表和订单表,现在将两者关联起来:
data class OrderNew(var OrderID:Int ,var Client:String, var SellerId:Employee ,var Amount:Double ,var OrderDate:Date )
val result = Orders.map { o->var emp=Employees.firstOrNull{ it.EId==o.SellerId
}
emp?.let{ OrderNew(o.OrderID,o.Client,emp,o.Amount,o.OrderDate)
}
}
.filter {o->o!=null}
很容易看出 Kotlin 的缺点。 只要代码长了,Lambda 表达式就变得难读,不像普通代码那么容易理解; 关联的数据结构需要提前定义,灵活性差,影响解题的流畅性。
Scala 比 Kotlin 更专业。 它不仅内置了多种数据源接口,还提供了跨源计算的功能。 对于同样的计算,Scala 代码要简单得多:
val join=Orders.join(Employees,Orders("SellerId")===Employees("EId"),"Inner")
可见,Scala不仅有专门用于计算结构化数据的对象和函数,而且与Lambda语言的配合也很好,使得代码更容易理解,而且不需要提前定义数据结构。
SPL更专业,结构化数据对象更专业,跨源计算函数更方便,代码更短:
join(Orders:o,SellerId;Employees:e,EId)
自己的存储格式
重复使用的中间数据通常以一定格式存储为本地文件,以提高数据检索性能。 Kotlin 支持多种格式的文件。 理论上,它可以存储和重新计算中间数据。 但是由于它在数据处理方面并不专业,基本的读写操作需要写一大段代码,相当于没有自己的存储格式。 .
Scala支持多种存储格式,其中parquet文件比较常用,使用方便。 Parquet是一种开源的存储格式,支持列式存储,可以存储大量数据。 中间计算结果 (DataFrame) 可以轻松地与 parquet 文件相互转换。 遗憾的是,parquet 的索引还不成熟。
val df = spark.read.parquet("input.parquet")
val result=df.groupBy(data("Dept"),data("Gender")).agg(sum("Amount"),count("*"))
result.write.parquet("output.parquet")
SPL 支持两种私有二进制存储格式,btx 和 ctx。 btx是简单的行存储,ctx支持行存储、列存储和索引。 它可以存储大量数据并执行高性能计算。 中间计算结果(表序列/游标)可以与这两种文件进行比较,方便交换。
A
1个
=file("input.ctx").open()
2个
=A1.cursor(Dept,Gender,Amount).groups(Dept,Gender;sum(Amount):amt,count(1):cnt)
3个
=file("output.ctx").create(#Dept,#Gender,amt,cnt).append(A2.cursor())
结构化数据计算
结构化数据对象
数据处理的核心是计算,尤其是结构化数据的计算。 结构化数据对象的专业性深刻决定了数据处理的便捷性。
Kotlin 没有专业的结构化数据对象。 List常用于结构化数据计算,EntityBean可以使用数据类来简化定义过程。
List 是一个有序的集合(可重复),Kotlin 很好地支持所有涉及成员序号和集合的功能。 例如,通过序列号访问成员:
Orders[3] //按下标取记录,从0开始
Orders.take(3) //前3条记录
Orders.slice(listOf(1,3,5)+IntRange(7,10)) //下标是1、3、5、7-10的记录
您还可以通过倒数获取成员:
Orders.reversed().slice(1,3,5) //倒数第1、3、5条
Orders.take(1)+Orders.takeLast(1) //第1条和最后1条
涉及阶数的计算相对困难。 Kotlin支持有序集合,进行相关计算更方便。 List作为集合的一种,擅长对集合成员进行增删改查、交叉、拆分等功能。 但是List并不是一个专业的结构化数据对象。 一旦涉及到字段结构相关的功能,Kotlin就很难实现了。 例如,将Orders中的两个字段组成一个新的结构化数据对象。
data class CliAmt(var Client: String, var Amount: Double)
var CliAmts=Orders.map{it.let{CliAmt(it.Client,it.Amount) }}
上面的函数很常用,相当于简单的SQL语句select Client, Amount from Orders,但是Kotlin写起来很繁琐。 不仅必须预先定义新的结构,而且字段分配必须是硬编码的。 简单的取字段功能就这么麻烦,更高级的功能就更麻烦了,比如:按字段序号取,按参数取,获取字段名列表,修改字段结构,在字段上定义键和索引,以及按字段查询和计算。
Scala也有List,和Kotlin差别不大,但是Scala设计了更专业的数据对象DataFrame(还有RDD、DataSet)来进行结构化数据处理。
DataFrame是一种结构化的数据流webservice接口开发 java,有点类似于数据库的结果集。 都是无序集合,所以不支持下标检索,只能变相实现。 比如第10条记录:
Orders.limit(10).tail(1)(0)
可以想象,DataFrame对于顺序相关的计算实现起来很麻烦,比如区间、移动平均数、反向排序等。
除了数据乱序,DataFrame不支持修改(不可变特性)。 如果要更改数据或结构,则必须生成新的 DataFrame。 比如修改字段名,实际上是通过复制记录来实现的:
Orders.selectExpr("Client as Cli")
DataFrame支持常见的集合计算,如拆分、合并、交叉合并。 union可以通过去重来实现,但是因为需要通过复制记录来实现,所以集合计算的性能一般不高。
虽然缺点很多,但DataFrame作为专业的结构化数据对象,访问字段的能力是Kotlin所望尘莫及的。 例如,要获取元数据/字段名称列表:
Orders.schema.fields.map(it=>it.name).toList
使用字段获取数字也很方便,比如取两个字段组成一个新的dataframe:
Orders.select("Client","Amount") //可以只用字段名
或使用计算列形成一个新的 DataFrame:
Orders.select(Orders("Client"),Orders("Amount")+1000) //不能只用字段名
不幸的是,DataFrame 只支持使用字符串名称来引用字段,不支持使用字段编号或默认名称,这在很多场景下使用起来并不方便。 另外,DataFrame不支持索引的定义,不能进行高性能的随机查询,专业性有缺陷。
SPL的结构化数据对象是表序列,具有足够专业、简单易用、表达能力强等优点。 按序号访问成员:
Orders(3) //按下标取记录,从1开始
Orders.to(3) //前3条记录
Orders.m(1,3,5,7:10) //序号是1、3、5、7-10的记录
根据倒数取记录。 独特之处在于支持负号表示倒数,比Kotlin更专业更方便:
Orders.m(-1,-3,-5) //倒数第1,3,5条
Orders.m(1,-1) //第1条和最后1条
作为集合的一种,表序还支持集合成员的增、删、改、交、并、差、分等功能。 由于表序列和List一样是一个可变集合(mutable),在集合的计算中尽量使用自由记录,而不是复制记录,性能比Scala好很多,内存占用也少.
表序列是一种专业的结构化数据对象。 除了集合相关的功能外,更重要的是可以方便地访问字段。 例如,要获取字段名称列表:
Orders.fname()
取两个字段组成一个新的表序列:
Orders.new(Client,Amount)
用计算列形成一个新的表序列:
Orders.new(Client,Amount*0.2)
修改字段名称:
Orders.alter(;OrderDate) //不复制记录
在某些场景下,需要通过字段号或者默认名称来访问字段,SPL提供了相应的访问方式:
Orders(Client) //按字段名(表达式取)
Orders([#2,#3]) //按默认字段名取
Orders.field(“Client”) //按字符串(外部参数)
Orders.field(2) //按字段序号取
作为专业的结构化数据对象,表序还支持在字段上定义键和索引:
Orders.keys@i(OrderID) //定义键,同时建立哈希索引
Orders.find(47) //用索引高速查找
计算功能
Kotlin 支持一些基本的计算功能,包括:过滤、排序、去重、集合的交叉合并、各种聚合以及分组和汇总。 但是,这些功能都是针对普通集合的。 如果将计算对象改为结构化数据对象,计算函数库就非常不足,通常需要通过硬编码来补充实现计算。 还有很多Kotlin不支持,只能通过编码实现的基本集合操作,包括:关联、窗函数、排序、行列转换、合并、二分查找等。其中,归并和二分查找是订单相关的操作。 由于 Kotlin List 是一个有序的集合,所以通过自编码实现这样的操作并不太困难。 总的来说,在结构化数据计算面前,Kotlin的函数库可以说是弱不禁风。
Scala的计算功能比较丰富,都是针对结构化数据对象设计的,包括Kotlin不支持的功能:排序、关联、窗口函数、行列转换,但基本上没有超出SQL的框架。 还有一些基本的集合操作是Scala不支持的,尤其是那些与顺序相关的操作,比如合并和二分查找。 由于Scala DataFrame沿袭了SQL中数据乱序的概念,这样的操作自己写代码很难实现。 的。 总的来说,Scala 的函数库比 Kotlin 丰富,但是基本的操作还是欠缺。
SPL的计算功能最为丰富,都是为结构化数据对象设计的。 SPL大大丰富了结构化数据操作的内容,设计了很多SQL之外的内容。 当然,这也是Scala/Kotlin不支持的功能,比如有序计算:合并、二分查找、按区间取记录、满足条件的记录序号; 除了常规的等价分组外,还支持枚举分组、对齐分组、有序分组; 将关联类型分为外键和主要孩子; 支持主键约束数据,支持索引快速查询; 多层结构数据(多表关联或Json\XML)的递归查询等
以分组为例,SPL除了常规的等价分组外,还提供了更多的分组方案:
枚举分组:分组是根据几个条件表达式,将满足相同条件的记录组合在一起。
对齐分组:分组依据是外部集合,将字段值等于集合成员的记录归为一组。 组的顺序与集合成员的顺序一致。 允许空组,一组“没有属于集合的记录”。
有序分组:分组是根据已经排序的字段进行的,比如当某个字段发生变化或者满足某个条件时,会创建一个新的分组。 SPL直接提供了这种有序的分组,在常规分组功能上增加一个选项即可完成。 它非常简单,计算性能更好。 其他语言(包括SQL)没有这种分组,只能转成传统的等价分组或者自己硬编码。
下面我们通过几个常规的例子来感受一下这三种语言在计算函数的方式上的区别。
排序
按客户和金额倒序排序。 科特林:
Orders.sortedBy{it.Amount}.sortedByDescending{it.Client}
Kotlin代码不长,但还是有不便之处,包括:倒序和正序是两个不同的函数,字段名必须有表名,代码中写的字段顺序是相反的实际排序顺序。
斯卡拉:
Orders.orderBy(Orders("Client"),-Orders("Amount"))
Scala就简单多了,负号代表倒序,代码中写的字段顺序和排序的顺序是一样的。 不幸的是,字段仍然需要有表名; 编译型语言只能使用字符串来实现表达式的动态解析,导致代码风格不一致。
声压级:
Orders.sort(Client,-Amount)
SPL代码更简单,字段不需要有表名,解释型语言的代码风格容易统一。
小组总结
科特林:
data class Grp(var Dept:String,var Gender:String)
data class Agg(var sumAmount: Double,var rowCount:Int)
var result1=data.groupingBy{Grp(it!!.Dept,it.Gender)}
.fold(Agg(0.0,0),{acc, elem -> Agg(acc.sumAmount + elem!!.Amount,acc.rowCount+1)})
.toSortedMap(compareBy { it.Dept }.thenBy { it.Gender })
Kotlin代码比较繁琐,不仅要用到groupingBy和fold函数,还要硬编码实现分组汇总。 当出现新的数据结构时,必须事先定义好才能使用,比如分组双域结构和汇总双域结构,不仅灵活性差,而且影响解题的流畅性. 最后的排序要和其他语言的结果排序一致,不是必须的。
斯卡拉:
val result=data.groupBy(data("Dept"),data("Gender")).agg(sum("Amount"),count("*"))
Scala的代码就简单多了,不仅容易理解,而且不需要事先定义数据结构。
声压级:
data.groups(Dept,Gender;sum(Amount),count(1))
SPL代码最简单,表达能力不亚于SQL。
关联计算
两张表有同名字段,关联并分组汇总。 科特林代码:
data class OrderNew(var OrderID:Int ,var Client:String, var SellerId:Employee ,var Amount:Double ,var OrderDate:Date )
val result = Orders.map { o->var emp=Employees.firstOrNull{it.EId==o.EId}
emp?.let{ OrderNew(o.OrderID,o.Client,emp,o.Amount,o.OrderDate)}
}
.filter {o->o!=null}
data class Grp(var Dept:String,var Gender:String)
data class Agg(var sumAmount: Double,var rowCount:Int)
var result1=data.groupingBy{Grp(it!!.EId.Dept,it.EId.Gender)}
.fold(Agg(0.0,0),{acc, elem -> Agg(acc.sumAmount + elem!!.Amount,acc.rowCount+1)})
.toSortedMap(compareBy { it.Dept }.thenBy { it.Gender })
Kotlin代码比较繁琐,很多地方都要定义新的数据结构,包括关联结果、分组双字段结构、聚合双字段结构等。
斯卡拉
val join=Orders.as("o").join(Employees.as("e"),Orders("EId")===Employees("EId"),"Inner")
val result= join.groupBy(join("e.Dept"), join("e.Gender")).agg(sum("o.Amount"),count("*"))
Scala 比 Kolin 简单多了,不需要繁琐的定义数据结构,也不需要硬编码。
SPL 更简单:
join(Orders:o,SellerId;Employees:e,EId).groups(e.Dept,e.Gender;sum(o.Amount),count(1))
综合数据处理对比
CSV content is not standardized, every three lines correspond to a record, and the second line contains three fields (that is, a collection of collections), organize the file into a standardized structured data object, and sort by the 3rd and 4th fields.
科特林:
data class Order(var OrderID: Int,var Client: String,var SellerId: Int, var Amount: Double, var OrderDate: Date)
var Orders=ArrayList()
var sdf = SimpleDateFormat("yyyy-MM-dd")
var raw=File("d:\\threelines.txt").readLines()
raw.forEachIndexed{index,it->
if(index % 3==0) {
var f234=raw[index+1].split("\t")
var r=Order(raw[index].toInt(),f234[0],f234[1].toInt(),f234[2].toDouble(),
sdf.parse(raw[index+2]))
Orders.add(r)
}
}
var result=Orders.sortedByDescending{it.Amount}.sortedBy{it.SellerId}
Koltin is not professional enough in data processing, and most functions require hard-coding, including fetching fields by position and fetching fields from collections of collections.
斯卡拉:
val raw=spark.read.text("D:/threelines.txt")
val rawrn=raw.withColumn("rn", monotonically_increasing_id())
var f1=rawrn.filter("rn % 3==0").withColumnRenamed("value","OrderId")
var f5=rawrn.filter("rn % 3==2").withColumnRenamed("value","OrderDate")
var f234=rawrn.filter("rn % 3==1")
.withColumn("splited",split(col("value"),"\t"))
.select(col("splited").getItem(0).as("Client")
,col("splited").getItem(1).as("SellerId")
,col("splited").getItem(2).as("Amount"))
f1.withColumn("rn1",monotonically_increasing_id())
f5=f5.withColumn("rn1",monotonically_increasing_id())
f234=f234.withColumn("rn1",monotonically_increasing_id())
var f=f1.join(f234,f1("rn1")===f234("rn1"))
.join(f5,f1("rn1")===f5("rn1"))
.select("OrderId","Client","SellerId","Amount","OrderDate")
val result=f.orderBy(col("SellerId"),-col("Amount"))
Scala is more specialized in data processing, using a large number of structured calculation functions instead of hard-writing loop codes. However, Scala lacks the ability to perform sequential calculations, and related functions usually need to be processed after adding serial number columns, resulting in lengthy overall code.
声压级:
A
1个
=file("D:\\data.csv").import@si()
2个
=A1.group((#-1)\3)
3个
=A2.new(~(1):OrderID,(line=~(2).array("\t"))(1):Client,line(2):SellerId,line(3):Amount,~( 3): Order Date )
4个
=A3.sort(SellerId,-Amount)
SPL is the most specialized in data processing, and can achieve the goal with only structured calculation functions. SPL supports ordered calculations. It can directly group by location, fetch fields by location, and fetch fields from collections in collections. Although the implementation idea is similar to Scala, the code is much shorter.
application structure
Java application integration
Kotlin is compiled into bytecode, which can be easily called by Java just like ordinary class files. For example, the static method fun multiLines(): List in KotlinFile.kt will be correctly recognized by Java and can be called directly:
java.util.List result=KotlinFileKt.multiLines();
result.forEach(e->{System.out.println(e);});
After Scala is compiled, it is also bytecode, which can also be easily called by Java. For example, the static method def multiLines():DataFrame of the ScalaObject object will be recognized as a Dataset type by Java, and can be called with a little modification:
org.apache.spark.sql.Dataset df=ScalaObject.multiLines();
df.show();
SPL provides a common JDBC interface, and simple SPL code can be directly embedded in Java like SQL:
Class.forName("com.esproc.jdbc.InternalDriver");
Connection connection =DriverManager.getConnection("jdbc:esproc:local://");
Statement statement = connection.createStatement();
String str="=T(\"D:/Orders.xls\").select(Amount>1000 && Amount<=3000 && like(Client,\"*s*\"))";
ResultSet result = statement.executeQuery(str);
Complicated SPL codes can be stored as script files first, and then called by Java in the form of stored procedures, which can effectively reduce the coupling between calculation codes and front-end applications.
Class.forName("com.esproc.jdbc.InternalDriver");
Connection conn =DriverManager.getConnection("jdbc:esproc:local://");
CallableStatement statement = conn.prepareCall("{call scriptFileName(?, ?)}");
statement.setObject(1, "2020-01-01");
statement.setObject(2, "2020-01-31");
statement.execute();
SPL is an interpreted language, which can be executed directly without compiling after modification, and supports code hot switching, which can reduce maintenance workload and improve system stability. Kotlin and Scala are compiled languages, and the application must be restarted at a certain time after compilation.
interactive command line
Kotlin's interactive command line requires an additional download, launched with the Kotlinc command. The Kotlin command line can theoretically perform arbitrarily complex data processing, but because the code is generally long and difficult to modify on the command line, it is more suitable for simple digital calculations:
>>>Math.sqrt(5.0)
2.236.6797749979
Scala's interactive command line is built-in, launched with the command of the same name. The Scala command line can theoretically perform data processing, but because the code is relatively long, it is more suitable for simple numerical calculations:
scala>100*3
rest1: Int=300
SPL has an interactive command line built in, which is started with the "esprocx -r -c" command. SPL codes are generally short and allow for simple data processing at the command line.
(1): T("d:/Orders.txt").groups(SellerId;sum(Amount):amt).select(amt>2000)
(2):^C
D:\raqsoft64\esProc\bin>Log level:INFO
1 4263.900000000001
3 7624.599999999999
4 14128.599999999999
5 26942.4
Through various comparisons, it can be seen that for the common data processing tasks in application development, Kotlin is not professional enough, and the development efficiency is very low; Scala has a certain degree of professionalism, and the development efficiency is higher than Kotlin, but not as good as SPL; SPL syntax is more efficient. Conciseness, higher expression efficiency, more types of data sources, easier-to-use interfaces, more professional structured data objects, richer functions and stronger computing power, the development efficiency is much higher than Kotlin and Scala.
SPL download address:
SPL open source address: