> For the complete documentation index, see [llms.txt](https://docs.graphlit.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.graphlit.dev/api-guides/use-cases/knowledge-graph/observable-query-graph.md).

# Query Knowledge Graph

## Observable: Query Knowledge Graph

### User Intent

"I want to explore entity relationships and visualize my knowledge graph"

### Operation

* **SDK Method**: `graphlit.queryContentsGraph()`
* **GraphQL**: `queryContentsGraph` query
* **Entity Type**: Content/Observable (graph relationships)
* **Common Use Cases**: Visualize knowledge graphs, explore entity relationships, discover connections, graph analytics

### TypeScript (Canonical)

```typescript
import { Graphlit } from 'graphlit-client';
import { ObservableTypes } from 'graphlit-client/dist/generated/graphql-types';

const graphlit = new Graphlit();

// Query knowledge graph for specific content
const graphResponse = await graphlit.queryContentsGraph({
  contents: [{ id: contentId }]
});

console.log('Knowledge Graph:');
console.log(`Nodes: ${graphResponse.graph.nodes?.length || 0}`);
console.log(`Edges: ${graphResponse.graph.edges?.length || 0}`);

// Access nodes (entities)
graphResponse.graph.nodes?.forEach(node => {
  console.log(`\n${node.type}: ${node.name}`);
  if (node.description) {
    console.log(`  Description: ${node.description}`);
  }
});

// Access edges (relationships)
graphResponse.graph.edges?.forEach(edge => {
  const from = graphResponse.graph.nodes?.find(n => n.id === edge.from);
  const to = graphResponse.graph.nodes?.find(n => n.id === edge.to);
  console.log(`${from?.name} → ${edge.type} → ${to?.name}`);
});

// Query graph across all content
const fullGraph = await graphlit.queryContentsGraph();

console.log(`\nFull knowledge graph:`);
console.log(`Total entities: ${fullGraph.graph.nodes?.length || 0}`);
console.log(`Total relationships: ${fullGraph.graph.edges?.length || 0}`);
```

## Query knowledge graph (snake\_case)

graph\_response = await graphlit.queryContentsGraph( filter=ContentFilterInput( contents=\[EntityReferenceFilterInput(id=content\_id)] ) )

print(f"Nodes: {len(graph\_response.graph.nodes or \[])}") print(f"Edges: {len(graph\_response.graph.edges or \[])}")

## Access nodes

for node in (graph\_response.graph.nodes or \[]): print(f"{node.type}: {node.name}")

## Access edges

for edge in (graph\_response.graph.edges or \[]): print(f"Relationship: {edge.from\_name} → {edge.type} → {edge.to\_name}")

````

**C#**:
```csharp
using Graphlit;

var client = new Graphlit();

// Query knowledge graph (PascalCase)
var graphResponse = await graphlit.QueryContentsGraph(new ContentFilter {
    Contents = new[] { new EntityReferenceFilter { Id = contentId } }
});

Console.WriteLine($"Nodes: {graphResponse.Graph.Nodes?.Count ?? 0}");
Console.WriteLine($"Edges: {graphResponse.Graph.Edges?.Count ?? 0}");

// Access nodes
foreach (var node in graphResponse.Graph.Nodes ?? new List<Node>())
{
    Console.WriteLine($"{node.Type}: {node.Name}");
}

// Access edges
foreach (var edge in graphResponse.Graph.Edges ?? new List<Edge>())
{
    Console.WriteLine($"{edge.From} → {edge.Type} → {edge.To}");
}
````

### Parameters

#### ContentFilter (Optional)

* **`contents`** (EntityReferenceFilter\[]): Filter by specific content
  * Query graph for specific documents
* **`collections`** (EntityReferenceFilter\[]): Filter by collection
* **`observableTypes`** (ObservableTypes\[]): Filter by entity types
  * `PERSON`, `ORGANIZATION`, `PLACE`, etc.

### Response

```typescript
{
  graph: {
    nodes: GraphNode[];  // Entities
    edges: GraphEdge[];  // Relationships
  }
}

interface GraphNode {
  id: string;              // Entity ID
  name: string;            // Entity name
  type: ObservableType;    // Entity type
  description?: string;    // Entity description
}

interface GraphEdge {
  from: string;            // Source entity ID
  to: string;              // Target entity ID
  type: string;            // Relationship type
  weight?: number;         // Relationship strength
}
```

### Developer Hints

#### Graph Must Be Built First

**Important**: Knowledge graph requires content with extraction workflow.

```typescript
// 1. Create extraction workflow
const workflow = await graphlit.createWorkflow({
  name: 'Entity Extraction',
  extraction: {
    jobs: [{
      connector: {
        type: EntityExtractionServiceTypes.ModelText,
        modelText: {
          specification: { id: extractionSpecId }
        }
      }
    }]
  }
});

// 2. Ingest with extraction
await graphlit.ingestUri(
  uri, undefined, undefined, undefined, true,
  { id: workflow.createWorkflow.id }
);

// 3. Now query graph
const graph = await graphlit.queryContentsGraph();
```

#### Filter by Content

```typescript
// Graph for specific document
const docGraph = await graphlit.queryContentsGraph({
  contents: [{ id: contentId }]
});

// Graph for collection
const collectionGraph = await graphlit.queryContentsGraph({
  collections: [{ id: collectionId }]
});

// Entire knowledge graph
const fullGraph = await graphlit.queryContentsGraph();
```

#### Analyze Relationships

```typescript
const graph = await graphlit.queryContentsGraph();

// Find most connected entities
const connectionCount = new Map<string, number>();

graph.graph.edges?.forEach(edge => {
  connectionCount.set(edge.from, (connectionCount.get(edge.from) || 0) + 1);
  connectionCount.set(edge.to, (connectionCount.get(edge.to) || 0) + 1);
});

// Sort by connections
const sorted = Array.from(connectionCount.entries())
  .sort((a, b) => b[1] - a[1])
  .slice(0, 10);

console.log('Top 10 most connected entities:');
sorted.forEach(([nodeId, count]) => {
  const node = graph.graph.nodes?.find(n => n.id === nodeId);
  console.log(`${node?.name}: ${count} connections`);
});
```

#### Visualize Graph

```typescript
// Export to visualization format (e.g., vis.js, d3.js)
function exportGraphForVisualization(graph: any) {
  const nodes = graph.graph.nodes?.map(node => ({
    id: node.id,
    label: node.name,
    title: node.description,
    group: node.type
  }));
  
  const edges = graph.graph.edges?.map(edge => ({
    from: edge.from,
    to: edge.to,
    label: edge.type,
    value: edge.weight
  }));
  
  return { nodes, edges };
}

const graph = await graphlit.queryContentsGraph();
const vizData = exportGraphForVisualization(graph);

// Use with visualization library
console.log(JSON.stringify(vizData, null, 2));
```

### Variations

#### 1. Query Full Knowledge Graph

Get entire graph:

```typescript
const graph = await graphlit.queryContentsGraph();

console.log(`Knowledge Graph:`);
console.log(`- Entities: ${graph.graph.nodes?.length || 0}`);
console.log(`- Relationships: ${graph.graph.edges?.length || 0}`);
```

#### 2. Graph for Specific Document

Single document graph:

```typescript
const docGraph = await graphlit.queryContentsGraph({
  contents: [{ id: contentId }]
});

console.log(`Document entities: ${docGraph.graph.nodes?.length || 0}`);
```

#### 3. Graph by Entity Type

Filter by entity types:

```typescript
const peopleGraph = await graphlit.queryContentsGraph({
  observableTypes: [
    ObservableTypes.Person,
    ObservableTypes.Organization
  ]
});

console.log('People and Organizations network');
```

#### 4. Collection Knowledge Graph

Graph for collection:

```typescript
const collectionGraph = await graphlit.queryContentsGraph({
  collections: [{ id: collectionId }]
});

console.log(`Collection graph:`);
console.log(`- Entities: ${collectionGraph.graph.nodes?.length || 0}`);
console.log(`- Relationships: ${collectionGraph.graph.edges?.length || 0}`);
```

#### 5. Find Entity Connections

Explore specific entity relationships:

```typescript
const graph = await graphlit.queryContentsGraph();

// Find entity by name
const targetEntity = graph.graph.nodes?.find(
  n => n.name.includes('Microsoft')
);

if (targetEntity) {
  // Find all connections
  const connections = graph.graph.edges?.filter(
    e => e.from === targetEntity.id || e.to === targetEntity.id
  );
  
  console.log(`${targetEntity.name} has ${connections?.length || 0} connections`);
  
  connections?.forEach(edge => {
    const other = graph.graph.nodes?.find(
      n => n.id === (edge.from === targetEntity.id ? edge.to : edge.from)
    );
    console.log(`- ${edge.type}: ${other?.name}`);
  });
}
```

#### 6. Graph Analytics

Analyze graph structure:

```typescript
const graph = await graphlit.queryContentsGraph();

// Count by entity type
const typeCounts = graph.graph.nodes?.reduce((acc, node) => {
  acc[node.type] = (acc[node.type] || 0) + 1;
  return acc;
}, {} as Record<string, number>);

console.log('Entity Distribution:');
Object.entries(typeCounts || {}).forEach(([type, count]) => {
  console.log(`  ${type}: ${count}`);
});

// Relationship type distribution
const edgeTypes = graph.graph.edges?.reduce((acc, edge) => {
  acc[edge.type] = (acc[edge.type] || 0) + 1;
  return acc;
}, {} as Record<string, number>);

console.log('\nRelationship Types:');
Object.entries(edgeTypes || {}).forEach(([type, count]) => {
  console.log(`  ${type}: ${count}`);
});
```

### Common Issues

**Issue**: Empty graph returned\
**Solution**: Ensure content was ingested with extraction workflow. Check entities were actually extracted.

**Issue**: No relationships/edges\
**Solution**: Relationships are automatically inferred from co-occurrence and context. More content = more relationships.

**Issue**: Graph too large to visualize\
**Solution**: Filter by specific content or collections. Use entity type filters to reduce scope.

**Issue**: Missing expected entities\
**Solution**: Check extraction workflow configuration. Try better extraction model (Claude Sonnet 3.7).

### Production Example

**Knowledge graph visualization pipeline**:

```typescript
// 1. Query knowledge graph
const graph = await graphlit.queryContentsGraph({
  collections: [{ id: collectionId }]
});

console.log('=== KNOWLEDGE GRAPH ANALYSIS ===\n');

// 2. Analyze graph structure
const nodeCount = graph.graph.nodes?.length || 0;
const edgeCount = graph.graph.edges?.length || 0;

console.log(`Total Entities: ${nodeCount}`);
console.log(`Total Relationships: ${edgeCount}`);
console.log(`Average Connections: ${(edgeCount / nodeCount * 2).toFixed(2)}\n`);

// 3. Find central entities (most connected)
const connectionCount = new Map<string, number>();

graph.graph.edges?.forEach(edge => {
  connectionCount.set(edge.from, (connectionCount.get(edge.from) || 0) + 1);
  connectionCount.set(edge.to, (connectionCount.get(edge.to) || 0) + 1);
});

const topEntities = Array.from(connectionCount.entries())
  .sort((a, b) => b[1] - a[1])
  .slice(0, 10);

console.log('Top 10 Central Entities:');
topEntities.forEach(([nodeId, count]) => {
  const node = graph.graph.nodes?.find(n => n.id === nodeId);
  console.log(`  ${count} connections: ${node?.name} (${node?.type})`);
});

// 4. Export for visualization
const vizData = {
  nodes: graph.graph.nodes?.map(node => ({
    id: node.id,
    label: node.name,
    title: node.description || node.name,
    group: node.type,
    value: connectionCount.get(node.id) || 1
  })),
  edges: graph.graph.edges?.map(edge => ({
    from: edge.from,
    to: edge.to,
    label: edge.type,
    value: edge.weight || 1
  }))
};

// Save for visualization tool
console.log('\nGraph exported for visualization');
// Use with vis.js, d3.js, Cytoscape.js, etc.
```

**Entity relationship explorer**:

```typescript
// Find relationships for specific entity
async function exploreEntityRelationships(entityName: string) {
  const graph = await graphlit.queryContentsGraph();
  
  // Find entity
  const entity = graph.graph.nodes?.find(
    n => n.name.toLowerCase().includes(entityName.toLowerCase())
  );
  
  if (!entity) {
    console.log(`Entity "${entityName}" not found`);
    return;
  }
  
  console.log(`\n=== ${entity.name} (${entity.type}) ===`);
  if (entity.description) {
    console.log(`Description: ${entity.description}`);
  }
  
  // Find all relationships
  const outgoing = graph.graph.edges?.filter(e => e.from === entity.id) || [];
  const incoming = graph.graph.edges?.filter(e => e.to === entity.id) || [];
  
  console.log(`\nOutgoing Relationships (${outgoing.length}):`);
  outgoing.forEach(edge => {
    const target = graph.graph.nodes?.find(n => n.id === edge.to);
    console.log(`  ${edge.type} → ${target?.name} (${target?.type})`);
  });
  
  console.log(`\nIncoming Relationships (${incoming.length}):`);
  incoming.forEach(edge => {
    const source = graph.graph.nodes?.find(n => n.id === edge.from);
    console.log(`  ${source?.name} (${source?.type}) → ${edge.type}`);
  });
}

// Usage
await exploreEntityRelationships('Microsoft');
await exploreEntityRelationships('John Smith');
```
