wenmo8 发布的文章

最近工作用到Spark,这里记一些自己接触到的Spark基本概念和知识。

本文链接:https://www.cnblogs.com/hhelibeb/p/10288915.html

名词

RDD:在高层,每个Spark应用包含一个driver程序,它运行用户的主函数,在集群上执行不同的并行作业。Spark中提供的主要抽象是弹性分布式数据集(resilient distributed dataset, RDD),它是分布在集群节点中的已分区的元素集合,可以被并行处理。RDD从Hadoop文件系统中的文件创建,或者从驱动程序中已有的Scala集创建。用户也可以要求Spark将RDD持久化在内存中,允许它在并行操作中被高效地复用。最后,RDD可以从节点故障中自动恢复。

Spark SQL:一个用于处理结构化数据的Spark模块。和RDD API不同,Spark SQL提供的接口会提供给Spark关于数据的结构和计算的更多信息。在内部,Spark SQL使用额外的信息来执行额外优化。有许多方式可以与Spark SQL交互,包含SQL和Dataset API。在进行计算时,无论使用哪种API/编程语言,都会使用相同的执行引擎。这意味着开发者可以基于数据变换的需要来自由切换不同的API。

Dataset:Dataset是分布式的数据集合。Dataset是Spark 1.6中新加入的接口,提供了RDD的优势(强类型化,应用lambda函数的能力),也提供了Spark SQL的优化执行引擎的优势。Dataset可以由JVM对象构造,然后通过函数变换(map, flatMap, filter等)来操纵。Dataset API在Scala和Java中可用。Python不支持Dataset API,但是由于Python的动态性,已经可以享受许多Dataset API的好处。(例如你可以通过row.columnName的方式自然地访问行中的字段)。R语言的情形与之类似。

DataFrame:DataFrame是一种有列名的Dataset。它在概念上等于关系数据库中的表或者R/Python中的数据帧,但是在底层有更多的优化。DataFrame可以从一个多重源构造,比如:结构化数据文件、Hive中的表、外部数据库或者既有的RDD。DataFrame API在Scala、Java、Python和R中可用。在Scala和Java,DataFrame被表示为多行Dataset。在Scala API中,Dataframe可以简单地表示为Dataset[Row]。而在Java API中,用户需要使用Dataset<Row>来表示Dataframe。

 

TempView:createOrReplaceTempView方法会创建(如果已存在同名视图的话,则替换)一个惰性计算视图,你可以将这个视图视作hive表来使用。除非你将Dataset缓存,否则它不会持久化到内存中。可以使用spark.catalog.dropTempView("tempViewName")来删除视图。

Caching and Persistence:缓存或持久化是Spark计算的优化技术。 它们有助于保存临时部分结果,以便可以在后续阶段重复使用。 因此,RDD的这些中间结果保存在内存(默认)或固态存储(如磁盘和/或复制)中。

SparkSession:Spark SQL的入口点。在开发Spark SQL应用时,这是首先要创建的对象之一。

你可以使用SparkSession.builder方法来创建SparkSession。

importorg.apache.spark.sql.SparkSession
val spark
=SparkSession.builder
.appName(
"My Spark Application") // optional and will be autogenerated if notspecified
.master(
"local[*]") // only for demo and testing purposes, use spark-submit instead
.enableHiveSupport()
// self-explanatory, isn't it? .config("spark.sql.warehouse.dir", "target/spark-warehouse")
.withExtensions { extensions
=>extensions.injectResolutionRule { session=>...
}
extensions.injectOptimizerRule { session
=>...
}
}
.getOrCreate

如管理学学者彼得·德鲁克所说:你无法管理你不能衡量的东西( If you can't measure it, you can't manage it)。要对已有程序进行性能优化,首先要对它的运行状况做出量化分析。

将代码下推到ABAP CDS,是SAP推荐的一种优化方式。但正因逻辑从应用服务器向数据库的转移,传统运行时分析工具SAT也有了力所不能及之处。这时,我们需要新的工具来对这一新的开发对象的运行情况进行分析。

本文将介绍Plan Visualizer(以下简称PlanViz)在ABAP CDS性能分析方面的应用。

 

本文链接:https://www.cnblogs.com/hhelibeb/p/10472856.html

1,示例CDS视图

本文会用到一个系统自带的简单示例视图,DEMO_CDS_JOIN。它的代码如下,

@AbapCatalog.sqlViewName: 'DEMO_CDS_JOIN'defineviewdemo_cds_scarr_spfli 
(id, carrier, flight, departure, destination)
as select fromspflijoinscarr on scarr.carrid =spfli.carrid
{
keyspfli.carrid,keyscarr.carrname,keyspfli.connid,
spfli.cityfrom,
spfli.cityto }

