YamlJdbc Treiber

Einleitung

Der YamlJdbc Treiber erlaubt es, YAML-Dateien über Jdbc zu lesen. Mit Hilfe von SQL-Abfragen können damit Daten aus einer YAML-Datei genauso wie aus einer Datenbanktabelle extrahiert und weiterverarbeitet werden.

Zur Abfrage werden Sequenzen (Listen) in einem YAML-Dokument als Tabellen angesprochen. Dazu verwendet man drei Komponenten in der Abfrage:

  • als Datenbank wird eine Dummyverbindung 'jdbc:yaml:' verwendet
  • das Schema ist eine YAML-Datei (in der FROM Klausel)
  • die Tabelle ist ein ein Pfad-Ausdruck mit Punkt-Notation (in der FROM Klausel), der zu YAML-Sequenzen führt, die als Zeilen behandelt werden
  • die Spalten sind Schlüssel innerhalb der Mapping-Elemente (Dictionary/Map) in der Sequenz

Das folgende YAML-Dokument kann man zum Beispiel mit Hilfe des Treibers einlesen:

people:
  - id: 10
    profession: scientist
    fname: Henry
    lname: Cavendish
  - id: 21
    profession: scientist
    fname: Isaac
    lname: Newton
  - id: 33
    profession: scientist
    fname: Doctor
    lname: Seltsam

Eine SQL-Abfrage über den YamlJdbc Treiber sieht dann so aus:

SELECT fname
    , lname
    , profession
FROM "yamljdbc/src/test/resources/de/softquadrat/jdbc/yaml/people.yaml"."people"
COLUMNS(fname, lname, profession)

Dabei wird der Dateiname "yamljdbc/src/test/resources/de/softquadrat/jdbc/yaml/people.yaml" als Schema angegeben und "people" ist ein Pfad-Ausdruck, der zu der "people" Sequenz im Dokument führt.

Innerhalb der "people" Sequenz werden mit "fname", "lname" und "profession" die Schlüssel der Mapping-Elemente angesprochen.

Das Ergebnis sieht dann so aus:

fname  lname     profession
------ --------- ----------
Henry  Cavendish scientist
Isaac  Newton    scientist
Doctor Seltsam   scientist

Aliase

Wie gewohnt können Spaltenaliase vergeben werden, um die Spaltennamen umzubenennen:

SELECT fname AS vorname
    , lname AS nachname
    , profession AS beruf
FROM "yamljdbc/src/test/resources/de/softquadrat/jdbc/yaml/people.yaml"."people"
COLUMNS(fname, lname, profession)

Das liefert dann:

vorname nachname beruf
------- --------- ---------
Henry   Cavendish scientist
Isaac   Newton    scientist
Doctor   Seltsam   scientist

Pseudo-Spalten

Neben den Datenspalten aus dem YAML-Dokument generiert der YamlJdbc Treiber zusätzliche Pseudospalten:

  • rownumber
  • $id
  • $parentid
SELECT rownumber AS rownum
    , "$id" AS zeilen_id
    , fname
    , lname
    , profession
FROM "yamljdbc/src/test/resources/de/softquadrat/jdbc/yaml/people.yaml"."people"
COLUMNS(fname, lname, profession)

Die Pseudospalte "rownumber" liefert eine fortlaufende Nummer für jeden Datensatz des Ergebnisses. Die Pseudospalte "$id" liefert eine fortlaufende Nummer für das Element im Dokument (beginnend bei 0). Das Ergebnis der Beispielabfrage sieht so aus:

rownum zeilen_id fname  lname     profession
------ --------- ------ --------- ----------
1      0         Henry  Cavendish scientist
2      1         Isaac  Newton    scientist
3      2         Doctor Seltsam   scientist

Hinweis: Es gibt weiterhin noch die Pseudospalte "$parentid". Sie liefert den Pfad des darüberliegenden Elements, dazu mehr im nächsten Abschnitt.

Verschachtelte Strukturen und Hierarchien

Ein Element in einem YAML-Dokument kann weitere verschachtelte Strukturen enthalten wie in dem folgenden Beispiel:

