Java 嵌入数据处理引擎:SQLite 的挑战者 esProc SPL

本文涉及的产品
云原生大数据计算服务MaxCompute,500CU*H 100GB 3个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: SQLite可以方便地嵌入Java,但数据源加载繁琐,计算能力不足,无法独立完成业务逻辑,架构上弱点颇多。SPL也很容易嵌入Java,且直接支持更多数据源,计算能力更强,流程处理方便,可独立实现业务逻辑。SPL还提供了多种优化体系结构的手段,代码既可外置也可内置于Java,支持解释执行和热切换,可进行高性能内存计算。

 

很多免费开源数据处理引擎都可以嵌入Java应用中,其中SQLite历史悠久、用户众多;后起之秀esProc SPL功能也较强,下面对两者进行多方面的比较。

基本特征

语言风格

SQLite使用传统的SQL代码(两者在本文等价),SQL在业界很流行,不必更多介绍。SPL是现代的数据计算语言,属于简化的面向对象的语言风格,有对象的概念,可以用点号访问属性并进行多步骤计算,但没有继承重载这些内容,不算彻底的面向对象语言。

运行模式

SQLite是用C语言开发的跨平台小型数据库,可嵌入其他开发语言,也可在单机执行。SPL是用Java开发的跨平台的数据计算语言,可嵌入Java,可在单机执行,可以数据计算服务的形式被远程调用。两者的代码都是解释执行的。

IDE

SQLite官方只提供了命令行工具,图形化工具要由第三方提供,但由于SQL的特性,这些工具大都没有断点调试、变量观察等基本的IDE功能。SPL提供了图形化IDE,包括完整的调试功能、表格形式的变量观察功能。

学习难度

SQL历史悠久资料丰富,入门学习时难度较低,但复杂运算时难度很大。而且,SQL缺乏流程处理能力(分支结构和循环结构),要借助Java的相关功能才能实现完整的业务逻辑,所以通常还要学习Java。

SPL的目标是简化Java和SQL的编码,刻意简化了许多概念,学习难度较低。SPL兼具结构化数据计算能力和流程处理能力,可以实现完整的业务逻辑,不必借助其他语言。

代码量

SQL进行简单计算时代码量很低,如果遇到较复杂计算,代码量会急剧增长。SQL经常要用Java配合实现完整的业务逻辑,Java的流程处理功能没有为结构化数据对象做优化,代码通常较繁琐。

SPL是现代计算语言,避免了SQL的诸多弱点,无论简单还是复杂计算,代码量都很低。SPL的流程处理功能为结构化数据对象做了优化,相关代码更加简单。

数据源读取

自有数据格式

SQLite有自有(私有)数据格式,即库文件,一个库文件包含多个表。可以用命令行命令或API(JDBC URL)创建库文件,但不能用SQL代码直接创建库文件。比如,用Java新建一个SQLite库文件,如果已存在则打开库文件

Class.forName("org.sqlite.JDBC");

Connection conn = DriverManager.getConnection("jdbc:sqlite: d:/ex1.db");

SPL有两种自有数据格式,其中一种是组表文件,专用于大数据高性能计算,不是本文重点;另一种是集文件,专用于中小数据量和嵌入式计算。SPL不需要建库,也没有库的概念,每个集文件对应一个表。

外部数据源

SQLite只支持文本数据文件,包括TAB分隔的txt、逗号分隔的csv,也可自定义其它分隔符。

