Header Background
 
 
 
Verstecken sich die Risiken in deinen Daten oder in den Verbindungen dazwischen? 
Bei der Aufdeckung von Geldwäsche und Sanktionsumgehungen stoßen relationale JOINs schnell an ihre Performance-Grenzen. Unser neuer Blogbeitrag zeigt, wie Graph-Datenbanken wie Neo4j komplexe Multi-Hop-Beziehungen in konstanter Zeit analysieren.
Inklusive praxisnahem Python-Beispiel („Operation Silicon Shield“) zum Herunterladen und Ausprobieren!

Sanktionsverstöße, Geldwäsche und Finanzbetrug aufspüren mit Neo4j

Wie Graph-Datenbanken dort brillieren, wo SQL und NoSQL aufhören zu funktionieren — mit einem vollständigen Python-Beispiel.

Dies ist ein Beitrag unseres Gastautors LinkedIn Profil von: Andrey Bulezyuk Andrey Bulezyuk
Den vollständigen Artikel inkl. der Sourcen finden Sie auf github Andrey Bulezyuk

Warum Graphen? Das Problem mit relationalen Daten

Betrug, Geldwäsche und Sanktionsumgehung haben eines gemeinsam: Sie verstecken sich in den Verbindungen zwischen Entitäten, nicht in den Entitäten selbst. Eine einzelne Transaktion zwischen zwei Firmen mag harmlos wirken — erst wenn man drei Schritte zurücktritt und das gesamte Netzwerk betrachtet, wird die Struktur sichtbar.

Genau hier trennen sich Graph-Datenbanken wie Neo4j fundamental von klassischen Ansätzen.

Neo4j vs. SQL vs. NoSQL — die wesentlichen Unterschiede

Relationale Datenbanken (PostgreSQL, MySQL) speichern Daten in starren Tabellen und verbinden sie über JOINs — effizient für direkte Abfragen, aber exponentiell langsamer bei tief verschachtelten Beziehungen über mehrere Ebenen. Wer in SQL herausfinden will, ob Firma A über drei Zwischenstellen mit einer sanktionierten Person verbunden ist, so wird er bei großen Datensätzen große Query Ausführungsdauer in Kauf nehmen müssen. Bei Ad-Hoc analytischen Abfragen, ist die Latenz akzeptabel. Braucht man aber eine real-time analytische Fähigkeit, so wird SQL schnell an eigene Grenzen stößen.

NoSQL-Datenbanken (MongoDB, Cassandra) lösen das Skalierungsproblem bei unstrukturierten oder hoch-volumigen Daten, sind aber nicht für relationale Traversierungen optimiert — eine Multi-Hop-Pfadsuche ist kein natives Paradigma dieser Systeme.

Neo4j hingegen speichert Knoten (Personen, Firmen, Konten) und Kanten (Transaktionen, Eigentümerschaft, Verbindungen) als native Graphstrukturen im Speicher. Ein Beziehungssprung — ob zwei oder zwanzig Ebenen tief — kostet konstante Zeit, weil die Verbindungen physikalisch als Pointer im Graphen existieren, nicht als JOINs, die zur Laufzeit berechnet werden. Das macht Neo4j für Financial Crime Analysis, Know-Your-Customer (KYC) und Sanctions Screening zur überlegenen Wahl.


Sanktionsverstöße, Geldwäsche & Finanzbetrug — Definitionen und reale Muster

Sanktionsumgehung: Wenn Dual-Use-Güter über Umwege reisen

Sanktionen sind wirtschaftliche oder rechtliche Beschränkungen, die Staaten oder internationale Organisationen gegen Länder, Unternehmen oder Personen verhängen. 2022 belegten die EU, die USA, Großbritannien und andere Staaten Russland mit umfassenden Exportrestriktionen — darunter ein striktes Verbot für sogenannte Dual-Use-Güter: Technologie, die sowohl zivil als auch militärisch genutzt werden kann. Dazu gehören FPGA-Chips, Trägheitssensoren, bestimmte Halbleiter und Drohnenkomponenten.

