Answer Relationship Questions from a Product
You need to answer a relationship question from within a product.
Examples are which people belong to an organization, which projects
reference a capability, and which resources share a type. The graph
service holds the RDF index in memory. It exposes three RPCs:
QueryByPattern, GetSubjects, and
GetOntology. This page shows each RPC with examples
that you can copy.
For the full setup, see Ground Agents in Context. That guide shows how to connect to both the graph and vector services.
Prerequisites
-
You completed the
Ground Agents in Context
guide. You installed
@forwardimpact/librpcand@forwardimpact/libtype. The graph service runs.createClient("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);
The query 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. You
can filter the result 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
The service resolves type synonyms automatically. The ontology
defines these synonyms with skos:altLabel. A query for
schema:Person also returns entities with the type
schema:Individual if the ontology maps them.
Read the ontology
The ontology is a SHACL description of all observed types and predicates in the graph. It shows you which 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 that contains SHACL shape definitions for every observed type and predicate.
Verify
You reach 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. -
A
filterwithlimitconstrains the result count.
What's next
Traverse Knowledge and Search Semantically
Query relationships and search content through shared graph and vector gRPC services, with no per-product stores.
Search for Related Content from a Product
Find related content by meaning from any product. The shared vector service manages the embeddings, so your product stores none.