Übung 4 · Contract-first entwerfen
Ein abgeleitetes Datenprodukt entwerfen, bevor du eine Zeile SQL schreibst.
Ein abgeleitetes Datenprodukt entwerfen, bevor du eine Zeile SQL schreibst.
Das Einkaufsteam will wissen, wie oft jede SKU pro Jahr gekauft wird, um bessere Konditionen mit Lieferanten auszuhandeln. Dafür baust du ein neues Datenprodukt auf Orders auf: SKU Sales.
Diesmal arbeitest du contract-first: Du entwirfst Datenkontrakt und Datenproduktbeschreibung, bevor du SQL schreibst. Der Kontrakt ist die Spezifikation. Implementiert wird er in der nächsten Übung.
Lege einen neuen Kontrakt an und öffne ihn im Editor. Bestätige, wenn die CLI fragt, ob die Datei angelegt werden soll.
datacontract edit sku_sales_per_year.odcs.yamlFile 'sku_sales_per_year.odcs.yaml' does not exist. Initialize a new data contract? [y/N]: y
📄 data contract written to sku_sales_per_year.odcs.yaml
Editing: /Users/you/learn.datacontract.com/sku_sales_per_year.odcs.yaml
Data Contract Editor running at http://localhost:4243
Press Ctrl+C to stopSetze die Grunddaten:
| Feld | Wert |
|---|---|
| Name | SKU Sales per Year |
| ID | sku_sales_per_year |
| Version | 1.0.0 |
| Status | draft |
Die View liegt in einem neuen Schema analytics in derselben Datenbank. Füge einen Server hinzu:
| Feld | Wert |
|---|---|
| Server | postgres |
| Type | postgres |
| Host | localhost |
| Port | 5433 |
| Database | workshop |
| Schema | analytics |
Füge ein Schema sku_sales_per_year hinzu, setze Advanced Metadata → Physical Type auf VIEW und lege diese Properties an:
| Property | Logical Type | Physical Type | Bedeutung |
|---|---|---|---|
sku | string | TEXT | Die Produkt-SKU |
year | integer | INTEGER | Jahr der Bestellung |
order_count | integer | BIGINT | In wie vielen Bestellungen die SKU vorkam |
total_quantity | integer | BIGINT | Insgesamt gekaufte Stückzahl |
Schreib die Bedeutung in die Description jeder Property. Genau das liest das Einkaufsteam.
Das Schema sagt, welche Spalten es gibt. Quality Checks sagen, was über sie wahr sein muss. Ergänze Checks wie:
sku und year ist eindeutigtotal_quantity ist nie kleiner als order_countNutze „fehlerhafte Zeilen zählen, null erwarten“, wie in Übung 1:
quality:
- type: sql
description: Ensure total_quantity is at least order_count
query: SELECT COUNT(*) FROM analytics.sku_sales_per_year WHERE total_quantity < order_count;
mustBe: 0Mit ODCS 3.2 legst du per semanticType fest, welche Rolle eine Property spielt.
Öffne im Editor unter Schemas eine Property und setze Semantic Type und Transform Logic, oder bearbeite das YAML:
properties:
- name: sku
semanticType: dimension
- name: year
semanticType: dimension
- name: order_count
semanticType: measure
transformLogic: COUNT(*)
- name: total_quantity
semanticType: measure
transformLogic: SUM(line_items.quantity)Analysten werden KI-Assistenten zu diesem Datenprodukt befragen. Sag ihnen mit einem context-Block, wie es zu nutzen ist (neu in ODCS 3.2, siehe Übung 1).
Öffne im Editor Context in der Navigation:
context:
instructions: >-
One row per SKU and year. Sum order_count or total_quantity across years for totals.
verifiedStatements:
- question: Which three SKUs sold the most units in 2024?
answer: SELECT sku, total_quantity FROM analytics.sku_sales_per_year WHERE year = 2024 ORDER BY total_quantity DESC LIMIT 3;Das Verified Statement ist eine Frage mit geprüfter Antwort. Du kontrollierst sie, sobald die View existiert.
Speichere und führe die Tests aus:
datacontract test sku_sales_per_year.odcs.yamlTesting sku_sales_per_year.odcs.yaml
Server: postgres (type=postgres, host=localhost, port=5433, database=workshop, schema=analytics)
╭────────┬────────────────────────────────────┬────────────────┬───────────────────────────────────╮
│ Result │ Check │ Field │ Details │
├────────┼────────────────────────────────────┼────────────────┼───────────────────────────────────┤
│ failed │ Ensure the view has data │ │ Could not read model │
│ │ │ │ 'sku_sales_per_year': │
│ │ │ │ sku_sales_per_year │
│ failed │ Check that field 'order_count' is │ order_count │ Could not read model │
│ │ present │ │ 'sku_sales_per_year': │
│ │ │ │ sku_sales_per_year │
…
╰────────┴────────────────────────────────────┴────────────────┴───────────────────────────────────╯
🔴 data contract is invalid, found the following errors:
1) 15 checks on sku, year, order_count, total_quantity: Could not read model 'sku_sales_per_year':
sku_sales_per_yearDie Tests schlagen fehl, natürlich: Es ist noch nichts implementiert. Genau darum geht es. Das Einkaufsteam kann die Schnittstelle schon prüfen, während du die Tests in der nächsten Übung grün machst.
Lege sku_sales_per_year.odps.yaml an, mit derselben Struktur wie in Übung 3:
| Feld | Wert |
|---|---|
id | sku_sales |
name | SKU Sales |
version | 1.0.0 |
status | draft |
domain | ecommerce |
Ergänze eine description mit purpose sowie team und support für das Purchasing-Analytics-Team (z. B. purchasing_analytics_team).
Das Produkt bietet einen Output-Port an, beschrieben durch deinen neuen Kontrakt:
outputPorts:
- name: sku_sales_per_year
description: Aggregated SKU sales per year as a PostgreSQL view
version: 1.0.0
contractId: sku_sales_per_yearDeklariere, auf welchen Daten (und Garantien) dein Produkt aufbaut. Du konsumierst orders_v2, denn nur v2 hat quantity:
inputPorts:
- name: orders
version: 2.0.0
contractId: orders_v2Validiere gegen den ODPS-Standard:
dataproduct lint sku_sales_per_year.odps.yaml✅ Data product is valid against ODPS v1.1.0
🟢 Data product is valid.