Investigative Berichte haben gezeigt, wie dieses Verbot systematisch umgangen wird. Das Muster ist immer ähnlich: Ein EU-Lieferant verkauft Bauteile an eine unauffällig klingende Firma in Estland, Lettland oder Deutschland. Diese Firma tritt nach außen als lokales Handelsunternehmen auf, ist aber im Eigentum sanktionierter Staatsangehöriger oder von sanktionierten Strukturen — oft über Briefkastenfirmen auf Zypern oder in anderen Offshore-Jurisdiktionen. Die Güter landen letztlich im saktionierten Gebiet.

Technisch definiert handelt es sich bei Sanktionsumgehung um das Vorhandensein eines gerichteten Pfades im Transaktionsgraphen von einer nicht-sanktionierten Quellentität zu einer sanktionierten Zielentität, wobei mindestens eine Zwischenentität als Verschleierungsschicht fungiert: (LegalSupplier)-[:TRANSFERRED_TO*1..N]->(SanctionedTarget). Je mehr Hops, desto schwerer die manuelle Erkennung — und desto mächtiger die Graph-Traversierung. Mehr Hops (Zwischen-Entitäten) auch mögliche Datenlücken, da Jurisdikationen unkooperativ agieren.

Geldwäsche: Der dreiaktige Kreislauf

Geldwäsche verfolgt das Ziel, kriminell erlangtes Geld in den legalen Finanzkreislauf einzuschleusen. Die Financial Action Task Force (FATF) beschreibt drei klassische Phasen: Placement (Einspeisung von Bargeld), Layering (Verschleierung durch komplexe Transaktionsketten) und Integration (Rückführung als scheinbar legale Einnahmen).

Das Hauptwerkzeug dabei sind Offshore-Strukturen: Eine Person einem Hochrisikoland gründet oder kauft Briefkastenfirmen auf Zypern, in den British Virgin Islands oder auf den Cayman Islands — Jurisdiktionen mit geringer Transparenzpflicht gegenüber Behörden. Diese Shells überweisen sich gegenseitig Gelder als „Beratungshonorare", „Lizenzgebühren" oder „Kapitaleinlagen", ohne zugrundeliegende wirtschaftliche Substanz. Das Layering hinterlässt eine scheinbar legitime Papierspur, die für manuelle Prüfung nahezu undurchdringlich ist. Kleinere Akteure agieren dagegen mit physischen Geschäften wie Autowäsche/Casinos oder fiktive Digital-Güter mit geringeren Besteuerung.

Technisch ist eine Geldwäschestruktur ein gerichteter Teilgraph mit zyklischen oder vielschichtigen Transferpfaden, bei dem Knotenattribute wie country auf bekannte Offshore-Jurisdiktionen hinweisen und die wirtschaftlich Berechtigten (Ultimate Beneficial Owner, UBO) — via OWNS-Kanten — risikobehaftete Personen sind, die keine direkten Verbindungen zu sanktionierten Entitäten auf der Oberfläche aufweisen, aber durch Graph-Traversierung auffindbar werden. Für kleinere Akteure dagegen ist eine detailiertere Analyse der Bilanz des Unternehmens sowie der granularen Transaktionen der Bankkonten des Unternehmens.

Offshore-Leaks: Die offene Datenbasis

Das International Consortium of Investigative Journalists (ICIJ) veröffentlicht seit den Panama Papers 2016 strukturierte Daten zu Offshore-Firmen aus Leaks wie den Pandora Papers, FinCEN Files und OpenCorporates. Die ICIJ Offshore Leaks Database ist öffentlich zugänglich und enthält Millionen von Knoten und Kanten — genau das richtige Format für eine Graphdatenbank. Ergänzend bietet OpenSanctions.org eine maschinenlesbare, täglich aktualisierte Sanktionsliste.