people:
  - id: 10
    profession: scientist
    fname: Henry
    lname: Cavendish
    research:
      - area: Chemistry
      - area: Density of the Earth
      - area: Electricity
  - id: 21
    profession: scientist
    fname: Isaac
    lname: Newton
    research:
      - area: Calculus
      - area: Optics
      - area: Gravity

Verschachtelte Strukturen - Zwei Möglichkeiten

Verschachtelte Strukturen können auf zwei Arten gelesen werden:

Option 1. Punkt-Notation für direkte Navigation

Bei einfachen verschachtelten Strukturen kann die Punkt-Notation verwendet werden:

company:
  name: Acme Corp
  employees:
    - name: John Doe
      department: IT
      salary: 75000
    - name: Jane Smith
      department: HR
      salary: 65000
SELECT name, department, salary
FROM "employees.yaml"."company.employees"
COLUMNS(name, department, salary)

Die Punkt-Notation "company.employees" navigiert durch die verschachtelte Struktur direkt zu der "employees" Sequenz.

Das liefert:

name       department salary
---------- ---------- ------
John Doe   IT         75000
Jane Smith HR         65000

Das ist das einfachste Verfahren, allerdings fehlt bei diesem Ansatz der Bezug zu den übergeordneten Elementen.

Option 2. Komma-separierte Hierarchie-Navigation

Der YamlJdbc Treiber unterstützt auch komma-separierte Navigation, ähnlich wie der JsonJdbc und XmlJdbc Treiber. Dies ist besonders nützlich bei verschachtelten Listen:

SELECT area
FROM "yamljdbc/src/test/resources/de/softquadrat/jdbc/yaml/researcher.yaml"."people,research"
COLUMNS(area)

Hier navigiert "people" zum ersten Hierarchie-Level (Liste der Personen) und "research" (nach dem Komma) zum zweiten Level relativ zu jedem gefundenen "people" Element.

Das liefert alle "research" Einträge aller Personen:

area
--------------------
Chemistry
Density of the Earth
Electricity
Calculus
Optics
Gravity

Mit der Pseudospalte "$parentid" können Sie die Zugehörigkeit sehen:

SELECT "$parentid", area
FROM "yamljdbc/src/test/resources/de/softquadrat/jdbc/yaml/researcher.yaml"."people,research"
COLUMNS(area)

Das liefert:

$parentid area
--------- --------------------
0         Chemistry
0         Density of the Earth
0         Electricity
1         Calculus
1         Optics
1         Gravity

Die "$parentid" zeigt, zu welchem "people" Element die "research" Einträge gehören (0 = erstes Element, 1 = zweites Element, usw.).

Korrelation mit Eltern-Elementen

Die Pseudospalte "$parentid" ermöglicht die Korrelation zwischen verschachtelten Elementen und ihren Eltern-Elementen.

Best Practice für verschachtelte Hierarchien:

  1. Erste Abfrage - Lesen Sie die Eltern-Elemente und speichern Sie die "$id" Pseudospalte als Primärschlüssel:
    SELECT "$id", fname, lname
    FROM "researcher.yaml"."people"
    COLUMNS(fname, lname)

Das liefert:

$id fname  lname
--- ------ ---------
0   Henry  Cavendish
1   Isaac  Newton
  1. Zweite Abfrage - Lesen Sie die Kind-Elemente mit komma-separierter Navigation:
    SELECT "$parentid", area
    FROM "researcher.yaml"."people,research"
    COLUMNS(area)

Das liefert:

$parentid area
--------- --------------------
0         Chemistry
0         Density of the Earth
0         Electricity
1         Calculus
1         Optics
1         Gravity
  1. Verknüpfung - Die "$parentid" aus der zweiten Abfrage entspricht der "$id" aus der ersten Abfrage, so können Sie die Datensätze in Ihrer Datenbank korrekt verknüpfen.

Unterschied zwischen Punkt-Notation und Komma-Separierung

Punkt-Notation (company.employees):

  • Navigiert durch die Struktur zu einer bestimmten verschachtelten Sequenz
  • Ideal für direkte Pfade zu den gewünschten Daten
  • Keine Hierarchie-Informationen verfügbar

