Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"id": "0a93ca502e05",
"metadata": {},
"source": [
"---\n",
"***\n",
"\n",
"## 0. Installation et Imports\n",
"\n",
Expand Down Expand Up @@ -136,7 +136,7 @@
"id": "538c3da5472e",
"metadata": {},
"source": [
"---\n",
"***\n",
"\n",
"## 1. Lecture de fichiers RDF\n",
"\n",
Expand Down Expand Up @@ -236,6 +236,28 @@
" print(\"rdflib non disponible : parsing chaine ignore.\")"
]
},
{
"cell_type": "markdown",
"id": "65a965f1",
"metadata": {},
"source": [
"### Lecture : une seule sémantique, deux syntaxes\n",
"\n",
"La même ligne — un sujet, un prédicat, un objet — est parsée deux fois, une\n",
"fois comme N-Triples (`format=\"nt\"`), une fois comme Turtle\n",
"(`format=\"turtle\"`), et les deux graphes contiennent exactement `1 triplet`.\n",
"C'est la démonstration la plus courte du principe fondateur de RDF : le\n",
"triplet est l'unité de sens, la syntaxe n'est qu'un habit. N-Triples est le\n",
"sous-ensemble minimal de Turtle — une ligne par triplet, URI complètes, point\n",
"final précédé d'une espace obligatoire ; Turtle ajoute préfixes,\n",
"points-virgules et regroupements — mais une fois PARSÉ, tout retombe dans le\n",
"même ensemble de triplets. Deux conséquences pratiques : un graphe chargé\n",
"depuis `.nt` et le même chargé depuis `.ttl` sont indiscernables (même\n",
"`len()`, même contenu), et choisir un format de sérialisation est un choix de\n",
"lisibilité et de compaction — jamais de sémantique. Le format se discute à\n",
"l'écriture ; à la lecture, seul l'ensemble de triplets compte."
]
},
{
"cell_type": "code",
"execution_count": 5,
Expand Down Expand Up @@ -302,7 +324,7 @@
"id": "ba88fba2619a",
"metadata": {},
"source": [
"---\n",
"***\n",
"\n",
"## 2. Ecriture de graphes RDF\n",
"\n",
Expand Down Expand Up @@ -536,7 +558,7 @@
"id": "c45c44fd8571",
"metadata": {},
"source": [
"---\n",
"***\n",
"\n",
"## 3. Fusion de graphes\n",
"\n",
Expand Down Expand Up @@ -621,7 +643,7 @@
"id": "450ade0ea577",
"metadata": {},
"source": [
"---\n",
"***\n",
"\n",
"## 4. Sélection de triplets\n",
"\n",
Expand Down Expand Up @@ -789,7 +811,7 @@
"id": "f8381e8f3bd8",
"metadata": {},
"source": [
"---\n",
"***\n",
"\n",
"## 5. Listes RDF\n",
"\n",
Expand Down Expand Up @@ -1027,7 +1049,7 @@
"id": "5baf4038d2e2",
"metadata": {},
"source": [
"---\n",
"***\n",
"\n",
"## 6. Comparaison cross-langage dotNetRDF vs rdflib\n",
"\n",
Expand Down Expand Up @@ -1057,7 +1079,7 @@
"id": "52c28c63bbbd",
"metadata": {},
"source": [
"---\n",
"***\n",
"\n",
"## 7. Exercices pratiques\n",
"\n",
Expand Down Expand Up @@ -1137,6 +1159,32 @@
" print(\"rdflib non disponible : exemple 1 ignore.\")"
]
},
{
"cell_type": "markdown",
"id": "99394809",
"metadata": {},
"source": [
"### Lecture : lire un graphe comme un schéma et ses instances\n",
"\n",
"Les `51` triplets se décomposent à la loupe de la sélection\n",
"`(None, RDF.type, None)` : quatorze triplets rdf:type dessinent l'ossature\n",
"complète du fichier. En haut, le VOCABULAIRE — les six classes `ex:Animal`,\n",
"`ex:Mammal`, `ex:Bird`, `ex:Dog`, `ex:Cat`, `ex:Parrot` déclarées\n",
"`rdfs:Class`, et les propriétés (`ex:name`, `ex:age`, `ex:sound`,\n",
"`ex:canFly`) déclarées `rdf:Property`. En bas, les INSTANCES — `ex:rex ->\n",
"ex:Dog`, `ex:buddy -> ex:Dog`, `ex:minou -> ex:Cat`, `ex:coco -> ex:Parrot`.\n",
"La hiérarchie (Dog sous Mammal sous Animal) vit dans d'autres triplets\n",
"`rdfs:subClassOf` que cette sélection n'affiche pas : rdf:type ne donne que\n",
"le type le plus CONCRET déclaré sur l'instance. La seconde sélection,\n",
"`(rex, None, None)`, rend les `4` liaisons de rex — `rdf:type`, `ex:name`,\n",
"`ex:age`, `ex:sound` : un individu complet tient en quatre triplets. Un\n",
"détail d'affichage mérite l'œil : la première boucle imprime la forme\n",
"préfixée (`ex:rex -> ex:Dog`, via `n3(g.namespace_manager)`) tandis que la\n",
"seconde rend `http://example.org/animals#Dog` en URI nue — même nœud du\n",
"graphe, deux rendus textuels ; la forme préfixée est une commodité\n",
"d'affichage, jamais une donnée du modèle."
]
},
{
"cell_type": "markdown",
"id": "3bfb1f02ecfa",
Expand Down Expand Up @@ -1314,6 +1362,34 @@
" print(\"rdflib non disponible : exemple 2 ignore.\")"
]
},
{
"cell_type": "markdown",
"id": "6d8bdaa5",
"metadata": {},
"source": [
"### Lecture : 4 + 51 = 55 — l'union qui ne compte pas deux fois\n",
"\n",
"`Avant fusion - g1: 4, g2: 51` puis `Apres fusion : 55 triplets` :\n",
"l'arithmétique est exacte parce que RDF définit un graphe comme un ENSEMBLE\n",
"de triplets — `g1 += g2` est une union ensembliste, et un triplet présent\n",
"des deux côtés ne serait pas dupliqué. Ici les deux fichiers sont disjoints,\n",
"donc 4 + 51 se vérifie sans perte ; avec des sources qui se recouvrent, la\n",
"somme serait INFÉRIEURE à l'addition des tailles — c'est même un test de\n",
"recouvrement entre sources : fusionner deux graphes et comparer `len()` à la\n",
"somme mesure leur intersection. Les blank nodes, isolés par graphe, ne\n",
"collisionnent jamais entre sources. La sortie sérialisée montre la suite :\n",
"Turtle regroupe les propriétés d'un même sujet avec `;`, ordonne les\n",
"déclarations, et FUSIONNE les préfixes des deux fichiers d'origine — `dc:`\n",
"venu de `Example.ttl` et `ns1:` de `animals.ttl` cohabitent dans le même\n",
"en-tête. La fusion de graphes est l'opération élémentaire par laquelle le Web\n",
"de données agrège des sources : chaque parse produit un ensemble, l'union\n",
"compose, la sérialisation rend un document unique. Dernier garde-fou : la\n",
"Turtle de sortie n'est PAS canonique — deux sérialisations du même graphe\n",
"peuvent différer par l'ordre des préfixes ou des sujets ; la comparaison\n",
"fiable entre graphes se fait toujours sur les ensembles de triplets, jamais\n",
"sur le texte."
]
},
{
"cell_type": "markdown",
"id": "fff1da298eaa",
Expand Down Expand Up @@ -1423,6 +1499,33 @@
" print(\"rdflib non disponible : exemple 3 ignore.\")"
]
},
{
"cell_type": "markdown",
"id": "9c44e108",
"metadata": {},
"source": [
"### Lecture : l'ordre dans la structure — une liste est un graphe déguisé\n",
"\n",
"`Initial : [Alice, Bob, Charlie]`, puis `Apres ajout : [Alice, Bob, Charlie,\n",
"Diana]`, puis la suppression rend `[Alice, Charlie, Diana]` — on croit voir\n",
"une liste Python ordinaire, et c'est précisément le tour de passe-passe :\n",
"`Collection(g, head, [...])` construit DANS LE GRAPHE une chaîne de nœuds\n",
"anonymes reliés par `rdf:first` (la valeur) et `rdf:rest` (la suite),\n",
"terminée par `rdf:nil`. L'ordre n'est PAS une propriété des éléments — RDF\n",
"n'a pas de position, pas d'index : il est encodé dans la TOPOLOGIE de la\n",
"chaîne. C'est pourquoi l'API Collection pilote le graphe sous-jacent :\n",
"`col.append(Literal(\"Diana\"))` insère un maillon en fin de chaîne et met à\n",
"jour le `rdf:rest` de l'ancien dernier maillon ; la suppression d'un élément\n",
"répare les liens entre ses deux voisins. Les crochets de la sortie ne sont\n",
"qu'une VUE reconstruite en parcourant la chaîne depuis la tête : sérialisé,\n",
"le graphe montre des blank nodes `_:b...` et leurs liaisons rdf:first /\n",
"rdf:rest, jamais de liste native. Deux pièges pratiques à retenir : la tête\n",
"(`head`) doit être conservée pour pouvoir relire la liste — le parcours part\n",
"d'elle — et une liste RDF n'est pas un conteneur du modèle mais un idiome\n",
"encodé, standard mais verbeux, que SPARQL ne parcourt qu'au prix de property\n",
"paths (`rdf:rest*`)."
]
},
{
"cell_type": "markdown",
"id": "01c61ed98956",
Expand Down Expand Up @@ -1481,7 +1584,7 @@
"id": "b0baf31f0c5d",
"metadata": {},
"source": [
"---\n",
"***\n",
"\n",
"## Resume\n",
"\n",
Expand All @@ -1497,7 +1600,7 @@
"\n",
"Dans **[SW-4b-Python-SPARQL](SW-4b-Python-SPARQL.ipynb)**, nous apprendrons a interroger les graphes RDF avec le langage SPARQL cote Python (equivalent de SW-4 C#).\n",
"\n",
"---\n",
"***\n",
"\n",
"**Navigation** : [Index](README.md) | [<< SW-3 C#](SW-3-CSharp-GraphOperations.ipynb) | [SW-4b Python >>](SW-4b-Python-SPARQL.ipynb)"
]
Expand Down
93 changes: 93 additions & 0 deletions MyIA.AI.Notebooks/SymbolicAI/SemanticWeb/SW-4b-Python-SPARQL.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,32 @@
" print(\"rdflib non disponible : exemple guide 1 ignore.\")"
]
},
{
"cell_type": "markdown",
"id": "34f3ad00",
"metadata": {},
"source": [
"### Lecture : `rdfs:subClassOf*` — le chemin transitif qui remonte l'arbre\n",
"\n",
"La requête ne demande PAS « les animaux typés Mammal » : elle demande les\n",
"animaux dont le type satisfait `rdfs:subClassOf* ex:Mammal` — zéro, un ou\n",
"plusieurs sauts de sous-classe au-dessus de Mammal. La sortie montre ce que\n",
"ça change : `Buddy (Chien) : 7 ans`, `Minou (Chat) : 3 ans`, `Rex (Chien) :\n",
"5 ans`, dans l'ordre alphabétique demandé par le `ORDER BY ?name`. Aucun\n",
"animal n'est typé `ex:Mammal` directement dans le fichier : Buddy est typé\n",
"`ex:Dog`, et le property path remonte Dog vers Mammal (un saut) pour\n",
"satisfaire la contrainte. Deux lectures fines. D'abord, la variable `?type`\n",
"reste liée au type CONCRET déclaré sur l'instance — le label rendu est\n",
"`Chien`, pas « Mammifère » : le chemin ne fait que VÉRIFIER l'ancêtre, il ne\n",
"remplace pas le type. Ensuite, l'étoile (`*` = zéro ou plus sauts) est le\n",
"réflexe « est-un » complet : elle accepterait aussi une instance typée\n",
"`ex:Mammal` directement (zéro saut), ce que la forme sans étoile exclurait.\n",
"Et Coco le perroquet brille par son absence : `ex:Bird` descend d'`Animal`,\n",
"jamais de `ex:Mammal` — aucun chemin ne mène à l'ancêtre exigé, la ligne\n",
"disparaît. C'est la mécanique exacte de l'héritage de classe interrogé par\n",
"motif, sans une ligne de code impératif."
]
},
{
"cell_type": "markdown",
"id": "exercise-2-intro",
Expand Down Expand Up @@ -1085,6 +1111,36 @@
" print(\"rdflib non disponible : exemple guide 2 ignore.\")"
]
},
{
"cell_type": "markdown",
"id": "602179a2",
"metadata": {},
"source": [
"### Lecture : la négation par échec — prouver une absence\n",
"\n",
"`Aucun animal sans age dans le graphe (tous renseignes).` — cette ligne est\n",
"le résultat d'un `FILTER NOT EXISTS { ?animal ex:age ?age . }`, et elle est\n",
"plus informative qu'elle n'y paraît. SPARQL ne sait pas interroger ce qui\n",
"n'existe pas : un motif ordinaire (`?animal ex:age ?age`) liste les liaisons\n",
"présentes, mais « les animaux SANS âge » exige la négation — et le standard\n",
"l'exprime par l'échec : pour chaque candidat, si le motif entre accolades\n",
"trouve ne serait-ce qu'une solution, le candidat est écarté ; s'il n'en trouve\n",
"aucune, il passe. La sortie vide n'est donc pas un échec de la requête mais\n",
"une PREUVE : les quatre animaux du graphe (Buddy, Minou, Rex, Coco) portent\n",
"tous un `ex:age`, l'inventaire est complet. C'est la négation par échec de la\n",
"programmation logique, avec sa force — concise, applicable à n'importe quel\n",
"motif, y compris complexes — et sa limite épistémologique : elle confond\n",
"« absence de déclaration dans CE graphe » et « propriété fausse » ; un animal\n",
"dont l'âge existerait dans une autre source resterait « sans âge » ici. Pour\n",
"se convaincre du comportement, l'expérience minimale : retirer le triplet\n",
"d'âge de rex dans `data/animals.ttl` et relancer — rex apparaît, et lui seul.\n",
"La forme cousine mérite d'être connue : `OPTIONAL { ?animal ex:age ?a }\n",
"FILTER(!BOUND(?a))` rend le même résultat ICI, mais `NOT EXISTS` reste la\n",
"forme canonique pour « aucun triplet ne matche » — l'autre exprime « la\n",
"variable n'est pas liée », une distinction qui compte dès que le motif négatif\n",
"porte plusieurs variables ou plusieurs solutions."
]
},
{
"cell_type": "markdown",
"id": "50dbcbfe",
Expand Down Expand Up @@ -1675,6 +1731,43 @@
" print(\"rdflib non disponible : synthese ignoree.\")"
]
},
{
"cell_type": "markdown",
"id": "d448be70",
"metadata": {},
"source": [
"### Lecture : `CONSTRUCT` projette, `GROUP BY` résume — deux lectures du même graphe\n",
"\n",
"La partie A extrait un sous-graphe : trois triplets exactement — `ns1:buddy a\n",
"ns1:Dog ; ns1:name \"Buddy\"`, et symétriquement pour minou (Cat) et rex (Dog).\n",
"Deux choses se lisent dans ce fragment. D'abord la PROJECTION : le template\n",
"du `CONSTRUCT` ne retient que les variables qu'il cite — le type et le nom ;\n",
"toute autre liaison possible du `WHERE` disparaît du résultat. CONSTRUCT est\n",
"un filtre ET une sélection de colonnes, jamais une copie du graphe source.\n",
"Ensuite la syntaxe : le préfixe `ns1:` est AUTO-GÉNÉRÉ par rdflib — le graphe\n",
"construit n'hérite d'aucune déclaration de préfixe de la requête — et le\n",
"point-virgule regroupe les propriétés d'un même sujet : la Turtle de sortie\n",
"réorganise canoniquement ce que la requête a assemblé. Et le graphe construit\n",
"est un objet comme les autres : il peut être interrogé à son tour par SPARQL,\n",
"sérialisé, fusionné — le CONSTRUCT est le pont entre le monde des requêtes et\n",
"le monde des graphes, et l'exercice 6 en donnera la réciproque : détruire par\n",
"un motif exactement ce qu'une construction a matérialisé.\n",
"La partie B change de posture : au lieu d'extraire des triplets, elle COMPTE —\n",
"`Chien : 2`, `Chat : 1`, `Perroquet : 1`, via `COUNT(?animal) AS ?nb` et\n",
"`GROUP BY ?type_label`. Le détail qui enseigne : ni `Animal`, ni `Mammal`, ni\n",
"`Bird` n'apparaissent — aucune instance n'est typée au niveau abstrait (rex\n",
"est `ex:Dog`, pas `ex:Mammal`), exactement la mécanique du property path de\n",
"l'exemple 1. Le GROUP BY compte les types DÉCLARÉS, pas l'ascendance : pour\n",
"compter « les mammifères », il faudrait le chemin transitif DANS la requête\n",
"d'agrégation. Ensemble, les deux parties illustrent la dualité centrale de\n",
"SPARQL : le même graphe se lit en extension (CONSTRUCT — quels triplets\n",
"satisfont le motif) et en mesure (GROUP BY — quelle statistique résume les\n",
"solutions). Une habitude d'écriture s'en dégage : formuler d'abord la\n",
"question en extension (« quels triplets ? ») pour la vérifier à l'œil sur un\n",
"petit graphe, puis la reformuler en mesure (« combien par groupe ? ») — le\n",
"même motif, lu deux fois, vaut un contrôle et une synthèse."
]
},
{
"cell_type": "markdown",
"id": "dc7cbffb",
Expand Down
Loading
Loading