Aller au contenu

Démarrage rapide

Ce guide vous montre la façon la plus rapide de charger un fichier DDI dans une base de données graphe. Nous commençons avec Neo4j — la configuration la plus courante — puis montrons les autres options.

Si vous n'avez pas encore installé ddigraph, commencez par Installation.


Étape 1 — Choisissez votre base de données

Choisissez la base de données que vous voulez utiliser. Si vous n'êtes pas sûr, choisissez Neo4j — c'est l'option la plus complète et la plus facile pour débuter.

Qu'est-ce que c'est ? Neo4j est une base de données graphe qui stocke les données sous forme de nœuds et de relations. C'est le choix recommandé pour la plupart des utilisateurs.

# Démarrer Neo4j avec Docker (une seule fois)
docker run -d --name neo4j \
    -p 7474:7474 -p 7687:7687 \
    -e NEO4J_AUTH=neo4j/password \
    neo4j:latest

# Indiquer à ddigraph où se trouve Neo4j
export DDIGRAPH_NEO4J_URI=bolt://localhost:7687
export DDIGRAPH_NEO4J_USER=neo4j
export DDIGRAPH_NEO4J_PASSWORD=password

# Initialiser le schéma de la base (une seule fois avant le premier chargement)
ddigraph bootstrap

# Charger votre fichier DDI
ddigraph load survey.xml --dataset-id demo

Après l'exécution, vos métadonnées DDI se trouvent dans Neo4j sous forme de graphe. Ouvrez http://localhost:7474 dans votre navigateur pour l'explorer visuellement.

Que fait bootstrap ? Il crée les index et contraintes dont Neo4j a besoin pour stocker correctement les données DDI. C'est sûr de l'exécuter plusieurs fois — si le schéma existe déjà, rien ne change.

Qu'est-ce que c'est ? RDF (Resource Description Framework) est un format pour représenter les données sous forme de triplets liés. Utilisez ceci si vous travaillez avec des outils du web sémantique ou des triplestores comme Virtuoso, GraphDB ou Stardog.

from rdflib import Graph, Namespace, Literal, URIRef
from rdflib.namespace import RDF, RDFS
from ddigraph import DDIFragmentParser

DDI = Namespace("http://ddi.example.org/")
g = Graph()
g.bind("ddi", DDI)

parser = DDIFragmentParser()
for fragment in parser.parse("survey.xml"):
    subj = DDI[fragment.fragment_id]
    g.add((subj, RDF.type, DDI[fragment.element_type]))
    if fragment.label:
        g.add((subj, RDFS.label, Literal(fragment.label)))

# Sauvegarder dans un fichier Turtle
g.serialize("output.ttl", format="turtle")

Qu'est-ce que c'est ? NetworkX est une bibliothèque Python pour analyser des graphes en mémoire — aucune base de données séparée requise. Utilisez ceci pour des analyses locales rapides ou du prototypage.

import networkx as nx
from ddigraph import DDIFragmentParser

G = nx.MultiDiGraph()
parser = DDIFragmentParser()

for fragment in parser.parse("survey.xml"):
    G.add_node(fragment.fragment_id,
               label=fragment.element_type,
               **fragment.to_dict())
    for rel_type, ref in fragment.references:
        G.add_edge(fragment.fragment_id, ref.id, key=rel_type)

print(f"Chargé : {G.number_of_nodes()} nœuds, {G.number_of_edges()} arêtes")

Qu'est-ce que c'est ? Gremlin est un langage de requête graphe pris en charge par des bases de données comme JanusGraph, Amazon Neptune et Azure Cosmos DB.

from gremlin_python.process.anonymous_traversal import traversal
from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
from ddigraph import DDIFragmentParser

connection = DriverRemoteConnection('ws://localhost:8182/gremlin', 'g')
g = traversal().withRemote(connection)

parser = DDIFragmentParser()
for fragment in parser.parse("survey.xml"):
    g.addV(fragment.element_type) \
        .property('id', fragment.fragment_id) \
        .property('label', fragment.label or '') \
        .iterate()

connection.close()

Étape 2 — Vérifier le format (optionnel)