类是不是越小越好?最近在读John Ousterhout的《A Philosophy of Software Design》,感到作者文笔流畅,书中内容具有启发性。这里摘要一部分内容,以供开发工作中的参考、学习。

本文链接:https://www.cnblogs.com/hhelibeb/p/10708951.html

转载请注明

 

在软件复杂度的管理当中,最重要的技术之一是通过对系统的设计,使开发者任何在时候都只需要面对整体复杂度中的一小部分。这个过程被称为模块化设计

复杂度是什么?在本文中,复杂度的定义是:和软件系统结构有关的、会导致理解和修改系统变困难的东西。

1,模块化设计

在模块设计中,软件系统被分解为相对独立的模块集合。模块的形式多种多样,可以是类、子系统、或服务等。在理想的世界中,每个模块都完全独立于其它模块:开发者在任何模块中工作的时候,都不需要知道有关其它模块的任何知识。在这种理想状态下,系统复杂度取决于系统中复杂度最高的模块。

当然,实践与理想不同,系统模块间总会多少有些依赖。当一个模块变化时,其它模块可能也需要随之而改变。模块化设计的目标就是最小化模块间的依赖。

为了管理依赖,我们可以把模块看成两部分:接口实现

接口包含了全部的在调用该模块时需要的信息。接口只描述模块做什么,但不会包含怎么做

完成接口所做出的承诺的代码被称为实现

在一个特定模块内部进行工作的开发者必须知道的信息是:当前模块的接口和实现+其它被该模块使用的模块的接口。他不需要理解其它模块的实现。

在本文中,包含接口/实现的任何代码单元,都是模块。面向对象语言中的类是模块,类中的方法也是模块,非面向对象语言中的函数也是模块。高层的子系统和服务也可以被看作模块,它们的接口也许是多种形式的,比如内核调用或HTTP请求。本文中的大部分内容针对的是类,但这些技术和理论对其它类型的模块也有效。

好模块的接口远远比实现更简单。这样的模块有2个优点。首先,简单的接口最小化了模块施加给系统其余部分的复杂度。其次,如果修改模块时可以不修改它的接口,那么其他模块就不会被修改所影响。如果模块的接口远远比实现简单,那么就更有可能在不改动接口的情况对模块进行修改。

2,接口里有什么

接口中包含2种信息:正式的和非正式的。

正式的信息在代码中被显式指定,程序语言可以检查其中的部分正确性。比如,方法的签名就是正式的信息,它包含参数的名称和类型,返回值的类型,异常的信息。很多程序语言可以保证代码中对方法的调用提供了与方法定义相匹配的参数值。

接口里面也包含非正式的元素。非正式部分无法被程序语言理解或强制执行。接口的非正式部分包含一些高层行为,比如函数会根据某个参数的内容删除具有相应名字的文件。如果某个类的使用存在某种限制,比如方法的调用需要符合特定顺序,那这也属于接口的一部分。凡是开发者在使用模块时需要了解的信息,都可以算作模块接口的一部分。接口的非正式信息只能通过注释等方式描述,程序语言无法确保描述是完整而准确的。大部分接口的非正式信息都比正式信息要更多、更复杂。

清晰的接口定义有助于开发者了解在使用模块时需要知道的信息,从而避免一些问题。

3,抽象

 抽象这一术语和模块设计思想的关系很近。抽象是实体的简化视图,省略了不重要的细节。抽象很有用,它可以使我们对细节的思考和操纵变简单。

在模块化编程中,每个模块通过接口提供其抽象。抽象代表了函数功能的简化视图。在函数抽象的立场上,实现的细节是不重要的,所以它们被省略了。

“不重要”这个词很关键。如果没有忽略掉不重要的细节,那么抽象会变得复杂,会增加开发者的认知负担;如果忽略掉了重要的细节,那么抽象会变得错误,失去对实践的指导意义。设计抽象的关键是理解什么是重要的,并寻找最小化重要信息的设计。

依赖抽象来管理复杂度不是编程的专利,它遍布在我们的日常生活中。就像车子会提供一个简单抽象来让我们驾驶,并不需要我们理解发动机、电池、ABS之类的东西。

4,深模块

最好的模块提供了强大的功能,又有着简单的接口。术语“”可以用于描述这种模块。为了让深度的概念可视化,试想每个模块由一个长方形表示,如下图,

长方形的面积大小和模块实现的功能多少成比例。顶部边代表模块的接口,边的长度代表它的复杂度。最好的模块是深的:他们有很多功能隐藏在简单的接口后。深模块是好的抽象,因为它只把自己内部的一小部分复杂度暴露给了用户。

浅模块的接口复杂,功能却少,它没有隐藏足够的复杂度。