Das konkrete Beispiel: Operation „Silicon Shield"

Disclaimer: Alle folgenden Firmen- und Personennamen sind vollständig fiktiv und dienen ausschließlich der technischen Veranschaulichung. Sie bilden jedoch bekannte, reale Muster aus investigativen Berichten nach.

Der Sachverhalt

Stellen wir uns folgendes Szenario vor: Der deutsche Halbleiterhändler MicroSemi Europe AG verkauft FPGA-Chips — Hochleistungsprozessoren, die in der militärischen Signalelektronik eingesetzt werden — an die in Frankfurt registrierte Alpha Circuit GmbH. Diese Firma erscheint im Handelsregister unauffällig, ihr tatsächlicher Eigentümer ist jedoch der russische Staatsbürger Dmitri Volkov, der sie über eine zypriotische Holding kontrolliert. Alpha Circuit reicht die Chips über eine weitere estnische Briefkastenfirma (Nordic Bridge Trading Ltd) weiter, wo sie letztlich bei Vostok Tech LLC in Moskau landen — einem Unternehmen auf der EU-Sanktionsliste.

Parallel dazu läuft eine Geldwäschestruktur: Die ebenfalls von sanktionierten Personen kontrollierte Kyra Investments Ltd auf Zypern empfängt Millionenbeträge aus Alpha Circuit als angebliche „Beratungshonorare" und transferiert sie anschließend direkt an die sanktionierte Person Alexei Petrov.

Wie wir mit Neo4j vorgehen

Das Ziel ist, diesen Ring mit Cypher-Queries schrittweise aufzudecken:

  • Query 1 sucht nach direkten Transfers zu sanktionierten Entitäten — low-hanging fruits.
  • Query 2 analysiert die Eigentümerschaftsstrukturen: Welche EU-Firmen werden von russischen Personen kontrolliert?
  • Query 3 verbindet beide Dimensionen: Sanktionierte Personen, die über eigene Shells Geld fließen lassen.
  • Query 4 findet alle vollständigen Lieferkettenpfade vom legitimen Lieferanten bis zum sanktionierten Endempfänger — das ist der endgültige forensische Beweis für indirekte Sanktionsumgehung.

Das Schöne an Graph-Traversierung: Für jeden dieser Schritte schreiben wir in Cypher einen einzigen, lesbaren Musterabgleich — ohne Subqueries, ohne Tabellen-JOINs, ohne explizite Schleifen.


Hands-on: Neo4j mit Python und JupyterLab

Voraussetzungen

# Neo4j lokal starten (z.B. via Docker)
docker run \
  --name neo4j-sanctions \
  -p 7474:7474 -p 7687:7687 \
  -e NEO4J_AUTH=neo4j/password \
  neo4j:5.18

# Python-Abhängigkeiten installieren
mkdir neo4j-sanctions && cd neo4j-sanctions
uv init 
uv venv
source ./venv/bin/activate
uv add neo4j pandas matplotlib networkx yfiles_jupyter_graphs_for_neo4j

Notebook-Zelle 1 — Imports & Datenbankverbindung

# ─── Imports ─────────────────────────────────────────────────────────────────
from neo4j import GraphDatabase
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.patheffects as pe
from yfiles_jupyter_graphs_for_neo4j import Neo4jGraphWidget

# ─── Verbindungsparameter ─────────────────────────────────────────────────────
NEO4J_URI      = "neo4j://localhost:7687"
NEO4J_USER     = "neo4j"
NEO4J_PASSWORD = "password"   # ← euer lokales Passwort hier eintragen

driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASSWORD))
visualize_cypher = Neo4jGraphWidget(driver)

# Verbindungstest
with driver.session() as session:
    result = session.run("RETURN 'Neo4j connected ✓' AS status")
    print(result.single()["status"])

Der offizielle Neo4j Python Driver kommuniziert über das Bolt-Protokoll mit der Datenbank. GraphDatabase.driver() erzeugt einen thread-sicheren Connection-Pool — geeignet für Produktivbetrieb und Batch-Analysen gleichermaßen. Neo4jGraphWidget ist das interaktive Visualisierungs-Widget, das wir später für die Kartenansicht nutzen.


Notebook-Zelle 2 — Schema & Dataimport

Wir legen zunächst einen eindeutigen Index auf die Entitäts-IDs an — das verhindert Duplikate bei wiederholtem Import und beschleunigt Lookups erheblich. Dann importieren wir unsere fiktiven Datensätze per MERGE-Statement (idempotent, kein Duplikat bei erneutem Ausführen):

# ─── Graph leeren (Achtung: löscht ALLE Knoten & Kanten!) ────────────────────
with driver.session() as session:
    session.run("MATCH (n) DETACH DELETE n")
    print("Graph geleert.")

# ─── Eindeutige Constraints / Indizes anlegen ─────────────────────────────────
constraints = [
    "CREATE CONSTRAINT IF NOT EXISTS FOR (e:Entity) REQUIRE e.id IS UNIQUE",
    "CREATE INDEX IF NOT EXISTS FOR (e:Entity) ON (e.country)",
    "CREATE INDEX IF NOT EXISTS FOR (e:Entity) ON (e.sanctioned)",
]
with driver.session() as session:
    for c in constraints:
        session.run(c)
print("Constraints & Indizes angelegt.")
# ─── Fiktives Datensample ─────────────────────────────────────────────────────
ALL_NODES = [
    # Sanktionierte Entitäten (Russland)
    {"id": "SE001", "name": "Vostok Tech LLC",      "country": "Russia", "type": "Company", "sanctioned": True,  "location_x": 37.6176, "location_y": 55.7558},
    {"id": "SE002", "name": "Alexei Petrov",          "country": "Russia", "type": "Person",  "sanctioned": True,  "location_x": 37.6176, "location_y": 55.7558},
    {"id": "SE003", "name": "Meridian Arms Group",    "country": "Russia", "type": "Company", "sanctioned": True,  "location_x": 37.6176, "location_y": 55.7558},
    # Shell-/Briefkastenfirmen (EU)
    {"id": "SH001", "name": "Nordic Bridge Trading Ltd", "country": "Estonia",  "type": "Company", "sanctioned": False, "location_x": 25.7482, "location_y": 58.5953},
    {"id": "SH002", "name": "Alpha Circuit GmbH",         "country": "Germany",  "type": "Company", "sanctioned": False, "location_x": 10.4515, "location_y": 51.1657},
    {"id": "SH003", "name": "Baltica Trade OÜ",           "country": "Estonia",  "type": "Company", "sanctioned": False, "location_x": 25.7482, "location_y": 58.5953},
    {"id": "SH004", "name": "Nexus Components SARL",      "country": "France",   "type": "Company", "sanctioned": False, "location_x":  2.2137, "location_y": 46.2276},
    {"id": "SH005", "name": "Kyra Investments Ltd",       "country": "Cyprus",   "type": "Company", "sanctioned": False, "location_x": 33.4299, "location_y": 35.1264},
    # Wirtschaftlich Berechtigte (verdeckt)
    {"id": "BO001", "name": "Dmitri Volkov",   "country": "Russia", "type": "Person", "sanctioned": False, "location_x": 37.6176, "location_y": 55.7558},
    {"id": "BO002", "name": "Irina Sorokina",  "country": "Russia", "type": "Person", "sanctioned": False, "location_x": 37.6176, "location_y": 55.7558},
    # Legitime EU-Lieferanten
    {"id": "SUP001", "name": "MicroSemi Europe AG",  "country": "Germany",     "type": "Company", "sanctioned": False, "location_x": 10.4515, "location_y": 51.1657},
    {"id": "SUP002", "name": "DronePartsHub GmbH",   "country": "Austria",     "type": "Company", "sanctioned": False, "location_x": 14.5501, "location_y": 47.5162},
    {"id": "SUP003", "name": "AdvancedChips B.V.",   "country": "Netherlands", "type": "Company", "sanctioned": False, "location_x":  5.2913, "location_y": 52.1326},
]