ddigraph détecte automatiquement si votre fichier est DDI Codebook, DDI Lifecycle ou DDI-CDI. Vous pouvez vérifier manuellement avec :

from ddigraph import detect_ddi_format

format_type = detect_ddi_format("survey.xml")
print(format_type)  # "codebook", "lifecycle" ou "cdi"

Que signifient ces formats ?

Format Élément XML racine À utiliser quand
codebook <codeBook> ou <codebook> Archives d'enquêtes traditionnelles
lifecycle <FragmentInstance> Outils de conception de questionnaires (DDI-L 3.2 / 3.3)
cdi Espace de noms DDI-CDI Projets d'intégration inter-domaines

Si vous n'êtes pas sûr du format de votre fichier, exécutez detect_ddi_format et il vous le dira.


Étape 3 — Charger depuis Python

L'API Python reflète la CLI. Un seul appel charge un fichier. Il détecte le format, initialise le schéma et écrit vers votre cible :

import ddigraph

result = ddigraph.load(
    "survey.xml",
    target="neo4j://localhost:7687",
    dataset_id="my-survey",
)
print(result.flavor, result.nodes_written, result.relationships_written)

target est une URL Neo4j (bolt://... ou neo4j://...). Omettez-la pour utiliser la connexion de votre environnement. Il existe aussi une forme asynchrone, ddigraph.aload(...), avec les mêmes arguments. Pour les autres backends (RDF, Gremlin, NetworkX, pandas), utilisez le parseur plus un adaptateur — voir les pages Backends et les exemples par backend ci-dessus.

Détecter le format d'un fichier sans le charger :

import ddigraph

print(ddigraph.detect("survey.xml"))  # 'codebook', 'lifecycle' ou 'cdi'

Plus de contrôle (avancé)

Si vous devez piloter vous-même les loaders, les classes de plus bas niveau restent disponibles :

import asyncio
from neo4j import AsyncGraphDatabase
from ddigraph import DDILoader, DDIFragmentLoader, detect_ddi_format
from ddigraph.config import Settings
from ddigraph.graph.bootstrap import ensure_schema

async def load_ddi(path: str, dataset_id: str = "default"):
    settings = Settings()
    driver = AsyncGraphDatabase.driver(
        settings.neo4j_uri,
        auth=(settings.neo4j_user, settings.neo4j_password.get_secret_value()),
    )

    try:
        # Initialiser le schéma (sûr à exécuter à chaque fois)
        await ensure_schema(driver, include_fragments=True)

        # Choisir le bon chargeur selon le format
        fmt = detect_ddi_format(path)
        if fmt == "lifecycle":
            loader = DDIFragmentLoader(driver, settings=settings)
            result = await loader.load(path)
        elif fmt == "cdi":
            from ddigraph.ingest.cdi_loader import CDILoader
            loader = CDILoader(driver, settings=settings)
            result = await loader.load(path)
        else:
            loader = DDILoader(driver, settings=settings)
            result = await loader.load(path, dataset_id=dataset_id)

        return result
    finally:
        await driver.close()

result = asyncio.run(load_ddi("survey.xml", "my-survey"))
print(f"Chargé : {result}")

Étape 4 — Explorer vos données

Maintenant que vos données sont chargées, exécutez quelques requêtes pour voir ce qu'il y a.

Dans Neo4j Browser (http://localhost:7474)

-- Compter tous les nœuds par type
MATCH (n) RETURN labels(n) AS type, count(n) AS nombre ORDER BY nombre DESC

-- Lister toutes les variables d'un jeu de données
MATCH (d:Dataset {id: 'demo'})<-[:IN_DATASET]-(v:Variable)
RETURN v.name, v.label

-- Questions avec leurs listes de réponses
MATCH (q:QuestionItem)-[:USES_CODELIST]->(cl:CodeList)
RETURN q.name, q.question_text, cl.name

En Python (NetworkX)

import networkx as nx

# Trouver des chemins entre deux nœuds
paths = list(nx.all_simple_paths(G, source="instrument-1", target="question-5", cutoff=5))

# Exporter pour la visualisation
nx.write_graphml(G, "ddi_graph.graphml")

Et ensuite ?