🏛️ Schweizer Museen-Navigator¶
Eine Python-Anwendung mit tkinter-GUI und Neo4j-Graphdatenbank zur Verwaltung und Exploration von Schweizer Museen.
📋 Voraussetzungen¶
System-Anforderungen
- Python 3.8+ installiert
- Neo4j Desktop installiert und läuft
- Neo4j-Datenbank erstellt
🚀 Installation¶
Schritt 1: Neo4j Desktop einrichten¶
Wichtig
Neo4j Desktop muss laufen, bevor die App gestartet wird!
- Neo4j Desktop herunterladen: https://neo4j.com/download/
- Installieren und starten
- Neue Datenbank erstellen:
- Name:
museum-db(oder beliebig) - Passwort setzen (z.B.
password) - Datenbank starten (grüner Play-Button)
Schritt 2: Python-Dependencies installieren¶
Schritt 3: Passwort konfigurieren¶
Passwort anpassen
Öffne museum_app.py und ändere Zeile 20:
▶️ Anwendung starten¶
Erste Schritte¶
Workflow
- Datenbank initialisieren: Klicke auf "📥 Datenbank initialisieren"
- Importiert ~28 Museen, 15 Kantone, 6 Kategorien, 5 Personen
-
Erstellt Beziehungen zwischen den Nodes
-
Museen durchsuchen:
- Wähle Kanton und/oder Kategorie
-
Klicke "🔍 Suchen"
-
Details ansehen: Klicke auf ein Museum in der Liste
-
Statistiken: Klicke "📊 Statistik" für Top 10 Kantone
📊 Graph-Modell (Neo4j Schema)¶
Node-Labels¶
CREATE (m:Museum {
name: "Kunsthaus Zürich",
city: "Zürich",
canton: "ZH",
type: "Kunstmuseum",
founded: 1787,
url: "https://www.kunsthaus.ch"
})
Properties:
| Property | Typ | Beschreibung |
|---|---|---|
name |
String | Museumsname (unique) |
city |
String | Stadt |
canton |
String | Kanton-Kürzel |
type |
String | Museumstyp |
founded |
Integer | Gründungsjahr |
url |
String | Website-URL |
Properties:
| Property | Typ | Beschreibung |
|---|---|---|
abbr |
String | Kürzel (unique) |
name |
String | Vollständiger Name |
region |
String | Sprachregion |
population |
Integer | Einwohnerzahl |
Properties:
| Property | Typ | Beschreibung |
|---|---|---|
name |
String | Kategoriename (unique) |
description |
String | Beschreibung |
Relationship-Typen¶
graph LR
M[Museum] -->|LOCATED_IN| C[Canton]
M -->|BELONGS_TO| Cat[Category]
M -->|FEATURES| P[Person]
M -->|NEAR| M2[Museum]
style M fill:#3498db,color:#fff
style C fill:#2ecc71,color:#fff
style Cat fill:#e74c3c,color:#fff
style P fill:#f39c12,color:#fff
style M2 fill:#3498db,color:#fff
| Relationship | Von → Nach | Properties | Beschreibung |
|---|---|---|---|
LOCATED_IN |
Museum → Canton | - | Museum befindet sich in Kanton |
BELONGS_TO |
Museum → Category | - | Museum gehört zu Kategorie |
FEATURES |
Museum → Person | description |
Museum zeigt Werke der Person |
NEAR |
Museum ↔ Museum | same_canton |
Museen im selben Kanton |
Beispiel-Cypher-Queries¶
Query-Beispiele
🎯 Features¶
Implementiert ✅
- Neo4j-Verbindung mit Driver
- Datenimport (Museen, Kantone, Kategorien, Personen)
- Filter nach Kanton und Kategorie
- Detailansicht mit verknüpften Personen
- Anzeige ähnlicher Museen im selben Kanton
- Statistik: Top 10 Kantone nach Museumsanzahl
- Responsives tkinter-GUI
Noch nicht implementiert ❌
- Export-Funktion (CSV/JSON)
- Graph-Visualisierung
- Person-Detail-Ansicht
- Shortest Path zwischen Museen
📸 Für deinen Screencast¶
🎤 Frage 1: Warum Graph-DB für diesen Anwendungsfall?¶
Antwort: 3 Hauptvorteile
1. Beziehungen sind First-Class Citizens
// Neo4j: Direkt traversierbar
MATCH (m:Museum)-[:FEATURES]->(p:Person {name: "Paul Klee"})
RETURN m.name
// MongoDB: Komplexe Joins nötig
db.museums.aggregate([
{ $lookup: { from: "persons", localField: "person_ids", ... } },
{ $match: { "persons.name": "Paul Klee" } }
])
2. Flexible Queries über mehrere Hops
- "Welche Museen zeigen Künstler aus dem gleichen Kanton?"
- Neo4j: 1 Query mit Pattern-Matching
- MongoDB: Multiple Queries + Application-Level-Logik
3. Neue Beziehungen ohne Schema-Änderung
In MongoDB müsste die Collection-Struktur angepasst werden.
Performance-Vergleich
| Operation | Neo4j | MongoDB |
|---|---|---|
| Beziehung traversieren | O(1) | O(log n) mit Index |
| 3-Hop-Query | Direkt | 3 separate Queries |
| Neue Beziehung | CREATE | Array-Update + Reindex |
🎤 Frage 2: Wie Neo4j an die App angebunden?¶
Python Neo4j Driver
from neo4j import GraphDatabase
# 1. Verbindung erstellen
driver = GraphDatabase.driver(
"bolt://localhost:7687",
auth=("neo4j", "password")
)
# 2. Session öffnen und Query ausführen
with driver.session() as session:
result = session.run("""
MATCH (m:Museum)-[:LOCATED_IN]->(c:Canton {abbr: $canton})
RETURN m.name, m.city
""", {"canton": "ZH"})
# 3. Ergebnisse verarbeiten
for record in result:
print(record["m.name"], record["m.city"])
# 4. Verbindung schließen
driver.close()
Wichtige Konzepte:
- Driver: Managed Connection Pool
- Session: Transaktions-Kontext
- Parametrisierte Queries:
$cantonverhindert Injection
🎤 Frage 3: Schema-Syntax?¶
Cypher-Syntax
🎤 Frage 4: Was funktioniert / Probleme / Ausblick?¶
Erfolgreich implementiert
- Datenimport: 28 Museen, 15 Kantone, 6 Kategorien, 5 Personen
- Filter-System: Kanton + Kategorie kombinierbar
- Detail-Ansicht: Museum-Info + verknüpfte Personen
- Statistik: Top 10 Kantone nach Museumsanzahl
- NEAR-Beziehungen: Museen im gleichen Kanton automatisch verknüpft
- Error Handling: Verbindungsfehler werden abgefangen
Nicht implementiert
Technisch machbar, aber Zeitrahmen:
-
Shortest Path: Routen zwischen Museen
-
Graph-Visualisierung: Mit matplotlib/networkx
- Export-Funktion: CSV/JSON-Export der Suchergebnisse
- Person-Detail-View: Biografie + alle Museen
Herausforderungen
- Neo4j-Passwort: Muss manuell konfiguriert werden
- First-Time-Setup: User muss Neo4j Desktop selbst starten
- Datenmenge: Nur 28 Museen (echte DB hätte 1100+)
- tkinter-Limits: Keine native Graph-Visualisierung
Erweiterungsmöglichkeiten
Kurz- bis mittelfristig (1-3 Wochen):
- 🗺️ Google Maps Integration
- Koordinaten zu Museen hinzufügen
-
Interactive Map mit Marker
-
📊 Graph-Visualisierung
- networkx + matplotlib für Static Graphs
-
Cytoscape.js für Interactive Web-View
-
📅 Event-Nodes
Langfristig (1-3 Monate):
- 🤖 Community Detection
- Welche Museen bilden thematische Cluster?
-
Graph Data Science Library nutzen
-
🔍 Semantic Search
- Volltextsuche in Beschreibungen
-
NLP für ähnliche Museen
-
🌐 Web-Frontend
- Flask/FastAPI Backend
- React Frontend mit D3.js
🛠️ Troubleshooting¶
Problem: 'Konnte nicht zu Neo4j verbinden'
Lösung:
- ✅ Prüfe, ob Neo4j Desktop läuft
- ✅ Prüfe, ob die Datenbank gestartet ist (grüner Status)
- ✅ Prüfe Passwort in
museum_app.pyZeile 20 - ✅ Teste Verbindung in Neo4j Browser:
http://localhost:7474
Terminal-Test:
Problem: 'Import fehlgeschlagen'
Lösung:
- Stelle sicher, dass
data_importer.pyim gleichen Ordner ist - Prüfe Neo4j-Logs in Desktop (drei Punkte → Logs)
- Lösche die Datenbank und erstelle sie neu
Manueller Test in Neo4j Browser:
Problem: 'Keine Museen gefunden'
Lösung:
- Klicke zuerst auf "📥 Datenbank initialisieren"
- Warte bis "Import abgeschlossen" in Statusleiste erscheint
- Prüfe Filter: "Alle" für Kanton und Kategorie wählen
Prüfe in Neo4j Browser:
📁 Dateistruktur¶
museum-project/
├── museum_app.py # 🎨 Haupt-GUI-Anwendung (tkinter)
├── data_importer.py # 📥 Daten-Import-Logik
├── requirements.txt # 📦 Python-Dependencies
└── README.md # 📖 Diese Datei
🎓 M165 NoSQL - Evaluation¶
Projekt-Zusammenfassung
Ziel: Schweizer Museen mit Neo4j-Graphdatenbank verwalten
Technologie-Stack:
- Backend: Python 3.10+
- GUI: tkinter (Standard-Library)
- Datenbank: Neo4j Desktop 5.x
- Driver: neo4j-python-driver 5.14.0
Zeitaufwand: ~4 Stunden (planbar in 5h)
Lernziele erfüllt:
- NoSQL-Datenbank praktisch eingesetzt
- Graph-Modell entworfen und implementiert
- CRUD-Operationen mit Cypher
- Python-Anbindung mit offiziellem Driver
- Unterschiede zu relationalen/dokumentenbasierten DBs verstanden
📚 Weiterführende Ressourcen¶
Links & Dokumentation
Erstellt für: M165 NoSQL 2026 Evaluation
Version: 1.0
Letztes Update: Januar 2026
Lizenz: MIT