Komma-Separierung (people,research):

  • Navigiert durch mehrere Hierarchie-Ebenen
  • Liefert Hierarchie-Informationen über "$parentid"
  • Jedes Komma startet eine neue Ebene relativ zur vorherigen

Beispiel des Unterschieds:

data:
  level1:
    - item: A
      level2:
        - value: 1
        - value: 2
-- Punkt-Notation: Direkt zu level2 (wenn Sie die Hierarchie nicht brauchen)
FROM "file.yaml"."data.level1.level2"

-- Komma-Separierung: Erhält Hierarchie-Information
FROM "file.yaml"."data.level1,level2"

Systemtabellen

Der YamlJdbc Treiber unterstützt Verzeichnisse als Systemtabellen. Das erlaubt in einer Loop-Query eines datasqill Moduls nach Dateien in einem Verzeichnis zu suchen, die dann anschließend geladen werden können.

Die folgende Abfrage benutzt die Funktion "files()" als Systemtabelle und ihre Spalten "directory" und "filename".

SELECT directory, filename
    FROM "yamljdbc/src/test/resources/de/softquadrat/jdbc/yaml".files()
    WHERE filename LIKE '%.yaml'
    ORDER BY filename

Als Ergebnis werden die gesuchten Dateien in dem verwendeten Verzeichnis zurückgeliefert:

directory                                           filename
--------------------------------------------------- --------------
yamljdbc/src/test/resources/de/softquadrat/jdbc/yaml books.yaml
yamljdbc/src/test/resources/de/softquadrat/jdbc/yaml employees.yaml
yamljdbc/src/test/resources/de/softquadrat/jdbc/yaml people.yaml
yamljdbc/src/test/resources/de/softquadrat/jdbc/yaml researcher.yaml

Anmerkungen

Datentypen

Der YamlJdbc Treiber liefert alle Ergebnisse als Text zurück. Eine Umwandlung in andere Datentypen muss in nachgelagerten Arbeitsschritten erfolgen.

YAML unterstützt verschiedene Datentypen (Strings, Numbers, Booleans, null), aber der Treiber konvertiert alle Werte in Strings für die JDBC-Ausgabe.

Leeres Ergebnis

Sollte eine Abfrage keine Datensätze zurückgeben, so ist zu prüfen, ob der Pfad-Ausdruck in der FROM-Klausel tatsächlich zu einer YAML-Sequenz navigiert. Ist dies nicht der Fall, ignoriert der YamlJdbc Treiber die Abfrage und gibt keine Ergebnisse zurück.

Null-Werte

Der YamlJdbc Treiber liefert für selektierte Spalten in der SELECT-Klausel deren Inhalt zurück. Ist der angesprochene Schlüssel nicht vorhanden, wird ein Null-Wert zurückgegeben.

items:
  - id: 1
    name: Test1
  - id: 2
    # name fehlt
SELECT id
    , name
    , description
FROM "test.yaml"."items"
COLUMNS(id, name, description)
id name  description
-- ----- -----------
1  Test1 null
2  null  null

YAML-Anker und -Aliase

Der YamlJdbc Treiber unterstützt aktuell keine YAML-Anker (&) und -Aliase (*). Diese werden vom YAML-Parser (SnakeYAML) aufgelöst, bevor die Daten verarbeitet werden.

Komplexe Strukturen

Wenn ein Wert selbst eine komplexe Struktur (verschachteltes Mapping oder Sequenz) ist, wird er als String-Repräsentation zurückgegeben:

items:
  - id: 1
    name: Test
    config:
      setting1: value1
      setting2: value2
SELECT id, name, config
FROM "test.yaml"."items"
COLUMNS(id, name, config)

Das "config" Feld wird als String-Repräsentation des verschachtelten Objekts zurückgegeben (z.B. {setting1=value1, setting2=value2}).

YAML-Formate

Der YamlJdbc Treiber unterstützt verschiedene YAML-Formate:

Sequenz am Root-Level:

- id: 1
  name: Item 1
- id: 2
  name: Item 2

Verwendung: FROM "file.yaml"."/"

Benannte Sequenz:

items:
  - id: 1
    name: Item 1
  - id: 2
    name: Item 2

Verwendung: FROM "file.yaml"."items"