TRANSACTIONS = [
    {"id": "TX001", "from": "SH001", "to": "SE001",  "amount": 480000,  "currency": "EUR", "date": "2024-03-15", "goods": "FPGA-Chips (Dual-Use)"},
    {"id": "TX002", "from": "SH002", "to": "SH001",  "amount": 510000,  "currency": "EUR", "date": "2024-02-20", "goods": "FPGA-Chips (Dual-Use)"},
    {"id": "TX003", "from": "SUP001","to": "SH002",  "amount": 490000,  "currency": "EUR", "date": "2024-01-18", "goods": "FPGA-Chips (Dual-Use)"},
    {"id": "TX004", "from": "SH003", "to": "SE003",  "amount": 270000,  "currency": "EUR", "date": "2024-04-02", "goods": "Drohnen-Komponenten"},
    {"id": "TX005", "from": "SH004", "to": "SH003",  "amount": 285000,  "currency": "EUR", "date": "2024-03-10", "goods": "Drohnen-Komponenten"},
    {"id": "TX006", "from": "SUP002","to": "SH004",  "amount": 260000,  "currency": "EUR", "date": "2024-02-28", "goods": "Drohnen-Komponenten"},
    {"id": "TX007", "from": "SH005", "to": "SE002",  "amount": 1200000, "currency": "EUR", "date": "2024-05-01", "goods": "Überweisung (Tarnung Gewinne)"},
    {"id": "TX008", "from": "SH002", "to": "SH005",  "amount": 1100000, "currency": "EUR", "date": "2024-04-10", "goods": "Beratungshonorar"},
]

OWNERSHIPS = [
    {"owner": "BO001", "company": "SH001", "share_pct": 100},
    {"owner": "BO001", "company": "SH002", "share_pct": 60},
    {"owner": "BO002", "company": "SH002", "share_pct": 40},
    {"owner": "BO002", "company": "SH003", "share_pct": 100},
    {"owner": "SE002", "company": "SH005", "share_pct": 100},  # ⚠ Risiko
    {"owner": "SE002", "company": "SH004", "share_pct": 51},
]

ASSOCIATIONS = [
    {"person": "SE002", "company": "SE001", "role": "Director"},
    {"person": "BO001", "company": "SE001", "role": "Geschäftspartner"},
    {"person": "BO002", "company": "SE003", "role": "Geschäftspartner"},
]

# ─── Cypher: Knoten & Kanten importieren ───────────────────────────────────────
with driver.session() as session:
    for node in ALL_NODES:
        label = "Person" if node["type"] == "Person" else "Company"
        cypher = f"""
            MERGE (e:Entity:{label} {{id: $id}})
            SET e.name       = $name,
                e.country    = $country,
                e.sanctioned = $sanctioned,
                e.location_x = $location_x,
                e.location_y = $location_y
        """
        session.run(cypher, **node)

    for tx in TRANSACTIONS:
        session.run("""
            MATCH (a:Entity {id: $from_id}), (b:Entity {id: $to_id})
            MERGE (a)-[r:TRANSFERRED_TO {id: $id}]->(b)
            SET r.amount   = $amount,
                r.currency = $currency,
                r.date     = $date,
                r.goods    = $goods
        """, from_id=tx["from"], to_id=tx["to"], **{k:v for k,v in tx.items() if k not in ("from","to")})

    for o in OWNERSHIPS:
        session.run("""
            MATCH (p:Entity {id: $owner}), (c:Entity {id: $company})
            MERGE (p)-[r:OWNS]->(c)
            SET r.share_pct = $share_pct
        """, **o)

    for a in ASSOCIATIONS:
        session.run("""
            MATCH (p:Entity {id: $person}), (c:Entity {id: $company})
            MERGE (p)-[r:ASSOCIATED_WITH]->(c)
            SET r.role = $role
        """, **a)

