landvex: IOL v3 + Identify API + Neo4j-graf + byggpipeline
- FastAPI Identify API (port 8081) - Neo4j propertygraf (64 noder, 80 kanter) - Ingest-pipeline (Python) - Byggscript + integrationstester - Docker Compose setup
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Ladda Landvex IOL in i Neo4j.
|
||||
Använder neo4j-driver (pip install neo4j).
|
||||
"""
|
||||
import json
|
||||
import csv
|
||||
from pathlib import Path
|
||||
from neo4j import GraphDatabase
|
||||
|
||||
URI = "bolt://localhost:7687"
|
||||
AUTH = ("neo4j", "quixzoom_neo4j_2026")
|
||||
DATA_DIR = Path(__file__).parent.parent / "10-data"
|
||||
DB_DIR = Path(__file__).parent
|
||||
|
||||
class Neo4jLoader:
|
||||
def __init__(self):
|
||||
self.driver = GraphDatabase.driver(URI, auth=AUTH)
|
||||
|
||||
def close(self):
|
||||
self.driver.close()
|
||||
|
||||
def load_noder(self, poster):
|
||||
with self.driver.session() as session:
|
||||
session.run("CREATE CONSTRAINT lvx_id_unique IF NOT EXISTS FOR (n:Objekt) REQUIRE n.lvx_id IS UNIQUE")
|
||||
for p in poster:
|
||||
prov = p.get("proveniens", {})
|
||||
session.run("""
|
||||
MERGE (o:Objekt {lvx_id: $lvx_id})
|
||||
SET o.posttyp = $posttyp,
|
||||
o.namn_sv = $namn_sv,
|
||||
o.namn_en = $namn_en,
|
||||
o.doman = $doman,
|
||||
o.tier = $tier,
|
||||
o.verifieringsniva = $verifieringsniva,
|
||||
o.konfidens = $konfidens
|
||||
""", {
|
||||
"lvx_id": p["lvx_id"],
|
||||
"posttyp": p.get("posttyp", ""),
|
||||
"namn_sv": p.get("namn", {}).get("sv", ""),
|
||||
"namn_en": p.get("namn", {}).get("en", ""),
|
||||
"doman": p.get("doman", ""),
|
||||
"tier": p.get("tier", 0),
|
||||
"verifieringsniva": prov.get("verifieringsniva", "obekraftad"),
|
||||
"konfidens": prov.get("konfidens", 0),
|
||||
})
|
||||
print(f"Laddade {len(poster)} noder")
|
||||
|
||||
def load_kanter(self, kanter):
|
||||
with self.driver.session() as session:
|
||||
count = 0
|
||||
for k in kanter:
|
||||
if k.get("objekt_typ") != "lvx":
|
||||
continue
|
||||
session.run("""
|
||||
MATCH (a:Objekt {lvx_id: $subjekt})
|
||||
MATCH (b:Objekt {lvx_id: $objekt})
|
||||
MERGE (a)-[r:RELATION {predikat: $predikat}]->(b)
|
||||
SET r.niva = $niva,
|
||||
r.beskrivning = $beskrivning
|
||||
""", {
|
||||
"subjekt": k["subjekt"],
|
||||
"objekt": k["objekt"],
|
||||
"predikat": k["predikat"],
|
||||
"niva": k.get("niva", ""),
|
||||
"beskrivning": k.get("beskrivning", ""),
|
||||
})
|
||||
count += 1
|
||||
print(f"Laddade {count} kanter")
|
||||
|
||||
def create_index(self):
|
||||
with self.driver.session() as session:
|
||||
session.run("CREATE TEXT INDEX objekt_namn_sv IF NOT EXISTS FOR (o:Objekt) ON (o.namn_sv)")
|
||||
session.run("CREATE TEXT INDEX objekt_namn_en IF NOT EXISTS FOR (o:Objekt) ON (o.namn_en)")
|
||||
print("Index skapade")
|
||||
|
||||
def main():
|
||||
poster = []
|
||||
for fn in ("lvx-klassposter-master-v3.json", "lvx-produktmodeller-vag2.json",
|
||||
"lvx-produktmodeller-vag3.json", "lvx-produktmodeller-auto.json"):
|
||||
fp = DATA_DIR / fn
|
||||
if not fp.exists(): continue
|
||||
with open(fp, encoding="utf-8") as f:
|
||||
poster.extend(json.load(f).get("poster", []))
|
||||
|
||||
with open(DATA_DIR / "lvx-graf-kanter-v3.json", encoding="utf-8") as f:
|
||||
kanter = json.load(f)["kanter"]
|
||||
|
||||
loader = Neo4jLoader()
|
||||
try:
|
||||
loader.load_noder(poster)
|
||||
loader.load_kanter(kanter)
|
||||
loader.create_index()
|
||||
print("✅ Graf laddad i Neo4j")
|
||||
finally:
|
||||
loader.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user