不讲废话,全程硬核,处理结构化数据的终极解决方案_结构化处理数据

35 阅读5分钟

img img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

Orders.new(OrderID, Amount, OrderDate)


计算列:



Orders.new(OrderID, Amount, year(OrderDate))


字段改名:



Orders.new(OrderID:ID, SellerId, year(OrderDate):y)


按序号使用字段:



Orders.groups(year(_5),_2; sum(_4))


序表改名(左关联)



join@1(Orders:o,SellerId ; Employees:e,EId).groups(e.Dept; sum(o.Amount))


序表支持所有的结构化计算函数,计算结果也同样是序表,而不是Map之类的数据类型。比如对分组汇总的结果,继续进行结构化数据处理:



Orders.groups(year(OrderDate):y; sum(Amount):m).new(y:OrderYear, m*0.2:discount)


在序表的基础上,SPL提供了丰富的结构化数据计算函数,比如过滤、排序、分组、去重、改名、计算列、关联、子查询、集合计算、有序计算等。这些函数具有强大的计算能力,无须硬编码辅助,就能独立完成计算:


组合查询:



Orders.select(Amount>1000 && Amount<=3000 && like(Client,"bro"))


排序:



Orders.sort(-Client,Amount)


分组汇总:



Orders.groups(year(OrderDate),Client; sum(Amount))


内关联:



join(Orders:o,SellerId ; Employees:e,EId).groups(e.Dept; sum(o.Amount))


#### 简洁的Lambda语法


SPL支持简单的Lambda语法,无须定义函数名和函数体,可以直接用表达式当作函数的参数,比如过滤:



Orders.select(Amount>1000)


修改业务逻辑时,也不用重构函数,只须简单修改表达式:



Orders.select(Amount>1000 && Amount<2000)


SPL是解释型语言,使用参数表达式时不必明确定义参数类型,使Lambda接口更简单。比如计算平方和,想在sum的过程中算平方,可以直观写作:



Orders.sum(Amount*Amount)

SQL类似,SPL语法也支持在单表计算时直接使用字段名:



Orders.sort(-Client, Amount)


#### 动态数据结构


SPL是解释型语言,天然支持动态数据结构,可以根据计算结果结构动态生成新序表。特别适合计算列、分组汇总、关联这类计算,比如直接对分组汇总的结果再计算:



Orders.groups(Client;sum(Amount):amt).select(amt>1000 && like(Client,"*S*"))


或直接对关联计算的结果再计算:



join(Orders:o,SellerId ; Employees:e,Eid).groups(e.Dept; sum(o.Amount))


较复杂的计算通常都要拆成多个步骤,每个中间结果的数据结构几乎都不同。SPL支持动态数据结构,不必先定义这些中间结果的结构。比如,根据某年的客户回款记录表,计算每个月的回款额都在前10名的客户:



Sales2021.group(month(sellDate)).(.groups(Client;sum(Amount):sumValue)).(.sort(-sumValue)) .(.select(#<=10)).(.(Client)).isect()


#### 直接执行SQL


SPL中还实现了SQL的解释器,可以直接执行SQL,从基本的WHEREGROUPJOIN、甚至WITH都能支持:



$select * from d:/Orders.csv where (OrderDate<date('2020-01-01') and Amount<=100)or (OrderDate>=date('2020-12-31') and Amount>100)



$select year(OrderDate),Client ,sum(Amount),count(1) from d:/Orders.csv group by year(OrderDate),Client having sum(Amount)<=100



$select o.OrderId,o.Client,e.Name e.Dept from d:/Orders.csv o join d:/Employees.csv e on o.SellerId=e.Eid



$with t as (select Client ,sum(amount) s from d:/Orders.csv group by Client) select t.Client, t.s, ct.Name, ct.address from t left join ClientTable ct on t.Client=ct.Client


### 更多语言优势


作为专业的结构化数据处理语言,SPL不仅覆盖了SQL的所有计算能力,在语言方面,还有更强大的优势:


#### 离散性及其支挂下的更彻底的集合化


集合化是SQL的基本特性,即支持数据以集合的形式参与运算。但SQL的离散性很不好,所有集合成员必须作为一个整体参于运算,不能游离在集合之外。而Java等高级语言则支持很好的离散性,数组成员可以单独运算。


但是,更彻底的集合化需要离散性来支持,集合成员可以游离在集合之外,并与其它数据随意构成新的集合参与运算 。


SPL兼具了SQL的集合化和Java的离散性,从而可以实现更彻底的集合化。


比如,SPL中很容易表达“集合的集合”,适合**分组后计算**。比如,找到各科成绩均在前10名的学生:




|  | A |
| --- | --- |
| 1 | =T(“score.csv”).group(subject) |
| 2 | =A2.(.rank(score).pselect@a(<=10)) |
| 3 | =A1.(~(A3(#)).(name)).isect() |
| SPL序表的字段可以存储记录或记录集合,这样可以用**对象引用**的方式,直观地表达关联关系,即使关系再多,也能直观地表达。比如,根据员工表找到女经理下属的男员工: |  |



Employees.select(性别:"男",部门.经理.性别:"女")


**有序计算**是离散性和集合化的典型结合产物,成员的次序在集合中才有意义,这要求集合化,有序计算时又要将每个成员与相邻成员区分开,会强调离散性。SPL兼具集合化和离散性,天然支持有序计算。


具体来说,SPL可以按绝对位置引用成员,比如,取第3条订单可以写成Orders(3),取第135条记录可以写成Orders([1,3,5])。


SPL也可以按相对位置引用成员,比如,计算每条记录相对于上一条记录的金额增长率:Orders.derive(amount/amount[-1]-1)


SPL还可以用#代表当前记录的序号,比如把员工按序号分成两组,奇数序号一组,偶数序号一组:Employees.group(#%2==1)


#### 更方便的函数语法


大量功能强大的结构化数据计算函数,这本来是一件好事,但这会让相似功能的函数不容易区分。无形中提高了学习难度。


SPL提供了特有的函数选项语法,功能相似的函数可以共用一个函数名,只用**函数选项**区分差别。比如select函数的基本功能是过滤,如果只过滤出符合条件的第1条记录,只须使用选项@1

Orders.select@1(Amount>1000)


数据量较大时,用并行计算提高性能,只须改为选项@m

Orders.select@m(Amount>1000)


对排序过的数据,用二分法进行快速过滤,可用@b

Orders.select@b(Amount>1000)


函数选项还可以组合搭配,比如:



Orders.select@1b(Amount>1000)


结构化运算函数的参数常常很复杂,比如SQL就需要用各种关键字把一条语句的参数分隔成多个组,但这会动用很多关键字,也使语句结构不统一。


SPL支持**层次参数**,通过分号、逗号、冒号自高而低将参数分为三层,用通用的方式简化复杂参数的表达:



join(Orders:o,SellerId ; Employees:e,EId)


#### 扩展的Lambda语法


普通的Lambda语法不仅要指明表达式(即函数形式的参数),还必须完整地定义表达式本身的参数,否则在数学形式上不够严密,这就让Lambda语法很繁琐。比如用循环函数select过滤集合A,只保留值为偶数的成员,一般形式是:



A.select(f(x):{x%2==0} )


这里的表达式是x%2==0,表达式的参数是f(x)里的x,x代表集合A里的成员,即循环变量。


SPL用**固定符号~代表循环变量**,当参数是循环变量时就无须再定义参数了。在SPL中,上面的Lambda语法可以简写作:A.select(~ %2==0)


普通Lambda语法必须定义表达式用到的每一个参数,除了循环变量外,常用的参数还有循环计数,如果把循环计数也定义到Lambda中,代码就更繁琐了。


SPL用**固定符号#代表循环计数变量**。比如,用函数select过滤集合A,只保留序号是偶数的成员,SPL可以写作:A.select(# %2==0)


相对位置经常出现在难度较大的计算中,而且相对位置本身就很难计算,当要使用相对位置时,参数的写法将非常繁琐。


SPL用**固定形式[序号]代表相对位置**:




|  | A | B |
| --- | --- | --- |
| 1 | =T(“Orders.txt”) | /订单序表 |
| 2 | =A1.groups(year(Date):y,month(Date):m; sum(Amount):amt) | /按年月分组汇总 |
| 3 | =A2.derive(amt/amt[-1]:lrr, amt[-1:1].avg():ma) | /计算比上期和移动平均 |


### 无缝集成、低耦合、热切换


作为用Java解释的脚本语言,SPL提供了JDBC驱动,可以无缝集成进Java应用程中。


简单语句可以像SQL一样直接执行:



… Class.forName("com.esproc.jdbc.InternalDriver"); Connection conn =DriverManager.getConnection("jdbc:esproc:local://"); PrepareStatement st = conn.prepareStatement("=T("D:/Orders.txt").select(Amount>1000 && Amount<=3000 && like(Client,"*S*"))"); ResultSet result=st.execute(); ...


复杂计算可以存成脚本文件,以存储过程方式调用



… Class.forName("com.esproc.jdbc.InternalDriver"); Connection conn =DriverManager.getConnection("jdbc:esproc:local://");

img img img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取