Einzelnes Mapping als Sequenz: Der Treiber behandelt auch ein einzelnes Mapping-Element als einzeilige Sequenz:

person:
  id: 1
  name: John

Verwendung: FROM "file.yaml"."person"

Dies gibt eine einzelne Zeile zurück.

Technische Details

Implementierung

Der YamlJdbc Treiber nutzt:

  • SnakeYAML (Version 1.28) für YAML-Parsing
  • In-Memory-Verarbeitung für schnellen Zugriff
  • Rekursive Navigation für verschachtelte Strukturen

Performance-Optimierung

Für optimale Performance bei großen YAML-Dateien:

  • Verwenden Sie möglichst spezifische Pfad-Ausdrücke in der FROM-Klausel
  • Begrenzen Sie die Anzahl der Spalten in der COLUMNS-Klausel auf das Notwendige
  • Nutzen Sie WHERE-Klauseln zur Filterung wenn möglich
  • Beachten Sie, dass das gesamte YAML-Dokument in den Speicher geladen wird

Praktische Richtlinien für Dokumentgrößen

Da YAML-Dateien vollständig in den Speicher geladen werden:

  • < 10 MB: Kein Problem, sehr schnelle Verarbeitung
  • 10 MB - 50 MB: Funktioniert gut, normale Performance
  • 50 MB - 200 MB: Funktioniert, aber achten Sie auf verfügbaren Heap-Speicher
  • > 200 MB: Kann zu Speicherproblemen führen, erwägen Sie Alternativen (z.B. Aufteilen der Datei)

Hinweis: YAML ist für kleinere Konfigurationsdateien optimiert. Für sehr große Datenmengen sind Formate wie JSON oder CSV effizienter.

Zeichensätze

Der YamlJdbc Treiber verwendet UTF-8 als Standard-Zeichensatz zum Lesen von YAML-Dateien. Dies ist der empfohlene Standard für YAML-Dokumente.

Beispiele

Beispiel 1: Bücherliste

books:
  - id: 1
    category: fiction
    title: The Great Gatsby
    author: F. Scott Fitzgerald
    year: 1925
    price: 10.99
  - id: 2
    category: fiction
    title: To Kill a Mockingbird
    author: Harper Lee
    year: 1960
    price: 12.99
SELECT category, title, author, year, price
FROM "books.yaml"."books"
COLUMNS(category, title, author, year, price)
WHERE category = 'fiction'

Beispiel 2: Verschachtelte Mitarbeiter-Struktur

company:
  name: Acme Corp
  departments:
    - name: IT
      employees:
        - name: John Doe
          salary: 75000
        - name: Jane Smith
          salary: 80000
    - name: HR
      employees:
        - name: Bob Johnson
          salary: 65000
-- Alle Mitarbeiter mit Department-Info
SELECT "$parentid" AS dept_id, name, salary
FROM "company.yaml"."company.departments,employees"
COLUMNS(name, salary)

Beispiel 3: Konfigurationsdaten

servers:
  - hostname: web01
    ip: 192.168.1.10
    role: webserver
    active: true
  - hostname: db01
    ip: 192.168.1.20
    role: database
    active: true
  - hostname: backup01
    ip: 192.168.1.30
    role: backup
    active: false
SELECT hostname, ip, role
FROM "servers.yaml"."servers"
COLUMNS(hostname, ip, role, active)
WHERE active = 'true'

Zusammenfassung

Der YamlJdbc Treiber bietet eine einfache und intuitive Möglichkeit, YAML-Dateien über SQL-Abfragen zu lesen:

  • ✅ Einfache Punkt-Notation für Navigation
  • ✅ Komma-separierte Hierarchie-Navigation wie bei JSON und XML
  • ✅ Systemtabellen für Datei-Listings
  • ✅ Pseudo-Spalten für Hierarchie-Informationen
  • ✅ Vollständig kompatibel mit datasqill-Modulen
  • ✅ Gleiche Syntax-Patterns wie JsonJdbc und XmlJdbc

Der Treiber eignet sich besonders für:

  • Konfigurationsdateien
  • Test-Daten
  • Kleine bis mittelgroße Datensätze (< 50 MB)
  • Strukturierte Daten mit klaren Hierarchien