在本文中,我會通過CDS視圖來介紹虛拟資料模型(Virtual Data Model,以下簡稱VDM)。
在SAP HANA平台出現後,SAP的業務應用開發模式已經産生了變化,新的經驗法則是:盡可能在資料庫中做更多的事情(PUSH DOWN),以得到最佳的性能。
本文連結:https://www.cnblogs.com/hhelibeb/p/9223993.html
嵌入式分析
SAP S/4嵌入式分析是S/4的一部分,用于對業務資料執行複雜的實時報表和分析。SAP S/4嵌入式分析的關鍵架構元件包括SAP HANA資料庫,VDM,分析引擎(嵌入式SAP BW),OData服務,和如下圖所示的接口。
本文将介紹其中的VDM。
CDS視圖
為了在應用開發中利用SAP HANA的優點,SAP引入了新的資料模組化基礎設施,名為Core Data Service(以下簡稱CDS)。通過CDS,資料模型會在資料庫而非應用伺服器中定義和消費。CDS也提供了傳統資料模組化工具的相容性,包含支援概念模組化和關系定義,内置函數和擴充。
技術上講,CDS是提供資料定義語言(DDL)的加強版SQL,用于在資料庫中定義富語義資料庫表/視圖(CDS entity)和使用者定義的類型。增強包括:
- Expression:用于在資料模型中計算和查詢。
- Association:在概念層上,通過簡單的path expression代替join(關于Association可參考之前的文章)。
- Annotation:通過附加的(特定領域的)中繼資料來豐富資料模型。
CDS在ABAP和SAP HANA中都得到了原生支援。資料模型通過資料定義語言(DDL)表達,并且定義為CDS視圖,可以在ABAP程式中通過Open SQL語句通路。CDS為業務和開發提供了一系列優點,包含:
- 富語義資料模型:CDS基于衆所周知的實體-關系模型,并且實質上是聲明式的,非常接近概念思維。
- 相容任何資料庫平台:CDS會被生成為受管理的Open SQL視圖,并且原生地內建進入SAP HANA層。這些基于Open SQL的視圖得到了所有主流資料庫供應商的支援。
- 高效:CDS提供了多樣化和高效的内置函數,例如SQL運算符,聚合和表達式,來幫助開發者建構視圖。
- 支援annotation:CDS文法支援特定領域的annotation,可以輕松的被其他元件利用,比如UI,分析和OData服務。
- 支援概念關聯( conceptual associations):CDS幫助你定義association,作為不同視圖的關系。Path expression可以用于在關系間導航。association引入了抽象的外鍵關系和join,來對可消費的entity進行導航。
- 可擴充性:客戶可以擴充SAP定義的CDS視圖,擴充字段将随其使用層次結構自動添加到CDS視圖中。
VDM
在HANA之前,查詢ERP系統中的大量資料集會花很多時間,并會降低系統的整體性能。資料倉庫可以通過進階模組化技術建立持久化的資料模型,以提高查詢性能。SAP HANA去除了ERP中的性能問題,使我們能夠直接在ERP中建立虛拟資料模型(VDM),并提供令人難以置信的高性能。
VDM是什麼?VDM是富語義CDS視圖的結合,它将ERP源表的資料符合邏輯地結合到一起,建立成為有意義的資料集,并且可以被前端工具便利地消費。
VDM的核心原理是在現有的S/4資料庫模型之上建構語義層,隐藏它的技術細節。基于提供的内容和複用選項,VDM中的CDS視圖被分為接口視圖或消費視圖,如下:
私有視圖
私有視圖(Private Views)實際上不是提供給終端使用者消費的視圖,它是技術驅動的輔助視圖。引入私有模型是為了幫助底層資料模型到公共視圖模型的轉換。私有CDS視圖的名字字首是P_。不建議修改或擴充它們。
接口視圖
接口視圖(Interface views)是VDM最重要的組成部分。接口視圖組成了可複用的entity視圖,在業務語義是定義上的重點。接口視圖對任何消費者而言都是公開的、穩定的并且可複用的。公共接口視圖的結構需要不受correction、更新檔和更新的影響。
接口視圖分兩種:
基本接口視圖(Basic interface Views)代表沒有資料備援的核心entity,即對每個核心entity做單一的表示,(比如,正好一個客戶或者銷售訂單)并且隻帶有依賴于核心entity自身的、無法從其他字段計算得到的字段。基本視圖組成了低備援模型和SAP Business Suite資料庫表的簡單投影。
組合接口視圖(Composite Interface Views)繼承自多個簡單接口視圖,也許會有關聯、聚合和複雜計算。它們可以屬于特定消費域,或者被複用,根據設計,它們總是暴露備援的資料。按照實際的使用情況,組合接口視圖可以分為很多層。
消費視圖
如名字所示,消費視圖(Consumption Views)是暴露給終端使用者消費的視圖。消費視圖會使用到一個或更多接口視圖。消費視圖是共用的特定領域視圖,用于分析、搜尋和事務應用。VDM模組化的指導原則是,資料庫表一定不可以被消費視圖直接通路(即不可以繞過接口視圖)。
擴充包含視圖
擴充包含視圖(Extension include Views)用于暴露自定義新字段。可以擴充SAP釋出的擴充包含視圖,以條件附加字段。自定義擴充包含視圖會在單獨的DDL源中建立和傳輸。
總之,在高層上,CDS視圖從資料庫表得到資料,這些視圖又會被其它CDS視圖讀取,VDM就是由所有的這些CDS視圖組成。沒有任何持久化過程,一切都是實時的。
Annotation
Annotation用于描述CDS視圖,為CDS視圖中的字段提供語義和意義。
- 它可以應用在整個CDS視圖entity上;
- 它可以指定SELECT清單中特定的字段的語義;
- 總是在@符号後面
這面是annotation的清單:https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-US/abencds_annotations_sap.htm
也可以通過以下路徑通路:ABAP – Keyword Documentation > ABAP – Dictionary > ABAP CDS in ABAP Dictionary > ABAP CDS – Syntax > ABAP CDS – Annotations
下面是用于VDM的定義整個CDS視圖的一些關鍵的annotation:
Description | |
VDM.viewType | 定義VDM視圖的類型 |
Analytics.dataCategory | 分析查詢可以在CDS視圖之上定義。通過指定資料分類,開發者可以提供指令和hints,告訴analytic manager如何解釋各個實體。 |
Analytics.dataExtraction.enabled | 應用開發者通過該annotation标記适合于資料複制的視圖(例如,必須為海量資料提供增量複制能力)。 |
Analytics.query | 通過标記CDS視圖,開發者可以指定暴露給analytic manager的視圖。這類視圖會被analytic manager解釋為分析查詢。 |
ObjectModel.dataCategory | 定義資料分類(#TEXT 或 #HIERARCHY) |
ObjectModel.representativekey | Most specific element (field or managed association) of the primary key (indicated by the keyword KEY) that represents the entity which the view is based on |
AccessControl.authorizationCheck | 針對指定的CDS視圖啟用行級别權限控制 |
/名詞解釋:analytic manager是一個BW概念,它提供OLAP功能和服務,以及BW內建規劃和分析過程設計的服務。
因為我還是個BW開發者,我找了幾個最重要的VDM的annotation來和BW對象對比:
Annotation: @VDM.viewType
Value | BW 對等物 | |
#BASIC | 組成核心基礎的視圖,無資料榮譽,它隻是從資料庫實體表的SELECT。 | 等于ADSO(進階資料存儲對象),即通過某些ETL後的raw data。 |
#COMPOSITE | 提供從基礎視圖繼承和/或組合而成的資料 | 等同于Composite Provider,是允許進行join和union的虛拟資料層。 |
#CONSUMPTION | 為特定應用目的服務的視圖,也許會基于公共接口視圖定義(比如BASIC 視圖或COMPOSITE視圖) | 等于BW Query,可以指定特殊的樣式,變量,RKF,CKF,總計,等等。 |
Annotation: @Analytics.dataCategory
#DIMENSION | 表示主資料的視圖需要有annotation:ObjectModel.dataCategory: #DIMENSION | 等于Infoobject Attributes |
#FACT | 事實表表示業務資料(星型模型的中心)通常包含度量。這些視圖通常是複制所必須的,是以,他們不能和主資料視圖join。 | 等于從一個單一資料源加載的ADSO,沒有任何主資料。 |
#CUBE | CUBE也代表事實資料,和FACT很像,但是CUBE不必是無備援的。這意味着它可以和主資料join。查詢基本都是建構在CUBE之上的,CUBE從FACT複制資料。 | 等于從單一/多個資料源加載的ADSO,和主資料的attributes/texts/hiererachies連接配接。 |
Annotation: @Analytics.dataExtraction.enabled
#TRUE | 應用開發者用這個annotation表示視圖适合于資料複制。(比如對于大量資料必須提供增量複制能力) | N/A |
#FALSE | 不适合資料複制 |
Annotation: @ObjectModel.dataCategory
#TEXT | 表示該entity代表文本,通常一個key元素是語言。 NOTE: 在VDM中,文本視圖總是獨立于語言的。 | 等于 infoobject Texts/descriptions |
#HIERARCHY | 表示該entity代表層次相關的資料。可以是header相關的資料或者結構資訊。 | 等于 infoobject Hierarchy |
Annotation: @AccessControl.authorizationCheck
#NOT_REQUIRED | 不存在針對該視圖的DCL(行級别安全對象),是以不會對該CDS視圖進行權限檢查,所有資料都會被展示。 | |
#CHECK | 存在針對該視圖的DCL(行級别安全對象),會對該CDS視圖進行行級别權限檢查。 | 有點像 BW authorizations |
#NOT_ALLOWED | 存在針對該視圖的DCL(行級别安全對象),但是不會進行行級别的權限檢查。 |
現在我們看過了CDS的主要annotation,我們将會進一步審視VDM的詳細架構。
注意這些概念和BW環境中的那些有多麼相似。我們在CDS中有文本和次元,我們可以一次建構、多次在不同的事務性CDS視圖中重用它們。
假設這是在建構一個物料次元和文本視圖。 你隻需要建立它一次,因為基礎表不會改變(MARA和MAKT)。 但是,對于需要物料描述或屬性的各個事務模型(銷售,交貨,盈利分析,庫存等),你可以重複利用該次元和文本視圖。
例子
下面是有關上述各個CDS視圖的細節:
TEXT
@AbapCatalog.sqlViewName: 'ZBTMATERIAL'
@ObjectModel.dataCategory: #TEXT
@Analytics: { dataCategory: #TEXT, dataExtraction.enabled: true }
@AccessControl.authorizationCheck: #NOT_REQUIRED
@VDM.viewType: #BASIC
@EndUserText.label: 'Material Text'
@ObjectModel.representativeKey: 'Material'
define view Zbt_Material as
select from makt
{
@ObjectModel.text.element: [ 'MaterialName' ]
key makt.matnr as Material,
@Semantics.language: true
key makt.spras as Language,
@Semantics.text: true
makt.maktx as MaterialName}
where makt.spras = $session.system_language
DIMENSION
@AbapCatalog.sqlViewName: 'ZBDMATERIAL'
@Analytics: { dataCategory: #DIMENSION, dataExtraction.enabled: true }
@VDM.viewType: #BASIC
@AbapCatalog.compiler.compareFilter: true
@EndUserText.label: 'Material Attributes'
@ObjectModel.representativeKey: 'Material'
@AccessControl.authorizationCheck: #NOT_REQUIRED
define view Zbd_Material as select from mara
association [0..1] to Zbt_Material as _Text on $projection.Material = _Text.Material
association [0..1] to Zbd_MaterialType as _MaterialType on $projection.MaterialType = _MaterialType.MaterialType
association [0..1] to Zbd_MaterialGroup as _MaterialGroup on $projection.MaterialGroup = _MaterialGroup.MaterialGroup
association [0..1] to I_UnitOfMeasure as _BaseUnit on $projection.MaterialBaseUnit = _BaseUnit.UnitOfMeasure
association [0..1] to I_UnitOfMeasure as _WeightUnit on $projection.MaterialWeightUnit = _WeightUnit.UnitOfMeasure
association [0..1] to Zbt_Storage_Conditions as _StorCond on $projection.StorageCondition = _StorCond.StorageCond
{ @EndUserText.label: 'Material'
@ObjectModel.text.association: '_Text'
key mara.matnr as Material, _Text,
@ObjectModel.foreignKey.association: '_MaterialType'
@EndUserText.label: 'Material Type'
mara.mtart as MaterialType, _MaterialType,
@ObjectModel.foreignKey.association: '_MaterialGroup'
@EndUserText.label: 'Material Group'
mara.matkl as MaterialGroup, _MaterialGroup,
@EndUserText.label: 'Base Unit of Measure'
@Semantics.unitOfMeasure: true
@ObjectModel.foreignKey.association: '_BaseUnit'
mara.meins as MaterialBaseUnit, _BaseUnit,
@EndUserText.label: 'Gross Weight'
@Semantics.quantity.unitOfMeasure: 'MaterialWeightUnit'
@DefaultAggregation: #NONE
mara.brgew as MaterialGrossWeight,
@EndUserText.label: 'Net Weight'
@Semantics.quantity.unitOfMeasure: 'MaterialWeightUnit'
@DefaultAggregation: #NONE
mara.ntgew as MaterialNetWeight,
@EndUserText.label: 'Weight Unit'
@Semantics.unitOfMeasure: true
@ObjectModel.foreignKey.association: '_WeightUnit'
mara.gewei as MaterialWeightUnit, _WeightUnit,
mara.mfrnr as MaterialManufacturerNumber,
mara.mfrpn as MaterialManufacturerPartNumber,
@EndUserText.label: 'Storage Condition'
@ObjectModel.text.association: '_StorCond'
mara.raube as StorageCondition, _StorCond,
@EndUserText.label: 'Product Hierarchy'
mara.prdha as ProductHierarchy
}
BASIC/FACT
注意,在選擇清單中,我們沒有為字段添加任何語義(annotation),因為這是一個BASIC視圖,而且我們在建立模型的FACT。語義annotation會在COMPOSITE視圖中應用。
VDM可以根據需要由多個BASIC/FACT視圖組成。
@AbapCatalog.sqlViewName: 'ZBFACDOCAXX'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Universal Journal Entry, Basic'
@VDM.viewType: #BASIC
@Analytics.dataCategory: #FACT
@Analytics.dataExtraction.enabled: true
define view ZBF_ACDOCA_XX as select from acdoca
{
rbukrs as CompCode,
gjahr as FiscalYear,
poper as Period,
racct as GLAccount,
matnr as Material,
werks as Plant,
// UOMs - Currencies
runit as UOM,
rhcur as CCCurr,
// Measures
msl as Quantity,
hsl as AmtCC
}
COMPOSITE/CUBE
@AbapCatalog.sqlViewName: 'ZCCACDOCAXX'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Universal Journal Entry, Composite'
@VDM.viewType: #COMPOSITE
@Analytics.dataCategory: #CUBE
@Analytics.dataExtraction.enabled: true
define view ZCC_ACDOCA_XX as select from ZBF_ACDOCA_XX
association [0..1] to I_Material as _Mat on $projection.Material = _Mat.Material
association [0..1] to I_Plant as _Plant on $projection.Plant = _Plant.Plant
association [0..1] to I_CompanyCode as _CompCode on $projection.CompCode = _CompCode.CompanyCode
{
@ObjectModel.foreignKey.association: '_CompCode'
CompCode, _CompCode,
FiscalYear,
Period,
GLAccount,
@ObjectModel.foreignKey.association: '_Mat'
Material, _Mat,
@ObjectModel.foreignKey.association: '_Plant'
Plant, _Plant,
//UOMs - Currencies
@Semantics.unitOfMeasure: true
@EndUserText.label: 'Base UOM'
UOM,
@Semantics.currencyCode: true
@EndUserText.label: 'Comp. Code Curr.'
CCCurr,
//Measures
@DefaultAggregation: #SUM
@EndUserText.label: 'Quantity'
@Semantics.quantity.unitOfMeasure: 'UOM'
Quantity,
@DefaultAggregation: #SUM
@EndUserText.label: 'Amount CC'
@Semantics.amount.currencyCode: 'CCCurr'
AmtCC
}
CONSUMPTION
@AbapCatalog.sqlViewName: 'ZCCACDOCAXXQ001'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Universal Journal Entry, Query'
@VDM.viewType: #CONSUMPTION
@Analytics.query: true
define view ZCC_ACDOCA_XX_Q001 as select from ZCC_ACDOCA_XX
{
//ZCC_ACDOCA_XX
@Consumption.filter: {mandatory: false, selectionType: #SINGLE, multipleSelections: true}
CompCode,
FiscalYear,
Period,
GLAccount,
Material,
@AnalyticsDetails.query.display: #KEY_TEXT
@AnalyticsDetails.query.axis: #ROWS
Plant,
//UOMs - Currencies
UOM,
CCCurr,
//Measures
Quantity,
AmtCC
}
優勢
VDM的主要優勢之一是隻要建構一次即可在多種前端工具中消費:
- BOBJ
- WEBI
- Analysis for Office
- Crystal
- OLAP
- Lumira Discovery (even though it's being discontinued in favor of Analytics Cloud)
- Analytics Cloud
- ALV Grid
- OData services
- Fiori
此外,因為CDS視圖存在于應用層,我們可以通過PFCG借力于既有的ABAP安全模型。對于CDS視圖安全,我們可以使用Data Control Language (DCL)來控制。有關DCL的更多資訊,可以看以下文章:
- 教程:基于通路控制的ABAP CDS視圖權限
- 在CDS(Core Data Services)中使用DCL(Data Control Language)
一旦你學會了如何用CDS視圖模組化,開發VDM的速度會變得很快,可以借此為使用者提供快速、高效的報表解決方案。
性能
關于性能,VDM在高容量高聚合的場景的表現是驚人的。我建構了一個采購訂單視圖,從header到計劃行,有許多主資料的join。計劃行表有大概2500萬資料,資料時間跨越了8年。
當運作沒有過濾的彙總報表時,列上有3個度量而下鑽時隻有年度(8行,3列,24個資料點),報表在1-2秒内完成查詢!
現在,使用和上面相同的資料模型,當我運作一個非常詳細的報表時,查詢到計劃行項目,擷取許多不同的屬性,下鑽大概30行,擷取整個月份的資料。這時報表大概花了10分鐘來運作。為什麼?因為它實時進行了我在模型中定義過的所有join和計算,處理上十分密集。
上面的場景十分适合采用BW的持久化解決方案,它可以進行任何計算和資料連接配接。報表運作時,資料持久化為ADSO,可以簡單地基于選擇條件擷取資料,不需要任何附加處理,預期的查詢時間将短至亞秒級。
本文翻譯自以下文章:
S/4 Embedded Analytics – The Virtual Data Model
S/4 HANA Embedded Analytics
參考文章: