SDK
Haladó fejezet

KnowledgeGraphService – saját gráf-ingestion külső forrásból

A 10. fejezet a platform beépített útját mutatja be: a AbstractNERIngestionTool a platform saját, már feldolgozott és beágyazott (embedding) szöveges dokumentumaiból építi a tudásgráfot, LLM-alapú entitáskinyeréssel. Ez a fejezet a másik esetről szól: amikor a forrásadat nem a platform dokumentum-pipeline-ján megy át – például egy külső rendszer API-jából, adatbázisából vagy egyéb strukturált exportjából érkezik –, de a plugin mégis szeretné ugyanazt a domain-izolált gráf-reprezentációt felépíteni belőle, hogy egy másik tool később fel tudja használni.

Mikor van szükség erre?

A KnowledgeGraphService egy @Service singleton – bármely plugin tool vagy saját service osztály @Autowired-del injektálhatja, függetlenül attól, hogy van-e a domainhez NER ingestion tool. Közvetlen használata akkor indokolt, ha:

Ilyenkor a plugin a AbstractNERIngestionTool egész gépezetét (Spark batch, LLM-alapú entitáskinyerés, mondatszintű mention-ek) megkerülve, közvetlenül hívja a KnowledgeGraphService UPSERT metódusait – a saját, már ismert struktúrájú adatból nincs szükség LLM-es kinyerésre, a mezők közvetlenül leolvashatók.

💡
A KnowledgeGraphService @SdkApi(strip=true) jelölésű – az SDK JAR-ban stub formában szerepel (az aláírások megvannak, a metódustörzsek nem). Fordítási időben ez elég a plugin lefordításához; futásidőben a PluginClassLoader parent-first betöltése miatt mindig a platform valódi implementációja fut.

A gráf modell – collection-ok és named graph

A gráf három, domain-előtaggal ellátott ArangoDB collection-ből áll, ugyanazzal a névkonvencióval, mint a dokumentum-embedding collection-öknél:

CollectionTípusSzerepe
{domain}KnowledgeConcept document (vertex) Egy fogalom/csomópont: label, normalizedLabel, type, aliases, systems.
{domain}ConceptRelation edge Két fogalom közti irányított él: _from, _to, relationType, weight, systems.
{domain}ConceptMention document Egy fogalom előfordulása egy konkrét, visszakereshető dokumentum-egységben (opcionális – lásd lentebb).

Domain nélkül (domain = null) a prefix üres – ez egy alapértelmezett domain collection-jeit jelenti, amelyet lekérdezéskor nem kell külön megjelölni. A három collection-t és a rájuk épülő named graph-ot az initCollections(domain) hozza létre, idempotens módon (ha már léteznek, nem csinál semmit).

ℹ️
A domain = null eset a platform korai, egy-domain-es időszakából maradt meg fallback-ként. A platform adminisztrációs felületén ma már nem hozható létre névtelen domain – minden domaint kötelező elnevezni. A null-ág továbbra is működik (visszafelé kompatibilitásból), de új domain létrehozásakor mindig kapsz egy konkrét domain nevet, amit a KnowledgeGraphService hívásaiban (és minden más domain-szűrt API-ban) explicit át kell adnod.
⚠️
Az upsertConcept / upsertRelation / saveMention egyike sem hozza létre automatikusan a collection-öket – ha egyik sem létezik, az ArangoDB hibát dob. Ha a domainhez tartozik már egy AbstractNERIngestionTool (az a saját ingestion futásakor mindig meghívja az initCollections-t), a collection-ök már léteznek, és a direkt gráf-írás rájuk épülhet. Ha a domainben nincs semmilyen NER ingestion tool, a pluginnak magának kell meghívnia az initCollections(domain)-t legalább egyszer, mielőtt az első upsertConcept-et hívja (pl. egy IPluginConfigurer.configure()-ben vagy a saját ingestion service első futásakor).

Írás: a gráf felépítése

upsertConcept(domain, system, label, type, aliases)

Felvisz vagy frissít egy fogalmat. A deduplikálás a label normalizált formája (normalizeLabel() – kisbetűsítés + ékezet-eltávolítás) és a type párosa alapján történik: ha már létezik ugyanilyen normalizedLabel + type kombinációjú csomópont, a hívás frissíti azt UPSERT-tel ahelyett, hogy duplikálná. Azonos label, de eltérő type esetén két külön csomópont jön létre. Visszatérési érték: a csomópont ArangoDB _key-e – ezt kell továbbadni az upsertRelation és saveMention hívásoknak.

String patientKey = knowledgeGraphService.upsertConcept(
    domain, system,
    "Kovács Mária",           // label
    "PATIENT",                // type – szabadon választott, saját taxonómia
    List.of("K. Mária")       // aliases – kereséskor is találatot ad
);
⚠️
Ismételt upsertConcept hívás nem cseréli le az aliases / systems listákat, hanem hozzáfűzi (APPEND) az újakat a régiekhez. Ha egy teljesen tiszta újraingestion-t szeretnél (a régi állapot törlésével), előbb hívd meg a deleteBySystem(domain, system)-et.

upsertRelation(domain, system, fromConceptKey, toConceptKey, relationType, bidirectional)

Felvisz vagy frissít egy irányított élt két korábban upsertConcept-tel létrehozott csomópont között. A dedup kulcsa (_from, _to, relationType) – ismételt előfordulás esetén a weight nő (kezdetben 1.0, minden ismétlésnél +0.5). A bidirectional flag csak metaadat – a gráf-bejárás iránya mindig _from → _to, a flag a lekérdező logikának ad jelzést arra, hogy az élt visszafelé is érdemes-e követni.

knowledgeGraphService.upsertRelation(
    domain, system,
    patientKey, conditionKey,
    "DIAGNOSED_WITH",   // relationType – saját taxonómia
    false              // bidirectional
);

saveMention(domain, system, conceptKey, documentSentenceKey, documentCollection, mentionContext) – opcionális

Ez a metódus köti össze a fogalmat egy konkrét, visszakereshető szöveges dokumentum-egységgel – a platform szövegalapú retrieval pipeline-jában ez egy PageEmbedding1024 bejegyzés kulcsa. Ha a forrásadatod nem ilyen szöveges oldal (mint egy strukturált külső rekord), nyugodtan kihagyhatod – a fogalmak és relációk enélkül is felépülnek és lekérdezhetők label alapján (lásd lentebb). A saveMention csak akkor szükséges, ha azt szeretnéd, hogy a findPageKeysByLabels ezen fogalmakhoz retrievelhető oldal-kulcsokat is visszaadjon a RAG kontextushoz.

deleteBySystem(domain, system) – tiszta újraingestion

Törli az adott system összes bejegyzését a domain gráfjából: a csak ehhez a system-hez tartozó fogalmakat és éleket teljesen törli, a több system között megosztottaknál csak a system-jelölést veszi le. Idempotens – ismételt hívás hibátlanul lefut akkor is, ha már nincs mit törölni. A bevett minta egy teljes újraingestion elején:

knowledgeGraphService.deleteBySystem(domain, system);
for (ExternalRecord record : source.fetchAll()) {
    // ... upsertConcept / upsertRelation minden rekordra
}

Teljes példa – saját ingestion service külső forrásból

Az alábbi minta egy plugin saját, nem-IIngestionTool service osztálya, amely egy külső rendszer strukturált rekordjaiból épít gráfot – nincs LLM-hívás, nincs Spark, a mezők közvetlenül a forrásból olvashatók:

@Service
public class MyExternalDataGraphIngestionService {

    @Autowired
    private KnowledgeGraphService knowledgeGraphService;

    public void ingest(String domain, String system, List<ExternalRecord> records) throws Exception {
        // Tiszta újraingestion: előző állapot törlése erről a system-ről
        knowledgeGraphService.deleteBySystem(domain, system);

        for (ExternalRecord record : records) {
            String parentKey = knowledgeGraphService.upsertConcept(
                domain, system,
                record.getParentLabel(), record.getParentType(),
                record.getParentAliases());

            String childKey = knowledgeGraphService.upsertConcept(
                domain, system,
                record.getChildLabel(), record.getChildType(),
                List.of());

            knowledgeGraphService.upsertRelation(
                domain, system,
                parentKey, childKey,
                record.getRelationType(), false);
        }
    }
}

Ezt a service-t egy IPluginConfigurer.configure() triggerelheti induláskor, vagy egy saját, ütemezett/manuálisan hívható tool – attól függően, hogy a külső forrás milyen gyakran változik.

Olvasás: a gráf lekérdezése egy másik tool-ból

