Answer Relationship Questions from a Product
You need to answer a relationship question from within a product --
which people belong to an organization, which projects reference a
capability, which resources share a type. The graph service holds
the RDF index in memory and exposes three RPCs:
QueryByPattern, GetSubjects, and
GetOntology. This page walks through each RPC with
copy-pasteable examples.
For the full setup including connecting to both the graph and vector services, see Ground Agents in Context.
Prerequisites
-
Completed the
Ground Agents in Context
guide -- you have
@forwardimpact/librpcand@forwardimpact/libtypeinstalled, the graph service is running, andcreateClient("graph")connects successfully. -
A populated graph index at
data/graphs/index.jsonl.
Connect
import { createClient, createTracer } from "@forwardimpact/librpc";
import { createLogger } from "@forwardimpact/libtelemetry";
import { graph, common } from "@forwardimpact/libtype";
const logger = createLogger("my-product");
const tracer = await createTracer("my-product");
const graphClient = await createClient("graph", logger, tracer);
Query by triple pattern
QueryByPattern takes a subject, predicate, and object.
Use ? as a wildcard in any position. The service
returns resource identifiers whose triples match the pattern.
Find all entities with a given relationship
const query = graph.PatternQuery.fromObject({
subject: "?",
predicate: "schema:worksFor",
object: "?",
});
const result = await graphClient.QueryByPattern(query);
console.log("Matches:", result.identifiers?.length ?? 0);
for (const id of result.identifiers ?? []) {
console.log(String(id));
}
Expected output:
Matches: 3
common.Message.a1b2c3
common.Message.d4e5f6
common.Message.g7h8i9
Constrain to a specific object
const query = graph.PatternQuery.fromObject({
subject: "?",
predicate: "schema:worksFor",
object: "https://acme.example/org/engineering",
});
const result = await graphClient.QueryByPattern(query);
console.log("People in engineering:", result.identifiers?.length ?? 0);
Find all properties of a subject
const query = graph.PatternQuery.fromObject({
subject: "https://acme.example/people/alice",
predicate: "?",
object: "?",
});
const result = await graphClient.QueryByPattern(query);
This returns every resource that contributed triples about Alice.
Apply a result filter
Pass a filter object to limit results:
const query = graph.PatternQuery.fromObject({
subject: "?",
predicate: "rdf:type",
object: "schema:Person",
filter: { limit: "5", prefix: "common.Message" },
});
const result = await graphClient.QueryByPattern(query);
List subjects
GetSubjects returns all entity URIs in the graph,
optionally filtered by RDF type. Each line in the response is a
tab-separated subject URI and its type.
All subjects
const allSubjects = graph.SubjectsQuery.fromObject({});
const result = await graphClient.GetSubjects(allSubjects);
console.log(result.content);
Expected output:
https://acme.example/org/engineering https://schema.org/Organization
https://acme.example/people/alice https://schema.org/Person
https://acme.example/people/bob https://schema.org/Person
Filtered by type
const personSubjects = graph.SubjectsQuery.fromObject({
type: "schema:Person",
});
const result = await graphClient.GetSubjects(personSubjects);
console.log(result.content);
Expected output:
https://acme.example/people/alice https://schema.org/Person
https://acme.example/people/bob https://schema.org/Person
Type synonyms defined via skos:altLabel in the ontology
are resolved automatically -- querying for
schema:Person also returns entities typed as
schema:Individual if the ontology maps them.
Read the ontology
The ontology is a SHACL description of all types and predicates observed in the graph. It tells you what questions the graph can answer before you write queries:
const ontology = await graphClient.GetOntology(common.Empty.fromObject({}));
console.log(ontology.content.substring(0, 300));
The response is a Turtle RDF string containing SHACL shape definitions for every observed type and predicate.
Verify
You have reached the outcome of this guide when:
-
QueryByPatternwith a subject/predicate/object pattern returns matching resource identifiers. -
GetSubjectswith a type filter returns only entities of that type. -
GetOntologyreturns Turtle RDF that describes the available types and predicates. -
Applying a
filterwithlimitconstrains the result count.
Related
- Ground Agents in Context -- the end-to-end setup for connecting to both the graph and vector services.
- Search for Related Content -- when you need ranked similarity rather than exact triple matching.
- Query a Graph -- the library guide for querying the graph index directly without the gRPC service.