print("\n✅ Daten erfolgreich in Neo4j importiert.")

Der MERGE-Befehl ist in Cypher das Äquivalent zu INSERT OR IGNORE — sicher für wiederholten Aufruf. Das Graph-Schema ergibt sich organisch aus den Daten; kein Schema-Migration-Skript wie in SQL nötig. Die location_x/location_y-Koordinaten (Längen- und Breitengrad) werden später für die Kartenvisualisierung benötigt.

Zwischenschritt: Simple Visualisierung mit yFiles (Neo4jGraphWidget)

visualize_cypher.show_cypher("MATCH p=()-[]-() RETURN p LIMIT 50", layout="orthogonal")

Visualisierung zeigt den extrahierten Graphen direkt im Jupyter Notebook

Notebook-Zelle 3 — Query 1: Direkte Transaktionen zu sanktionierten Entitäten

# ─── Cypher Abfrage für direkte Transfers ─────────────────────────────────────
QUERY_1 = """
MATCH (sender:Entity)-[tx:TRANSFERRED_TO]->(target:Entity {sanctioned: true})
RETURN
    sender.name    AS Absender,
    sender.country AS Absender_Land,
    tx.amount      AS Betrag_EUR,
    tx.goods       AS Güter,
    tx.date        AS Datum,
    target.name    AS Empfänger
ORDER BY tx.amount DESC
"""

with driver.session() as session:
    rows = session.run(QUERY_1).data()

df_q1 = pd.DataFrame(rows)
display(df_q1)

Ergebnis:

Absender Absender_Land Betrag_EUR Güter Datum Empfänger
Kyra Investments Ltd Cyprus 1.200.000 € Überweisung (Tarnung Gewinne) 2024-05-01 Alexei Petrov
Nordic Bridge Trading Ltd Estonia 480.000 € FPGA-Chips (Dual-Use) 2024-03-15 Vostok Tech LLC
Baltica Trade OÜ Estonia 270.000 € Drohnen-Komponenten 2024-04-02 Meridian Arms Group

Drei direkte Treffer — aber die Absender selbst erscheinen unverdächtig. Ohne Eigentümerschaftsdaten ist nicht erkennbar, dass hinter Kyra Investments und Nordic Bridge dieselben russischen Akteure stecken.


Notebook-Zelle 4 — Query 2: Shell-Firmen mit russischen Eigentümern

QUERY_2 = """
MATCH (owner:Entity {country: 'Russia'})-[o:OWNS]->(shell:Entity)
WHERE shell.country <> 'Russia'
RETURN
    owner.name    AS Eigentümer,
    CASE owner.sanctioned WHEN true THEN '⚠ SANKTIONIERT' ELSE 'nicht sanktioniert' END AS Status,
    o.share_pct   AS Anteil_Pct,
    shell.name    AS Shell_Firma,
    shell.country AS Shell_Land
ORDER BY owner.sanctioned DESC, o.share_pct DESC
"""

Ergebnis:

Eigentümer Status Anteil_Pct Shell_Firma Shell_Land
Alexei Petrov ⚠ SANKTIONIERT 100 Kyra Investments Ltd Cyprus
Alexei Petrov ⚠ SANKTIONIERT 51 Nexus Components SARL France
Dmitri Volkov nicht sanktioniert 100 Nordic Bridge Trading Ltd Estonia
Irina Sorokina nicht sanktioniert 100 Baltica Trade OÜ Estonia
Dmitri Volkov nicht sanktioniert 60 Alpha Circuit GmbH Germany
Irina Sorokina nicht sanktioniert 40 Alpha Circuit GmbH Germany

