MDX – Attribute Relationships in Analysis Services Multidimensional

Von Lukas Hillesheim, 2. Januar 2023
Blog Article & Copyright by Lukas Hillesheim
Attribute Relationships sind interne Objekte der Analysis Services MultiDimensional Engine. Sie sind vom MDX-Client aus nicht sichtbar, nur indirekt zu nutzen und nur in der Entiwcklungs-Umgebung konfigurierbar. Sie wirken sich aber auf MDX-Objekte und implizite Verhaltensweisen aus. Relationships zu verstehen, ist daher grundsätzlich wichtig für das Verständnis von MDX. 

1. Allgemeines

Attribute sind die elementaren Bausteine innerhalb von Analysis Services MultiDimensional. Aus ihnen leiten sich Attributs-Hierarchieen, Hierarchieen mit mehreren Ebenen und Element-Eigenschaften ab. Außerdem steuern sie implizite Verhaltensweisen wie MDX [<hierarchy>].CurrentMember und AutoExist.
Für die nachfolgenden Beispiele wird folgendes Datenmodell verwendet:
Figure 1 - Data Source View
Figure 1 - Data Source View
Extraktion von Attributen aus Tabellen-Spalten. Über Attribute werden die Inhalte von Tabellen-Spalten der Analysis Services Engine zur Verfügung gestellt. Das Mapping von Attributen auf Tabellen-Spalten geschieht im im SSDT-Designer an folgender Stelle:
Figure 2 - Attribute-Column Mapping
Figure 2 - Attribute-Column Mapping
Im Beispiel gibt es ein Key-Attribut [Customer], das auf die Spalte [dimCustomer].[Id] gemappt ist und in "Customer" umbenannt wurde. Zusätzlich existieren diverse Non-Key-Attribute [City], [Country], [Region] und [Phone No]. Standardmäßig haben alle Attribute eine direkte Relationship zum Key-Attribut:
Figure 3 - Initial Attribute Relationships
Figure 3 - Initial Attribute Relationships
Bitte beachten Sie, dass es zwei Typen von Relationships gibt: 1. Relationships zwischen Attributen im MultiDimensionalen Cube und 2. Relationships zwischen Tabellen der relationalen Quell-Struktur. Für das Verständnis von MDX sind nur Attribute-Relationships relevant.
Hinweis: Bezüglich der Relationships gibt es einen grundsätzlichen Unterschied zum Analysis Services Tabular. In der Tabularen Umgebung sind die Relationships der relationalen Quellstruktur für den DAX-Client sichtbar und müssen beim DAX-Coding berücksichtigt werden.

2. Attributs-Hierarchieen

Für den MDX-Client macht der MultiDimensionale Cube folgende Objekte sichtbar:
  • - Dimension
  • - Hierarchie
  • - Member
  • - Property
  • - Measures