A felépített gráfot bármelyik tool lekérdezheti, amely szintén @Autowired-eli a KnowledgeGraphService-t. A kész lekérdező metódusok mindegyike normalizeLabel()-lel normalizált kulcsszavakat vár bemenetként.

ℹ️
Az ezen a fejezeten belüli összes lekérdező metódus (findAliasesByLabels, findConceptInfoByLabels, findConceptsByFuzzyLabel, findPageKeysByLabels, findConnectedConcepts) automatikusan figyelmen kívül hagyja a logikailag törölt ("kuka") állapotú fogalmakat - ezek úgy viselkednek a hívó szempontjából, mintha nem is léteznének a gráfban. Ha egy korábban megtalált fogalom váratlanul eltűnik a találatokból, ennek egyik lehetséges oka, hogy valamelyik gráf-karbantartó feladat logikailag törölte - lásd a Logikai törlés (kuka) szakaszt.

findAliasesByLabels(domain, normalizedLabels)

A megadott label-ekhez egyező fogalmak összes ismert (eredeti, ékezetes) alias-át adja vissza – az input label-ekkel megegyezőket kizárva. Csak a KnowledgeConcept collection-t nézi, ConceptMention függetlenül is működik.

findConceptInfoByLabels(domain, normalizedLabels)

A megadott label-ekhez egyező fogalmak strukturált metaadatát adja vissza: label, type, aliases – Map-ek listájaként. Ugyanúgy ConceptMention-független; ez a fő belépési pont, ha a forrásadatod nem szöveges, és egyszerűen csak "van-e ilyen fogalom, és mi a típusa, milyen alias-okon ismert" kérdésre keresel választ.

findConceptsByFuzzyLabel(domain, conceptTypes, normalizedTerm, maxDistance, limit)

Elgépelés-toleráns fogalom-keresés: a normalizedLabel mezőt és a normalizedAliases tömb egyes elemeit külön-külön Levenshtein-szerkesztési távolság alapján hasonlítja össze a keresett névvel (betűcsere/transzpozíció is egyetlen szerkesztési lépésnek számít), és a maxDistance-en belüli találatokat adja vissza key/label párokként. Arra való, amikor a pontos vagy szuffix-alapú névkeresés (findConceptInfoByLabels, vagy egy saját executeReadOnlyQuery-alapú lekérdezés) nulla találatot ad, és ennek indoka valószínűleg a felhasználó elgépelése, nem a fogalom tényleges hiánya.

⚠️
A normalizedAliases önálló ellenőrzése szándékos, nem csak kiegészítés: egy fogalom teljes label-je gyakran a rövid nevet egy hosszú, kiszerelést/ hatáserősséget leíró szöveggel együtt tartalmazza (pl. "Flamborin 500 mg/ml belsőleges oldatos cseppek"), aminek a szerkesztési távolsága egy rövid, elgépelt névtől már a hosszkülönbség miatt is jóval meghaladja a reális küszöböt. A rövidebb, önálló nevet tartalmazó alias viszont közvetlenül összevethető - ha csak a normalizedLabel-t vizsgálnánk, egy ilyen összetett label-ű fogalom gyakorlatilag sosem adna fuzzy találatot.
ℹ️
Ez a keresési mód domainenkénti platform-oldali előfeltételt igényel, amit a plugin nem lát és nem is állít be - ha egy adott domainhez ez az előfeltétel hiányzik, a metódus egyszerűen üres listával tér vissza, kivétel nélkül. Üres eredmény tehát nem feltétlenül azt jelenti, hogy nincs a keresett névhez közeli fogalom - jelentheti azt is, hogy az adott domainen ez a funkció még nincs bekapcsolva. Ha rendszeresen üres találatot kapsz olyan domainen, ahol számítanál rá, jelezd a platform üzemeltetőjének.

A visszaadott jelöltek - pontosan úgy, mint egy alias-egyezés - nem garantáltan a keresett fogalomhoz tartoznak: egy kis szerkesztési távolság véletlenül egy teljesen más fogalomra is illeszkedhet. A bevett minta ezért a fuzzy találatokat egy LLM-alapú relevancia-szűrőn engedi át, mielőtt elfogadná őket - ugyanazon a szűrőn, amit egy alias-alapú találatra is használnál:

List<Map<String, Object>> directHits = findByExactOrSuffixMatch(domain, normalizedTerm);
if (directHits.isEmpty()) {
    int maxDistance = Math.min(3, Math.max(1, (normalizedTerm.length() + 3) / 4));
    List<Map<String, Object>> fuzzyHits = knowledgeGraphService.findConceptsByFuzzyLabel(
        domain, List.of("DRUG"), normalizedTerm, maxDistance, 10);
    // fuzzyHits minden elemét LLM-mel ellenőrizd, mielőtt elfogadnád találatnak
}

findPageKeysByLabels(domain, systems, normalizedLabels, allowedRelationTypes, minRelationWeight)

A megadott label-ekhez tartozó fogalmakhoz, majd (opcionálisan) az 1-hop gráf-szomszédaikhoz tartozó ConceptMention.documentSentenceKey értékeket adja vissza – ezek PageEmbedding1024 kulcsok, tehát a RAG kontextushoz retrievelhető oldalakat azonosítanak. Ha nem hívtál saveMention-t az adott fogalmakra, ez a metódus üres listával tér vissza rájuk – ez esetben a findConceptInfoByLabels / findAliasesByLabels a releváns lekérdező eszköz.

ℹ️
Az allowedRelationTypes és minRelationWeight paraméterek null értékkel nincsenek korlátozva; üres Set az allowedRelationTypes-nak letiltja az 1-hop bejárást (csak a közvetlen egyezés oldalai jönnek vissza).
⚠️
A KnowledgeConcept csúcsok domain-szinten (nem system-szinten) megosztottak – egy fogalmat több system NER futása is bővítheti ugyanazon a csúcson. A systems paraméterrel a visszaadott oldalkulcsok a megadott system-ekhez tartozó ConceptMention rekordokra szűkíthetők (null vagy üres lista = nincs szűrés, minden system mention-je számít). System-szűrés nélkül egy megosztott fogalom más system-ekhez tartozó oldalai is bekerülhetnek a találatba.

findConceptPagesByLabels(domain, systems, normalizedLabels, allowedRelationTypes, minRelationWeight)

Ugyanazokat a fogalmakat járja be, mint a findPageKeysByLabels, de az oldalakat nem egyesíti: fogalmanként ad vissza egy ConceptPages rekordot (a fogalom kulcsa, normalizált címkéje, az, hogy közvetlen egyezés vagy szomszéd, és az említéseinek oldalkulcsai). Akkor hasznos, ha a hívó maga dönti el, mely fogalmaknak van megkülönböztető ereje – például kihagyja azokat, amelyek szinte minden oldalon szerepelnek –, vagy azt vizsgálja, hány fogalom említi ugyanazt az oldalt. Csak az említéssel rendelkező fogalmak szerepelnek; hiba esetén üres listát ad. A paraméterek jelentése megegyezik a findPageKeysByLabels-ével.

countMentionedPages(domain, systems)

Azoknak az oldalaknak a száma, amelyeken a megadott system-ekben legalább egy fogalom-említés szerepel – a fogalmak oldalgyakoriságának viszonyítási alapja. Az eredmény domain és system-lista szerint néhány percig gyorsítótárazott, így egy frissen ingestált dokumentum rövid késéssel jelenik meg benne. Hiba esetén 0.

findConnectedConcepts(domain, normalizedLabels, relationType, reverse, targetType)

A megadott label-ekhez egyező fogalmakból kiindulva, egy megadott relationType értékű élen 1 lépésben elérhető fogalmakat adja vissza – opcionálisan a célfogalom type mezőjére szűrve. Általános, tetszőleges relációtípusra alkalmazható bejárás: a visszatérési érték a talált fogalmak key/label/ type metaadata (nem oldalkulcs, mint a findPageKeysByLabels-nél).

List<Map<String, Object>> results = knowledgeGraphService.findConnectedConcepts(
    domain,
    List.of(normalizedLabel),
    "DIAGNOSED_WITH",   // relationType
    true,               // reverse
    "PATIENT"           // targetType – null = nincs típusszűrés
);

Az irány paraméterezhető: reverse=false esetén a bejárás a matched fogalom felől kimenő élen megy (a matched fogalom az él _from oldalán áll), reverse=true esetén a bejárás a matched fogalom felé bejövő élen megy (a matched fogalom az él _to oldalán áll).