SPL支持多种数据源,包括:

    • JDBC(即所有的RDB)
    • csv、TXT、JSON、XML、Excel
    • HBase、HDFS、Hive、Spark
    • Restful、WebService、Webcrawl
    • Elasticsearch、MongoDB、Kafka、R2dbc、FTP
    • Cassandra、DynamoDB、influxDB、Redis、SAP

    这些数据源都可以直接使用,非常方便。对于其他未列入的数据源,SPL也提供了接口规范,只要按规范输出为SPL的结构化数据对象,就可以进行后续计算。

    访问自有数据格式

    SQLite通过SQL访问库文件中的表,生成SQL结果集,即内存中的结构化数据对象。读取表时一般伴随着查询:

    select * from Orders where Amount>2000 and Amount<=3000

    image.gif

    SPL通过SPL的T函数或import函数读取集文件,生成序表(相当于SQL结果集)。等价的代码:

    T("d:/Orders.btx").select(Amount>2000 && Amount<=3000)

    image.gif

    读取csv文件

    SQLite读取csv文件需要三步,第一步:进入管理命令行。

    #在Windows命令行,打开或新建名为dbname的数据库

    sqlite3.exe new.db

    第二步,在管理命令行新建库表,并导入数据:

    #当字段类型都是字符串时,不必手工建表。


    create table Orders(
    OrderID int,
    Client varchar(100),
    SellerID int,
    Amount float,
    OrderDate date
    );
    .import --csv d:/Orders.csv Orders

    image.gif

    第三步,在Java代码中嵌入SQL查询代码:

    select * from Orders where Amount>2000 and Amount<=3000

    image.gif

    上面的方法需要人工参与,比较繁琐。也可以全部用Java代码实现,第一步,先在操作系统建立一个文本文件(比如importOrders.txt),内容即上面第二步。

    第二步,在Java代码调用操作系统命令行,即用Runtime.getRuntime().exec(…)执行命令:

    sqlite3.exe dbname.db < importOrders.txt

    image.gif

    第三步不变。

    这种方法需要额外的操作系统执行权限,安全风险比较大。如果想降低安全风险,就要用循环语句执行SQL一条条插入记录,代码冗长,修改麻烦。

    SPL读取csv文件,只需一步,在Java里嵌入下面的SPL代码:

    T("d:/Orders.csv").select(Amount>2000 && Amount<=3000)

    image.gif

    函数T不仅可以读取集文件,也可以读取csv文件,并生成序表。序表是SPL的结构化数据对象,可类比为SQL结果集。SPL导入数据时,数据类型会自动解析,不必手工指定。整个过程无需人工参与,权限要求低,代码简短,比SQLite方便多了。

    如果csv格式不规范,还可以使用import函数指定分隔符、字段类型、跳过行数,并处理转义符、引号、括号等,比SQLite提供的功能丰富多了。

    对于csv之外的数据源,SQLite都没有提供方便的导入方法,取数过程非常繁琐,而SPL支持多种数据源,取数过程简单方便,可以显著提高开发效率。

    读取多层结构数据

    Json和XML是常用的多层结构数据。SQLite架构简单,又有Json计算能力,有时会承担Json文件/RESTful的计算功能,但SQLite不能直接解析Json文件/RESTful,需要用Java代码硬写,或借助第三方类库,最后再拼成insert语句插入数据表,代码非常繁琐,这里就不展示了。

    SPL架构同样简单,且可以直接解析Json文件/RESTful,可以大幅简化代码,比如:

    json(file("d:/xml/emp_orders.json").read()).select(Amount>2000 && Amount<=3000)
    json(httpfile("http://127.0.0.1:6868/api/orders").read()).select(Amount>2000 && Amount<=3000)

    image.gif

    SQLite没有XML计算能力,也不能直接解析XML文件/WebService,只能借助外部Java代码解析计算,非常繁琐。 SPL可以直接读取XML文件:

    A
    1 =file("d:/xml/emp_orders.xml").read()
    2 =xml(A1,"xml/row")
    3 =A2.select(Amount>1000 && Amount<=2000 && like@c(Client,"*business*"))

    也可以方便地读取WebService:

    A
    1 =ws_client("http://127.0.0.1:6868/ws/RQWebService.asmx?wsdl")
    2 =ws_call(A1,"RQWebService":"RQWebServiceSoap":"getEmp_orders")
    3 =A2.select(Amount>1000 && Amount<=2000 && like@c(Client,"*business*"))

    SPL序表支持多层结构数据,比SQL库表的二维结构更容易表达Json/XML,计算代码也更简单。这部分内容不是本文重点,就此略过。

    跨源计算

    SQLite的外部数据源只支持csv文件,跨源计算就是csv文件和库表间的关联、交集、子查询等计算。SQL是封闭的计算语言,不能直接计算库外数据,需要经过一个入库的过程,把csv文件变成库表之后才能进行跨源计算。参考前面的代码可知,入库的过程比较麻烦,不能只用SQL,还要借助Java或命令行。

    SPL开放性较好,可以直接计算多种数据源,数据源之间可以方便地进行跨源计算。比如csv和RESTful左关联:

    =join@1(json(httpfile("http://127.0.0.1:6868/api/orders").read()):o,SellerId; T("d:/Emp.csv"):e,EId)

    image.gif

    写成多步骤的形式更易读:

    A
    1 =Orders=json(httpfile("http://127.0.0.1:6868/api/orders").read())
    2 =Employees=T("d:/Emp.csv")
    3 =join@1(Orders:o,SellerId;Employees:e,EId)

    只用SPL语言就可以实现跨源计算,不必借助Java或命令行,代码简短易懂,比SQL的开发效率高得多。

    数据计算

    基础计算

    SQLite支持常见的基础计算:

    #选出部分字段


    select Client,Amount from Orders

    image.gif

    #模糊查询


    select * from Orders where Amount>1000 and Client like '%s%'

    image.gif

    #排序


    select * from Orders order by Client, Amount desc

    image.gif

    #去重


    select distinct Client from Orders

    image.gif

    #分组汇总


    select strftime('%Y',OrderDate) as y, Client, sum(Amount) as amt from Orders group by strftime('%Y',OrderDate), Client having amt>3000

    image.gif

    #并集


    select * from Orders9 where Amount>3000 
    union 
    select * from Orders9 where strftime('%Y',OrderDate)='2009';

    image.gif

    #子查询


    select * from (select strftime('%Y',OrderDate) as y, Client, sum(Amount) as amt from Orders group by strftime('%Y',OrderDate), Client) where  Client like '%s%';

    image.gif

    SPL实现常见的基础计算:

    A B
    1 =Orders.new(Client,Amount) //选出部分字段
    2 =Orders.select(Amount>1000 && like(Client,\"*s*\")) //模糊查询
    3 = Orders.sort(Client,-Amount) //排序
    4 = Orders.id(Client) //去重
    5 =Orders.groups(year(OrderDate):y,Client;sum(Amount):amt).select(amt>3000) //分组汇总
    6 =[Orders.select(Amount>3000),A1.select(year(OrderDate)==2009)].union() //并集
    7 =Orders.groups(year(OrderDate):y,Client;sum(Amount):amt).select(like(Client,\"*s*\")) //子查询

    SQLite和SPL都有丰富的函数进行基础计算,学习掌握都不难。

    综合计算

    先看简单些的,计算TopN,SQLite:

    select * from Orders order by Amount limit 3

    image.gif

    SQLite代码简短,但因为不支持top函数,也不支持序号伪列(比如Oracle的rownum),只能改用limit实现,理解起来不够直观。

    SPL实现TopN:

    Orders.top(3;Amount)

    image.gif

    SPL支持真正的行号,也支持top函数,代码更短,且易于理解。

    组内TopN,SQLite:

    select * from (select *, row_number() over (partition by Client order by Amount) as row_number from Orders) where row_number<=3

    image.gif

    SQL代码略显复杂,主要因为SQLite不支持top函数,而limit函数只能限制总记录数,不能限制各组记录数,这种情况下必须用组内行号。SQLite没有真正的行号字段,要用窗口函数生成伪列再用,代码自然复杂。事实上,缺乏行号并非SQLite自身的问题,而是整个SQL体系的问题,其他数据库也没有行号。

    SPL实现组内TopN:

    Orders.group(Client).(~.top(3;Amount)).conj()

    image.gif

    SPL代码简单多了,而且很好理解,先按Client分组,再对各组(即符号~)计算TopN,最后合并各组的计算结果。SPL之所以代码简单,表面上是因为直接支持Top函数,本质是因为SPL有真正的行号字段,或者说,SPL支持有序集合。SPL代码简单,还因为集合化更加彻底,可以实现真正的分组,即只分组不汇总,这就可以直观地计算组内数据。SQL集合化不彻底,分组时必须汇总,不能直观地计算组内数据,只能借助窗口函数。

    再看复杂些的计算,某支股票的最大连续上涨天数,SQLite:

    select max(continuousdays)
    from (
    select count(*) continuousdays
    from (
    select sum(risingflag) over (order by day) norisingdays
    from (
    select day, case when price>
    lag(price) over (order by day) then 0 else 1 end risingflag from tbl
    )
    ) group by norisingdays
    )

    image.gif

    上面代码冗长复杂。SQL很难直接表达连续上涨的概念,只能换个方法变相实现,即通过累计不涨天数来计算连续上涨天数,这种方法技巧性强,编写难度大且不易理解。而且,SQL难以调试,导致维护困难。

    SPL求最大连续上涨天数:

    A
    1 =tbl.sort(day)
    2 =t=0,A1.max(t=if(price>price[-1],t+1,0))

    上面代码简单多了。SPL容易表达连续上涨的概念,先按日期排序;再遍历记录,发现上涨则计数器加1。这里既用到了循环函数max,也用到了有序集合,代码中[-1]表示上一条,是相对位置的表示方法,price[-1]表示上一个交易日的股价,比整体移行(lag函数)更直观。

    找出销售额占到一半的前n个客户,并按销售额从大到小排序。SQLite:

    with A as
    (select client,amount,row_number() over (order by amount) ranknumber
    from sales)
    select client,amount
    from (select client,amount,sum(amount) over (order by ranknumber) acc
    from A)
    where acc>(select sum(amount)/2 from sales)
    order by amount des

    image.gif

    上面代码复杂。SQL很难处理恰好要过线的客户,只能换个方法变相实现,即计算销售额从小到大的累计值,反过来找出累计值不在后一半的客户。这种方法技巧性强,代码冗长,而且难以调试。 SPL求销售额占到一半的前n个客户:

    A B
    2 =sales.sort(amount:-1) /销售额逆序排序,可在SQL中完成
    3 =A2.cumulate(amount) /计算累计序列
    4 =A3.m(-1)/2 /最后的累计即总额
    5 =A3.pselect(~>=A4) /超过一半的位置
    6 =A2(to(A5)) /按位置取值

    上面代码相对简单。SPL集合化成更彻底,可以用变量方便地表达集合,并在下一步用变量引用集合继续计算,因此特别适合多步骤计算。将大问题分解为多个小步骤,可以方便地实现复杂的计算目标,代码不仅简短,而且易于理解。此外,多步骤计算天然支持调试,无形中提高了开发效率。

    从上面例子可以看出,SQL只适合较简单的计算,而SPL支持有序集合,集合化更彻底,从简单到复杂的计算都可以很好的完成。此外,SPL还支持游离记录,可以用点号直观地引用关联表,从而简化复杂的关联计算。

    日期和字符串函数。SQLite支持日期和字符串函数,比如日期增减、截取字符串等,但还不够丰富,很多常用函数并不直接支持,比如季度增减、工作日计算等。

    SPL提供了更丰富的日期和字符串函数,在数量和功能上远远超过了SOLite。比如:

    季度增减:elapse@q("2020-02-27",-3)   //返回2019-05-27

    N个工作日之后的日期:workday(date("2022-01-01"),25) //返回2022-02-04

    判断是否全为数字:isdigit("12345")   //返回true

    取子串前面的字符串:substr@l("abCDcdef","cd")  //返回abCD

    按竖线拆成字符串数组:"aa|bb|cc".split("|")  //返回["aa","bb","cc"]

    SPL还支持年份增减、求季度、按正则表达式拆分字符串、拆出SQL的where或select部分、拆出单词、按标记拆HTML等大量函数。

    SPL函数选项和层次参数

    值得一提的是,为了进一步提高开发效率,SPL还提供了独特的函数语法。

    有大量功能类似的函数时,SQL要用不同的名字或者参数进行区分,使用不太方便。而SPL提供了非常独特的函数选项,使功能相似的函数可以共用一个函数名,只用函数选项区分差别。比如,select函数的基本功能是过滤,如果只过滤出符合条件的第1条记录,可使用选项@1:

    T.select@1(Amount>1000)

    image.gif

    对有序数据用二分法进行快速过滤,使用@b:

    T.select@b(Amount>1000)

    image.gif

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

    Orders.select@1b(Amount>1000)

    image.gif

    结构化运算函数的参数有些很复杂,SQL需要用各种关键字把一条语句的参数分隔成多个组,但这会动用很多关键字,也使语句结构不统一。SPL使用层次参数简化了复杂参数的表达,即通过分号、逗号、冒号自高而低将参数分为三层:

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

    image.gif

    数据持久化

    SQLite通过直接处理库表来实现数据持久化,分为增、改、删三种:

    insert into Orders values(201,'DSL',10,2000.0,'2019-01-01')
    update Orders set Client='IBM' where orderID=201
    delete from Orders where orderID=201

    image.gif

    批量新增是常见的需求,SQLite代码如下:

    insert into Orders(OrderID,Client,SellerID,Amount,OrderDate) 
    select 201,'DSL',10,2000.0,'2019-01-01'
    union all
    select 202,'IBM',10,3000.0,'2019-01-01'

    image.gif

    SPL集文件的持久化有两种方式。第一种方式:直接处理集文件,可实现记录新增(及批量新增)。比如:

    A
    1 =create(OrderID,Client,SellerID,Amount,OrderDate)
    2 =A1.record([201,"HDR",9,2100.0,date("2021-01-01"),202,"IBM",9,1900,date("2021-01-02")])
    3 =file("d:/Orders.btx").export@ab(A2)

    第二种方式:先处理内存里的序表,再将序表覆盖写入原来的集文件。这种方式可实现增、改、删。只要将上面A3格里的export@ab改为export@b即可,@a表示追加,@b表示集文件格式。这种方式性能不如SQLite,但嵌入计算的数据量普遍不大,覆写的速度通常可接受。

    SPL组表支持高性能增删改,适用于大数据量高性能计算,不是本文重点。

    SQLite只支持库表的持久化,不支持其他数据源,包括csv文件,硬要实现的话只能借助Java硬编码或第三方类库,代码非常繁琐。

    SPL除了支持集文件的持久化,也支持其他数据源,同样是通过序表为媒介。

    file("d:/Orders.csv").export@t(A2)      //csv文件
    file("d:/Orders.xlsx").xlsexport@t(A2)      //xls文件
    file("d:/Orders.json").write(json(A2))      //json文件

    image.gif

    特别地,SPL支持任意数据库的持久化。比如:

    A B
    1 =connect("orcl") /连接外部oracle
    2 =T=A1.query("select * from salesR where SellerID=?",10) /批量查询,序表T
    3 =NT=T.derive() /复制出新序表NT
    4 =NT.field("SELLERID",9) /批量修改新序表
    5 =A1.update(NT:T,sales;ORDERID) /持久化

    数据库的持久化依然以序表为媒介,可以明显看出这种方式的优点:函数update自动比对修改(增改删)前后的序表,可方便地实现批量数据地持久化。

    流程处理

    SQLite缺乏流程处理能力,无法实现完整的业务逻辑,只能将SQL数据对象转为Java的resultSet/List<EntityBean>,再用for/if语句处理流程,最后再转回SQL的数据对象,代码非常繁琐。复杂的业务逻辑要在SQL对象和Java对象之间转换多次,更加麻烦。

    SPL提供了流程控制语句,配合内置的结构化数据对象,可以方便地实现各类业务逻辑。

    分支结构:

    A B
    2
    3 if T.AMOUNT>10000 =T.BONUS=T.AMOUNT*0.05
    4 else if T.AMOUNT>=5000 && T.AMOUNT<10000 =T.BONUS=T.AMOUNT*0.03
    5 else if T.AMOUNT>=2000 && T.AMOUNT<5000 =T.BONUS=T.AMOUNT*0.02

    循环结构:

    A B
    1 =db=connect("db")
    2 =T=db.query@x("select * from sales where SellerID=? order by OrderDate",9)
    3 for T =A3.BONUS=A3.BONUS+A3.AMOUNT*0.01
    4 =A3.CLIENT=CONCAT(LEFT(A3.CLIENT,4), " co.,ltd.")
    5

    上述代码之外,SPL还有更多针对结构化数据的流程处理功能,可进一步提高开发效率,比如:每轮循环取一批而不是一条记录;某字段值变化时循环一轮。

    应用结构

    Java集成

    SQLite提供了JDBC接口,可以被Java代码方便地集成:

    Class.forName("org.sqlite.JDBC");
    Connection conn = DriverManager.getConnection("jdbc:sqlite: d:/ex1.db");
    Statement statement = conn.createStatement();
    ResultSet results = statement.executeQuery("select * from Orders where Amount>1000 and Client like '%s%'");

    image.gif

    SQLite的内核是C语言编写的,虽然可以被集成到Java应用中,但不能无缝集成,和Java主程序交换数据时要耗费额外的时间,在数据量较大或交互较频繁时性能就会明显下降。同样因为内核是C程序,SQLite会在一定程度上破坏Java架构的一致性和健壮性。

    SPL同样提供了JDBC接口,集成方法和SQLite类似:

    Class.forName("com.esproc.jdbc.InternalDriver");
    Connection conn =DriverManager.getConnection("jdbc:esproc:local://");
    Statement statement = conn.createStatement();
    ResultSet result = statement.executeQuery("=T(\"D:/Orders.csv\").select(Amount>1000 && like(Client,\"*s*\"))");

    image.gif

    SPL是纯Java编写的,可被Java应用无缝集成,架构一致性强,系统更稳定,不需要耗费额外时间交换数据,性能更有保障。

    业务逻辑外置

    一般的RDB支持存储过程,可将业务逻辑外置于Java程序,但SQLite不支持存储过程,完整的业务逻辑通常要借助Java的流程处理功能才能实现,也就不能外置于Java程序。业务逻辑不能外置于Java代码,导致两者耦合性过高。

    SPL可实现完整的业务逻辑,业务逻辑(或复杂的、经常变化的计算代码)可保存为脚本文件,并外置于Java程序。Java程序以存储过程的形式引用脚本文件名:

    Class.forName("com.esproc.jdbc.InternalDriver");
    Connection conn =DriverManager.getConnection("jdbc:esproc:local://");
    CallableStatement statement = conn.prepareCall("{call queryOrders()}");
    statement.execute();

    image.gif

    外置的SPL脚本不仅可以有效降低系统耦合性,还具有热切换的特点。SPL是解释型代码,修改后不必编译就可直接运行,也不必重启Java应用,可有效降低维护成本。

    内存计算

    SQLite可用于内存计算,一般在应用启动时将数据加载至内存(URL有变化):

    Connection conn= DriverManager.getConnection("jdbc:sqlite:file::memory:?cache=shared");
    Statement st =conn.createStatement();
    st.execute("restore from d:/ex1");

    image.gif

    需要进行业务计算时,就可以直接利用之前加载好的内存数据:

    Class.forName("org.sqlite.JDBC");
    Connection conn= DriverManager.getConnection("jdbc:sqlite:file::memory:?cache=shared");
    Statement statement = conn.createStatement();
    ResultSet results = statement.executeQuery("select OrderID,Client,Amount,Name,Gender Dept from Orders left join Employees on Orders.SellerId=Empoyees.EId");

    image.gif

    SPL同样可用于内存计算,在应用启动时执行脚本,将数据加载至内存(URL不变):

    A
    1 = connect("orcl").query@x("select OrderID,Client,SellerID,OrderDate,Amount from orders order by OrderID")
    2 >env(Orders,A1)
    3 >env(Employees,T("d:/Employees.csv"))

    需要进行业务计算时,可直接利用之前加载好的内存数据:

    Class.forName("com.esproc.jdbc.InternalDriver");
    Connection conn =DriverManager.getConnection("jdbc:esproc:local://");
    Statement statement = conn.createStatement();
    ResultSet result = statement.executeQuery("=join@1(Orders:O,SellerId; Employees:E,EId).new(O.OrderID, O.Client,O.Amount,E.Name,E.Gender,E.Dept)");

    image.gif

    关联计算如果频繁发生,性能必然下降,改用宽表的话又太占内存,SQL没有好办法解决这个问题。SPL独有预关联技术,可大幅提升关联计算的性能,且不占用额外内存。SPL还有更多内存计算技术,通常比SQLite性能好得多,包括并行计算、指针式复用、内存压缩等。

    SQLite可以方便地嵌入Java,但数据源加载繁琐,计算能力不足,无法独立完成业务逻辑,架构上弱点颇多。SPL也很容易嵌入Java,且直接支持更多数据源,计算能力更强,流程处理方便,可独立实现业务逻辑。SPL还提供了多种优化体系结构的手段,代码既可外置也可内置于Java,支持解释执行和热切换,可进行高性能内存计算。

    SPL资料

      相关实践学习
      基于MaxCompute的热门话题分析
      本实验围绕社交用户发布的文章做了详尽的分析,通过分析能得到用户群体年龄分布,性别分布,地理位置分布,以及热门话题的热度。
      SaaS 模式云数据仓库必修课
      本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps&nbsp;
      目录
      相关文章
      |
      3月前
      |
      Java API Spring
      打造未来电商新引擎:揭秘Java可扩展API设计,让支付与物流灵活如丝,引领电商时代潮流!
      【8月更文挑战第30天】本文通过电商平台案例,探讨了如何设计可扩展的Java API。首先定义支付和物流服务的接口与抽象类,然后实现具体服务,接着引入工厂模式或依赖注入管理服务实例,最后通过配置实现灵活扩展。这种设计确保了应用架构的灵活性和长期稳定性。
      53 3
      |
      5月前
      |
      存储 监控 Java
      使用Java实现实时数据处理系统
      使用Java实现实时数据处理系统
      |
      4月前
      |
      监控 Java 大数据
      如何在Java中实现批量数据处理
      如何在Java中实现批量数据处理
      |
      12天前
      |
      自然语言处理 安全 Java
      Aviator Java 表达式引擎
      AviatorScript 是一门高性能、轻量级寄宿于 JVM 之上的脚本语言。
      29 10
      |
      4月前
      |
      消息中间件 存储 Java
      使用Java构建实时数据处理流程
      使用Java构建实时数据处理流程
      |
      3月前
      |
      Java 数据库连接 数据库
      java系列之~如何给sqlite数据库添加表
      这篇文章介绍了如何在Java中使用SQLite JDBC驱动来连接SQLite数据库,并提供了示例代码来演示如何创建一个新的数据库表。
      |
      3月前
      |
      存储 Java API
      探索Java中的Stream API: 提升数据处理的效率与优雅
      在Java的海洋中,Stream API如同一股清流,为数据处理注入了新的活力。本文将深入探讨Stream API的核心概念、操作以及它如何改变我们编写和理解代码的方式。通过实际案例,我们将揭示这一现代编程范式如何简化集合处理,提高代码的可读性与性能。
      |
      3月前
      |
      Java 数据库连接 缓存
      Hibernate性能调优:五大秘籍,让应用效能飙升,告别慢如蜗牛的加载,体验丝滑般流畅!
      【8月更文挑战第31天】本文深入探讨了提升Hibernate应用性能的五大技巧,包括选择合适的缓存策略、优化查询语句、合理使用Eager与Lazy加载、批量操作与事务管理以及利用索引和数据库优化。通过正确配置多级缓存、分页查询、延迟加载、批量处理及合理创建索引,能够显著提高应用响应速度与吞吐量,改善用户体验。这些技巧需根据具体应用场景灵活调整,以实现最佳性能优化效果。
      143 0
      |
      4月前
      |
      设计模式 安全 Java
      Java面试题:如何实现一个线程安全的单例模式,并确保其在高并发环境下的内存管理效率?如何使用CyclicBarrier来实现一个多阶段的数据处理任务,确保所有阶段的数据一致性?
      Java面试题:如何实现一个线程安全的单例模式,并确保其在高并发环境下的内存管理效率?如何使用CyclicBarrier来实现一个多阶段的数据处理任务,确保所有阶段的数据一致性?
      56 0
      |
      4月前
      |
      存储 搜索推荐 算法
      Java中的文本搜索与全文检索引擎
      Java中的文本搜索与全文检索引擎