A worked example
A folder of research papers, taken end to end. Every statement here is runnable; the domain is invented, so swap the nouns for yours.
1. What we have
A shared drive folder holding a few hundred PDFs. Each is a paper: a title and DOI, some authors with affiliations, funding acknowledgements, and a reference list. Today, answering "which of our funded papers cite work we've since retracted?" means someone opening files.
2. Declare the shape
The schema is a decision about what matters. Three principles worth borrowing:
One root per document kind. These are all papers, so Paper is the root
and everything else hangs beneath it.
A column that is only sometimes true is the wrong schema. Not every paper
names a funder. So funding is its own entity. A row exists when there is one,
rather than a mostly-empty column on Paper.
Key on what identifies, not on what is convenient. KEY is how two
mentions across documents are recognised as the same thing.
CREATE ONTOLOGY research; CREATE ENTITY research.Paper (doi TEXT KEY,title TEXT,published_on DATE,peer_reviewed BOOLEAN) ROOT SINGULAR PER DOC; CREATE ENTITY research.Author (full_name TEXT KEY,affiliation TEXT,role TEXT CHECK (role IN ('lead','contributing','reviewer'))) UNDER research.Paper; CREATE ENTITY research.Grant (funder TEXT,reference TEXT,amount FLOAT,KEY (funder, reference)) UNDER research.Paper; CREATE ENTITY research.Citation (cited_title TEXT KEY,cited_doi TEXT,cited_year INTEGER) UNDER research.Paper;Note Grant's composite key: neither the funder nor the reference number
identifies a grant on its own, but together they do.
3. Connect the relationships
An author's name appears on the paper as written: "R. Okonkwo" in one, "Rita
Okonkwo" in another. RESOLVE FUZZY is what collapses those into one node;
WITHIN keeps the comparison pool tight.
CREATE EDGE research.written_byON research.Paper WRITTEN_BY research.AuthorLINK BY author_name RESOLVE FUZZY WITHIN research.Author; -- A citation lives inside the paper that makes it: no matching needed.CREATE EDGE research.citesON research.Paper CITES research.Citation;4. Point it at the documents
The corpus claims a path. Nothing is copied anywhere. The documents stay where they are, and their permissions come with them.
CREATE CORPUS libraryON gdrive."Shared Drive".Research.PapersUSING ONTOLOGY research; BIND CORPUS library TO ONTOLOGY research; RUN BINDING library.research;BIND freezes the draft to an immutable version. RUN BINDING is what extracts.
5. Ask the question
The one that used to mean opening files:
SELECT p.title, g.funder, c.cited_titleFROM library.Paper pJOIN library.Grant g USING (_doc)JOIN library.Citation c VIA p.citesWHERE g.funder = 'Coastal Science Fund'AND c.cited_year < 2015ORDER BY p.published_on DESCLIMIT 4;6. Save it as vocabulary
A view turns a query into a named thing people can ask for.
CREATE VIEW v_funded_citations ASSELECT DISTINCT p.doi, p.title, g.funder, c.cited_title, c.cited_yearFROM library.Paper pJOIN library.Grant g USING (_doc)JOIN library.Citation c VIA p.cites; -- Now the question is one line.SELECT funder, COUNT(*) AS pre_2015_citationsFROM v_funded_citationsWHERE cited_year < 2015GROUP BY funderORDER BY pre_2015_citations DESC;7. Decide who sees it
GRANT SELECT ON CORPUS library TO GROUP researchers;A grant can only narrow. It never widens what the source system already allows.
Where to go next
- The schema is a draft until you bind it. Reshape freely, then
REBIND - Add a column later and backfill with
RUN BINDING … EXTRACT (…) - Wrong extraction? Hint the root entity, not the child
SHOW LINEAGE OF '<node_id>'traces any row back to the document it came from