⚠️
Ha a lekérdezett relációtípust AbstractNERIngestionTool-on keresztül, LLM-alapú kinyeréssel hozták létre, a reláció iránya (melyik végpont került a from, melyik a to oldalra) kinyerésenként eltérhet – a platform sem a promptban, sem kódban nem kényszeríti ki egy adott entitástípus rögzített oldalra kerülését. Egy ilyen relációtípusra épülő bejárásnál emiatt érdemes mindkét irányban lekérdezni (reverse=false és reverse=true), és a találatokat a key mező alapján deduplikálni – különben a "másik" irányban tárolt találatok kimaradnak. Ez a kockázat nem áll fenn a saját, kódból hívott upsertRelation-nel létrehozott relációkra, ott az irány mindig a hívó kódban rögzített, garantált.

executeReadOnlyQuery(domain, aql, bindVars)

Tetszőleges, a hívó által összeállított, csak olvasó AQL lekérdezést futtat a domain tudásgráfján – olyan egyedi, több lépésben láncolt bejárási mintákhoz, amelyeket a findPageKeysByLabels (egy ugrás) és a findConnectedConcepts (egy relationType) nem fed le, például amikor egy fogalomhalmazból egy adott relációtípuson át elért fogalmakból egy második, eltérő relációtípusú ugrással kell tovább bejárni a gráfot.

A lekérdezés szövegében a három tudásgráf collection-re kizárólag négy lefoglalt placeholder néven keresztül lehet hivatkozni – a metódus ezeket a domainhez tartozó valódi collection-névre cseréli futtatás előtt, a hívó kód sosem szerez tudomást a tényleges elnevezési konvencióról:

PlaceholderFeloldásHasználat az AQL szövegében
@@concepta domain KnowledgeConcept collection-jecollection bind-változóként, pl. FOR c IN @@concept
@@relationa domain ConceptRelation collection-jecollection bind-változóként, pl. FOR r IN @@relation
@@mentiona domain ConceptMention collection-jecollection bind-változóként, pl. FOR m IN @@mention
@grapha domain named graph neveegyszeres kukac, string bind-változóként egy GRAPH-záradékban
ℹ️
A metódus csak azt a placeholder-t köti be, amelyik ténylegesen szerepel a lekérdezés szövegében – az ArangoDB ugyanis a lekérdezésben nem hivatkozott, de mégis átadott bind-változót is hibaként utasítja el ("too many bind parameters"), ugyanúgy, ahogy egy hivatkozott, de át nem adott bind-változót is. Ha tehát a lekérdezés csak @@concept-et és @@relation-t használja, a @@mention és a @graph nem kerül bekötésre – nem kell (és nem is szabad) a nem használt placeholder-eket "biztonságból" megemlíteni a lekérdezésben.
Map<String, Object> bindVars = Map.of(
    "labels", List.of("fejfajas"),
    "minWeight", 2.0
);

String aql = """
    FOR c IN @@concept
        FILTER c.normalizedLabel IN @labels
        FOR r IN @@relation
            FILTER r._to == c._id OR r._from == c._id
            FILTER r.weight >= @minWeight
            LET other = r._from == c._id ? DOCUMENT(r._to) : DOCUMENT(r._from)
            RETURN { label: other.label, type: other.type, weight: r.weight }
    """;

List<Map<String, Object>> rows = knowledgeGraphService.executeReadOnlyQuery(domain, aql, bindVars);
⚠️
A bindVars egyik kulcsa sem kezdődhet "@" karakterrel – ez a négy lefoglalt placeholder kizárólagosságát kényszeríti ki: a hívó nem deklarálhat saját collection bind-változót. A lekérdezés szövege emellett nem tartalmazhatja (szóhatáron, kis- és nagybetűt nem megkülönböztetve) az INSERT, UPDATE, REPLACE, REMOVE, UPSERT kulcsszavak egyikét sem, sem pontosvesszőt, sem a fenti négytől eltérő "@@" collection-hivatkozást. A négy lefoglalt placeholder közül legalább az egyiknek szerepelnie kell a lekérdezésben – enélkül a metódus elutasítja, hogy a csatorna kizárólag a tudásgráffal kapcsolatos lekérdezésekre legyen felhasználható, ne egy általános célú, tetszőleges AQL-futtató legyen. Bármelyik feltétel megsértése IllegalArgumentException-t vált ki, még a lekérdezés elindítása előtt. A ténylegesen lefutó lekérdezésre futásidő- és memóriakorlát vonatkozik.
ℹ️
Amit ez a védelem nem garantál: hogy a lekérdezés szövege ne hivatkozzon közvetlenül, hardcode-olt névvel egy, a placeholder-eken kívüli collection-re – az AQL FOR x IN kifejezés szintaxisa ugyanabban a szintaktikai pozícióban fogad el collection-nevet és egy korábban LET-tel számolt helyi listát is, ezt a két esetet egy egyszerű szöveg-ellenőrzés nem tudja megbízhatóan megkülönböztetni valódi AQL-parser nélkül. A hívó felelőssége, hogy collection-re kizárólag a lefoglalt placeholder-eken keresztül hivatkozzon.

