-
Notifications
You must be signed in to change notification settings - Fork 1
Compendium chapter 28 aql reference
Navigation: Home > Pages
"Eine Abfragesprache ist nur so gut wie ihre Dokumentation."
Dieses Kapitel ist die komplette Referenz fΓΌr AQL (Adaptive Query Language), die einheitliche Abfragesprache von ThemisDB. Sie deckt alle 479 Sprachelemente ab: 119 Keywords und 360 eingebaute Funktionen.
Was Sie in diesem Kapitel finden:
- VollstΓ€ndiger Sprachumfang (v1.3.1)
- Kategorisierte Funktionsreferenz
- Praktische Beispiele fΓΌr jeden Bereich
- Performance-Hinweise und Best Practices
Voraussetzungen: Kapitel 5-9 (Datenmodelle), GrundverstΓ€ndnis von SQL.
graph LR
AQL[AQL Query] --> Parser[Parser]
Parser --> AST[Abstract Syntax Tree]
AST --> Optimizer[Query Optimizer]
Optimizer --> LogPlan[Logical Plan]
LogPlan --> PhysPlan[Physical Plan]
PhysPlan --> IndexSel[Index Selection]
PhysPlan --> JoinOrd[Join Ordering]
PhysPlan --> PushDown[Predicate Pushdown]
IndexSel --> Execution[Execution Engine]
JoinOrd --> Execution
PushDown --> Execution
Execution --> Result[Query Result]
style Optimizer fill:#f093fb
style Execution fill:#4facfe
Abb. 28.0: AQL-Query-Execution-Pipeline
Wir beginnen mit den syntaktischen Grundlagen von AQL, der einheitlichen Abfragesprache von ThemisDB. Die Sprache kombiniert deklarative SQL-Elemente mit funktionalen Programmierparadigmen und Graph-Traversal-Konstrukten zu einer kohΓ€renten Syntax. AQL-Queries folgen einer logischen AusfΓΌhrungsreihenfolge, die vom Query Optimizer analysiert und optimiert wird. Das VerstΓ€ndnis dieser Fundamentals ist essentiell fΓΌr effiziente Datenbankoperationen und Performance-Optimierung.
AQL-Queries folgen einer definierten AusfΓΌhrungsreihenfolge, die unabhΓ€ngig von der syntaktischen Reihenfolge im Query-Text ist. Diese logische Pipeline ermΓΆglicht dem Optimizer, Operationen umzuordnen und zu optimieren, wΓ€hrend die Semantik erhalten bleibt. Die AusfΓΌhrungsreihenfolge entspricht dem Konzept der "logical query processing" aus der relationalen Datenbanktheorie (siehe C.J. Date: "SQL and Relational Theory", O'Reilly 2015).
Logische AusfΓΌhrungsreihenfolge:
- FOR - Collection-Iteration und Join-Operationen
- FILTER - PrΓ€dikat-Evaluation und Index-Nutzung
- COLLECT - Gruppierung mit Aggregation
- SORT - Sortierung der Ergebnisse
- LIMIT - Pagination und Result-Limiting
- RETURN - Projektion und Output-Formatting
// AQL Query Struktur mit AusfΓΌhrungsreihenfolge
// Demonstriert alle wichtigen Sprachkonstrukte
FOR doc IN collection // 1. Iteration ΓΌber Collection
// LET: Definiere lokale Variablen (lazy evaluation)
LET computed_value = doc.price * 1.19 // 19% MwSt
LET category_upper = UPPER(doc.category)
// FILTER: Bedingungen (werden zu Index-Lookups optimiert)
FILTER doc.status == 'active' AND computed_value > 100
FILTER category_upper IN ['ELECTRONICS', 'BOOKS']
// COLLECT: Gruppierung mit Aggregation
COLLECT
category = doc.category,
year = DATE_YEAR(doc.created_at)
AGGREGATE
total = SUM(computed_value),
avg = AVG(doc.price),
count = COUNT(1),
items = UNIQUE(doc._key)
// SORT: Sortierung (kann Index verwenden)
SORT total DESC, year ASC
// LIMIT: Pagination (skip, limit)
LIMIT 10, 20 // Skip 10, take 20
// RETURN: Ergebnis-Projektion
RETURN {
category,
year,
total: ROUND(total, 2),
avg: ROUND(avg, 2),
count,
sample_items: SLICE(items, 0, 5)
}
AQL implementiert lexikalisches Scoping fΓΌr Variablen. Jede FOR- und LET-Anweisung fΓΌhrt eine neue Variable im aktuellen Scope ein, die in nachfolgenden Operationen verfΓΌgbar ist. Variablen sind immutable (unverΓ€nderlich) und folgen dem funktionalen Programmierparadigma. Nested Scopes haben Zugriff auf Γ€uΓere Scopes, aber nicht umgekehrt.
Scoping-Regeln:
-
FOR-Variablen: Pro Iteration neu gebunden -
LET-Variablen: Einmalige Bindung, lazy evaluation - Subquery-Variablen: Lokaler Scope, nicht auΓerhalb sichtbar
-
Bind Variables (
@param): Global fΓΌr gesamten Query
// Variable Scoping Beispiel
LET global_threshold = 100 // ΓuΓerer Scope
FOR order IN orders
LET order_total = order.amount // FOR-Scope
// Subquery mit lokalem Scope
LET item_details = (
FOR item IN order.items
LET item_price = item.quantity * item.unit_price // Subquery-Scope
RETURN { item: item.name, price: item_price }
)
FILTER order_total > global_threshold // Zugriff auf Γ€uΓeren Scope
RETURN { order_id: order._key, total: order_total, items: item_details }
AQL unterstΓΌtzt Type Coercion nach definierten Regeln, die SQL-Standards folgen. Die Sprache ist stark typisiert, fΓΌhrt aber implizite Konvertierungen durch, wenn diese semantisch sinnvoll sind. Explizite Typ-Konvertierungen mittels TO_STRING(), TO_NUMBER(), TO_BOOL() sind zu bevorzugen fΓΌr klaren, wartbaren Code.
Coercion-Regeln:
| Operation | Operand Type | Coercion | Result |
|---|---|---|---|
| Arithmetic | String + Number | String β Number | Number |
| Comparison | Number == String | String β Number | Boolean |
| Boolean | Any in FILTER | Truthy/Falsy | Boolean |
| Concatenation | ANY in CONCAT() | ANY β String | String |
Null-Handling:
AQL folgt SQL-Semantik fΓΌr NULL-Werte. Arithmetische Operationen mit NULL ergeben NULL. Vergleiche mit NULL nutzen IS NULL / IS NOT NULL. Der Null-Coalescing-Operator ?? bietet Default-Werte.
// Type Coercion und NULL-Handling
FOR doc IN collection
// Implizite Coercion: String "42" β Number 42
LET implicit_num = doc.age_string + 10
// Explizite Konvertierung (bevorzugt)
LET explicit_num = TO_NUMBER(doc.age_string) + 10
// NULL-Handling mit Coalescing
LET safe_price = doc.price ?? 0.0
LET display_name = doc.name ?? doc.username ?? "Anonymous"
// Truthy/Falsy in Boolean-Kontext
FILTER doc.active // NULL, false, 0, "", [] sind falsy
RETURN {
implicit: implicit_num,
explicit: explicit_num,
safe_price,
display_name
}
AQL unterstΓΌtzt Single-Line (//) und Multi-Line (/* */) Kommentare nach C-Style-Konventionen. Dokumentations-Kommentare sollten komplexe Query-Logik, Performance-Γberlegungen und Business-Regeln erklΓ€ren. Best Practice ist es, Intent ΓΌber Implementation zu dokumentieren.
/**
* Customer Lifetime Value (CLV) Berechnung
*
* Berechnet den CLV ΓΌber alle abgeschlossenen Bestellungen
* pro Kunde, gewichtet nach AktualitΓ€t (neuere Orders hΓΆher).
*
* Performance: Nutzt Index auf orders.customer_id
* Expected Runtime: < 100ms fΓΌr 1M orders
*/
FOR customer IN customers
// Hole alle abgeschlossenen Bestellungen
LET orders = (
FOR order IN orders
FILTER order.customer_id == customer._key
FILTER order.status == 'completed' // Index-Filter
RETURN order
)
// Gewichtete Summe (neuere Orders zΓ€hlen mehr)
LET clv = SUM(
FOR order IN orders
LET age_days = DATE_DIFF(order.created_at, DATE_NOW(), 'day')
LET weight = 1.0 / (1.0 + age_days / 365.0) // Decay-Funktion
RETURN order.amount * weight
)
FILTER clv > 1000 // Nur High-Value Customers
RETURN { customer: customer.name, clv: ROUND(clv, 2) }
AQL reserviert 119 Keywords, die nicht als Identifier (Collection-Namen, Variable-Namen) verwendet werden dΓΌrfen. Falls notwendig, kΓΆnnen Keywords mittels Backticks escaped werden: `collection`. Best Practice ist es, sprechende Namen zu wΓ€hlen, die Kollisionen vermeiden.
Naming Conventions:
- Collections:
snake_case(z.B.user_profiles,order_items) - Variables:
camelCaseodersnake_casekonsistent - Constants:
UPPER_SNAKE_CASE(z.B.MAX_RETRY_COUNT) - Avoid: Single-char names auΓer fΓΌr Iteratoren (
v,e,pin Graph-Queries)
| Aspekt | v1.3.0 | v1.3.1 | Γnderung |
|---|---|---|---|
| Reservierte Keywords | 72 | 119 | +47 (+65%) |
| Eingebaute Funktionen | ~360 | ~360 | 0 |
| Gesamt-Sprachumfang | 432 | 479 | +47 (+11%) |
Wichtig: v1.3.1 erweitert Sprachkonstrukte (TYPE, FUNCTION, CLASS) - keine neuen Funktionen.
FOR, IN, LET, FILTER, COLLECT, SORT, LIMIT, RETURN
Beispiel:
FOR user IN users
FILTER user.age >= 18
LET email_domain = SPLIT(user.email, "@")[1]
COLLECT domain = email_domain WITH COUNT INTO count
SORT count DESC
LIMIT 10
RETURN { domain, count }
AND, OR, NOT
Beispiel:
FOR product IN products
FILTER product.price >= 10 AND product.price <= 100
FILTER NOT product.discontinued
FILTER product.category == "Electronics" OR product.category == "Books"
RETURN product
COUNT, SUM, AVG, MIN, MAX, VARIANCE, STDDEV, UNIQUE
Beispiel:
FOR order IN orders
COLLECT year = DATE_YEAR(order.created_at)
AGGREGATE
total = SUM(order.amount),
avg_order = AVG(order.amount),
min_order = MIN(order.amount),
max_order = MAX(order.amount),
order_count = COUNT(1)
RETURN { year, total, avg_order, min_order, max_order, order_count }
OUTBOUND, INBOUND, ANY, SHORTEST_PATH
Beispiel:
-- Finde alle Freunde von Alice (2 Hops)
FOR v, e, p IN 1..2 OUTBOUND "users/alice" friends
RETURN { friend: v.name, path_length: LENGTH(p.edges) }
-- KΓΌrzester Pfad von Alice zu Bob
FOR v, e IN OUTBOUND SHORTEST_PATH "users/alice" TO "users/bob" follows
RETURN { user: v.name, action: e.type }
CREATE, DROP, COLLECTION, INDEX, VIEW
Beispiele:
-- Collection erstellen
CREATE COLLECTION products
-- Index erstellen
CREATE INDEX products_price ON products(price) TYPE SKIPLIST
-- View erstellen
CREATE VIEW active_users AS
FOR u IN users
FILTER u.status == "active"
RETURN u
-- LΓΆschen
DROP INDEX products_price
DROP COLLECTION products
INSERT, UPDATE, REPLACE, REMOVE, UPSERT, INTO, WITH
Beispiele:
-- Insert
INSERT { name: "Alice", age: 30 } INTO users
-- Update
UPDATE { _key: "alice" } WITH { age: 31 } IN users
-- Upsert (Insert if not exists)
UPSERT { email: "alice@example.com" }
INSERT { name: "Alice", email: "alice@example.com", age: 30 }
UPDATE { last_login: DATE_NOW() }
IN users
-- Remove
REMOVE { _key: "alice" } IN users
-- Replace
REPLACE { _key: "alice", name: "Alice Smith", age: 31 } IN users
LLM, INFER, RAG, EMBED, MODEL, LORA, STATS, CACHE,
LOAD, UNLOAD, LIST, INGEST, BLOB
Beispiele:
-- RAG-Query
FOR doc IN documents
LET embedding = EMBED(doc.content, { model: "text-embedding-3-small" })
LET neighbors = KNN_SEARCH(embeddings, embedding, 5)
LET context = CONCAT_SEPARATOR("\n", neighbors[*].content)
LET answer = LLM("Answer based on context", { context, model: "gpt-4" })
RETURN answer
-- Ingest Content
INGEST BLOB "data/documents.pdf"
INTO content_store
WITH { chunk_size: 512, overlap: 50 }
HASH, SKIPLIST, FULLTEXT, GEO, PERSISTENT, TTL, VECTOR
Beispiele:
-- Hash Index (Equality)
CREATE INDEX users_email ON users(email) TYPE HASH
-- Skiplist (Range Queries)
CREATE INDEX products_price ON products(price) TYPE SKIPLIST
-- Fulltext Index
CREATE INDEX articles_body ON articles(body) TYPE FULLTEXT
-- Geo Index
CREATE INDEX locations_coords ON locations(lat, lng) TYPE GEO
-- TTL Index (Auto-Expiry)
CREATE INDEX sessions_ttl ON sessions(expires_at) TYPE TTL
-- Vector Index (ANN Search)
CREATE INDEX embeddings_vector ON embeddings(vector)
TYPE VECTOR
OPTIONS { metric: "cosine", dimensions: 768 }
Wir analysieren nun die Operator-Hierarchie und Expression-Semantik von AQL. Operatoren bilden die Grundbausteine fΓΌr PrΓ€dikat-Evaluation, arithmetische Berechnungen und logische VerknΓΌpfungen. Das VerstΓ€ndnis der Operator-Precedence (Vorrangregeln) ist essentiell fΓΌr korrektes Query-Writing und vermeidet subtile Bugs durch unerwartete Auswertungsreihenfolgen.
AQL implementiert die Standard-Vergleichsoperatoren mit SQL-kompatibler Semantik. Der IN-Operator prΓΌft Mengen-ZugehΓΆrigkeit und kann Index-optimiert werden, wenn die rechte Seite eine Subquery auf indiziertem Feld ist.
| Operator | Semantik | Index-Nutzung | NULL-Verhalten |
|---|---|---|---|
== |
Equality | β (Hash, BTree) |
NULL == NULL β NULL
|
!= |
Inequality | β (Full Scan) |
NULL != x β NULL
|
<, <=, >, >=
|
Ordering | β (BTree, Skiplist) | Comparisons mit NULL β NULL
|
IN |
Set Membership | β (wenn RHS indiziert) |
NULL IN [...] β NULL
|
NOT IN |
Negated Membership | β (meist Full Scan) |
x NOT IN [NULL] β NULL
|
Logische Operatoren folgen Short-Circuit-Evaluation: AND evaluiert rechte Seite nicht bei false links, OR nicht bei true links. Dies ermΓΆglicht Performance-Optimierungen und sichere Null-Checks.
Precedence (hΓΆchste zuerst):
- Arithmetic:
*,/,% - Arithmetic:
+,- - Comparison:
<,<=,>,>= - Equality:
==,!=,IN,NOT IN - Logical:
NOT - Logical:
AND - Logical:
OR - Ternary:
? :
// Operators mit deutschen Kommentaren
FOR user IN users
// Comparison: Range-Check mit Index
FILTER user.age >= 18 AND user.age <= 65
// Set Membership (Index auf status)
FILTER user.status IN ['active', 'premium', 'trial']
// Negation mit Subquery
FILTER user.email NOT IN (
FOR blocked IN blacklist
RETURN blocked.email
)
// Ternary Operator fΓΌr bedingte Werte
LET discount = user.premium ? 0.20 : 0.10
LET tier = user.lifetime_value > 10000 ? 'gold' :
user.lifetime_value > 5000 ? 'silver' : 'bronze'
// Range Operator (..) fΓΌr numerische Bereiche
LET age_group = user.age IN 18..25 ? 'young' :
user.age IN 26..45 ? 'middle' :
user.age IN 46..65 ? 'senior' : 'retired'
// Arithmetic mit NULL-Handling (Coalescing)
LET base = user.base_price ?? 100.0
LET total = base * (1 - discount)
// Short-Circuit: Zweite Bedingung nur wenn erste false
FILTER user.verified == true OR
(user.email_confirmed AND user.phone_confirmed)
RETURN {
user: user.name,
discount_percent: discount * 100,
age_group,
tier,
total_price: ROUND(total, 2)
}
Arithmetische Operationen folgen IEEE 754 Standard fΓΌr FlieΓkomma-Arithmetik. Division durch Null ergibt NULL (nicht Infinity), um SQL-KompatibilitΓ€t zu gewΓ€hrleisten.
| Operator | Operation | Beispiel | Result Type |
|---|---|---|---|
+ |
Addition | 5 + 3 |
Number |
- |
Subtraktion | 5 - 3 |
Number |
* |
Multiplikation | 5 * 3 |
Number |
/ |
Division | 5 / 2 |
Number (2.5) |
% |
Modulo | 5 % 2 |
Integer (1) |
Subqueries in AQL ermΓΆglichen verschachtelte Datenverarbeitung und komplexe Aggregationen. Wir unterscheiden zwischen correlated (abhΓ€ngigen) und non-correlated (unabhΓ€ngigen) Subqueries, die drastisch unterschiedliche Performance-Charakteristiken aufweisen. Das VerstΓ€ndnis dieser Unterschiede ist kritisch fΓΌr Query-Optimierung in produktiven Systemen (siehe auch β Kapitel 21: Performance Tuning).
Non-Correlated Subqueries werden einmal ausgefΓΌhrt und ihr Ergebnis materialisiert. Dies ist optimal fΓΌr Performance, da keine wiederholte Evaluation stattfindet. Correlated Subqueries hΓ€ngen von Γ€uΓeren Variablen ab und werden pro Iteration der Γ€uΓeren Schleife ausgefΓΌhrt - dies kann zu nΓm KomplexitΓ€t fΓΌhren.
| Subquery Type | Execution Count | Performance | Optimization Strategy |
|---|---|---|---|
| Non-Correlated | 1Γ | Excellent | Materialize einmal, cache result |
| Correlated (no index) | n Γ m | Poor (O(nΒ²)) | Index hinzufΓΌgen oder zu JOIN refactoren |
| Correlated (indexed) | n Γ log(m) | Good (O(n log m)) | Index auf Join-Key |
| Existence Check | n | Good |
LIMIT 1 fΓΌr early exit |
// Correlated Subquery mit deutschen Kommentaren
FOR order IN orders
// Subquery in LET: Berechne Bestellsumme
// Correlated: HΓ€ngt von order._key ab
LET order_total = (
FOR item IN order_items
FILTER item.order_id == order._key // Index auf order_id essentiell!
RETURN item.quantity * item.price
)
// Subquery in FILTER: Existence Check
// LIMIT 1 fΓΌr Early Exit (Performance)
FILTER LENGTH(
FOR review IN reviews
FILTER review.order_id == order._key
LIMIT 1 // Stoppe nach erstem Match
RETURN 1
) > 0
RETURN {
order_id: order._key,
total: SUM(order_total),
has_review: true
}
// Non-Correlated Subquery (wird einmal ausgefΓΌhrt)
LET premium_users = (
FOR user IN users
FILTER user.subscription == 'premium'
RETURN user._key
)
// Hauptquery nutzt materialisiertes Ergebnis
FOR order IN orders
FILTER order.user_id IN premium_users // O(1) Lookup in Hash-Set
RETURN order
Subqueries kΓΆnnen in verschiedenen Kontexten verwendet werden, mit unterschiedlichen Semantiken:
- FOR-Subquery: Lateral Join, explodiert nested Arrays
- LET-Subquery: Berechnet Array/Object fΓΌr spΓ€tere Nutzung
- FILTER-Subquery: Boolean Predicate, oft Existence Check
// Verschiedene Subquery-Kontexte
FOR customer IN customers
// LET-Subquery: Berechne alle Bestellungen
LET customer_orders = (
FOR order IN orders
FILTER order.customer_id == customer._key
SORT order.created_at DESC
RETURN order
)
// LET-Subquery: Aggregation
LET total_spent = SUM(
FOR order IN customer_orders
RETURN order.amount
)
// FILTER-Subquery: Hat Kunde in letzten 30 Tagen bestellt?
FILTER LENGTH(
FOR order IN customer_orders
FILTER order.created_at >= DATE_NOW() - DAYS(30)
LIMIT 1
RETURN 1
) > 0
RETURN {
customer: customer.name,
order_count: LENGTH(customer_orders),
total_spent: ROUND(total_spent, 2),
last_order: FIRST(customer_orders).created_at
}
JOIN-Operationen verknΓΌpfen Daten aus mehreren Collections. AQL implementiert JOINs deklarativ durch verschachtelte FOR-Schleifen mit FILTER-Bedingungen. Der Query Optimizer erkennt JOIN-Patterns und wΓ€hlt optimale Execution Strategies (Nested Loop, Hash Join, Merge Join) basierend auf KardinalitΓ€ten und verfΓΌgbaren Indizes.
INNER JOIN behΓ€lt nur Zeilen, fΓΌr die ein Match existiert. LEFT JOIN behΓ€lt alle Zeilen der linken Seite, auch ohne Match (rechte Seite dann NULL). AQL implementiert LEFT JOINs durch LET + FIRST() Pattern, da FOR nur matched Rows zurΓΌckgibt.
// Multi-Collection JOIN mit deutschen Kommentaren
FOR order IN orders
// LEFT JOIN: Hole Kunden-Daten (kann NULL sein bei gelΓΆschten Kunden)
LET customer = FIRST(
FOR c IN customers
FILTER c._key == order.customer_id
RETURN c
)
// INNER JOIN: Hole Bestellpositionen
// FOR wirkt als INNER JOIN (keine Zeile ohne Match)
FOR item IN order_items
FILTER item.order_id == order._key
// Nested JOIN: Hole Produkt-Details
// DOCUMENT() ist schneller als FOR fΓΌr einzelne Lookups
LET product = DOCUMENT('products', item.product_id)
// Join mit Edge-Collection (Graph-Traversal Alternative)
// "Kunden die X kauften, kauften auch Y"
FOR edge IN purchased_with
FILTER edge._from == item._id
LET related_product = DOCUMENT(edge._to)
RETURN {
order_id: order._key,
customer_name: customer.name ?? 'Deleted User', // NULL-Handling
product: product.name,
quantity: item.quantity,
item_total: item.quantity * product.price,
also_bought: related_product.name
}
Die Wahl der JOIN-Strategie hΓ€ngt von Collection-GrΓΆΓen, Cardinalities und Indizes ab:
- Nested Loop Join: Optimal bei kleinen inneren Collections oder guten Indizes
- Hash Join: Optimal bei groΓen Collections ohne Index
- Merge Join: Optimal wenn beide Seiten sortiert sind
Optimization Checklist:
- Index auf Join-Keys (z.B.
order.customer_id,item.order_id) - Kleine Collection als innere Schleife (wenn mΓΆglich)
- Filter vor JOIN (reduziert Join-Kandidaten)
-
DOCUMENT()fΓΌr 1:1 Lookups (schneller alsFOR)
Transaktionen garantieren ACID-Eigenschaften fΓΌr Multi-Document-Operationen. ThemisDB unterstΓΌtzt Stream Transactions fΓΌr AQL-Queries und JavaScript Transactions fΓΌr prozedurale Logik. Wir fokussieren hier auf AQL Stream Transactions, die deklarative Syntax mit transaktionalen Garantien kombinieren (siehe auch β Kapitel 2: ACID & MVCC, Kapitel 34: Transaction Processing).
Stream Transactions in AQL nutzen MVCC (Multi-Version Concurrency Control) fΓΌr non-blocking Reads. Das Isolation Level ist standardmΓ€Γig READ COMMITTED, was bedeutet, dass nur committete Γnderungen sichtbar sind. FΓΌr hΓΆhere Isolation kann SERIALIZABLE gewΓ€hlt werden, was jedoch zu erhΓΆhtem Lock-Contention fΓΌhrt.
// AQL Stream Transaction mit deutschen Kommentaren
// JavaScript-Wrapper fΓΌr transaktionale Operationen
db._executeTransaction({
collections: {
write: ['accounts', 'transactions'], // Write-Lock
read: ['users'] // Read-Lock
},
action: function() {
const db = require('@arangodb').db;
const errors = require('@arangodb').errors;
// Hole beide Konten (atomare Snapshot-Isolation)
const fromAccount = db.accounts.document('account/123');
const toAccount = db.accounts.document('account/456');
const amount = 100.00;
// PrΓΌfe Kontostand (Business Logic)
if (fromAccount.balance < amount) {
throw new errors.ERROR_ARANGO_CONFLICT(
'Insufficient balance: ' + fromAccount.balance
);
}
// Atomare Updates (beide oder keine)
db.accounts.update(fromAccount._key, {
balance: fromAccount.balance - amount,
last_modified: Date.now()
});
db.accounts.update(toAccount._key, {
balance: toAccount.balance + amount,
last_modified: Date.now()
});
// Log Transaction (Audit Trail)
db.transactions.insert({
from: fromAccount._key,
to: toAccount._key,
amount: amount,
timestamp: Date.now(),
status: 'completed',
tx_id: require('@arangodb').generateUUID()
});
return {
success: true,
amount,
new_balance_from: fromAccount.balance - amount,
new_balance_to: toAccount.balance + amount
};
}
});Transaktionen werden automatisch bei uncaught Exceptions abgebrochen (rollback). Alle Γnderungen werden verworfen und die Datenbank bleibt konsistent. Explizites Abort ist mΓΆglich durch throw von Fehlern.
Performance Considerations:
- Transaktionen halten Locks β kurze TX bevorzugen
- Read-only Queries benΓΆtigen keine TX (MVCC ausreichend)
- Large Bulk Operations: Batch in kleinere TXs (z.B. 1000 Docs pro TX)
Graph-Traversal in AQL ermΓΆglicht Pfad-Analysen und Netzwerk-Queries auf Graph-Strukturen. Die Syntax unterstΓΌtzt variable Traversal-Tiefe, Richtungs-Spezifikation (OUTBOUND, INBOUND, ANY) und Pruning fΓΌr Performance-Optimierung. ThemisDB implementiert effiziente Graph-Algorithmen wie Breadth-First Search (BFS) und Depth-First Search (DFS) (siehe auch β Kapitel 10: Graph Model, Kapitel 21: Graph Query Optimization).
Breadth-First Search (BFS) exploriert alle Nachbarn einer Ebene, bevor zur nΓ€chsten Ebene gewechselt wird. Optimal fΓΌr Shortest Path Queries. Depth-First Search (DFS) folgt einem Pfad bis zur maximalen Tiefe, dann Backtracking. Optimal fΓΌr "alle Pfade finden".
| Algorithm | Use Case | Memory | Time Complexity |
|---|---|---|---|
| BFS | Shortest Path, Closeness | O(V) | O(V + E) |
| DFS | All Paths, Cycle Detection | O(depth) | O(V + E) |
// Graph Traversal mit Pruning und deutschen Kommentaren
FOR v, e, p IN 1..5 OUTBOUND 'users/alice'
GRAPH 'social_network'
// Pruning: Stoppe Traversal bei bestimmten Bedingungen
// Verhindert Exploration von "privaten" Profilen
PRUNE v.private == true OR v.blocked == true
// Filter Edges (nur bestimmte Beziehungstypen)
OPTIONS {
uniqueVertices: 'path', // Vermeide Zyklen (jeder Vertex max 1x pro Pfad)
uniqueEdges: 'path', // Jede Edge max 1x pro Pfad
bfs: true // Breadth-First Search (fΓΌr Shortest Paths)
}
// Filter nach Path-LΓ€nge (mindestens 2 Hops)
FILTER LENGTH(p.edges) >= 2
FILTER LENGTH(p.edges) <= 4
// Berechne Pfad-Gewicht (Summe der Edge-Weights)
LET path_weight = SUM(
FOR edge IN p.edges
RETURN edge.weight ?? 1.0 // Default weight 1.0
)
// Sortiere nach kΓΌrzestem gewichteten Pfad
SORT path_weight ASC, LENGTH(p.edges) ASC
LIMIT 10
RETURN {
friend: v.name,
distance: LENGTH(p.edges), // Hop-Distanz
path_weight, // Gewichtete Distanz
via: SLICE(p.vertices, 1, LENGTH(p.vertices) - 1)[*].name, // IntermediΓ€re Knoten
relationship_path: p.edges[*].type
}
AQL bietet spezielle Funktionen fΓΌr Shortest Path Queries: SHORTEST_PATH fΓΌr einen Pfad, K_SHORTEST_PATHS fΓΌr die k kΓΌrzesten Pfade. Diese Algorithmen sind optimiert und nutzen bidirektionale Suche fΓΌr bessere Performance.
// KΓΌrzester Pfad zwischen zwei Usern
FOR v, e IN OUTBOUND SHORTEST_PATH
'users/alice' TO 'users/bob'
GRAPH 'social_network'
OPTIONS {
weightAttribute: 'weight', // Nutze Edge-Weight
defaultWeight: 1.0
}
RETURN {
user: v.name,
connection_type: e.type
}
// K kΓΌrzeste Pfade (Top 3)
LET all_paths = (
FOR path IN OUTBOUND K_SHORTEST_PATHS
'users/alice' TO 'users/bob'
GRAPH 'social_network'
LIMIT 3
RETURN path
)
FOR path IN all_paths
LET path_length = LENGTH(path.edges)
LET path_weight = SUM(path.edges[*].weight)
LET path_index = POSITION(all_paths, path)
RETURN {
path_number: path_index + 1,
length: path_length,
weight: path_weight,
vertices: path.vertices[*].name
}
Query-Optimierung ist essentiell fΓΌr Performance in produktiven Systemen. AQL bietet das EXPLAIN-Statement zur Analyse von Query Plans und zur Identifikation von Performance-Bottlenecks. Wir analysieren systematisch Optimierungs-Strategien wie Index-Nutzung, Early Filtering, Projection Pushdown und Covering Indexes (siehe auch β Kapitel 21: Query Performance, Kapitel 34: Execution Plans).
EXPLAIN zeigt den logischen und physischen Query Plan inklusive geschΓ€tzter Kosten, Index-Nutzung und Execution Nodes. Die Interpretation erfordert VerstΓ€ndnis der Optimizer-Strategien:
Key Metrics:
- estimatedCost: GeschΓ€tzte Query-Kosten (niedriger = besser)
- estimatedNrItems: Erwartete Anzahl Ergebnisse
- Index Usage: Welche Indizes werden genutzt?
- Full Collection Scan: Wird gesamte Collection gelesen? (vermeiden!)
// EXPLAIN fΓΌr Query-Analyse
EXPLAIN
FOR user IN users
FILTER user.email == 'alice@example.com'
RETURN user
// Output zeigt:
// - IndexNode: users.email (Hash Index) β O(1) Lookup
// - estimatedCost: ~1.5 (sehr gut)
// - estimatedNrItems: 1
Der Optimizer wΓ€hlt automatisch den besten Index basierend auf Statistiken. Covering Indexes enthalten alle benΓΆtigten Felder und vermeiden Document-Lookups komplett - dies bringt 2-5Γ Speedup.
| Optimization | Impact | When to Apply | Example |
|---|---|---|---|
| Index Usage | 100-1000Γ | Filters auf indiziertem Feld | FILTER doc.email == @email |
| Early Filtering | 10-50Γ | Vor teuren Operationen (JOINs, Subqueries) |
FILTER vor FOR (JOIN) |
| Limit Pushdown | 5-20Γ | Pagination Queries |
LIMIT am Ende |
| Covering Index | 2-5Γ | Alle SELECT-Felder im Index |
INDEX(a, b, c) fΓΌr SELECT a, b, c
|
| Projection Pushdown | 2-10Γ | GroΓe Documents |
RETURN { id, name } statt RETURN doc
|
// Optimization Examples
// β SCHLECHT: Keine Index-Nutzung (Function Call)
FOR user IN users
FILTER UPPER(user.email) == "ALICE@EXAMPLE.COM"
RETURN user
// β
GUT: Index auf email wird genutzt
FOR user IN users
FILTER user.email == "alice@example.com"
RETURN user
// β SCHLECHT: Filter nach JOIN (alle Orders geladen)
FOR order IN orders
FOR user IN users
FILTER user._key == order.user_id
FILTER order.amount > 100 // Zu spΓ€t!
RETURN { order, user }
// β
GUT: Early Filtering vor JOIN
FOR order IN orders
FILTER order.amount > 100 // Index auf amount nutzen!
FOR user IN users
FILTER user._key == order.user_id
RETURN { order, user }
// β SCHLECHT: VollstΓ€ndige Documents
FOR user IN users
FILTER user.status == 'active'
RETURN user // 100+ Felder, nur 2 gebraucht
// β
GUT: Projection auf benΓΆtigte Felder
FOR user IN users
FILTER user.status == 'active'
RETURN { id: user._id, name: user.name } // Nur 2 Felder
// β
BEST: Covering Index auf (status, _id, name)
// β Kein Document-Lookup nΓΆtig, alle Daten im Index
// Note: Index creation ist ein DDL-Befehl, nicht Teil von AQL-Queries
// Wird via Database Management Interface ausgefΓΌhrt:
// db._createIndex("users", {type: "skiplist", fields: ["status", "_id", "name"]})
Der Optimizer schiebt Filter-Bedingungen mΓΆglichst frΓΌh in die Execution Pipeline (Filter Pushdown) und reduziert ΓΌbertragene Daten durch Projektion (Projection Pushdown). Dies minimiert I/O und Memory-Usage.
Benchmark: Query Optimization Impact
| Query Type | No Optimization | With Index | + Early Filter | + Projection | Speedup |
|---|---|---|---|---|---|
| Simple Filter | 1000 ms | 10 ms | 8 ms | 5 ms | 200Γ |
| JOIN Query | 5000 ms | 500 ms | 50 ms | 25 ms | 200Γ |
| Aggregation | 2000 ms | 100 ms | 80 ms | 60 ms | 33Γ |
Wir prΓ€sentieren nun eine systematische Kategorisierung aller 360+ eingebauten Funktionen von AQL. Diese Funktionen decken String-Manipulation, numerische Berechnungen, Datum/Zeit-Operationen, Array-Verarbeitung, Objekt-Manipulation, Geospatial-Queries und Vector-Operationen ab. Das VerstΓ€ndnis der Funktions-Kategorien und ihrer Performance-Charakteristiken ist fundamental fΓΌr effektives Query-Writing.
Die folgende Tabelle quantifiziert den Funktionsumfang und dokumentiert typische Use Cases sowie Performance-Impact. String- und numerische Funktionen haben minimalen Overhead (< 1 Β΅s), wΓ€hrend Graph-Funktionen mehrere Millisekunden benΓΆtigen kΓΆnnen.
| Function Category | Function Count | Performance Impact | Common Use Cases | Beispiele |
|---|---|---|---|---|
| String | 25+ | Low-Medium (1-10 Β΅s) | Text processing, search, validation |
CONCAT, REGEX_TEST, SUBSTRING
|
| Numeric | 18+ | Low (< 1 Β΅s) | Calculations, aggregations, rounding |
ROUND, ABS, CEIL, FLOOR, SQRT
|
| Date/Time | 45+ | Low (1-5 Β΅s) | Temporal queries, filtering, grouping |
DATE_NOW, DATE_DIFF, DATE_FORMAT
|
| Array | 22+ | Medium (10-100 Β΅s) | Collection manipulation, filtering |
PUSH, POP, UNIQUE, FLATTEN, INTERSECTION
|
| Object | 15+ | Medium (10-50 Β΅s) | Document transformation, merging |
MERGE, UNSET, KEEP, KEYS, VALUES
|
| Geo | 35+ | Medium-High (100-1000 Β΅s) | Spatial queries, distance calculations |
GEO_DISTANCE, GEO_CONTAINS, GEO_POINT
|
| Vector | 20+ | Medium-High (50-500 Β΅s) | Similarity search, embeddings |
COSINE_SIMILARITY, KNN_SEARCH, VECTOR_NORM
|
| Graph | 15+ | High (1-100 ms) | Traversal, path finding, centrality |
SHORTEST_PATH, PAGERANK, BETWEENNESS
|
String-Funktionen ermΓΆglichen Text-Manipulation, Pattern-Matching und Validierung. Regular Expressions werden mittels PCRE2-Library implementiert und unterstΓΌtzen moderne Regex-Features. Performance ist exzellent fΓΌr einfache Operationen, komplexe Regex kΓΆnnen jedoch Millisekunden benΓΆtigen.
Key Functions:
- CONCAT(str1, str2, ...): Concatenation ohne Separator
-
CONCAT_SEPARATOR(sep, str1, ...): Mit Trennzeichen (z.B.
", "fΓΌr CSV) - SUBSTRING(str, start, length): Extraktion von Teilstrings (0-indexed)
- UPPER(str) / LOWER(str): Case Conversion fΓΌr Normalisierung
- TRIM(str) / LTRIM(str) / RTRIM(str): Whitespace-Entfernung
- SPLIT(str, sep): String β Array (z.B. CSV-Parsing)
- REGEX_TEST(str, pattern): Boolean match (schnell fΓΌr Validierung)
- REGEX_MATCHES(str, pattern): Alle Matches extrahieren
- REGEX_REPLACE(str, pattern, repl): Pattern-basierte Ersetzung
// String Functions mit deutschen Kommentaren
FOR user IN users
// Email-Domain extrahieren
LET domain = SPLIT(user.email, "@")[1]
// Case-insensitive Normalisierung
LET normalized_name = UPPER(TRIM(user.name))
// Email-Validierung mit Regex
LET valid_email = REGEX_TEST(
user.email,
"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
)
// Extrahiere alle URLs aus Bio
LET urls = REGEX_MATCHES(
user.bio,
"https?://[^\\s<>\"]+",
true // Return all matches
)
// Anonymisiere Telefonnummer (zeige nur letzte 4 Ziffern)
LET phone_masked = REGEX_REPLACE(
user.phone,
"^(.*)(.{4})$",
"***-***-$2"
)
FILTER valid_email
RETURN {
name: normalized_name,
domain,
urls,
phone: phone_masked
}
Numerische Funktionen decken Basis-Arithmetik, trigonometrische Operationen und statistische Berechnungen ab. Alle Funktionen folgen IEEE 754 Standard fΓΌr Floating-Point-Arithmetik.
Key Functions:
- ROUND(x, decimals): KaufmΓ€nnisches Runden (Banker's Rounding)
- CEIL(x) / FLOOR(x): Aufrunden / Abrunden zu Integer
- ABS(x): Absoluter Betrag (Distanz zu 0)
- SQRT(x) / POW(x, y): Wurzel / Potenz
- MIN(...) / MAX(...): Minimum / Maximum mehrerer Werte
- SIN(x) / COS(x) / TAN(x): Trigonometrie (Radians!)
- LOG(x) / LOG10(x): Logarithmen (natΓΌrlich / Basis 10)
// Numeric Functions: Preisberechnung mit Rundung
FOR product IN products
// MwSt berechnen (19%) und auf 2 Dezimalstellen runden
LET price_with_tax = ROUND(product.price * 1.19, 2)
// Rabatt-Stufen basierend auf Preis
LET discount_pct =
product.price > 1000 ? 0.15 :
product.price > 500 ? 0.10 :
product.price > 100 ? 0.05 : 0.0
LET final_price = ROUND(price_with_tax * (1 - discount_pct), 2)
// Berechne Euklidische Distanz fΓΌr 2D-Koordinaten
LET distance = SQRT(
POW(product.x - @target_x, 2) +
POW(product.y - @target_y, 2)
)
RETURN {
product: product.name,
price: final_price,
discount: discount_pct * 100,
distance: ROUND(distance, 1)
}
Array-Funktionen ermΓΆglichen funktionale Programmierung mit Collections. Operationen wie MAP, FILTER, REDUCE folgen JavaScript-Semantik und ermΓΆglichen deklarative Datenverarbeitung.
Key Functions:
- PUSH(array, value) / POP(array): Stack-Operationen (LIFO)
- UNIQUE(array): Duplikate entfernen (nutzt Hash-Set intern)
- FLATTEN(array, depth): Nested Arrays flach machen
- INTERSECTION(a1, a2) / UNION(a1, a2): Mengen-Operationen
- SORT_ARRAY(array) / REVERSE_ARRAY(array): Ordnung
- SLICE(array, start, end): Teilarray extrahieren
// Array Functions: Finde gemeinsame Interessen
FOR user1 IN users
FOR user2 IN users
FILTER user1._key < user2._key // Vermeide Duplikate
// Gemeinsame Tags/Interests
LET common_tags = INTERSECTION(user1.tags, user2.tags)
// Vereinigung aller Tags
LET all_tags = UNIQUE(UNION(user1.tags, user2.tags))
// Similarity Score (Jaccard)
LET similarity = LENGTH(common_tags) / LENGTH(all_tags)
FILTER similarity > 0.3 // Mind. 30% Γberlappung
RETURN {
user1: user1.name,
user2: user2.name,
common: common_tags,
similarity: ROUND(similarity, 2)
}
Datum/Zeit-Funktionen unterstΓΌtzen Zeitzonen, Arbeitstage-Berechnungen und Interval-Arithmetik. ThemisDB nutzt ISO 8601 Format fΓΌr Timestamps und unterstΓΌtzt alle gΓ€ngigen Kalendersysteme.
Key Functions:
- DATE_NOW(): Current timestamp (UTC)
- DATE_DIFF(date1, date2, unit): Differenz in days/hours/minutes
- DATE_ADD(date, amount, unit): Datum + Interval
- DATE_FORMAT(date, format): Formatierung (strftime-like)
- WORKDAYS(start, end, calendar): Arbeitstage zwischen Daten
- WORKDAYS_ADD(date, days, calendar): Addiere Arbeitstage
// Date/Time Functions: SLA-Tracking
FOR ticket IN support_tickets
// Berechne SLA-Deadline (5 Arbeitstage)
LET sla_deadline = WORKDAYS_ADD(
ticket.created_at,
5,
"DE" // Deutscher Kalender (mit Feiertagen)
)
// Verbleibende Zeit
LET remaining_hours = DATE_DIFF(
DATE_NOW(),
sla_deadline,
'hour'
)
// Status
LET status =
remaining_hours < 0 ? 'OVERDUE' :
remaining_hours < 24 ? 'CRITICAL' :
remaining_hours < 48 ? 'WARNING' : 'OK'
FILTER status IN ['CRITICAL', 'OVERDUE']
RETURN {
ticket_id: ticket._key,
created: DATE_FORMAT(ticket.created_at, "%Y-%m-%d %H:%M"),
sla_deadline: DATE_FORMAT(sla_deadline, "%Y-%m-%d %H:%M"),
remaining_hours,
status
}
Wichtigste Funktionen:
-
DATE_NOW()- Aktueller ISO-Timestamp -
CURRENT_DATE()/CURRENT_TIME()- Nur Datum/Zeit -
UNIX_TIMESTAMP()- Unix Epoch
RETURN {
now: DATE_NOW(),
unix: UNIX_TIMESTAMP()
}
-- β {"now": "2025-01-15T10:30:45Z", "unix": 1736936445}
Interval-Arithmetik:
DAYS(n), HOURS(n), WEEKS(n) etc. fΓΌr Zeitberechnungen.
-- Letzte 30 Tage
FILTER order.created_at >= DATE_NOW() - DAYS(30)
-- FΓ€lligkeitsdatum berechnen
LET due = invoice.created_at + DAYS(14)
Komponenten extrahieren:
DATE_YEAR(), DATE_MONTH(), DATE_DAY(), DATE_HOUR(), etc.
-- Gruppierung nach Monat
COLLECT month = DATE_MONTH(sale.date)
AGGREGATE total = SUM(sale.amount)
WORKDAYS(start, end, calendar) -- Arbeitstage zwischen zwei Daten
WORKDAYS_ADD(date, days, calendar) -- Addiere Arbeitstage
IS_WEEKEND(date) -- true wenn Samstag/Sonntag
IS_WORKDAY(date, calendar) -- true wenn Arbeitstag
HOLIDAYS(country, year) -- Liste der Feiertage
HOLIDAYS_BETWEEN(start, end, country) -- Feiertage in Zeitraum
Beispiele:
-- Berechne SLA-Frist (5 Arbeitstage)
FOR ticket IN support_tickets
RETURN {
ticket_id: ticket._key,
created: ticket.created_at,
sla_deadline: WORKDAYS_ADD(ticket.created_at, 5, "DE")
}
-- Finde Tickets, die am Wochenende erstellt wurden
FOR ticket IN support_tickets
FILTER IS_WEEKEND(ticket.created_at)
RETURN ticket
CONCAT(str1, str2, ...) -- Strings zusammenfΓΌgen
CONCAT_SEPARATOR(sep, str1, ...) -- Mit Trennzeichen
SUBSTRING(str, start, length) -- Teilstring
UPPER(str) -- GroΓbuchstaben
LOWER(str) -- Kleinbuchstaben
TRIM(str) -- Whitespace entfernen
LTRIM(str) -- Links trimmen
RTRIM(str) -- Rechts trimmen
LENGTH(str) -- LΓ€nge
REVERSE(str) -- Umkehren
REPLACE(str, search, replace) -- Ersetzen
SPLIT(str, separator) -- In Array aufteilen
JOIN(array, separator) -- Array zu String
STARTS_WITH(str, prefix) -- Startet mit
ENDS_WITH(str, suffix) -- Endet mit
CONTAINS(str, substring) -- EnthΓ€lt
FIND(str, substring) -- Position finden
REGEX_TEST(str, pattern) -- Regex-Match?
REGEX_MATCHES(str, pattern) -- Alle Matches
REGEX_REPLACE(str, pattern, repl) -- Regex-Ersetzung
Beispiele:
-- Email-Domain extrahieren
FOR user IN users
LET domain = SPLIT(user.email, "@")[1]
RETURN { user: user.name, domain }
-- Case-insensitive Suche
FOR article IN articles
FILTER CONTAINS(LOWER(article.title), LOWER("ThemisDB"))
RETURN article
-- Email-Validierung mit Regex
FOR user IN users
FILTER REGEX_TEST(user.email, "^[^@]+@[^@]+\\.[^@]+$")
RETURN user
-- Basic Math
ABS(x) -- Betrag
CEIL(x) -- Aufrunden
FLOOR(x) -- Abrunden
ROUND(x, d) -- Runden auf d Dezimalstellen
SQRT(x) -- Quadratwurzel
POW(x, y) -- x hoch y
EXP(x) -- e^x
LOG(x) -- NatΓΌrlicher Logarithmus
LOG10(x) -- Logarithmus zur Basis 10
LN(x) -- Alias fΓΌr LOG
-- Trigonometric
SIN(x) -- Sinus
COS(x) -- Kosinus
TAN(x) -- Tangens
ASIN(x) -- Arkussinus
ACOS(x) -- Arkuskosinus
ATAN(x) -- Arkustangens
ATAN2(y, x) -- Arkustangens mit Vorzeichen
SINH(x) -- Hyperbelsinus
COSH(x) -- Hyperbelkosinus
TANH(x) -- Hyperbeltangens
-- Utilities
MIN(a, b, ...) -- Minimum
MAX(a, b, ...) -- Maximum
RAND() -- Zufallszahl [0, 1)
RAND_INT(a, b) -- Ganzzahl zwischen a und b
PI() -- Ο
E() -- e
SIGN(x) -- Vorzeichen (-1, 0, 1)
TRUNC(x) -- Ganzzahlteil
MOD(x, y) -- Modulo
QUOTIENT(x, y) -- Ganzzahlige Division
Beispiele:
-- Berechne Entfernung mit Pythagoras
FOR point IN points
LET distance = SQRT(POW(point.x, 2) + POW(point.y, 2))
RETURN { point: point._key, distance }
-- ZufΓ€lliges Sampling (10%)
FOR doc IN documents
FILTER RAND() < 0.1
RETURN doc
-- Preisberechnung mit Rundung
FOR product IN products
LET price_with_tax = ROUND(product.price * 1.19, 2)
RETURN { product: product.name, price_with_tax }
PUSH(array, value) -- Element anhΓ€ngen
POP(array) -- Letztes Element entfernen
SHIFT(array) -- Erstes Element entfernen
UNSHIFT(array, value) -- Element vorne einfΓΌgen
APPEND(array, value) -- Alias fΓΌr PUSH
PREPEND(array, value) -- Alias fΓΌr UNSHIFT
FIRST(array) -- Erstes Element
LAST(array) -- Letztes Element
NTH(array, n) -- n-tes Element
SLICE(array, start, end) -- Teilarray
FLATTEN(array, depth) -- Array flach machen
UNIQUE(array) -- Duplikate entfernen
UNION(array1, array2) -- Vereinigung
INTERSECTION(array1, array2) -- Schnittmenge
DIFFERENCE(array1, array2) -- Differenz
MAP(array, fn) -- Transform
FILTER(array, fn) -- Filtern
REDUCE(array, fn, init) -- Reduzieren
SORT_ARRAY(array) -- Sortieren
REVERSE_ARRAY(array) -- Umkehren
Beispiele:
-- Finde gemeinsame Tags
FOR doc1 IN documents
FOR doc2 IN documents
FILTER doc1._key < doc2._key
LET common_tags = INTERSECTION(doc1.tags, doc2.tags)
FILTER LENGTH(common_tags) > 0
RETURN { doc1: doc1._key, doc2: doc2._key, common_tags }
-- Extrahiere alle einzigartigen Kategorien
RETURN UNIQUE(FLATTEN(
FOR product IN products
RETURN product.categories
))
GEO_POINT(lng, lat)
GEO_MULTIPOINT(points)
GEO_LINESTRING(coords)
GEO_MULTILINESTRING(lines)
GEO_POLYGON(rings)
GEO_MULTIPOLYGON(polygons)
Beispiel:
-- Erstelle Restaurant mit Location
INSERT {
name: "Bella Italia",
location: GEO_POINT(13.405, 52.520) -- Berlin
} INTO restaurants
GEO_CONTAINS(geo1, geo2) -- geo1 enthΓ€lt geo2
GEO_INTERSECTS(geo1, geo2) -- geo1 schneidet geo2
ST_Contains(geo1, geo2) -- Alias
ST_Within(geo2, geo1) -- geo2 innerhalb geo1
ST_Intersects(geo1, geo2) -- Alias
GEO_EQUALS(geo1, geo2) -- Geometrisch gleich
Beispiel:
-- Finde Restaurants in Polygon (Stadtteil)
LET polygon = GEO_POLYGON([
[13.40, 52.52], [13.41, 52.52],
[13.41, 52.51], [13.40, 52.51],
[13.40, 52.52]
])
FOR restaurant IN restaurants
FILTER GEO_CONTAINS(polygon, restaurant.location)
RETURN restaurant
GEO_DISTANCE(geo1, geo2) -- Haversine-Distanz (Meter)
ST_Distance(geo1, geo2) -- Alias
GEO_IN_RANGE(geo, center, radius) -- Innerhalb Radius
GEO_AREA(polygon) -- FlΓ€che (mΒ²)
ST_Area(polygon) -- Alias
ST_Length(linestring) -- LΓ€nge (Meter)
Beispiel:
-- Finde Restaurants innerhalb 1 km
LET my_location = GEO_POINT(13.405, 52.520)
FOR restaurant IN restaurants
LET distance = GEO_DISTANCE(my_location, restaurant.location)
FILTER distance <= 1000
SORT distance ASC
RETURN { name: restaurant.name, distance }
ST_TRANSFORM(geo, from_crs, to_crs)
ST_SRID(geo) -- SRID auslesen
ST_SetSRID(geo, srid) -- SRID setzen
WGS84_TO_UTM(lng, lat) -- WGS84 β UTM
UTM_TO_WGS84(easting, northing, zone)
ETRS89_TO_WGS84(x, y)
WGS84_TO_ETRS89(lng, lat)
HELMERT_TRANSFORM(x, y, params) -- 7-Parameter-Transformation
GAUSS_KRUEGER_TO_UTM(x, y)
UTM_TO_GAUSS_KRUEGER(easting, northing)
Beispiel:
-- Transformiere GPS-Koordinaten nach UTM (fΓΌr genaue Distanzmessung)
FOR location IN survey_points
LET utm = WGS84_TO_UTM(location.lng, location.lat)
RETURN { location: location._key, utm }
-- Similarity Metrics
COSINE_SIMILARITY(v1, v2)
DOT_PRODUCT(v1, v2)
EUCLIDEAN_DISTANCE(v1, v2)
MANHATTAN_DISTANCE(v1, v2)
HAMMING_DISTANCE(v1, v2)
JACCARD_SIMILARITY(v1, v2)
-- Vector Operations
VECTOR_NORM(v) -- L2-Norm
VECTOR_NORMALIZE(v) -- Auf LΓ€nge 1 normalisieren
VECTOR_ADD(v1, v2)
VECTOR_SUBTRACT(v1, v2)
VECTOR_MULTIPLY(v, scalar)
VECTOR_DIVIDE(v, scalar)
VECTOR_DOT(v1, v2) -- Alias fΓΌr DOT_PRODUCT
VECTOR_CROSS(v1, v2) -- Kreuzprodukt (nur 3D)
-- Distance Metrics
L1_DISTANCE(v1, v2) -- Manhattan
L2_DISTANCE(v1, v2) -- Euclidean
CHEBYSHEV_DISTANCE(v1, v2) -- Max-Norm
-- Search
KNN_SEARCH(collection, query_vector, k)
VECTOR_QUANTIZE(v, bits) -- Quantisierung (SQ8, SQ4)
Beispiele:
-- Semantic Search mit Embeddings
LET query_embedding = EMBED("machine learning tutorial")
FOR doc IN embeddings
LET similarity = COSINE_SIMILARITY(query_embedding, doc.vector)
SORT similarity DESC
LIMIT 10
RETURN { doc: doc.title, similarity }
-- KNN-Search mit Prefilter
FOR result IN KNN_SEARCH(
embeddings,
EMBED("neural networks"),
20,
{ filter: "category == 'AI'" }
)
RETURN result
-- Traversal
OUTBOUND(vertex, edge_collection)
INBOUND(vertex, edge_collection)
ANY(vertex, edge_collection)
SHORTEST_PATH(start, end, edge_collection)
-- Path Metrics
PATH_LENGTH(path)
PATH_VERTICES(path)
PATH_EDGES(path)
-- Algorithms
CONNECTED_COMPONENTS(graph)
PAGERANK(graph)
BETWEENNESS_CENTRALITY(graph, vertex)
CLOSENESS_CENTRALITY(graph, vertex)
COMMUNITY_DETECTION(graph)
-- Utilities
IS_CONNECTED(graph, v1, v2)
GRAPH_DIAMETER(graph)
GRAPH_RADIUS(graph)
Beispiele:
-- PageRank auf Social Graph
LET pageranks = PAGERANK({
vertexCollections: ["users"],
edgeCollections: ["follows"]
})
FOR user IN users
SORT pageranks[user._key] DESC
LIMIT 10
RETURN { user: user.name, score: pageranks[user._key] }
-- Finde Communities
LET communities = COMMUNITY_DETECTION({
vertexCollections: ["users"],
edgeCollections: ["friends"]
})
FOR user IN users
RETURN { user: user.name, community: communities[user._key] }
-- β SCHLECHT: Keine Index-Nutzung
FOR user IN users
FILTER UPPER(user.email) == "ALICE@EXAMPLE.COM"
RETURN user
-- β
GUT: Index auf email (case-insensitive)
FOR user IN users
FILTER user.email == "alice@example.com"
RETURN user
-- β SCHLECHT: Filter nach JOIN
FOR order IN orders
FOR user IN users
FILTER user._key == order.user_id
FILTER order.amount > 100
RETURN { order, user }
-- β
GUT: Filter vor JOIN
FOR order IN orders
FILTER order.amount > 100
FOR user IN users
FILTER user._key == order.user_id
RETURN { order, user }
-- β SCHLECHT: VollstΓ€ndige Dokumente
FOR user IN users
RETURN user
-- β
GUT: Nur benΓΆtigte Felder
FOR user IN users
RETURN { name: user.name, email: user.email }
AQL bietet 479 Sprachelemente:
- 119 Keywords fΓΌr Struktur und Semantik
- 360 Funktionen fΓΌr Datenmanipulation
- Date/Time (45): Umfassende ZeitzonenunterstΓΌtzung, Arbeitstage
- Strings (20): Regex, Splitting, Manipulation
- Math (30): Trigonometrie, Statistik
- Arrays (20): Funktionale Programmierung
- Geo (35): GeoJSON, CRS-Transformationen
- Vectors (20): ANN-Search, Similarity
- Graph (15): Traversal, Centrality, Communities
- Kapitel 5-9: Praktische Beispiele fΓΌr jedes Datenmodell
- Kapitel 21: Query Optimization
- AQL Grammar: aql/AQL_GRAMMAR_EXTENDED_v1.3.1.ebnf
-- Find all ancestors up to depth N
LET find_ancestors = FUNCTION(person_id, max_depth) {
RETURN (
FOR v, e, p IN 0..max_depth OUTBOUND person_id GRAPH 'family'
FILTER CURRENT.generation < person_id.generation
RETURN {
person: v.name,
generation: v.generation,
depth: LENGTH(p.edges)
}
)
}
RETURN find_ancestors('persons/alice', 3)
-- Get all projects reachable from a given person (including transitive deps)
FOR p IN projects
FILTER p._id == 'projects/prj1'
LET all_deps = (
FOR dep IN 0..10 OUTBOUND p GRAPH 'depends_on'
RETURN dep._id
) | UNIQUE()
RETURN {
project: p.name,
dependencies: all_deps,
dep_count: LENGTH(all_deps)
}
-- Calculate moving average with time window (7 days)
FOR current_date IN DATE_RANGE(@start_date, @end_date, '1d')
LET window_start = DATE_SUBTRACT(current_date, 7, 'd')
LET daily_data = (
FOR event IN events
FILTER event.date >= window_start AND event.date <= current_date
RETURN event.value
)
RETURN {
date: current_date,
moving_avg: AVG(daily_data),
moving_sum: SUM(daily_data),
moving_count: COUNT(daily_data)
}
-- Unnest nested arrays
FOR order IN orders
LET items = order.items -- Array of {product_id, quantity}
FOR item IN items
LET product = DOCUMENT('products/' + item.product_id)
RETURN {
order_id: order._id,
product_name: product.name,
quantity: item.quantity,
item_total: item.quantity * product.price
}
-- Convert months to columns
FOR record IN sales
COLLECT year = YEAR(record.date)
AGGREGATE
jan = SUM(record.amount FILTER MONTH(record.date) == 1),
feb = SUM(record.amount FILTER MONTH(record.date) == 2),
mar = SUM(record.amount FILTER MONTH(record.date) == 3),
q1_total = SUM(record.amount FILTER MONTH(record.date) IN [1,2,3])
RETURN { year, jan, feb, mar, q1_total }
-- Rank students by score within each class
FOR s IN students
SORT s.class, s.score DESC
LET rank_in_class = (
SELECT COUNT(*) FROM students s2
WHERE s2.class == s.class AND s2.score >= s.score
)
RETURN {
name: s.name,
class: s.class,
score: s.score,
rank: rank_in_class
}
-- Sales running total
FOR order IN SORT(orders, 'created_at')
COLLECT idx = @row_number
AGGREGATE
order_value = order.amount,
cumulative = SUM(orders[* FILTER @row_number <= idx].amount)
RETURN {
order_id: order._id,
order_value,
cumulative,
running_total: cumulative
}
-- Get first and last transaction per account
FOR t IN transactions
SORT t.account_id, t.timestamp
COLLECT account = t.account_id INTO group = t
RETURN {
account,
first_transaction: group[0],
last_transaction: group[LENGTH(group)-1],
total_transactions: LENGTH(group)
}
-- Compare consecutive values
FOR metric IN SORT(metrics, 'timestamp')
LET current_idx = @row_number
LET prev = (
FOR m IN metrics
FILTER m.timestamp < metric.timestamp
SORT m.timestamp DESC
LIMIT 1
RETURN m
)[0]
RETURN {
timestamp: metric.timestamp,
value: metric.value,
previous_value: prev?.value || NULL,
change: metric.value - (prev?.value || metric.value)
}
-- Type predicates (return true/false)
IS_ARRAY(value) -- Array type
IS_BOOL(value) -- Boolean
IS_NUMBER(value) -- Number (int or float)
IS_INTEGER(value) -- Integer specifically
IS_STRING(value) -- String
IS_NULL(value) -- Null/undefined
IS_OBJECT(value) -- Object/Document
IS_LIST(value) -- Alias for IS_ARRAY
IS_DEFINED(value) -- Has definition (not null)
-- Examples
FOR doc IN collection
FILTER IS_STRING(doc.email) && IS_NUMBER(doc.age)
RETURN doc
-- Convert between types
TO_STRING(value) -- Convert to string
TO_NUMBER(value) -- Convert to number
TO_BOOL(value) -- Convert to boolean
TO_ARRAY(value) -- Convert to array
TO_ARRAY(list) -- Ensure is array
TO_LIST(value) -- Alias for TO_ARRAY
-- Examples
FOR doc IN collection
RETURN {
id: doc._id,
price_str: TO_STRING(doc.price),
age: TO_NUMBER(doc.age_str),
is_active: TO_BOOL(doc.active_flag)
}
-- Safe type operations
COALESCE(a, b, c) -- Return first non-null
FIRST_ITEM(array) -- Get first item safely
LAST_ITEM(array) -- Get last item safely
NTH_ITEM(array, n) -- Get nth item safely
-- Examples
FOR doc IN collection
RETURN {
id: doc._id,
phone: COALESCE(doc.phone, doc.mobile, "N/A"),
first_tag: FIRST_ITEM(doc.tags),
primary_contact: NTH_ITEM(doc.contacts, 0)
}
-- Basic error handling
BEGIN
TRY
LET result = 100 / 0 -- Will error
RETURN result
CATCH err
RETURN { error: err.message, code: err.code }
COMMIT
-- Throw custom errors
FOR user IN users
FILTER user.balance < 0
THROW "INVARIANT_VIOLATED: Negative balance for user " + user._id
RETURN user
-- Validate document structure
FOR doc IN users
LET valid = (
IS_STRING(doc.name) &&
IS_STRING(doc.email) &&
IS_OBJECT(doc.address) &&
IS_ARRAY(doc.tags) &&
CONTAINS(doc.email, "@")
)
FILTER valid
RETURN doc
-- Indexes for: email (unique), status, created_at
-- β Index not used (UPPER)
FOR u IN users
FILTER UPPER(u.email) == "ALICE@EXAMPLE.COM"
RETURN u
-- β
Index used (direct match)
FOR u IN users
FILTER u.email == "alice@example.com"
RETURN u
-- β
Composite index: (status, created_at)
FOR u IN users
FILTER u.status == 'active'
FILTER u.created_at >= '2025-01-01'
RETURN u
-- β οΈ Index partial (filter before join)
FOR u IN users
FILTER u.status == 'active'
FOR o IN orders FILTER o.user_id == u._id
RETURN { u, o }
-- β Slow: Iterate then aggregate
LET users_active = (
FOR u IN users
FILTER u.status == 'active'
RETURN u
)
RETURN { count: LENGTH(users_active) }
-- β
Fast: Aggregate in query
FOR u IN users
FILTER u.status == 'active'
COLLECT WITH COUNT INTO count
RETURN { count }
-- β
Fastest: With aggregation function
FOR u IN users
FILTER u.status == 'active'
AGGREGATE count = COUNT(1)
RETURN { count }
-- β Subquery in FILTER (repeats for each row)
FOR order IN orders
FILTER order.user_id IN (
SELECT _id FROM users WHERE status == 'premium'
)
RETURN order
-- β
Join directly (index on user_id)
FOR user IN users
FILTER user.status == 'premium'
FOR order IN orders
FILTER order.user_id == user._id
RETURN order
-- Batch processing
FOR page IN 0..@max_pages
LET batch_start = page * @page_size
FOR user IN users
SORT user._key
LIMIT batch_start, @page_size
RETURN {
batch_number: page,
user
}
-- Update multiple documents
FOR user IN users
FILTER user.created_at < DATE_SUBTRACT(DATE_NOW(), 1, 'y')
UPDATE user WITH {
status: 'inactive',
last_updated: DATE_NOW(),
archive_flag: true
} IN users
RETURN OLD -- Return before-update document
-- Delete with rollback on condition
BEGIN
LET to_delete = (
FOR d IN documents
FILTER d.archived == true
FILTER d.created_at < DATE_SUBTRACT(DATE_NOW(), 2, 'y')
RETURN d
)
IF LENGTH(to_delete) > 0 THEN
FOR doc IN to_delete
REMOVE doc IN documents
COMMIT
ELSE
ABORT "No documents to delete"
ENDIF
RETURN { deleted: LENGTH(to_delete) }
- Iteration: FOR...IN
- Condition: FILTER
- Binding: LET
- Grouping: COLLECT
- Ordering: SORT
- Limiting: LIMIT
- Output: RETURN
- Transactions: BEGIN...COMMIT
- COUNT - Aggregation
- FILTER - Predicate logic
- LENGTH - Array/string size
- SUM - Numeric aggregation
- CONCAT - String joining
- CONTAINS - Substring search
- SPLIT - String splitting
- SORT - Ordering
- LIMIT - Result limiting
- DATE_NOW - Current timestamp
- UPPER/LOWER - Case conversion
- ROUND - Numeric rounding
- AVG - Mean aggregation
- MIN/MAX - Range extremes
- REGEX - Pattern matching
- DISTANCE - Geospatial
- SUBSTRING - String slicing
- TO_STRING - Type conversion
- FLATTEN - Array flattening
- UNIQUE - Deduplication
| Goal | Use | Example |
|---|---|---|
| Iterate docs | FOR...IN | FOR u IN users RETURN u |
| Filter rows | FILTER | FILTER u.status == 'active' |
| Create variable | LET | LET age = DATE_DIFF(u.birth, NOW()) |
| Group rows | COLLECT | COLLECT status = u.status |
| Order results | SORT | SORT u.created_at DESC |
| Limit results | LIMIT | LIMIT 100 |
| Return data | RETURN | RETURN u.name |
| Atomic ops | BEGIN...COMMIT | Transactions |
- Indexes on FILTER fields
- Indexes on SORT fields
- Early filtering (before JOINs)
- Projections (only needed fields)
- COLLECT for aggregations
- Avoid expressions in FILTER
- Use bind parameters
- Batch operations with LIMIT
Kapitel 28 von 30 | Teil IV: Referenz | ~7.800 WΓΆrter
-
ArangoDB Documentation Team (2024). ArangoDB AQL Documentation - Query Language Reference. ArangoDB GmbH. https://www.arangodb.com/docs/stable/aql/ - Offizielle Referenz fΓΌr AQL-Syntax, Funktionen und Best Practices.
-
Date, C.J. (2015). SQL and Relational Theory: How to Write Accurate SQL Code (3rd Edition). O'Reilly Media. ISBN: 978-1491941171 - Fundamentale Prinzipien relationaler Query-Sprachen und logischer Query-Verarbeitung.
-
Silberschatz, A., Korth, H.F., Sudarshan, S. (2020). Database System Concepts (7th Edition). McGraw-Hill Education. ISBN: 978-0078022159 - Kapitel ΓΌber Query Processing, Optimization und Transaction Management.
-
Robinson, I., Webber, J., Eifrem, E. (2015). Graph Databases: New Opportunities for Connected Data (2nd Edition). O'Reilly Media. ISBN: 978-1491930892 - Graph-Traversal-Algorithmen, Pfadsuche und Pattern-Matching in Graph-Datenbanken.
-
Garcia-Molina, H., Ullman, J.D., Widom, J. (2008). Database Systems: The Complete Book (2nd Edition). Pearson. ISBN: 978-0131873254 - Umfassende Behandlung von Query-Execution, Index-Strukturen und Optimizer-Strategien.
-
Sadalage, P.J., Fowler, M. (2012). NoSQL Distilled: A Brief Guide to the Emerging World of Polyglot Persistence. Addison-Wesley. ISBN: 978-0321826626 - Query-Patterns fΓΌr NoSQL-Systeme, Multi-Model-Datenbanken und Aggregat-orientierte Modelle.
-
Winand, M. (2012). SQL Performance Explained. Markus Winand. ISBN: 978-3950307818 - Index-Nutzung, Query-Optimization und Performance-Tuning-Techniken (ΓΌbertragbar auf AQL).
-
ThemisDB Community (2024). AQL Performance Tuning Guide. GitHub Repository. https://github.com/themisdb/docs/aql-performance - Community Best Practices fΓΌr AQL-Optimierung und Benchmark-Ergebnisse.
- Kapitel 2: Architektur & Core Concepts (ACID, MVCC, Base Entity)
- Kapitel 7: AQL Advanced Topics (Complex Queries, Optimization)
- Kapitel 8: Multi-Model Queries (Cross-Model Joins)
- Kapitel 10: Graph Database Model (Traversal Algorithms)
- Kapitel 21: Performance Tuning & Benchmarking
- Kapitel 34: Query Optimizer Internals (Execution Plans, Statistics)
- AQL Grammar: aql/AQL_GRAMMAR_EXTENDED_v1.3.1.ebnf
#include "aql/aql_query_builder.h"
// Fluent API fΓΌr AQL-Queries
themis::aql::AQLQueryBuilder builder;
auto query = builder
.from("orders")
.filter("amount > 1000")
.filter("status == 'shipped'")
.sort("created_at", /*ascending=*/ false)
.limit(100)
.offset(0)
.select({"id", "customer_id", "amount", "created_at"})
.build();
// Query validieren
if (!builder.isValid()) {
auto issues = builder.getIssues();
for (auto& issue : issues) {
std::cerr << "AQL-Fehler: " << issue.message << "\n";
}
}
// Query ausfΓΌhren
auto result = query_engine.execute(query.toString());
// JOIN-Query
auto join_query = builder
.from("orders AS o")
.join("customers AS c ON o.customer_id == c.id")
.filter("c.country == 'DE'")
.select({"o.id", "o.amount", "c.name"})
.build();#include "aql/aql_query_validator.h"
themis::aql::AQLQueryValidator validator(schema_manager);
// Query validieren
auto result = validator.validate(aql_query_string);
if (result.hasErrors()) {
for (auto& issue : result.errors()) {
// issue.severity: ERROR / WARNING / INFO
// issue.message, issue.line, issue.column
std::cerr << "[" << to_string(issue.severity) << "] "
<< issue.message
<< " at line " << issue.line << "\n";
}
}
if (result.hasWarnings()) {
// Warnungen anzeigen (Query kann trotzdem ausgefΓΌhrt werden)
for (auto& w : result.warnings()) {
std::cerr << "Warning: " << w.message << "\n";
}
}ValidationIssue::Severity: ERROR / WARNING / INFO
#include "aql/aql_optimizer_advisor.h"
themis::aql::AQLOptimizerAdvisor advisor(schema_manager, stats_collector);
// Query analysieren
auto advice = advisor.analyze(aql_query_string);
// Empfehlungen ausgeben
for (auto& rec : advice.recommendations) {
// rec.type: ADD_INDEX / REWRITE_FILTER / USE_COVERING_INDEX / ...
// rec.description: "Consider adding index on orders.customer_id"
// rec.estimated_speedup: 5.2x
std::cout << rec.description
<< " (speedup: " << rec.estimated_speedup << "x)\n";
}
// Optimierten Query-Plan ausgeben
std::cout << advice.optimized_query << "\n";
// Index-Empfehlungen extrahieren
auto index_recs = advisor.getIndexRecommendations(query_history);
// index_recs: [{table, column, type, estimated_benefit}, ...]#include "aql/aql_conversation_context.h"
themis::aql::AQLConversationContext::Config ctx_cfg;
ctx_cfg.max_turns = 10;
ctx_cfg.remember_schema = true;
ctx_cfg.auto_correct = true;
themis::aql::AQLConversationContext ctx(llm_handler, ctx_cfg);
ctx.setSchemaContext(schema_json);
// Erste Frage
auto turn1 = ctx.ask("Zeige mir alle Bestellungen ΓΌber 1000β¬");
// turn1.aql_query: "FOR o IN orders FILTER o.amount > 1000 RETURN o"
// turn1.explanation: "Filtert Bestellungen mit amount > 1000"
// Follow-up (nutzt Kontext aus Turn 1)
auto turn2 = ctx.ask("Nur die aus Deutschland");
// turn2.aql_query: "FOR o IN orders FILTER o.amount > 1000 AND o.country == 'DE' RETURN o"
// Kontext zurΓΌcksetzen
ctx.reset();#include "aql/aql_migration_assistant.h"
themis::aql::AQLMigrationAssistant migrator(llm_handler);
// SQL-Query migrieren
auto result = migrator.migrate(
"SELECT o.id, c.name, o.amount "
"FROM orders o "
"JOIN customers c ON o.customer_id = c.id "
"WHERE o.amount > 1000 "
"ORDER BY o.created_at DESC "
"LIMIT 100"
);
// Ergebnis prΓΌfen
if (result.is_fully_automatable) {
std::cout << "Migrierter AQL:\n" << result.aql_query << "\n";
} else {
// Teilweise manuell
for (auto& issue : result.issues) {
// issue.severity: BLOCKING / WARNING / INFO
// issue.original_construct: "LATERAL JOIN"
// issue.recommendation: "Nutze Subquery in AQL"
std::cout << issue.original_construct
<< " β " << issue.recommendation << "\n";
}
}MigrationIssue::Severity: BLOCKING / WARNING / INFO
#include "aql/aql_agent.h"
// Tool-Definitionen fΓΌr den Agenten
themis::aql::AgentTool query_tool{"execute_aql",
"FΓΌhrt einen AQL-Query aus und gibt Ergebnisse zurΓΌck",
&execute_aql_fn};
themis::aql::AgentTool schema_tool{"get_schema",
"Gibt das Schema einer Collection zurΓΌck",
&get_schema_fn};
// Agent konfigurieren
themis::aql::AgentConfig agent_cfg;
agent_cfg.max_steps = 10;
agent_cfg.verbose = true;
agent_cfg.model = "llama3-70b";
// Agent instanziieren
auto agent = themis::aql::createAgent(llm_handler, agent_cfg);
agent->registerTool(query_tool);
agent->registerTool(schema_tool);
// Aufgabe ausfΓΌhren
auto result = agent->run("Finde die Top-10 Kunden nach Umsatz letzten Monat");
// result.succeeded, result.answer, result.steps, result.aql_queries_executed
for (auto& step : result.steps) {
// step.thought: "Ich muss die Bestellungen gruppieren"
// step.action: "execute_aql"
// step.observation: "[{customer_id: ..., total: ...}]"
std::cout << "Step: " << step.thought << "\n";
}ThemisDB 1.9.0-beta Β· Home Β· Module-Index Β· GitHub Β· Issues
ThemisDB 1.9.0-beta Β· Home Β· Wiki-Index Β· Module-Index Β· FAQ Β· Quick-Reference Β· GitHub Β· Issues Β· Discussions Β· License
- Home
- Hero Articles
- All Wiki Pages
- FAQ
- Edition Comparison
- Repository README
- Changelog
- Roadmap
- Versioning
- Integration Mapping
- Overview
- Readme
- Appendix D Feature Status
- Appendix E Incident Runbooks
- Appendix F AQL Cheatsheet
- Appendix G Configuration
- Appendix H Glossary
- Appendix I Troubleshooting
- Appendix Literatur
- Chapter 00 Genesis
- Chapter 01 Introduction
- Chapter 02 Architecture
- Chapter 03 Multimodel
- Chapter 04 Installation
- Chapter 05 Relational
- Chapter 06 Graph
- Chapter 07 Document
- Chapter 08 Storage Layer
- Chapter 08 Vector
- Chapter 09 Timeseries
- Chapter 10 Enterprise
- Chapter 11 Realtime
- Chapter 12 Computervision
- Chapter 13 Fulltext
- Chapter 14 Geospatial
- Chapter 15 Analytics
- Chapter 16 Ml
- Chapter 16 Sharding
- Chapter 17 LLM Integration
- Chapter 17 Scaling
- Chapter 18 HA
- Chapter 18 Ml
- Chapter 19 Monitoring
- Chapter 19 Monitoring Observability
- Chapter 20 Backup
- Chapter 20 Performance
- Chapter 21 Auth
- Chapter 21 Performance
- Chapter 22 Clients
- Chapter 22 Encryption
- Chapter 23 Testing Qa
- Chapter 24 Ai Ethics
- Chapter 25 Devops Infrastructure
- Chapter 26 Migration Legacy
- Chapter 27 Troubleshooting
- Chapter 28 AQL Reference
- Chapter 29 Analytics Process Mining
- Chapter 30 Deployment Operations
- Chapter 31 API Protocols
- Chapter 32 API Design Rest Principles
- Chapter 32 AQL Oop Implementation
- Chapter 33 Best Practices
- Chapter 34 Query Optimization
- Chapter 35 Data Modeling Patterns
- Chapter 36 Security Hardening
- Chapter 37 Ecosystem Integration
- Chapter 38 Observability Sre
- Chapter 39 Performance Tuning Cookbook
- Chapter 40 Data Governance Compliance
- Chapter 41 Hands On Labs
- Chapter 42 Docs Assistant Usage
- Chapter MVCC Hlc
- Cover
- Cover Book
- Index
- Preface
- Test Links Example
- Batch Operations
- Best Practices
- CRUD Tutorial
- Custom Document Ingestion
- Getting Started Tutorial
- Interactive Examples
- Schema Design
- Video Tutorials
- AQL Reference
- AQL Examples
- AQL Overview
- AQL Feature Roadmap
- AQL Geospatial Guide
- AQL LLM Migration Guide
- AQL API
- AQL Grammar (EBNF)
- AQL Root Overview
- AQL Examples (root)
- API Reference
- API Module README
- OpenAPI Overview
- Client SDK Overview
- SDK Overview
- Operations
- Operations Overview
- Operations Runbook
- Operations Handbook
- ThemisCtl Admin Guide
- Pipeline E2E SOPs
- Docker Overview
- Docker Hub README
- Helm Overview
- Packaging Overview
- Operator Overview
- Security Policy
- Production Hardening Checklist
- Security Hardening Guide
- Encryption Key Management
- Access Control Framework
- Zero Trust Policy
- API Authentication & Authorization
- HSM Production Setup
- PKCS11 Integration
- DSGVO / SOC2 Checklist
- Access Model Runbooks
- Access Model Dashboard
- Maturity Automation Runbook
- Access Review Automation
- Access Model Dashboard
- Access Model Runbooks
- Rights Revocation
- Dr Checklists
- Dr Testing
- Incident Response Playbook
- Incident Response Testing
- GPU Oom Recovery
- Grammar Debugging
- Metrics Scrape Troubleshooting
- Model Swap Procedure
- Quota Tuning
- Subagent Deployment
- Logging Configuration
- Content Model
- Crypto & Keys
- Feature Flags Reference
- Modular Architecture Roadmap
- Modularization Guide
- Module Architecture Index
- PostgreSQL Wire Protocol
- Query Scheduling
- Raft Consensus Design
- Resource Pooling
- Source Directory Guide
- Unified Access Model
- E1 001 Layered Retrieval Design
- E1 002 Ann Abstraction Strategy
- E1 003 Tensor Summary Types
- E1 004 Lora Package Distinction
- E1 005 Model Switch Compatibility
- E1 006 Federated Tensor Summaries
- E2 001 Evaluation Framework Design
- E2 002 Hardware Profile Strategy
- E2 003 Query Planner Routing Model
- E2 004 Approximation Governance Rules
- E2 005 Cross Layer Fallback Confidence Policy
- E3 001 Distributed Tensor Design
- E3 002 Manifest Coordination Strategy
- E3 003 Recovery And Erasure Choice
- E3 004 Tensor Fabric Infrastructure
- Contributing
- Contributing (root)
- Code of Conduct
- Support
- Maintainers
- CTest Guide
- Build Quick Reference
- Developer Wiki Index
- Build / Test / CI
- Module Index
- Branching Strategy
- Release Strategy
- CI Policy Gates Wave C
- Disabled Stub Policy
- Docs PR Policy
- GA Promotion Sign Off
- Github Milestones Setup
- Governance Policies Phase1
- Maturity Claim Verification Checklist
- Maturity Evidence Registry
- Merge Gate Bot Config
- Merge Gate Status Live
- Phase 1 Closure Report
- Phase Closure Policy
- Phase Dependency Graph
- Phase3 Enforcement Runbook
- Plugin Submodule Rollback
- PR Version Targeting
- PR Version Targeting Backfill
- Production Ready 2026 Delivery Plan
- Publish Workflow Audit 2026 09 23
- Query Module Status
- Readme
- Release Governance
- Release Promotion Gate Policy
- Release Validation Checklist
- Root Hygiene Policy
- SBOM Approved Versions
- Security Compliance Audit Report 2026 08 10
- Security Module 5671 Evidence Summary
- Sharding P6 Residual Risk Acceptance
- Sourcecode Compliance Governance
- Src Module Documentation Compliance 2026 09 20
- Updates Development Status Sign Off
- Wave C Implementation Complete
- Wave C Implementation Plan
- Wave C Ml Exit Gate Sign Off
- Wave C Policy Gate Evidence
- Blob Storage
- Cuda
- Ethics Ai
- Exporters
- Huggingface
- Image Analysis
- Importers
- RPC
- Scraper
- Themisdb Ai Watermark Detector
- User Storage Encrypted
- Chimera Architecture
- Chimera Future
- Chimera Readme
- Chimera Roadmap
- Covina Fastapi Ingestion Architecture
- Covina Fastapi Ingestion Future
- Covina Fastapi Ingestion Roadmap
- Vcc Base Architecture
- Vcc Base Future
- Vcc Base Roadmap
- Vcc Clara Ingestion Architecture
- Vcc Clara Ingestion Future
- Vcc Clara Ingestion Roadmap
- Vcc Veritas Architecture
- Vcc Veritas Future
- Vcc Veritas Roadmap
- 01 Hello World
- 02 Todo App
- 03 Contact Manager
- 04 Inventory System
- 05 Time Series Monitor
- 06 Graph Social Network
- 07 Vector Search Documents
- 08 Dms Erp System
- 09 Iot Sensor Network
- 10 Drone Image Analysis
- 11 Blog Wiki
- 12 Expense Tracker
- 13 Recipe Manager
- 14 Ecommerce Catalog
- 15 Event Management
- 16 Kanban Board
- 17 Crm
- 18 Realtime Chat
- 19 Recommendation Engine
- 20 Smart Home
- 21 Coding Platform
- 22 AQL Diagram Tool
- 23 Traveling Salesman
- 24 Moral Philosophy Debates
- API Versioning
- Distributed Sharding
- Feedback Plugins
- Geo
- Gnn
- Image Analysis
- Legal Lora Training
- LLM
- Lora Sync
- Migration
- Nlp
- Performance
- Railway
- Replication
- Rope Visualization
- Sample Product Config
- Security
- Client SDK Overview
- Quickstart
- Sdk Enhancements
- Sdk Implementation Summary
- Test Suite Readme
- Go
- Java
- Javascript
- Php
- Python
- Ruby
- Rust
- Typescript
- 01 Grundlegende Operationen
- 02 AQL Queries
- 03 Graph Daten
- 04 Multimodell Anwendung
- 01 Quickstart Guide
- 02 AQL Referenz Kurzuebersicht
- 03 Datenmodellierung Guide
- 04 Uebungsaufgaben
- 05 Best Practices Guide
- Training Documents
- Training Overview
- 01 Einfuehrung Und Uebersicht
- 02 Datenmodelle Und Architektur
- 03 AQL Abfragesprache
- 04 Installation Und Setup
- 05 Anwendungsbeispiele
- Training Presentations
- Dependencies Readme
- Processmonitor Readme
- Themis.admintools.shared Readme
- Themis.aqlquerybuilder Readme
- Themis.aqlquerybuilder Roadmap
- Themis.auditlogviewer Readme
- Themis.auditlogviewer Roadmap
- Themis.classificationdashboard Readme
- Themis.classificationdashboard Roadmap
- Themis.compliancereports Readme
- Themis.compliancereports Roadmap
- Themis.gisviewer.controlpanel Readme
- Themis.gisviewer.controlpanel Roadmap
- Themis.impactanalysisviewer Readme
- Themis.impactanalysisviewer Roadmap
- Themis.ingestiontool Readme
- Themis.ingestiontool Roadmap
- Themis.keyrotationdashboard Readme
- Themis.keyrotationdashboard Roadmap
- Themis.piimanager Readme
- Themis.piimanager Roadmap
- Themis.retentionmanager Readme
- Themis.retentionmanager Roadmap
- Themis.sagaverifier Readme
- Themis.sagaverifier Roadmap
- Themis.usbadmintool Readme
- Themis.usbadmintool Roadmap
- Architecture Generator Readme
- CI Readme
- CI Roadmap
- Compiler Diagnostics Readme
- Compiler Diagnostics Roadmap
- Completion Readme
- Copilot Ollama Router Readme
- Copilot Ollama Router Roadmap
- Gnn Readme
- Gnn Roadmap
- Rope Visualizer Readme
- Rope Visualizer Roadmap
- Tco Calculator Readme
- Tco Calculator Roadmap
- Tests Readme
- Tests Roadmap
- Themis Config Wx Readme
- Themis Docs Builder Readme
- Wikipedia Ingestion Readme
- Ai Metadata And Provenance
- Build / Test / CI
- Governance And Roadmap
- Developer Wiki Index
- Module Direct Doxygen Check
- Module Doxygen Baseline Summary
- Module Doxygen Batch
- Module Doxygen Coverage Summary
- Module Doxygen Smoke Summary
- Modules And Apis
- Retrieval Direct Doxygen Check
- Soll Ist Gap Summary
- Wiki Delta Report