Der Unterschied zwischen "Attribute-Hierarchie" und "Hierarchie mit mehreren Ebenen" wird zwar in diesem Artikel berücksichtig, ist aber in syntaktischer Hinsicht nicht relevant. 
Ohne weiteren Eingriff des Entwicklers wird zunächst jedes Attribut als Hierarchie exportiert. Liste von Attributen:
Figure 4 - List of Attributes
Figure 4 - List of Attributes
Liste von Hierarchieen der Dimension [dCustomer]:
Figure 5 - List of Hierarchies
Figure 5 - List of Hierarchies
Dieses Standard-Verhalten wird über die Eigenschaften „AttributeHierarchyEnabled“ des Attributs festgelegt. Beispiel für das Attribut [City]:
Figure 6 - Property 'AttributeHierarchyEnabled' true
Figure 6 - Property 'AttributeHierarchyEnabled' true
Die Aggregierbarkeit des Attributs sorgt dafür, dass für die Member der Hierarchie, also z.B. für die einzelnen Städte, Aggregate gebildet werden. Zusätzlich wird ein künstlicher Member [ALL] erstellt und der Hierarchie hinzugefügt. [ALL] stellt den Total der Aggregate dar.
Figure 7 - Hierarchy Members including [ALL]
Figure 7 - Hierarchy Members including [ALL]
Manche Daten des Cubes sind nicht im Sinne von Aggregation interessant, sondern im Sinne einer Beschreibung. Dies trifft z.B. auf das Attribut [Phone No] zu. Es ist nicht sinnvoll, Aggregate nach Telefon-Nummern zu bilden, aber es ist nützlich, zusätzlich zu einem Kunden auch die Telefon-Nummer anzuzeigen.
Die Deaktivierung der Aggregierbarkeit läßt das Attribut aus der Liste der Hierarchieen verschwinden, aber die Daten des Attributs sind noch immer Teil des Cubes (s.u.):
Figure 8 - Property 'AttributeHierarchyEnabled' false
Figure 8 - Property 'AttributeHierarchyEnabled' false
[Phone No] ist weiterhin Teil der Attributs-Liste; jedoch mit einem anderen Symbol markiert:
Figure 9 - [Phone No] Attribute as Member Property
Figure 9 - [Phone No] Attribute as Member Property
Nach außen hin ist [Phone No] nicht mehr Teil der Hierarchie-Liste:
Figure 10 - [Phone No] missing
Figure 10 - [Phone No] missing

3. Member Properties

Über Attribute-Relationships wird ein Attribut auf der rechten Seite einer Relationship zu einer Property des Attributs auf der linken Seite.
Die Änderung bei der Aggregierbarkeit von [Phone No] hat sich nicht auf die Relationships (s.o.) ausgewirkt. Somit befindet sich [Phone No] weiterhin auf der rechten Seite und [Customer] auf der linken Seite. Anders ausgedrückt: [Phone No] ist eine Member-Property von [Customer]. Diese Tatsache drückt der folgende MDX-Code aus:
Figure 11 - Use [Phone No] as Member Property
Figure 11 - Use [Phone No] as Member Property
Unabhängig von der Tatsache, ob die Aggregierbarkeit aktiviert oder deaktiviert ist, kann bei jeder Attribute-Relationship die jeweilige rechte Seite als Property der linken Seite betrachtet werden. Also sind auch die Attribute [City], [Region] und [Country] Eigenschaften von [Customer]:
Figure 12 - Use of all Hierarchies as [Customer] Member Property
Figure 12 - Use of all Hierarchies as [Customer] Member Property

4. CurrentMember

Ein weiterer Effekt von Attribute Relationships ist, dass die Selektion eines Members auf einer Seite implizit eine Member-Selektion auf der anderen Seite nach sich zieht. Dies funktioniert sowohl von links nach rechts, als auch in ungekehrter Richtung.
Beispiel: Durch die Selektion von [Customer].[John] auf der linken Seite wird [City].CurrentMember implizit auf [City].[Madrid] gesetzt. Umgekehrt gilt: Würde [City].[Madrid] auf der rechten Seite selektiert, ergäbe sich implizit auf der linken Seite [Customer].[ALL]. Bitte nehmen Sie außerdem zur Kenntnis, dass der Zugriff auf [Phone No].CurrentMember einen Fehler verursacht, da die CurrentMember Funktion nur auf eine Hierarchie angewandt werden kann: [<hierarchy>].CurrentMember.
Beispiel für eine Attribute Relationship mit impliziter Member-Selektion von links nach rechts:
Figure 13 - Attribute Relationships: from left to right
Figure 13 - Attribute Relationships: from left to right
Das folgende Beispiel zeigt, wie Attribute Relationships von rechts nach links wirken. Während mit Hilfe der Expression "[dCustomer].[City].[City].Members" eine Iteration über die Members der [City] Hierarchie stattfindet, wird pro [City] Member die Measure-Expression "[dCustomer].[Customer].CurrentMember" evaluiert. Die Attribute Relationship steuert implizit [Customer].CurrentMember und überschreibt dabei die Slicer Axis. Die Slicer Axis trägt zum Initial Context mit einer Einschränkung auf [Ann] und [John] bei. Auf Grund der Einschränkung, die sich auf der linken Seite einer Relationship befindet, werden schließlich nur die Städte herausgefiltert, wo [Ann] und [John] residieren. Dies erklärt, warum nur zwei Städte für die Iteration zur Verfügung stehen. Während der Iteration wird dann der Initial Context mit [Ann] und [John] überschrieben durch einen neuen Runtime Context, der [Customer].CurrentMember konstant auf [Customer].[ALL] setzt. Dieses Beispiel zeigt den Effekt von Attribute Relationships in zweifacher Hinsicht!
Figure 13b - Attribute Relationships: from right to left
Figure 13b - Attribute Relationships: from right to left
Zwischen der Dimension [dCustomer] und der Dimension [dProduct] existieren keine Relationship. Relationships verbinden nur Attribute ein und derselben Dimension. Dadurch, dass eine Relationship zwischen [Customer] und [Category] fehlt, kann [Category].CurrentMember nicht modifiziert werden und bleibt konstant [ALL]:
Figure 14 - Current Member in a non-related Dimension
Figure 14 - Current Member in a non-related Dimension