A lekérdezés RETURN záradékának objektumot kell visszaadnia (pl. RETURN { label: c.label }), nem primitív értéket – a visszaadott List<Map<String, Object>> minden eleme egy-egy visszaadott sor mező-érték párjait tartalmazza.

Logikai törlés (kuka)

Egy fogalom nem csak a deleteBySystem-mel távolítható el fizikailag: a KnowledgeGraphService egy logikai törlési ("kuka") állapotot is támogat, amelyet tipikusan egy gráf-karbantartó feladat állít be olyan fogalmakra, amelyekről utólag kiderül, hogy tévesen kerültek a gráfba (pl. egy kinyerési hiba miatt). Logikailag törölt állapotban a fogalom-dokumentum, a hozzá kapcsolódó élek és mention-ök változatlanul megmaradnak, csak a fenti lekérdező metódusok elől válnak láthatatlanná - az adat nem vész el, a döntés visszavonható.

listDeletedConcepts(domain)

Az adott domainben jelenleg logikailag törölt állapotú összes fogalmat adja vissza - key, label, type, a törlés időpontja és a törlés mellett rögzített indoklás mezőkkel. Arra való, hogy egy adminisztrációs felület vagy karbantartó tool át tudja tekinteni, mi került a kukába, mielőtt döntene a visszaállításról vagy a végleges eltávolításról.

restoreConcept(domain, conceptKey)

Visszavonja egy fogalom logikai törlését - a fogalom ismét megjelenik a lekérdező metódusok találatai között, pontosan úgy, mintha sosem lett volna törölve. A hozzá kapcsolódó élek és mention-ök a törlés alatt is érintetlenek maradtak, így nincs mit helyreállítani rajtuk.

purgeDeletedConcepts(domain)

Az adott domainben logikailag törölt állapotú összes fogalmat, valamint a hozzájuk kapcsolódó éleket és mention-öket véglegesen, visszavonhatatlanul eltávolítja a tudásgráfból. Visszatérési érték: a véglegesen eltávolított fogalmak száma. Ezt a metódust csak akkor érdemes hívni, ha a listDeletedConcepts alapján megerősítést nyert, hogy a kukában lévő fogalmakra a jövőben sincs szükség - utána a restoreConcept már nem tudja visszahozni őket.

Viszonya a NER ingestion pipeline-hoz

A KnowledgeGraphService ugyanaz az alaprétege mindkét útnak: a 10. fejezetben tárgyalt AbstractNERIngestionTool valójában ugyanezeket az UPSERT metódusokat hívja a Spark-alapú, LLM-es entitáskinyerés eredményéből, plusz minden feldolgozott mondathoz saveMention-t is hív (mert ott a forrás mindig egy retrievelhető szöveges oldal). A különbség tehát nem a gráf-modellben van, hanem abban, hogy ki és honnan tölti fel:

HelyzetAjánlott megközelítés
A forrás a platform által ingesztált, embedding-elt szöveges dokumentum AbstractNERIngestionTool leszármaztatása – LLM-alapú entitáskinyerés, automatikus saveMention, beépül a standard ingestion pipeline-ba (10. fejezet)
A forrás nem a platform szöveg-pipeline-ján megy át (külső API, struktúrált rekord, más adatbázis) Saját service/tool, amely közvetlenül hívja a KnowledgeGraphService UPSERT metódusait – nincs szükség LLM-es kinyerésre, a mezők ismert struktúrából olvashatók
A direkt úton felépített gráf fogalmait egy másik tool-nak metaadatként kell elérnie (típus, alias-ok) findConceptInfoByLabels / findAliasesByLabels – ConceptMention nélkül is működnek
A direkt úton felépített fogalmakat retrievelhető szöveges oldalakhoz is szeretnéd kötni saveMention hívása minden fogalom-előforduláshoz, majd findPageKeysByLabels a lekérdezéshez