Sechs EU-registrierte Firmen unter russischer Kontrolle — darunter die entscheidende Verbindung: Alexei Petrov (sanktioniert) hält 100 % an Kyra Investments Ltd (Zypern) und 51 % an Nexus Components SARL (Frankreich). Das ist die OWNS-Kante, die jeden Compliance-Alarm auslösen müsste.


Notebook-Zelle 5 — Query 3: Sanktionierte Person → Shell → Geldfluss

QUERY_3 = """
MATCH (sp:Person {sanctioned: true})
      -[:OWNS]->(shell:Entity)
      -[tx:TRANSFERRED_TO]->(target:Entity)
RETURN
    sp.name     AS Sanktionierte_Person,
    shell.name  AS Shell_Firma,
    shell.country AS Shell_Land,
    tx.amount   AS Betrag_EUR,
    tx.goods    AS Güter,
    target.name AS Empfänger,
    CASE target.sanctioned WHEN true THEN '⚠ SANKTIONIERT' ELSE 'unverdächtig' END AS Empfänger_Status
ORDER BY tx.amount DESC
"""

Ergebnis:

Sanktionierte_Person Shell_Firma Shell_Land Betrag_EUR Güter Empfänger Empfänger_Status
Alexei Petrov Kyra Investments Ltd Cyprus 1.200.000 € Überweisung (Tarnung Gewinne) Alexei Petrov ⚠ SANKTIONIERT
Alexei Petrov Nexus Components SARL France 285.000 € Drohnen-Komponenten Baltica Trade OÜ unverdächtig

Diese Query verbindet zwei Kantentypen in einem Atemzug: OWNS und TRANSFERRED_TO. In SQL wären das drei Tabellen-JOINs. In Cypher ist es ein natürliches Muster, das der tatsächlichen Struktur der Realität entspricht. Der erste Treffer ist besonders brisant: Alexei Petrov überweist sich über seine eigene Offshore-Shell letztlich selbst Geld — ein klassisches Geldwäsche-Schema.


Notebook-Zelle 6 — Query 4: Vollständige Lieferkettenpfade

QUERY_4 = """
MATCH path = (supplier:Entity)-[:TRANSFERRED_TO*1..4]->(target:Entity {sanctioned: true})
WHERE NOT supplier.sanctioned
  AND NOT EXISTS {
      MATCH (x:Entity)-[:TRANSFERRED_TO]->(supplier)
      WHERE NOT x.sanctioned = false
  }
WITH path,
     [n IN nodes(path) | n.name + ' [' + n.country + ']'] AS Stationen,
     reduce(total = 0, r IN relationships(path) | total + r.amount) AS Gesamtbetrag,
     length(path) AS Hops
RETURN Stationen, Hops, Gesamtbetrag
ORDER BY Gesamtbetrag DESC
"""

Ergebnis:

Pfad Hops Gesamtbetrag
MicroSemi Europe AG [Germany] → Alpha Circuit GmbH [Germany] → Kyra Investments Ltd [Cyprus] → Alexei Petrov [Russia] 3 2.790.000 €
Alpha Circuit GmbH [Germany] → Kyra Investments Ltd [Cyprus] → Alexei Petrov [Russia] 2 2.300.000 €
MicroSemi Europe AG [Germany] → Alpha Circuit GmbH [Germany] → Nordic Bridge Trading Ltd [Estonia] → Vostok Tech LLC [Russia] 3 1.480.000 €
Kyra Investments Ltd [Cyprus] → Alexei Petrov [Russia] 1 1.200.000 €
Alpha Circuit GmbH [Germany] → Nordic Bridge Trading Ltd [Estonia] → Vostok Tech LLC [Russia] 2 990.000 €
DronePartsHub GmbH [Austria] → Nexus Components SARL [France] → Baltica Trade OÜ [Estonia] → Meridian Arms Group [Russia] 3 815.000 €
Nexus Components SARL [France] → Baltica Trade OÜ [Estonia] → Meridian Arms Group [Russia] 2 555.000 €
Nordic Bridge Trading Ltd [Estonia] → Vostok Tech LLC [Russia] 1 480.000 €
Baltica Trade OÜ [Estonia] → Meridian Arms Group [Russia] 1 270.000 €
? 9 Sanktionsumgehungs-Pfade entdeckt!

