3.17 Text into the graph, and one query as a pipeline — ai.fromText
CALL ai.fromText($notes, '(t:Attendee)-[:RAISED]->(i:Issue), (t)-[:WORKS_FOR]->(a:CustomerAccount)') YIELD t, i, aWITH DISTINCT i, aMATCH (a)-[:HAS_CASE]->(c:SupportCase) WHERE c.status IN ['open', 'pending']WITH i, relevant(c, 'the same problem as: ' + i.summary) AS trackedUNWIND tracked AS tcCREATE (i)-[:TRACKED_BY]->(tc)WITH count(*) AS linkedMATCH (t2:Attendee)-[:RAISED]->(untracked:Issue)WHERE NOT EXISTS { (untracked)-[:TRACKED_BY]->() }RETURN untracked.summary, untracked.severity, t2.name, t2.roleMeans: “From these meeting notes, what did the customer raise that we have no open ticket for?”
Four things happen in one ordinary query:
- The notes become a graph.
ai.fromTextreads the text into the pattern’s shape.AttendeeandIssueare realm types markedprojected: true— nothing fetches or stores them — and their descriptions are what the model is shown, so “a problem, not a request or a wish” keeps “they want annual billing” out ofIssue.CustomerAccountis a world type, so it is resolved through its spine, never created: a company the books do not know comes back as a warning, not a fake account. - The model judges nodes, per group.
relevant(c, …)keeps the cases that are the same problem as this issue — the criterion reads the grouping key — and what it keeps are the group’s own nodes. - The query writes, and nothing is stored.
CREATEof a projected relationship lands in the run’s scratch: the rest of the query sees it, no other run does, and it is gone when the run ends. - The label is the isolation.
MATCH (untracked:Issue)reads exactly what this run projected, becauseIssuehas no stored instances.
Habits: use fresh names across stages (tc, t2, untracked); write only projected types; and read
the warnings — a declined personal address or an unresolved company is said, never silently empty.
See §7.8 and §7.9 of the spec.

