Knowledge Graph Integration
What a research paper knows is locked in prose, findable only by someone who already knows to read that particular paper. The knowledge graph is where the platform keeps published papers as data. It is a SPARQL triple store in which every paper is a named graph, so the question of which papers touch a concept, and who wrote them, is a query instead of a literature review.
The graph is maintained by BioAgents and reached through the API. It is loaded from curated JSON-LD records of published papers rather than extracted from the files you upload. What an uploaded paper gets from the graph is enrichment, described below.
What it is built from
RDF in named graphs
The store is Oxigraph. Each paper is one named graph whose name is the paper's DOI as an IRI, and the paper itself is the subject of the triples inside it. The vocabulary is bibliographic. It uses Dublin Core terms, schema.org, FOAF, and the SPAR ontologies FaBiO, CiTO and DEO for document structure.
# Inside the named graph <https://doi.org/10.1038/s41586-021-03819-2>
<https://doi.org/10.1038/s41586-021-03819-2>
dcterms:title "CRISPR-Cas9 Gene Editing for Neurodegenerative Diseases" ;
dcterms:abstract "..." ;
schema:datePublished "2021-08-05" ;
dcterms:creator _:a1 ;
schema:keywords "gene editing" , "neurodegeneration" ;
schema:about <https://example.org/term/crispr-cas9> .
_:a1 foaf:name "Jane Smith" .
<https://example.org/term/crispr-cas9> dcterms:name "CRISPR-Cas9" .JSON-LD
Papers arrive as JSON-LD documents. That makes the graph loadable from ordinary files and readable by tools that do not care about RDF.
{
"@context": {
"dcterms": "http://purl.org/dc/terms/",
"schema": "https://schema.org/",
"foaf": "http://xmlns.com/foaf/0.1/"
},
"@id": "https://doi.org/10.1038/s41586-021-03819-2",
"dcterms:title": "CRISPR-Cas9 Gene Editing for Neurodegenerative Diseases",
"schema:datePublished": "2021-08-05",
"dcterms:creator": [{ "foaf:name": "Jane Smith" }],
"schema:keywords": ["gene editing", "neurodegeneration"]
}SPARQL
Oxigraph answers SPARQL on its query endpoint and accepts inserts through the Graph Store Protocol. Both are internal to the BioAgents deployment, configured by KG_TRIPLE_STORE_URL. The API does not expose a raw SPARQL endpoint. Every query the plugin runs is assembled from typed inputs, and nothing a caller types becomes query text. A concept search has this shape, lightly simplified here.
SELECT DISTINCT ?doi ?title ?abstract ?date
(GROUP_CONCAT(DISTINCT ?matched; SEPARATOR="; ") AS ?matchedTerms)
WHERE {
GRAPH ?doi {
?doi dcterms:title ?title .
OPTIONAL { ?doi dcterms:abstract ?abstract . }
OPTIONAL { ?doi schema:datePublished ?date . }
{ ?doi schema:about ?term . ?term dcterms:name ?termName .
FILTER(CONTAINS(LCASE(?termName), "crispr")) BIND(?termName AS ?matched) }
UNION
{ ?doi schema:keywords ?keyword .
FILTER(CONTAINS(LCASE(?keyword), "crispr")) BIND(?keyword AS ?matched) }
UNION
{ ?doi dcterms:title ?t . FILTER(CONTAINS(LCASE(?t), "crispr")) BIND("title" AS ?matched) }
UNION
{ ?doi dcterms:abstract ?a . FILTER(CONTAINS(LCASE(?a), "crispr")) BIND("abstract" AS ?matched) }
}
}
GROUP BY ?doi ?title ?abstract ?date
ORDER BY RAND()
LIMIT 8A concept matches a paper's subject terms, keywords, title or abstract. An author matches on the surname, which is the stable part of how papers cite people.
How knowledge gets in
A loader script reads JSON-LD files, one per paper and named after the URL encoded DOI, converts each to N-Quads and stores it as that DOI's named graph, skipping papers already present. There is no other ingestion path for the graph.
Uploaded papers do not become triples. When you register a paper with a DOI, the API looks the DOI up in the graph and fills in the fields you left empty. Those are the abstract, venue, date, authors, keywords, and the paper's subject terms as its entities. The paper record then links the graph's knowledge to a DID and a CID.
Hypotheses are the one thing the platform writes into the store. Each run of the question pipeline can propose connections and stores them, with their rationale, method, keywords and source DOIs, in a named graph reserved for them.
Querying
Every route takes a session token. Terms are comma separated, at most ten, each three or more characters. limit runs from 1 to 50. order is random, the default, or recent.
| Operation | Endpoint |
|---|---|
| Papers matching concepts | GET /api/bioagents/kg/papers?concepts=crispr,neurodegeneration&limit=8&order=recent |
| Papers by author, optionally narrowed by concept | GET /api/bioagents/kg/authors?authors=Smith&concepts=crispr |
| One paper with its sections | GET /api/bioagents/kg/paper?doi=10.1038/s41586-021-03819-2 |
| Stored hypotheses | GET /api/bioagents/kg/hypotheses?concepts=crispr |
| Ask a question | POST /api/bioagents/kg/ask |
| Store reachable, paper count | GET /api/bioagents/kg/health (public) |
curl "https://api.ekayana.io/api/bioagents/kg/papers?concepts=crispr&limit=2" \
-H "Authorization: Bearer $TOKEN"{
"papers": [{
"doi": "https://doi.org/10.1038/s41586-021-03819-2",
"title": "CRISPR-Cas9 Gene Editing for Neurodegenerative Diseases",
"abstract_text": "...",
"date": "2021-08-05",
"authors": "Jane Smith; John Doe",
"keywords": "gene editing; neurodegeneration",
"terms": "CRISPR-Cas9; Neurodegeneration",
"matched_terms": "CRISPR-Cas9; title"
}]
}Concatenated fields use ; as the separator, which is how the store groups them.
In plain English
POST /api/bioagents/kg/ask takes a question of 3 to 2000 characters and up to six lines of context. The agent's text model decides which searches to run. The plugin runs them as the typed queries above. The model writes a synthesis that cites the papers it used. The response carries all of it.
{
"question": "What links CRISPR delivery vectors to neuroinflammation?",
"synthesis": "...",
"papers": [{ "doi": "...", "title": "...", "matched_terms": "..." }],
"hypotheses": [{
"id": "...", "statement": "...", "rationale": "...", "method": "...",
"keywords": ["..."], "sources": ["https://doi.org/..."], "creator": "...", "created": "..."
}],
"plan": { "...": "the steps the model chose" }
}A run may take up to 100 seconds before the API gives up on it.
What this is for
The first use is discovery. Find related work you did not know existed, by concept or by author, with the graph's own citations. The second is hypothesis generation. The pipeline sees which papers a question pulls together and can propose a connection to test, with the papers that suggested it. Whether a proposed connection is real is still the researcher's job. The graph makes the candidates enumerable and keeps each one attached to its sources.
The graph is also a junction. A paper you register links a DID and a file to a DOI. The DOI links to the graph. An answer's citations lead back through the DOI to your record and the file behind it. That chain lets one question span published literature and your own registered work.