5. Hierarchieen mit mehreren Ebenen

Die in den Attributen einer Dimension gespeicherten Daten können hierarchische Sachverhalte ausdrücken. Beispielsweise befinden sich Kunden in einer bestimmten Stadt, die sich wiederum in einer bestimmten Region befindet. Von „oben“ betrachtet ergibt sich ein Baum – mit einem [ALL]-Member auf dem Top-Level, einem 2nd-Level mit Regionen, einem 3rd-Level mit Städten und einem 4th-Level mit Kunden.
Im Dimensions-Editor lassen sich Hierarchie-aktivierte Attribute zum Aufbau einer solchen Hierarchie mit mehreren Ebenen nutzen. Im Beispiel wird eine Hierarchie [hCustomer] aus den Attributen [Region], [City] und [Customer] erstellt:
Figure 15 - Custom Hierarchy  with multiple Levels
Figure 15 - Custom Hierarchy with multiple Levels
Damit die Hierarchie „funktioniert“, gilt es, zwei Bedingungen zu beachten:
1. Es sollten Relationships definiert sein, die das Verhältnis der Level ausdrücken. D.h. das niedrigere Level sollte zum übergeordneten Level eine N:1-Relationship haben. Ohne diese Relationship gibt es entweder Schema-Fehler oder Performance-Probleme. Hinweis: die besonderen Aufgaben, die durch Nichtbeachtung dieser Regel verursacht werden, entstehen durch zahlreiche verschiedene Konstellation und müssen gesondert (in einem anderen Dokument) betrachtet werden. 
2. Die Daten müssen den Relationships genügen. Eine als N:1 definierte Relationship verlangt beispielsweise, dass für die Stadt „Madrid“ nur eine Kombination mit der Region „South“ existiert. Sollte beim Aufbereiten der Dimension eine weitere Kombination von „Madrid“ mit einer anderen Region wie z.B. „North“ gefunden werden, bricht der Cube den Aufbereitungsprozess mit Fehler ab.
Relationships für das Beispiel:
Figure 16 - List of Attributes
Figure 16 - List of Attributes
Transitive Relationships. Durch die geänderten Relationships ergeben sich weitere Verhaltensweisen: Attribute-Relationships sind transitiv. Beispiel: wenn auf der linken Seite der Relationship „Customer -> City“ der Member [Customer].[John] selektiert wird, ergibt sich nicht nur auf der rechten Seit [City].[Madrid], sondern die transitive Natur der Relationships sorgt zusätzlich dafür, dass auch die nächsten Relationships „City -> Region“ und „City -> Country“ gesteuert werden. Also ergeben sich für [Customer].[John] in direkter Weise [City].[Madrid] und in indirekter Weise [Region].[South] und [Country].[Spain].
Member als Pointer. Die vom Cube-Entwickler definierte Hierarchie mit mehreren Ebenen stellt technisch einen Haufen von Pointern auf die zu Grunde liegen Attribute dar. Der Member [John] aus der Hierarchie [dCustomer].[hCustomer] ist letztlich ein Pointer auf den Member [John] aus der Hierarchie [dCustomer].[Customer]. Im Hintergrund sorgen die Relationships für eine Art „Synchronisierung“ der Pointer.
Das nachfolgende Beispiel zeigt eine Iteration über die Members von [hCustomer]. Im Rahmen der Iteration werden mittels Attribute-Relationship die CurrentMember aller involvierten Hierarchieen modifiziert. Die Iteration schließt alle Member der Hierarchy [hCustomer] ein, also Member auf den Levels "Region", "City" und "Customer". Für Member auf dem Level „Customer“ ergibt sich eine vollständige „Information“ bezüglich [City], [Region] und [Country]. Die Member dieses Levels wie z.B. „Karen“ befinden sich auf der „linkesten“ Seite der Relationships. Durch Transitivität werden alle Hierarchieen und deren CurrentMember der rechten Seite erreicht. Bei Membern des „City“-Levels wie z.B. [Prague] ergibt sich eine unvollständige „Information“. Oder anders ausgedrückt: [Customer].CurrentMember wurde nicht geändert, sondern bleibt [ALL]. Der Grund hierfür ist, dass [City] sich auf der rechten Seite der Relationship befindet und [Customer] auf der linken. Das Modifizieren eines CurrentMembers wirkt aber nur von links nach rechts.
Figure 17 - Synchronizing Member Pointers
Figure 17 - Synchronizing Member Pointers

