Once you've built a knowledge graph, querying it effectively unlocks powerful insights—finding relationships, co-occurrences, and patterns across your content. This guide covers advanced query patterns beyond basic entity extraction.
What You'll Learn
- Relationship queries (who works where)
- Entity co-occurrence analysis
- Graph traversal patterns
- Temporal entity queries
- Guided search with entities
- Building recommendation engines
Part 1: Relationship Queries
Find Person-Organization Relationships
import { Graphlit } from 'graphlit-client';
import { ObservableTypes } from 'graphlit-client/dist/generated/graphql-types';
const graphlit = new Graphlit();
// Get all people
const people = await graphlit.queryObservables({
filter: {
types: [ObservableTypes.Person]
}
});
// For each person, find related organizations
const relationships = [];
for (const personResult of people.observables?.results || []) {
const person = personResult.observable;
// Get content mentioning this person
const personContent = await graphlit.queryContents({
filter: {
observations: {
observables: [{ id: person.id }]
}
}
});
// Extract organizations from same content
for (const content of personContent.contents.results) {
const details = await graphlit.getContent(content.id);
const orgs = details.content.observations
?.filter(obs => obs.type === ObservableTypes.Organization)
.map(obs => obs.observable.name);
orgs?.forEach(org => {
relationships.push({
person: person.name,
organization: org
});
});
}
}
// Display relationships
console.log('Person → Organization relationships:');
relationships.forEach(rel => {
console.log(` ${rel.person} ↔ ${rel.organization}`);
});
Example output:
Person → Organization relationships:
Alice Johnson ↔ Acme Corp
Alice Johnson ↔ OpenAI
Bob Smith ↔ Acme Corp
Carol Lee ↔ Google
Part 2: Entity Co-Occurrence
Find Entities Mentioned Together
// Get content
const content = await graphlit.getContent(contentId);
// Build co-occurrence matrix
interface CoOccurrence {
entity1: string;
entity2: string;
pages: number[];
strength: number;
}
const cooccurrences: CoOccurrence[] = [];
const observations = content.content.observations || [];
// For each pair of entities
for (let i = 0; i < observations.length; i++) {
for (let j = i + 1; j < observations.length; j++) {
const obs1 = observations[i];
const obs2 = observations[j];
// Get pages where each appears
const pages1 = new Set(obs1.occurrences?.map(occ => occ.pageIndex));
const pages2 = new Set(obs2.occurrences?.map(occ => occ.pageIndex));
// Find shared pages
const sharedPages = Array.from(pages1).filter(p => pages2.has(p));
if (sharedPages.length > 0) {
cooccurrences.push({
entity1: obs1.observable.name,
entity2: obs2.observable.name,
pages: sharedPages,
strength: sharedPages.length
});
}
}
}
// Sort by strength
cooccurrences
.sort((a, b) => b.strength - a.strength)
.slice(0, 10)
.forEach(co => {
console.log(`${co.entity1} ↔ ${co.entity2} (${co.strength} pages)`);
});
Use cases:
- "Find people who work together" (co-mentioned)
- "Find related products" (discussed together)
- "Find connected topics" (appear in same docs)
Part 3: Temporal Entity Analysis
Track Entity Mentions Over Time
// Get entity
const entity = await graphlit.queryObservables({
filter: {
searchText: "Project Phoenix",
types: [ObservableTypes.Product]
}
});
const entityId = entity.observables?.results?.[0]?.observable.id;
// Get all content mentioning this entity
const mentions = await graphlit.queryContents({
filter: {
observations: {
observables: [{ id: entityId }]
}
}
});
// Group by month
const timeline = new Map<string, number>();
mentions.contents.results.forEach(content => {
const date = new Date(content.creationDate);
const monthKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
timeline.set(monthKey, (timeline.get(monthKey) || 0) + 1);
});
// Display timeline
console.log('Mentions of "Project Phoenix" over time:');
Array.from(timeline.entries())
.sort((a, b) => a[0].localeCompare(b[0]))
.forEach(([month, count]) => {
console.log(` ${month}: ${count} mentions`);
});
Example output:
Mentions of "Project Phoenix" over time:
2024-01: 5 mentions
2024-02: 12 mentions
2024-03: 8 mentions
2024-04: 15 mentions
Use cases:
- Track project activity
- Monitor competitor mentions
- Identify trending topics
Part 4: Guided Search
Entity-Filtered Search
// Find Alice
const aliceEntity = await graphlit.queryObservables({
filter: {
searchText: "Alice Johnson",
types: [ObservableTypes.Person]
}
});
const aliceId = aliceEntity.observables?.results?.[0]?.observable.id;
// Search content mentioning Alice about "budget"
const results = await graphlit.queryContents({
search: "budget allocation",
filter: {
observations: {
observables: [{ id: aliceId }]
}
}
});
console.log(`Documents about "budget" mentioning Alice: ${results.contents.results.length}`);
Multi-Entity Filter
// Find content mentioning BOTH Alice AND Acme Corp
const acmeEntity = await graphlit.queryObservables({
filter: {
searchText: "Acme Corp",
types: [ObservableTypes.Organization]
}
});
const acmeId = acmeEntity.observables?.results?.[0]?.observable.id;
const multiFilter = await graphlit.queryContents({
search: "partnership",
filter: {
observations: {
observables: [
{ id: aliceId },
{ id: acmeId }
]
}
}
});
console.log('Documents about Alice AND Acme Corp:', multiFilter.contents.results.length);
Part 5: Building Recommendation Engines
Content Recommendation by Entities
// User reads document A
const docA = await graphlit.getContent(documentAId);
// Extract entities from doc A
const entitiesA = docA.content.observations
?.map(obs => obs.observable.id) || [];
// Find other docs with similar entities
const recommendations = await graphlit.queryContents({
filter: {
observations: {
observables: entitiesA.slice(0, 5).map(id => ({ id })) // Top 5 entities
}
},
limit: 10
});
console.log('Recommended documents:');
recommendations.contents.results.forEach(doc => {
console.log(` - ${doc.name}`);
});
Use cases:
- "More like this" features
- Related articles
- Cross-document discovery
Part 6: Network Analysis
Entity Influence Score
// Calculate "influence" based on co-mentions
async function calculateInfluence() {
const people = await graphlit.queryObservables({
filter: { types: [ObservableTypes.Person] }
});
const influence = new Map<string, number>();
for (const personResult of people.observables?.results || []) {
const person = personResult.observable;
// Count mentions
const mentionCount = person.observationCount || 0;
// Count unique documents mentioning them
const docs = await graphlit.queryContents({
filter: {
observations: {
observables: [{ id: person.id }]
}
}
});
const uniqueDocs = docs.contents.results.length;
// Influence = mentions * unique docs
influence.set(person.name, mentionCount * uniqueDocs);
}
// Top influencers
Array.from(influence.entries())
.sort((a, b) => b[1] - a[1])
.slice(0, 10)
.forEach(([name, score]) => {
console.log(`${name}: influence score ${score}`);
});
}
Common Patterns
Pattern 1: Find Clusters
// Find people who work on same projects
const projectClusters = new Map<string, Set<string>>();
const projects = await graphlit.queryObservables({
filter: { types: [ObservableTypes.Product] }
});
for (const project of projects.observables?.results || []) {
const docs = await graphlit.queryContents({
filter: {
observations: {
observables: [{ id: project.observable.id }]
}
}
});
const peopleInProject = new Set<string>();
for (const doc of docs.contents.results) {
const details = await graphlit.getContent(doc.id);
details.content.observations
?.filter(obs => obs.type === ObservableTypes.Person)
.forEach(person => {
peopleInProject.add(person.observable.name);
});
}
projectClusters.set(project.observable.name, peopleInProject);
}
// Display clusters
projectClusters.forEach((people, project) => {
console.log(`${project}: ${Array.from(people).join(', ')}`);
});
Pattern 2: Expertise Mapping
// Map people to topics
const expertise = new Map<string, Set<string>>();
const people = await graphlit.queryObservables({
filter: { types: [ObservableTypes.Person] }
});
for (const personResult of people.observables?.results || []) {
const docs = await graphlit.queryContents({
filter: {
observations: {
observables: [{ id: personResult.observable.id }]
}
}
});
const topics = new Set<string>();
for (const doc of docs.contents.results) {
const details = await graphlit.getContent(doc.id);
// Extract product/topic entities
details.content.observations
?.filter(obs => obs.type === ObservableTypes.Product)
.forEach(topic => {
topics.add(topic.observable.name);
});
}
expertise.set(personResult.observable.name, topics);
}
// Display expertise
expertise.forEach((topics, person) => {
console.log(`${person} is expert in: ${Array.from(topics).join(', ')}`);
});
What's Next?
You now understand advanced knowledge graph queries. Next steps:
- Build entity dashboards showing relationships
- Create recommendation engines based on entities
- Track entity evolution over time
Related guides:
- Building Knowledge Graphs - Entity extraction basics
- Complete Guide to Search - Entity-filtered search
- Metadata Filtering - Advanced filtering
Happy querying! 🔍