Indexes
🗂️ Système d’Indexation & Query Engine
Ce module gère l’indexation des collections JSON et l’exécution des requêtes. Il est conçu pour offrir des performances élevées (O(1) ou O(log N)) tout en restant extrêmement permissif face aux structures de données variables (JSON) et aux entrées SQL.
📊 Flux d’Exécution (Query Pipeline)
Le diagramme ci-dessous illustre comment le moteur traite une requête, de la sélection de la stratégie (Index vs Scan) jusqu’à la résolution intelligente des champs.
graph TD
User([User Query]) -->|SQL / JSON| Engine[Query Engine]
Engine --> Optimizer[Optimizer]
subgraph "🔎 Stratégie de Chargement"
Optimizer --> CheckIndex{Index Exists?}
%% Chemin Rapide
CheckIndex -->|Yes| IndexHit[⚡ Index Search]
IndexHit -->|Get IDs| LoadSpecific[Read Specific Docs]
%% Chemin Lent
CheckIndex -->|No| FullScan[🐢 Full Scan]
FullScan -->|List All| LoadAll[Read All Docs]
end
LoadSpecific --> Candidates[Candidate Documents]
LoadAll --> Candidates
subgraph "🧠 Smart Filtering (executor.rs)"
Candidates -->|For each doc| Eval[Evaluate Condition]
Eval -->|1. Normalize| Clean[Strip Quotes & Prefix]
Clean -->|2. Resolve Field| SmartRes{Field Found?}
SmartRes -->|Yes| Compare
SmartRes -->|No| DeepScan[🕵️ Deep Scan / Leaf Fallback]
DeepScan -->|Found in Sub-Object| Compare[Robust Comparison]
DeepScan -->|Not Found| Discard[❌ Discard]
Compare -->|Case Insensitive / Fuzzy| Match{Match?}
Match -->|Yes| Keep[✅ Keep]
Match -->|No| Discard
end
Keep --> Result([Final Result])
🏗️ Architecture
Le système est découpé en plusieurs couches :
IndexManager: Point d’entrée principal. Il gère le cycle de vie des index (création, suppression, reconstruction) et coordonne les écritures.QueryEngine: Cerveau de la lecture. Il orchestre l’optimiseur, le fournisseur d’index et le filtrage en mémoire.- Drivers : Implémentations spécifiques des algorithmes de stockage (
btree,hash,text).
⚙️ Types d’Index Supportés
| Type | Algorithme | Cas d’usage idéal | Complexité |
|---|---|---|---|
hash | HashMap persistée | IDs, Emails, UUIDs, Codes uniques (Égalité stricte) | O(1) |
btree | BTreeMap | Nombres, Dates, Tris, Plages (>, <, BETWEEN) | O(log N) |
text | Inverted Index | Recherche de mots-clés dans du texte | Variable |
Définition (_meta.json)
Les définitions d’index sont stockées dans le fichier _meta.json à la racine de la collection.
{
"indexes": [
{
"name": "email_idx",
"field_path": "email",
"index_type": "hash",
"unique": true
}
]
}
🔍 Capacités Avancées du Query Engine
Le moteur de requête (executor.rs) a été durci pour traiter les cas limites souvent rencontrés avec des données JSON hétérogènes (ex: ActivityPub) ou des requêtes SQL générées.
1. Smart Field Resolution (Résolution Intelligente)
Le moteur trouve le champ ciblé même si le chemin fourni est imparfait :
- Suppression de Préfixe :
users.age→ trouveage(gestion des alias SQLtable.column). - Insensibilité à la Casse :
displayName→ trouvedisplaynameouDisplayName. - Leaf Fallback : Si le chemin complet
data.attributes.nameéchoue, le moteur tente de trouvername(la feuille) n’importe où.
2. Deep Scan (Recherche en Profondeur)
Si un champ n’est pas trouvé à la racine du document, le moteur scanne automatiquement les sous-objets immédiats (ex: data, object, actor).
- Exemple :
SELECT * WHERE name = 'Alice'trouvera la valeur dans{ "id": 1, "object": { "name": "Alice" } }.
3. Opérateurs Étendus & Tolérants
LIKEsur Tableaux :tags LIKE 'rust'retournetruesi le tableautagscontient l’élément “rust”.LIKE“Fuzzy” : Si le motif ne contient pas de%(ex:LIKE 'Alice'), il se comporte comme unCONTAINS(partiel).- Nettoyage Automatique : Les guillemets parasites envoyés par les parseurs SQL (ex:
"'valeur'") sont nettoyés récursivement avant comparaison.
🛠️ Utilisation (Rust)
Création d’un index
use raise::json_db::indexes::{IndexManager, IndexType};
// Créer un index unique sur le champ "email"
manager.create_index(
"users",
"email_idx",
"email",
IndexType::Hash,
true // unique
).expect("Impossible de créer l'index");
Exécution d’une requête
Le QueryEngine sélectionne automatiquement le meilleur index disponible.
use raise::json_db::query::{Query, Condition, QueryEngine};
let engine = QueryEngine::new(&manager);
// Cette requête utilisera l'index "email_idx" si disponible (O(1))
// Sinon, elle basculera en Full Scan (O(N))
let query = Query::new("users")
.filter(Condition::eq("email", json!("alice@example.com")));
let result = engine.execute_query(query).await?;