6. AutoExist

Die Frage, ob ein bestimmtes Tupel "existiert", kann aus der Sicht eines Anwenders auf zweiterlei Arten definiert werden:
1. Tupels existieren dann, wenn es einen Wert gibt. Beispielsweise könnte sich für das Tupel ( [East], [2010] ) ein [Amount] von NULL ergeben. Der fachliche Grund könnte sein, dass es Kunden in der Region „East“ erst ab dem Jahr 2018 gab. Nach dieser Regel gibt es das Tupel also nicht. Technisch drückt sich Existenz und Nicht-Existenz bei dieser Regel durch entsprechende existierende oder nicht-existierende Faktenzeilen aus.
2. Tupels existieren dann, wenn das Dimensions-Schema eine Kombination der entsprechenden Member erlaubt. Beispielsweise könnte die Kombination von [Madrid] mit [South] erlaubt sein, weil das Schema eine N:1-Relationship zwischen [City] und [Region] festlegt. Das Tupel ([Madrid], [South]) wäre in diesem Sinne auch dann gültig, wenn der dazugehörige [Amount] NULL ist.
„AutoExist“ ist eine Verhaltensweise der Vertipaq-Engine. Hiermit werden Tupels unterdrückt, die nicht „existieren“ und zwar im Sinne der 2ten Regel. Es werden solche Tupels automatisch ausgeschlossen, deren Existenz auf Grund des Schemas nicht möglich ist. AutoExist wirkt sich auf verschiedenste Konstellationen aus. Am meisten offensichtlich ist die einschränkende Wirkung beim CrossJoin.
Nachfolgend zwei Beispiele. Im ersten Beispiel wird ein CrossJoin zwischen [Region] und [Year] durchgeführt. Da sich beide Hierarchieen in verschiedenen Dimensionen befinden, kann AutoExist keine Einschränkung vornehmen.
In zweiten Beispiel wird ein CrossJoin zwischen [Region] und [City] durchgeführt. In diesem Fall entfaltet AutoExist eine einschränkende Wirkung.
Beispiel 1: [Region] CrossJoin [Year]. Das vollständige kartesische Produkt wird gebildet.
Figure 18 - AutoExist - No Restriction
Figure 18 - AutoExist - No Restriction
Beispiel 2. [Region] CrossJoin [City]. Kein vollständiges kartesisches Produkt. Jede Region taucht nur einmal im Ergebnis auf:
Figure 19 - Restriction by AutoExist
Figure 19 - Restriction by AutoExist