可以从成本与收益的角度思考模块深度。模块提供的收益是它的功能。模块的成本(从系统复杂度的角度考虑)是它的接口。接口代表了模块施加给系统其余部分的复杂度。接口越小而简单,它引入的复杂度就越少。好的模块就是那些成本低收益高的模块

某些语言中的垃圾回收(GC)是深模块的例子之一。这个模块没有接口,它在需要回收无用内存的场景下不可见地工作。在系统中加入垃圾回收的做法,缩小了系统的总接口,因为这种做法消除了用于释放对象的接口。垃圾回收的具体实现是相当复杂的,但这一复杂度在实际使用程序语言的时候是隐藏的。

5,浅模块

相对的,浅模块就是接口相对功能而言很复杂的模块。下面是个可能有些极端的例子,

private voidaddNullValueForAttribute(String attribute) {
  data.put(attribute,
null);
}

关于将SAP ABAP应用服务器组件容器化和在Kubernetes中部署它们,我们在SPA LinuxLab中做了概念验证(PoC),本文将介绍一些我们的发现和经验。本文会也会指出这项工作的一些潜在的收益和挑战。

 

作者:Richard Treu, Henning Sackewitz

英文原文:Proof of Concept: Deploying ABAP in Kubernetes

本文链接:https:////www.cnblogs.com/hhelibeb/p/12320295.html

 

请注意,本文档并非完整解决方案,当前不提供任何产品或开发内容。

参考 SAP note 1122387,可以获取有关当前ABAP应用服务器在容器(-orchestration)中运行的支持文档。

 

请随意评论和分享本文。

 

SAP预测分析库(SAP Predictive Analysis Library,PAL)是SAP HANA中的一项功能,它允许我们在SAP HANA SQLScript过程中执行分析算法。

基于ABAP的SAP应用可以调用PAL提供的功能,包含分类,回归,聚类,关联规则,社交网络分析,推荐系统等。通常使用AMDP来实现调用。

AMDP(ABAP-Managed Database Procedures)是一种在SAP HANA中进行ABAP开发时可以使用的代码优化模式,简而言之,它可以让开发者在ABAP中写HANA数据库存储过程。

 

本文链接:https://www.cnblogs.com/hhelibeb/p/12610644.html

英文原文:An example to call PAL Apriori via AMDP

示例

接下来用一个例子来展示如何使用PAL。这里用到的PAL函数是Apriori

步骤一(可选) 熟悉使用SQLScript调用PAL函数

如果你已经熟悉PAL的HANA存储过程接口和它的调用,可以跳过这步。

通过HANA Studio连接HANA数据库,运行下面的脚本:

SET SCHEMAZHAOJE;DROP TABLEPAL_APRIORI_PARAMETER_TBL;CREATE COLUMN TABLEPAL_APRIORI_PARAMETER_TBL (
“PARAM_NAME ”
VARCHAR(100),
“INT_VALUE”
INTEGER,
“DOUBLE_VALUE”
DOUBLE,
“STRING_VALUE”
VARCHAR (100)
);
INSERT INTO PAL_APRIORI_PARAMETER_TBL VALUES (‘MIN_SUPPORT’, null, 0.1, null);INSERT INTO PAL_APRIORI_PARAMETER_TBL VALUES (‘MIN_CONFIDENCE’, null, 0.3, null);INSERT INTO PAL_APRIORI_PARAMETER_TBL VALUES (‘MIN_LIFT’, null, 1.1, null);INSERT INTO PAL_APRIORI_PARAMETER_TBL VALUES (‘MAX_CONSEQUENT’, 1, null, null);INSERT INTO PAL_APRIORI_PARAMETER_TBL VALUES (‘PMML_EXPORT’, 1, null, null);DROP TABLEPAL_APRIORI_TRANS_TBL;CREATE COLUMN TABLEPAL_APRIORI_TRANS_TBL (
“CUSTOMER”
INTEGER,
“ITEM”
VARCHAR(20)
);
INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (2, ‘item2’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (2, ‘item3’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (3, ‘item1’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (3, ‘item2’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (3, ‘item4’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (4, ‘item1’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (4, ‘item3’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (5, ‘item2’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (5, ‘item3’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (6, ‘item1’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (6, ‘item3’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (0, ‘item1’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (0, ‘item2’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (0, ‘item5’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (1, ‘item2’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (1, ‘item4’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (7, ‘item1’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (7, ‘item2’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (7, ‘item3’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (7, ‘item5’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (8, ‘item1’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (8, ‘item2’);INSERT INTO PAL_APRIORI_TRANS_TBL VALUES (8, ‘item3’);

CALL _SYS_AFL.PAL_APRIORI(PAL_APRIORI_TRANS_TBL, PAL_APRIORI_PARAMETER_TBL, ?, ?);