Das Endergebnis: Neun Lieferkettenpfade werden aufgedeckt. Der gravierendste: MicroSemi Europe AG [Germany] → Alpha Circuit GmbH [Germany] → Kyra Investments Ltd [Cyprus] → Alexei Petrov [Russia] mit einem Gesamtvolumen von 2.790.000 €. Genau dieser Pfad wäre in einer normalen Transaktionsdatenbank unsichtbar — drei separate Lieferketten ohne offensichtliche Verbindung auf Tabellenebene.

Das [:TRANSFERRED_TO*1..4] in Cypher ist die elegante Syntax für „bis zu vier Hops" — Neo4j's variable-length path queries traversieren den Graphen intern ohne explizite Rekursion.


Notebook-Zelle 7 — Geographische Kartenvisualisierung

Mit yfiles_jupyter_graphs_for_neo4j lassen sich die Pfade direkt auf einer interaktiven Weltkarte darstellen. Die location_x/location_y-Koordinaten aus dem Dataimport werden als geographische Positionen verwendet — Knoten erscheinen an ihrem tatsächlichen Standort.

# Mappings & Widget aufrufen
visualize_cypher.add_node_configuration("*", coordinate=coordinate_mapping)
visualize_cypher.show_cypher(QUERY_4_MAP, layout="map")

Die geografische Visualisierung mappt die Handelsrouten über Landesgrenzen hinweg.

Notebook-Zelle 8 — Netzwerkgraph (NetworkX)

# Code zur Generierung des Matplotlib-Netzwerk-Graphen ausführen
fig, ax = plt.subplots(figsize=(16, 10), facecolor="#0d1117")
nx.draw_networkx_nodes(G, pos, node_color=colors, node_size=sizes)
# ... (vollständiges Zeichnen der Kanten und Labels)
plt.show()

Visualisierung des fiktiven Geflechts aus legalen Lieferanten, Shells und sanktionierten Entitäten.

Das erzeugte Diagramm macht den Unterschied von Graph-Denken gegenüber Tabellen-Denken auf einen Blick sichtbar: Links die legitimen EU-Lieferanten (blau), in der Mitte das Shell-Netzwerk (orange), rechts die sanktionierten russischen Endempfänger (rot). Die gestrichelten lila Linien zeigen die Eigentümerschaftsketten — die Information, die in einer klassischen Transaktionstabelle vollständig fehlen würde.


Ausblick: Was mit Graph-Datenbanken noch möglich ist — und wird

Dieses Beispiel kratzt nur an der Oberfläche. Was in professionellen Financial-Crime-Systemen bereits heute mit Neo4j und ähnlichen Graph-Engines eingesetzt wird — und wohin die Entwicklung geht:

Graph Data Science (GDS) ist das leistungsstärkste Erweiterungspaket von Neo4j. Die Neo4j Graph Data Science Library beinhaltet Algorithmen wie Community Detection (Louvain, Label Propagation) zur automatischen Ringfindung, PageRank-Varianten für Risikoanalysen und vieles mehr.

Autor: Michael Deinhard Autor

LinkedIn Profil von: Michael Deinhard Michael Deinhard

Artikel erstellt: 12.06.2026
Artikel aktualisiert: 12.06.2026

zurück zur Übersicht

 
 
 
Diese Seite weiterempfehlen:
0
Merkzettel öffnen
0
Besuchsverlauf ansehen
Feedback
IT-Schulungen.com Control Panel