feature: fertig
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
dist
|
||||
.slidev
|
||||
*.local
|
||||
@@ -0,0 +1,101 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { useNav } from '@slidev/client'
|
||||
|
||||
const { isPresenter, currentSlideNo, nextSlide } = useNav()
|
||||
|
||||
const LIMIT = 20
|
||||
const elapsed = ref(0)
|
||||
const hasAdvanced = ref(false)
|
||||
const paused = ref(true)
|
||||
let timer: ReturnType<typeof setInterval> | null = null
|
||||
|
||||
const togglePause = () => {
|
||||
paused.value = !paused.value
|
||||
}
|
||||
|
||||
const advanceSlide = () => {
|
||||
if (hasAdvanced.value || elapsed.value < LIMIT)
|
||||
return
|
||||
|
||||
hasAdvanced.value = true
|
||||
nextSlide()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
timer = setInterval(() => {
|
||||
if (paused.value)
|
||||
return
|
||||
elapsed.value++
|
||||
advanceSlide()
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timer)
|
||||
clearInterval(timer)
|
||||
timer = null
|
||||
})
|
||||
|
||||
watch(currentSlideNo, () => {
|
||||
elapsed.value = 0
|
||||
hasAdvanced.value = false
|
||||
paused.value = false
|
||||
})
|
||||
|
||||
const remaining = computed(() => LIMIT - elapsed.value)
|
||||
const over = computed(() => remaining.value < 0)
|
||||
const warn = computed(() => !over.value && remaining.value <= 5)
|
||||
const pct = computed(() => Math.min(100, (elapsed.value / LIMIT) * 100))
|
||||
const label = computed(() => `${over.value ? '+' : ''}${Math.abs(remaining.value)}s`)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="isPresenter" class="pk-timer" :class="{ over, warn, paused }" @click="togglePause">
|
||||
<div class="pk-bar" :style="{ width: pct + '%' }" />
|
||||
<span class="pk-label">{{ paused ? '⏸' : label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.pk-timer {
|
||||
position: fixed;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
z-index: 9999;
|
||||
width: 130px;
|
||||
height: 38px;
|
||||
border-radius: 10px;
|
||||
background: rgba(20, 20, 25, 0.85);
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: 'Fira Code', monospace;
|
||||
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
.pk-timer.paused { border-color: rgba(96, 165, 250, 0.8); }
|
||||
.pk-timer.paused .pk-bar { background: rgba(96, 165, 250, 0.35); }
|
||||
.pk-bar {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background: rgba(74, 222, 128, 0.35);
|
||||
transition: width 1s linear;
|
||||
}
|
||||
.pk-timer.warn .pk-bar { background: rgba(251, 191, 36, 0.4); }
|
||||
.pk-timer.over { border-color: rgba(248, 113, 113, 0.8); }
|
||||
.pk-timer.over .pk-bar { width: 100% !important; background: rgba(248, 113, 113, 0.45); }
|
||||
.pk-label {
|
||||
position: relative;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
.pk-timer.over .pk-label { color: #fecaca; }
|
||||
</style>
|
||||
Generated
+9683
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "ringstats-zwischenpraesentation",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "slidev --open",
|
||||
"build": "slidev build",
|
||||
"export": "slidev export"
|
||||
},
|
||||
"dependencies": {
|
||||
"@slidev/cli": "^0.50.0",
|
||||
"@slidev/theme-seriph": "^0.25.0"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 787 KiB |
@@ -0,0 +1,681 @@
|
||||
---
|
||||
theme: seriph
|
||||
title: Ringstats – Zwischenpräsentation
|
||||
info: |
|
||||
## Ringstats
|
||||
Zwischenstandspräsentation – Moderne Datenbanken
|
||||
Justin Rost · Michelle Reichelt · Yasin Ergün
|
||||
class: text-center
|
||||
transition: slide-left
|
||||
mdc: true
|
||||
fonts:
|
||||
sans: Inter
|
||||
mono: Fira Code
|
||||
---
|
||||
|
||||
# Ringstats
|
||||
Eine Live Datenbank für Elden Ring
|
||||
|
||||
<div class="pt-6 opacity-80 text-lg">
|
||||
Justin Rost · Michelle Reichelt · Yasin Ergün
|
||||
</div>
|
||||
|
||||
<div class="pt-10 opacity-60 text-sm">
|
||||
Zwischenpräsentation · Moderne Datenbanken · 08.06.2026
|
||||
</div>
|
||||
|
||||
---
|
||||
layout: center
|
||||
class: text-center
|
||||
---
|
||||
|
||||
# Inhalt
|
||||
|
||||
<div class="flex justify-center items-stretch gap-3 pt-14">
|
||||
|
||||
<div class="w-36 p-5 rounded-xl bg-gray-400/10">
|
||||
<div class="text-4xl">🎯</div>
|
||||
<div class="pt-3 font-semibold text-sm">Szenario</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center text-2xl opacity-40">⮀</div>
|
||||
|
||||
<div class="w-36 p-5 rounded-xl bg-gray-400/10">
|
||||
<div class="text-4xl">🗺️</div>
|
||||
<div class="pt-3 font-semibold text-sm">ER-Modell</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center text-2xl opacity-40">⮀</div>
|
||||
|
||||
<div class="w-36 p-5 rounded-xl bg-gray-400/10">
|
||||
<div class="text-4xl">🧩</div>
|
||||
<div class="pt-3 font-semibold text-sm">Drei Modelle</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center text-2xl opacity-40">→</div>
|
||||
|
||||
<div class="w-36 p-5 rounded-xl bg-gray-400/10">
|
||||
<div class="text-4xl">⚖️</div>
|
||||
<div class="pt-3 font-semibold text-sm">Vergleich</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center text-2xl opacity-40">→</div>
|
||||
|
||||
<div class="w-36 p-5 rounded-xl bg-red-400/10">
|
||||
<div class="text-4xl">✅</div>
|
||||
<div class="pt-3 font-semibold text-sm">Auswahl</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- kurzer Fahrplan durch die Präsentation
|
||||
- erst Szenario, dann ER-Modell als Grundlage
|
||||
- drei NoSQL-Modelle an unseren Daten zeigen
|
||||
- vergleichen und am Ende eine Auswahl treffen
|
||||
-->
|
||||
|
||||
---
|
||||
layout: center
|
||||
class: text-center
|
||||
---
|
||||
|
||||
# Die Idee
|
||||
|
||||
<div class="opacity-70 pt-2">Eine Schnittstelle zwischen Spiel und Datenbank</div>
|
||||
|
||||
<div class="flex justify-center items-center gap-6 pt-12">
|
||||
|
||||
<div class="w-44 p-6 rounded-xl bg-gray-400/10">
|
||||
<div class="text-5xl">🎮</div>
|
||||
<div class="pt-3 font-semibold">Spiel</div>
|
||||
<div class="pt-1 text-xs opacity-70">liest Position, Leben, Ausrüstung live aus</div>
|
||||
</div>
|
||||
|
||||
<div class="text-3xl opacity-40">⇄</div>
|
||||
|
||||
<div class="w-44 p-6 rounded-xl bg-red-400/10">
|
||||
<div class="text-5xl">🗄️</div>
|
||||
<div class="pt-3 font-semibold">Datenbank</div>
|
||||
<div class="pt-1 text-xs opacity-70">speichert und liefert passende Infos</div>
|
||||
</div>
|
||||
|
||||
<div class="text-3xl opacity-40">⇄</div>
|
||||
|
||||
<div class="w-44 p-6 rounded-xl bg-gray-400/10">
|
||||
<div class="text-5xl">🌐</div>
|
||||
<div class="pt-3 font-semibold">Browser</div>
|
||||
<div class="pt-1 text-xs opacity-70">gleiche Daten parallel abrufbar</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- Schnittstelle zwischen Spiel und Datenbank
|
||||
- Im Spiel werden Daten ausgelesen
|
||||
- Daten werden an Server gesendet und in DB verwalten
|
||||
- Programm und Browser lesen Daten aus
|
||||
-->
|
||||
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Kernidee: Hilfe für Spieler
|
||||
|
||||
<div class="grid grid-cols-2 gap-6 pt-10 text-center">
|
||||
|
||||
<div class="p-6 rounded-xl bg-gray-400/10">
|
||||
<div class="text-4xl">🎮</div>
|
||||
<div class="pt-3 font-semibold">Im-Spiel Anzeige</div>
|
||||
<div class="pt-2 text-sm opacity-80">zeigt z.B. Bossangriffe live und Checkliste</div>
|
||||
</div>
|
||||
|
||||
<div class="p-6 rounded-xl bg-gray-400/10">
|
||||
<div class="text-4xl">🖥️</div>
|
||||
<div class="pt-3 font-semibold">Browser App</div>
|
||||
<div class="pt-2 text-sm opacity-80">Generelle Informationen und Analysen</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="pt-8 text-center opacity-70">
|
||||
Es muss extrem schnell gehen, ohne spürbare Verzögerung.
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- Die Kernidee ist Hilfe für den Spieler
|
||||
- Im Spiel wird Oberfläche angezeigt mit Informationen
|
||||
- Browser App zeigt detaillreicher Infos zum Spieler und Welt
|
||||
-->
|
||||
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Anwendungsfälle
|
||||
|
||||
<div class="grid grid-cols-3 gap-6 pt-12 text-center">
|
||||
|
||||
<div class="p-6 rounded-xl bg-gray-400/10">
|
||||
<div class="text-5xl">⚔️</div>
|
||||
<div class="pt-4 font-semibold">Bosskampf</div>
|
||||
<div class="pt-2 text-sm opacity-70">Fenster mit Resistenzen und Angriffe</div>
|
||||
</div>
|
||||
|
||||
<div class="p-6 rounded-xl bg-gray-400/10">
|
||||
<div class="text-5xl">📦</div>
|
||||
<div class="pt-4 font-semibold">Live-Standort</div>
|
||||
<div class="pt-2 text-sm opacity-70">Checkliste, Truhen und Objekte in der Nähe</div>
|
||||
</div>
|
||||
|
||||
<div class="p-6 rounded-xl bg-gray-400/10">
|
||||
<div class="text-5xl">🌐</div>
|
||||
<div class="pt-4 font-semibold">Website</div>
|
||||
<div class="pt-2 text-sm opacity-70">Builds und Statistiken</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- Einige Informationen sind:
|
||||
- Resistenzen und Angriffe von Bossen
|
||||
- Truhen, Objekte und Checklisten in der Nähe
|
||||
- Detaillierte Informationen zu Statistiken und Builds auf Website
|
||||
-->
|
||||
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Das ER-Modell
|
||||
|
||||
<div class="flex justify-center pt-2">
|
||||
<img src="/er-modell.png" class="h-100 rounded-lg bg-white p-2" />
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- Zentrale Entity ist Player/Spieler
|
||||
- Grear (Inventar) beinhaltet (Weapon, Armor, Shield, Talisman).
|
||||
- Das sind alles Items, werden von Gegnern fallengelassen.
|
||||
- In Regionen sind Player, Enemies und Items
|
||||
-->
|
||||
|
||||
---
|
||||
layout: center
|
||||
class: text-center
|
||||
---
|
||||
|
||||
# Drei NoSQL-Modelle
|
||||
|
||||
<div class="grid grid-cols-3 gap-8 pt-10">
|
||||
|
||||
<div class="p-8 rounded-xl bg-red-400/10">
|
||||
<div class="text-3xl font-bold">Key-Value</div>
|
||||
<div class="pt-3 opacity-80">Redis</div>
|
||||
<div class="pt-2 text-sm opacity-70">Alles über Schlüssel</div>
|
||||
</div>
|
||||
|
||||
<div class="p-8 rounded-xl bg-green-400/10">
|
||||
<div class="text-3xl font-bold">Dokument</div>
|
||||
<div class="pt-3 opacity-80">MongoDB</div>
|
||||
<div class="pt-2 text-sm opacity-70">Alles im Dokument</div>
|
||||
</div>
|
||||
|
||||
<div class="p-8 rounded-xl bg-blue-400/10">
|
||||
<div class="text-3xl font-bold">Graph</div>
|
||||
<div class="pt-3 opacity-80">Neo4j</div>
|
||||
<div class="pt-2 text-sm opacity-70">Alles über Kanten</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="pt-10 opacity-70">
|
||||
Wir bilden die gleichen Daten in allen drei ab.
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- Key-Value mit Redis: alles über Schlüssel
|
||||
- Dokument mit MongoDB: alles im Dokument
|
||||
- Graph mit Neo4j: alles über Kanten
|
||||
- gleiche Daten in allen drei abgebildet
|
||||
-->
|
||||
|
||||
---
|
||||
layout: two-cols
|
||||
layoutClass: gap-10
|
||||
---
|
||||
|
||||
# Key-Value mit Redis
|
||||
|
||||
Eine einfache und schnelle Lösung für unstrukturierte Daten.
|
||||
|
||||
Keys sind Strings und identifizieren ein Objekt eindeutig.
|
||||
|
||||
Aufbau: Name der Entität, Doppelpunkt, ID des Objekts.
|
||||
|
||||
::right::
|
||||
|
||||
<div class="pt-14">
|
||||
|
||||
```text
|
||||
weapon:213
|
||||
player:1
|
||||
region:1:items
|
||||
enemy:1
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
<div class="pt-6 opacity-80">
|
||||
|
||||
Die meisten Entitäten liegen als Hash Map. Listen und Mengen als SET.
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- Keys sind Strings und identifizieren ein Objekt eindeutig
|
||||
- Aufbau: Name der Entität, Doppelpunkt, ID
|
||||
- meiste Entitäten als Hash Map, Listen und Mengen als SET
|
||||
-->
|
||||
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Key-Value: Schlüsselaufbau
|
||||
|
||||
<div class="text-sm pt-4">
|
||||
|
||||
| Datentyp | Key-Struktur | Attribute |
|
||||
|----------|--------------|-----------|
|
||||
| HMAP | `weapon:{id}` | id, item_effect_id, item_type_id, weight, damage |
|
||||
| HMAP | `item:{id}` | id, name, gear_type, gear_id |
|
||||
| HMAP | `player:{id}` | id, name, health, stamina, level, region_id |
|
||||
| SET | `player:{id}:armor` | item_id |
|
||||
| STRING | `player:{id}:shield` | item_id |
|
||||
| HMAP | `region:{id}` | id, name |
|
||||
| SET | `region:{id}:enemies` | enemy_id |
|
||||
| HMAP | `enemy:{id}` | id, name, health, level, damage |
|
||||
|
||||
</div>
|
||||
|
||||
<div class="pt-4 opacity-70 text-sm">
|
||||
Über den Key kommen wir direkt an ein Objekt, ohne lange zu suchen.
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- jede Entität bekommt einen eigenen Key
|
||||
- Ausrüstung des Players über Sub-Keys, z.B. player:1:armor
|
||||
- über den Key direkt ans Objekt, ohne Suchen
|
||||
-->
|
||||
|
||||
---
|
||||
layout: two-cols
|
||||
layoutClass: gap-10
|
||||
---
|
||||
|
||||
# Dokument mit MongoDB
|
||||
|
||||
Alles was zusammengehört, liegt gebündelt in einem Dokument.
|
||||
|
||||
Jede Entität wird zu einem Dokument in einer eigenen Collection.
|
||||
|
||||
Der Player hält von seiner Ausrüstung nur die ids fest, denn Weapon und Co. liegen in eigenen Dokumenten.
|
||||
|
||||
::right::
|
||||
|
||||
<div class="pt-14">
|
||||
|
||||
```js
|
||||
player {
|
||||
id: 1,
|
||||
name: "Jonas",
|
||||
health: 100,
|
||||
stamina: 100,
|
||||
level: 1,
|
||||
region_id: 1,
|
||||
weapon: [ 12 ],
|
||||
shield: 30,
|
||||
armor: [ 41, 42 ],
|
||||
talisman: [ 7 ]
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- alles Zusammengehörige gebündelt in einem Dokument
|
||||
- jede Entität eigene Collection
|
||||
- Player hält von der Ausrüstung nur die ids fest
|
||||
-->
|
||||
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Dokument: Beispiele
|
||||
|
||||
<div class="grid grid-cols-3 gap-4 pt-6 text-sm">
|
||||
|
||||
```js
|
||||
weapon {
|
||||
id: 213,
|
||||
item_type: {
|
||||
id: 1,
|
||||
name: "Dolch"
|
||||
},
|
||||
item_effect: {
|
||||
id: 4,
|
||||
name: "Stärke",
|
||||
value: 5
|
||||
},
|
||||
weight: 2,
|
||||
damage: 70
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
enemy {
|
||||
id: 1,
|
||||
region_id: 1,
|
||||
name: "Tree_Sentinel",
|
||||
health: 30000,
|
||||
level: 20,
|
||||
damage: 70,
|
||||
items: [ 5, 10 ]
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
region {
|
||||
id: 1,
|
||||
name: "Limgrave",
|
||||
items: [ 12, 19, 248 ],
|
||||
enemies: [ 1, 245 ]
|
||||
}
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
<div class="pt-6 opacity-70 text-sm">
|
||||
Weapon bringt item_type und item_effect direkt mit. Player, Item, Region und Enemy zeigen meist nur über ids.
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- Weapon bringt item_type und item_effect direkt mit
|
||||
- Enemy und Region verweisen über ids auf ihre Items
|
||||
- bei uns meist nur ids statt tiefer Verschachtelung
|
||||
-->
|
||||
|
||||
---
|
||||
layout: two-cols
|
||||
layoutClass: gap-10
|
||||
---
|
||||
|
||||
# Graph mit Neo4j
|
||||
|
||||
Der Fokus liegt auf den Beziehungen zwischen den Objekten.
|
||||
|
||||
Jede Entität wird zu einem Knoten, der seine Werte direkt mitträgt.
|
||||
|
||||
::right::
|
||||
|
||||
<div class="pt-6 text-sm">
|
||||
|
||||
| Knoten | Attribute |
|
||||
|--------|-----------|
|
||||
| Player | id, name, health, stamina, level |
|
||||
| Weapon | id, weight, damage |
|
||||
| Type | id, name |
|
||||
| item_effect | id, name, value |
|
||||
| Item | id, name |
|
||||
| Region | id, name |
|
||||
| Enemy | id, name, health, level, damage |
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- Fokus liegt auf den Beziehungen zwischen Objekten
|
||||
- jede Entität wird ein Knoten und trägt seine Werte direkt
|
||||
-->
|
||||
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Graph: Kanten
|
||||
|
||||
<div class="text-sm pt-6">
|
||||
|
||||
| Von | Kante | Nach |
|
||||
|-----|-------|------|
|
||||
| Player | has_equipped | Weapon, Armor, Shield, Talisman |
|
||||
| Player | is_in | Region |
|
||||
| Weapon, Armor, Shield | has | Type |
|
||||
| Weapon, Armor, Shield, Talisman | has | item_effect |
|
||||
| Weapon, Armor, Shield, Talisman | is | Item |
|
||||
| Region | has | Item, Enemy |
|
||||
| Enemy | drops | Item |
|
||||
|
||||
</div>
|
||||
|
||||
<div class="pt-6 opacity-70 text-sm">
|
||||
Die Kanten verbinden die Knoten so, wie es schon das ER-Modell vorgibt.
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- Kanten sind die Beziehungen aus dem ER-Modell
|
||||
- has_equipped, is_in, has, drops
|
||||
- Beziehungen lassen sich direkt verfolgen
|
||||
-->
|
||||
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Vergleich: Key-Value
|
||||
|
||||
<div class="grid grid-cols-2 gap-8 pt-10">
|
||||
|
||||
<div class="p-6 rounded-xl bg-green-500/10">
|
||||
<div class="font-bold text-green-500 pb-3">Vorteil</div>
|
||||
Redis ist extrem schnell. Über die Keys kommen wir direkt an ein Objekt. Genau das brauchen wir für die Live Daten des Players.
|
||||
</div>
|
||||
|
||||
<div class="p-6 rounded-xl bg-red-500/10">
|
||||
<div class="font-bold text-red-500 pb-3">Nachteil</div>
|
||||
Komplexe Abfragen sind schwierig. Alle Weapon mit einem bestimmten item_effect müssen wir in der Anwendung selbst zusammenbauen.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- Vorteil: extrem schnell, direkter Zugriff über Key, ideal für Live-Daten
|
||||
- Nachteil: komplexe Abfragen müssen wir selbst zusammenbauen
|
||||
- Beispiel: alle Weapon mit bestimmtem item_effect
|
||||
-->
|
||||
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Vergleich: Dokument
|
||||
|
||||
<div class="grid grid-cols-2 gap-8 pt-10">
|
||||
|
||||
<div class="p-6 rounded-xl bg-green-500/10">
|
||||
<div class="font-bold text-green-500 pb-3">Vorteil</div>
|
||||
Sehr leserlich und einfach zu modellieren. Jedes Dokument ist für sich verständlich und man sieht direkt, welche Daten zusammengehören.
|
||||
</div>
|
||||
|
||||
<div class="p-6 rounded-xl bg-red-500/10">
|
||||
<div class="font-bold text-red-500 pb-3">Nachteil</div>
|
||||
Bei uns wird das meiste über ids referenziert und nur wenig verschachtelt. Wir nutzen die Stärke des Modells kaum.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- Vorteil: sehr leserlich und einfach zu modellieren
|
||||
- Nachteil: bei uns meist ids, kaum verschachtelt
|
||||
- die eigentliche Stärke nutzen wir kaum
|
||||
-->
|
||||
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Vergleich: Graph
|
||||
|
||||
<div class="grid grid-cols-2 gap-8 pt-10">
|
||||
|
||||
<div class="p-6 rounded-xl bg-green-500/10">
|
||||
<div class="font-bold text-green-500 pb-3">Vorteil</div>
|
||||
Beziehungen lassen sich sehr leicht abfragen. Welcher Player welche Weapon trägt oder welches Item ein Enemy fallen lässt, ohne Umwege.
|
||||
</div>
|
||||
|
||||
<div class="p-6 rounded-xl bg-red-500/10">
|
||||
<div class="font-bold text-red-500 pb-3">Nachteil</div>
|
||||
Neo4j ist für unseren Fall überdimensioniert. Wir schreiben und lesen vor allem schnell, statt ständig tiefe Beziehungen abzufragen.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- Vorteil: Beziehungen sehr leicht abfragbar
|
||||
- Beispiel: welcher Player welche Weapon trägt, welches Item ein Enemy droppt
|
||||
- Nachteil: für unseren Fall überdimensioniert
|
||||
- wir brauchen schnelles Schreiben und Lesen, keine tiefen Abfragen
|
||||
-->
|
||||
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Gegenüberstellung
|
||||
|
||||
<div class="pt-8 text-lg">
|
||||
|
||||
| | Key-Value | Dokument | Graph |
|
||||
|---|:---:|:---:|:---:|
|
||||
| Schreiben und Lesen | ✅ sehr schnell | 🟡 gut | 🟡 mehr Aufwand |
|
||||
| Direkter Objektzugriff | ✅ über Key | ✅ über Collection | 🟡 über Knoten |
|
||||
| Komplexe Abfragen | 🔴 schwierig | 🟡 mittel | ✅ stark |
|
||||
| Passt zu Live Daten | ✅ ideal | 🟡 ok | 🔴 überdimensioniert |
|
||||
|
||||
</div>
|
||||
|
||||
<div class="pt-8 opacity-70">
|
||||
Unsere Daten sind flach und ändern sich ständig. Tiefe Beziehungen brauchen wir kaum.
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- Tabelle fasst die drei Modelle zusammen
|
||||
- Key-Value vorn bei Tempo und direktem Zugriff
|
||||
- unsere Daten flach und ständig in Bewegung
|
||||
-->
|
||||
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Was uns wichtig ist
|
||||
|
||||
<div class="grid grid-cols-2 gap-8 pt-6 text-sm">
|
||||
|
||||
<div>
|
||||
|
||||
| Kriterium | Muss | Gewicht |
|
||||
|-----------|:----:|:-------:|
|
||||
| Hohe Performanz | ja | 5 |
|
||||
| Keine Lizenzkosten | ja | 5 |
|
||||
| Daten-Streaming | ja | 3 |
|
||||
| Niedrige Latenz | ja | 3 |
|
||||
| Indexing | nein | 2 |
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
| | MariaDB | Redis | MongoDB |
|
||||
|---|:---:|:---:|:---:|
|
||||
| Performanz | 0 | 2 | 1 |
|
||||
| Streaming | 0 | 2 | 0 |
|
||||
| Latenz | 1 | 2 | 0 |
|
||||
| **Summe** | **11** | **30** | **15** |
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="pt-6 opacity-70 text-sm">
|
||||
Latenzfrei und performant ist für uns Pflicht. In den Tests gewinnt Redis klar.
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- Kriterien aus dem Szenario gewichtet
|
||||
- Performanz und keine Lizenzkosten sind Pflicht
|
||||
- in den Tests gewinnt Redis klar: 30 vs 11 vs 15
|
||||
-->
|
||||
|
||||
---
|
||||
layout: center
|
||||
class: text-center
|
||||
---
|
||||
|
||||
# Fazit
|
||||
|
||||
<div class="text-2xl pt-4">
|
||||
Wir wählen <span class="text-red-500 font-bold">Key-Value mit Redis</span>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-3 gap-6 pt-10 text-left text-sm">
|
||||
|
||||
<div class="p-5 rounded-xl bg-gray-400/10">
|
||||
<div class="font-semibold pb-2">Geschwindigkeit</div>
|
||||
Daten des Players live schreiben und genauso live zurücklesen.
|
||||
</div>
|
||||
|
||||
<div class="p-5 rounded-xl bg-gray-400/10">
|
||||
<div class="font-semibold pb-2">Direkter Zugriff</div>
|
||||
Über die Keys sofort an ein Objekt, ohne lange Suche.
|
||||
</div>
|
||||
|
||||
<div class="p-5 rounded-xl bg-gray-400/10">
|
||||
<div class="font-semibold pb-2">Passende Größe</div>
|
||||
Rund 100 Regionen, 500 Gegner, 3.300 Gegenstände. Keine tiefe Verschachtelung nötig.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- Wahl fällt auf Key-Value mit Redis
|
||||
- drei Gründe: Geschwindigkeit, direkter Zugriff, passende Größe
|
||||
- komplexe Abfragen brauchen wir kaum
|
||||
-->
|
||||
|
||||
---
|
||||
layout: center
|
||||
class: text-center
|
||||
---
|
||||
|
||||
# Danke
|
||||
|
||||
<div class="opacity-80 pt-4 text-lg">
|
||||
Nächste Schritte: Datenbank auf dem Server aufsetzen und Schema umsetzen
|
||||
</div>
|
||||
|
||||
<div class="pt-10 opacity-60">
|
||||
Fragen?
|
||||
</div>
|
||||
|
||||
<div class="pt-8 opacity-50 text-sm">
|
||||
Justin Rost · Michelle Reichelt · Yasin Ergün
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- Dank fürs Zuhören
|
||||
- nächste Schritte: Datenbank auf Server aufsetzen, Schema umsetzen
|
||||
- offen für Fragen
|
||||
-->
|
||||
Reference in New Issue
Block a user