Query Entity Relationships in Knowledge Graph
User Intent
"How do I query relationships between entities? Show me how to find all people at an organization, products by a company, or events at a location."
Operation
SDK Methods: queryObservables() with relationship filters, queryContents() with entity filters
GraphQL Query: queryObservables, queryContents
Entity: Observable relationships and co-occurrence patterns
Prerequisites
Graphlit project with extracted entities (knowledge graph built)
Understanding of Observable/Observation model
Content with entity extraction completed
Complete Code Example (TypeScript)
import { Graphlit } from 'graphlit-client';
import { ObservableTypes, EntityState } from 'graphlit-client/dist/generated/graphql-types';
const graphlit = new Graphlit();
console.log('=== Querying Entity Relationships ===\n');
// Example 1: Find all people at Graphlit
console.log('Example 1: Person → Organization\n');
// First, find the Graphlit organization entity
const graphlitOrg = await graphlit.queryObservables({
search: "Graphlit",
filter: {
types: [ObservableTypes.Organization],
states: [EntityState.Enabled]
}
});
if (graphlitOrg.observables.results.length > 0) {
const orgId = graphlitOrg.observables.results[0].observable.id;
console.log(`Found organization: ${graphlitOrg.observables.results[0].observable.name}\n`);
// Find all content mentioning Graphlit
const graphlitContent = await graphlit.queryContents({
filter: {
observations: [{
type: ObservableTypes.Organization,
observable: { id: orgId }
}]
}
});
// Extract all people mentioned in that content
const peopleAtGraphlit = new Map<string, { id: string; name: string }>();
graphlitContent.contents.results.forEach(content => {
content.observations
?.filter(obs => obs.type === ObservableTypes.Person)
.forEach(obs => {
peopleAtGraphlit.set(obs.observable.id, {
id: obs.observable.id,
name: obs.observable.name
});
});
});
console.log(`People at Graphlit: ${peopleAtGraphlit.size}`);
Array.from(peopleAtGraphlit.values()).slice(0, 5).forEach(person => {
console.log(` - ${person.name}`);
});
if (peopleAtGraphlit.size > 5) {
console.log(` ... and ${peopleAtGraphlit.size - 5} more`);
}
}
console.log('\n---\n');
// Example 2: Find all events at a location
console.log('Example 2: Event → Place\n');
// Find a place entity
const seattle = await graphlit.queryObservables({
search: "Seattle",
filter: {
types: [ObservableTypes.Place],
states: [EntityState.Enabled]
}
});
if (seattle.observables.results.length > 0) {
const placeId = seattle.observables.results[0].observable.id;
console.log(`Found place: ${seattle.observables.results[0].observable.name}\n`);
// Find content mentioning both events and this place
const contentWithPlace = await graphlit.queryContents({
filter: {
observations: [{
type: ObservableTypes.Place,
observable: { id: placeId }
}]
}
});
// Extract events from that content
const eventsAtPlace = new Set<string>();
contentWithPlace.contents.results.forEach(content => {
content.observations
?.filter(obs => obs.type === ObservableTypes.Event)
.forEach(obs => {
eventsAtPlace.add(obs.observable.name);
});
});
console.log(`Events in Seattle: ${eventsAtPlace.size}`);
Array.from(eventsAtPlace).slice(0, 5).forEach(event => {
console.log(` - ${event}`);
});
}
console.log('\n---\n');
// Example 3: Find products by organization
console.log('Example 3: Product → Organization\n');
// Find Microsoft
const microsoft = await graphlit.queryObservables({
search: "Microsoft",
filter: {
types: [ObservableTypes.Organization],
states: [EntityState.Enabled]
}
});
if (microsoft.observables.results.length > 0) {
const msftId = microsoft.observables.results[0].observable.id;
console.log(`Found organization: ${microsoft.observables.results[0].observable.name}\n`);
// Find content mentioning Microsoft
const msftContent = await graphlit.queryContents({
filter: {
observations: [{
type: ObservableTypes.Organization,
observable: { id: msftId }
}]
}
});
// Extract products
const msftProducts = new Map<string, number>();
msftContent.contents.results.forEach(content => {
content.observations
?.filter(obs => obs.type === ObservableTypes.Product)
.forEach(obs => {
msftProducts.set(
obs.observable.name,
(msftProducts.get(obs.observable.name) || 0) + 1
);
});
});
console.log(`Products by Microsoft: ${msftProducts.size}`);
Array.from(msftProducts.entries())
.sort((a, b) => b[1] - a[1])
.slice(0, 5)
.forEach(([product, count]) => {
console.log(` - ${product} (mentioned ${count} times)`);
});
}
console.log('\n---\n');
// Example 4: Multi-hop relationship (Person → Organization → Event)
console.log('Example 4: Multi-hop Relationship (Person → Org → Event)\n');
// Find a person
const person = await graphlit.queryObservables({
search: "Kirk Marple",
filter: {
types: [ObservableTypes.Person],
states: [EntityState.Enabled]
}
});
if (person.observables.results.length > 0) {
const personId = person.observables.results[0].observable.id;
console.log(`Person: ${person.observables.results[0].observable.name}\n`);
// Step 1: Find organizations this person is associated with
const personContent = await graphlit.queryContents({
filter: {
observations: [{
type: ObservableTypes.Person,
observable: { id: personId }
}]
}
});
const relatedOrgs = new Set<string>();
personContent.contents.results.forEach(content => {
content.observations
?.filter(obs => obs.type === ObservableTypes.Organization)
.forEach(obs => {
relatedOrgs.add(obs.observable.id);
});
});
console.log(`Associated organizations: ${relatedOrgs.size}`);
// Step 2: For each organization, find events
const allEvents = new Set<string>();
for (const orgId of Array.from(relatedOrgs).slice(0, 3)) { // Limit for demo
const orgEvents = await graphlit.queryContents({
filter: {
observations: [{
type: ObservableTypes.Organization,
observable: { id: orgId }
}]
}
});
orgEvents.contents.results.forEach(content => {
content.observations
?.filter(obs => obs.type === ObservableTypes.Event)
.forEach(obs => {
allEvents.add(obs.observable.name);
});
});
}
console.log(`Events related to person's organizations: ${allEvents.size}`);
Array.from(allEvents).slice(0, 5).forEach(event => {
console.log(` - ${event}`);
});
}
console.log('\n✓ Relationship queries complete!');Step-by-Step Explanation
Step 1: Understanding Relationship Types
Direct Relationships (inferred from co-occurrence):
Person → Organization: People work at organizations
Event → Place: Events happen at locations
Product → Organization: Companies make products
Person → Event: People attend/organize events
Software → Organization: Companies develop software
Implicit Relationships (from content context):
Entities mentioned together in same document
Entities on same page (PDF documents)
Entities in same conversation thread
Entities in same time window (audio/video)
Step 2: Query Pattern 1 - Find Related Entities
Pattern: Entity A → Entity B
Step 3: Query Pattern 2 - Co-Occurrence Filtering
Pattern: Find content with BOTH entities
Step 4: Query Pattern 3 - Multi-Hop Relationships
Pattern: Entity A → Entity B → Entity C
Step 5: Relationship Strength (Frequency)
Pattern: Count co-occurrences to measure relationship strength
Configuration Options
Filtering by Content Type
Time-Based Relationship Queries
Confidence-Based Filtering
Variations
Variation 1: Build Network Graph
Create network visualization data:
Variation 2: Relationship Timeline
Track when relationships formed:
Variation 3: Entity Influence Score
Rank entities by relationship count:
Variation 4: Relationship Path Finding
Find shortest path between two entities:
Variation 5: Relationship Export for Analysis
Export relationship data for external analysis:
Common Issues & Solutions
Issue: Too Many API Calls for Large Graphs
Problem: Multi-hop queries make hundreds of API calls.
Solution: Batch queries and cache results:
Issue: No Relationships Found
Problem: Query returns no related entities.
Causes:
Entities from different content sources
Entities never co-occur
Filters too restrictive
Solution: Broaden query:
Issue: Duplicate Relationships
Problem: Same relationship counted multiple times.
Solution: Deduplicate by entity ID:
Issue: Slow Multi-Hop Queries
Problem: Deep relationship traversal very slow.
Solution: Limit depth and parallelize:
Developer Hints
Relationship Query Performance
Direct relationships (1-hop): Fast (<1s)
2-hop relationships: Moderate (1-5s)
3+ hop relationships: Slow (5-30s)
Cache aggressively for large graphs
Relationship Types by Content
Emails: Strong Person-Person, Person-Organization
Slack: Person-Person, Organization-Product
Documents: All types, especially Product-Organization
GitHub: Person-Repo, Software-Organization
Co-Occurrence Reliability
Same page (PDF): Very strong relationship indicator
Same document: Strong relationship
Same thread (Slack/email): Strong relationship
Different documents: Weaker relationship
Graph Traversal Strategies
Breadth-first: Find shortest paths
Depth-first: Explore deep relationships
Limited depth: Prevent explosion (max 3 hops)
Type-specific: Only traverse certain entity types
Last updated
Was this helpful?