[BUG] OntologyIngestor drops every class in a JSON-LD named graph and reports success
## Summary
`POST /api/ontology/load` returns `status: "success"` for a JSON-LD ontology whose terms live in a **named graph**, while loading none of them. The registry then reports `class_count: 0`, `property_count: 0`, and `/api/ontology/search` finds nothing.
A JSON-LD document with a top-level `@id` **and** `@graph` puts its `@graph` contents into a *named* graph. `rdflib.Graph.parse()` loads only the default graph and discards the rest — silently. `semantica/ingest/ontology_ingestor.py:109` uses `Graph()`.
This is the same `Graph` → `Dataset` migration that #756 identified and #757 merged for `JenaStore`. The ingest path was not covered by it.
## Reproduction
Twelve lines, two classes:
```json
{
"@context": {"ex": "https://example.org/ns#", "owl": "http://www.w3.org/2002/07/owl#", "rdfs": "http://www.w3.org/2000/01/rdf-schema#"},
"@id": "https://example.org/ns",
"@type": "owl:Ontology",
"@graph": [
{"@id": "ex:Thing", "@type": "owl:Class", "rdfs:label": "Thing"},
{"@id": "ex:Other", "@type": "owl:Class", "rdfs:label": "Other"}
]
}
```
```bash
curl -X POST http://127.0.0.1:8000/api/ontology/load \
-H 'Content-Type: application/json' \
-d "{\"content\": $(jq -Rs . minimal.jsonld), \"format\": \"json-ld\", \"name\": \"repro\"}"
```
Observed:
```
{"status":"success","uri":"https://example.org/ns","nodes_added":1,"edges_added":1,"format":"json-ld"}
```
```bash
curl -s http://127.0.0.1:8000/api/ontology/registry
# ... "uri": "https://example.org/ns", "class_count": 0, "property_count": 0, "concept_count": 0
```
Expected: `class_count: 2`, or a failure that says the document could not be read.
## Why the parser sees nothing
```python
from rdflib import Graph, Dataset, RDF, OWL
g = Graph(); g.parse("minimal.jsonld", format="json-ld")
len(g) # 5 (document header only)
len(set(g.subjects(RDF.type, OWL.Class))) # 0
ds = Dataset(); ds.parse("minimal.jsonld", format="json-ld")
len(ds) # includes the named graph
```
On a real ontology the gap is larger. Ours: **25 triples / 1 subject** with `Graph`, **719 triples / 45 classes / 40 object properties** with `Dataset`. Every term was dropped and the API said success.
## Suggested fix
In `OntologyIngestor.ingest_file`, parse into a `Dataset` and flatten the quads:
```python
from rdflib import Dataset
ds = Dataset()
ds.parse(file_path, **parse_kwargs)
g = Graph()
for s, p, o, _ctx in ds.quads((None, None, None, None)):
g.add((s, p, o))
```
`semantica/explorer/utils/rdf_parser.py:87` and `semantica/explorer/routes/sparql.py:125` construct a plain `Graph()` on the same kind of input and are likely to have the same blind spot, though I have not reproduced those.
Independently of the parse fix: a load that adds zero classes probably should not return `status: "success"`. The success value is what made this cost us an afternoon — we assumed the ontology was in and only found out when a downstream query returned nothing.
## Environment
`semantica-knowledge-explorer:latest` (Explorer 0.6.5), FalkorDB backend, Docker.
Happy to open a PR with the `Dataset` change and a regression test if that is useful.
1 条评论