Die Idee ist, dass Sie sich keine Gedanken mehr über die zugrunde liegende Technologie machen müssen, „Analysieren Sie einfach.“ Das ist die übliche Tonhöhe — und obwohl sie mehr oder weniger wahr ist, ist die Realität nuancierter.
Wo das Modell seine Risse zeigt
So mächtig das dimensionale Modell auch ist, es weist Mängel auf. Ein triviales, aber übliches ist das Berechnung eines gewichteten Durchschnitts.
- MDX unterstützt technisch gewichtete Durchschnittswerte, allerdings nur auf der Grundlage von Dimensionselementen, nicht auf Zeilenebene.
- Die Leistung verschlechtert sich, wenn im Durchschnitt Hunderttausende (oder sogar Millionen) von Objekten verarbeitet werden.
- Standardmäßig verarbeitet MDX Summen, Anzahlen und Durchschnittswerte, aber keine zeilenbasierten gewichteten Durchschnittswerte.
Die übliche Problemumgehung:
- Fügen Sie eine berechnete Spalte auf Zeilenebene hinzu (Wert × Gewicht)
Das multidimensionale Modell, dargestellt durch MDX, bietet Endbenutzern eine sehr bequeme Möglichkeit, Daten abzufragen. Sobald das Modell erstellt ist, können Benutzer Felder einfach per Drag-and-Drop verschieben und die Engine die Berechnungen durchführen lassen.
- Wenn das Modell aggregiert, dividieren Sie die summierten Produkte durch das Gesamtgewicht.
Das funktioniert, aber es ist klobig, fehleranfällig und bläht das Modell auf.
Und das ist nur der einfacher Fall. Reale Anforderungen benötigen oft eine Logik, die nicht gut mit dem OLAP zusammenpasst „Erst aggregieren, später berechnen“ philosophie.
Komplexere Szenarien
1. Umrechnungen von Devisen (FX)
Finanztransaktionen, die in mehreren Währungen aufgezeichnet wurden, erfordern Konvertierung auf Zeilenebene vor der Aggregation.
- Wenn Sie EUR-Transaktionen summieren und dann zum Zeitpunkt der Abfrage einen „durchschnittlichen“ Wechselkurs anwenden, sind die Ergebnisse falsch.
- Für die Genauigkeit muss zuerst der richtige Tageskurs pro Zeile angewendet und dann aggregiert werden.
2. Zeitabhängige Anpassungen
Werte müssen häufig durch Faktoren angepasst werden, die sich im Laufe der Zeit ändern:
- Regulatorische Koeffizienten
- Inflationsfaktoren
- Produktspezifische Multiplikatoren
Wenn sie auf aggregierter Ebene angewendet werden, sind die Ergebnisse verzerrt. Jede Zeile muss vor dem Rollup mit ihrem Faktor multipliziert werden.
3. Immobilienverwaltung (Kundenfall)
Ein anderer zeitabhängiges Szenario ist, wenn Werte für alle Daten zwischen einem bestimmten Startdatum und Enddatum gültig sind.
Ein Kunde aus der realen Welt hat Mietdaten in einem Delta-Modell gespeichert: Nur Änderungen (Mieterhöhung, Änderung der Heizkosten usw.) wurden gespeichert.
Bei der Berichterstattung sind jedoch monatliche Beträge erforderlich. Aktuelle Problemumgehungen:
- Vorab berechnen volle Werte für jeden Monat (enorme Speicherkosten).
- Benutzerdefinierte Java-MDX-Funktion mit icCube-Vektoren (chaotische, knifflige Nullbehandlung).
Beides sind Kompromisse. Was benötigt wird, ist Aggregation auf Zeilenebene direkt im Modell.
Die Lösung: MDX++ trifft Tabular
Version 9 führt eine Funktion ein, mit der Benutzer ein Objekt definieren können, das Daten zeilenweise aggregiert, indem die in der Faktentabelle einer Maßgruppen definierten Spalten verwendet werden.
- Aggregationen sind definiert in Java-Code.
- Kompiliert und optimiert wie die interne Engine von icCube.
- Keine aufgeblähten Modelle oder Vorverarbeitung mehr.
Jetzt können Sie die Logik auf Zeilenebene innerhalb des tabellarischen Modells selbst definieren. Die Engine führt die Aggregation automatisch durch.
Praktische Ergebnisse
- Gewichtete Durchschnittswerte → Der Motor verwaltet intern Wert × Gewicht + Gewicht→ jedes Mal das richtige Verhältnis.
- FX-Konvertierungen → Betrag jeder Zeile × täglicher Wechselkurs, der auf Zeilenebene angewendet wird → genaue Summen.
- Zeitbasierte Anpassungen → Pro Zeile angewendete Multiplikatoren → konsistente Ergebnisse im Laufe der Zeit.
- Verwaltung von Immobilien → Delta-basierter Speicher wird ohne Speicherüberflutung zu monatlichen Werten.
Hinzufügen eines Tabellenaggregators
Diese Funktion ist immer noch Alpha, also brauchst du ein bisschen Java-Code.
Schritt 1: Klasse mit gewichtetem Durchschnitt erstellen
public class WeightedAverage implements IOlapFactTableAggregatorFactory {
@Override
public IOlapFactTableAggregator newInstance() {
return new IOlapFactTableAggregator() {
int weightIdx;
int valueIdx;
double weightedSum = 0;
double weight = 0;
@Override
public String getName() {
return "WeightedAverage";
}
@Override
public void init(IFactTableContext namesToArrayPosition, String measureName, String factColumnName) {
weightedSum = weight = 0;
weightIdx = namesToArrayPosition.getFromColumnName("weight");
valueIdx = namesToArrayPosition.getFromColumnName("amount");
}
@Override
public boolean onRow(int rowNumber, IOlapFactsTableRow row) {
final double w = row.getAsDouble(weightIdx);
weight += w;
weightedSum += w * row.getAsDouble(valueIdx);
return true;
}
@Override
public OlapScalarEntity asScalarEntity() {
return weight == 0
? null
: new OlapNumericEntity(weightedSum / weight);
}
};
}
}
Schritt 2: Klasse hinzufügen plugin.xml
<tableAggregator name="WeightedAverage" className="com.myamazing.WeightedAverage"/>
Schritt 3: Aggregation in MDX überschreiben
CREATE SET_TABLE_AGGREGATOR [Measures].[Weighted Amount] ‘WeightedAverage’
Ergebnis
Analysten profitieren immer noch von der Einfachheit per Drag-and-Drop — allerdings mit Berechnungen, die Respekt zollen Datenkomplexität in der realen Welt.
- Keine Abkürzungen mehr, die „gut genug“ sind.
- Nur genaue Zahlen, jedes Mal.
Die Zukunft
- Fügen Sie die Möglichkeit hinzu, die Klasse direkt im Schema zu definieren.
- Erweitern Sie die Sprache, um Syntax wie die folgende zu ermöglichen:
MEASURE [Weighted Amount] AS
AGGREGATE ROWS SUM([amount] * [weight]) / SUM([weight])
Dieser Blog wurde mit Hilfe einer KI geschrieben. Dabei wurde keine KI geschädigt (nur ein paar CPUs sind überhitzt).