Files
semantica/cookbook/introduction/08_Your_First_Knowledge_Graph.ipynb
T

13 KiB

Open In Colab

🚀 Your First Knowledge Graph

Overview

This notebook walks you through creating your first knowledge graph from a simple document. You'll learn the complete end-to-end workflow from ingesting a file to visualizing the resulting knowledge graph — and every step consumes the real output of the step before it.

Tip

This is the perfect starting point if you are new to Semantica. No prior knowledge of knowledge graphs is required!

Documentation: API Reference

🎯 Learning Objectives

  • Understand the Workflow: Learn the File → Parse → Extract → Graph → Visualize pipeline
  • Ingest Data: Load documents using FileIngestor
  • Parse Content: Extract text using DocumentParser
  • Extract Knowledge: Identify entities and relations using NERExtractor and RelationExtractor
  • Build Graph: Construct a graph using GraphBuilder
  • Visualize: See your graph come to life with KGVisualizer

Installation

Install Semantica from PyPI:

pip install semantica
# Or with all optional dependencies:
pip install semantica[all]

🔄 Simple End-to-End Workflow

The complete workflow consists of five main steps:

  1. 📥 Ingest - Load data from files or other sources
  2. 📄 Parse - Extract and structure content from documents
  3. ⛏️ Extract - Identify entities and relationships
  4. 🕸️ Build Graph - Construct the knowledge graph
  5. 📊 Visualize - Render and analyze the graph

Each step is demonstrated in the code cells below, and each cell can be rerun on its own: the sample file is only removed by the optional cleanup cell at the very end.

Tip

Alternative: Using Semantica Framework

For a simpler, high-level approach, you can use the Semantica framework class which orchestrates all these steps:

from semantica.core import Semantica

framework = Semantica()
framework.initialize()

result = framework.build_knowledge_base(
    sources=["sample_document.txt"],
    embeddings=True,
    graph=True
)

framework.shutdown()

This notebook shows the step-by-step approach for learning. See Core Module Usage Guide for more details.


📂 Step 1: Ingest a File

In this step, we'll use FileIngestor to load a document. The ingestor supports various file formats including PDF, DOCX, TXT, and more. Writing the sample file is idempotent, so this cell can be rerun at any time.

In [ ]:
%pip install semantica

# spaCy models are distributed separately from the spaCy library. This lesson
# relies on the English model to recognize standalone places such as Cupertino.
import sys
import subprocess
import spacy

try:
    spacy.load("en_core_web_sm")
except OSError:
    subprocess.check_call([sys.executable, "-m", "spacy", "download", "en_core_web_sm"])
In [ ]:
from pathlib import Path

from semantica.ingest import FileIngestor

sample_text = """Apple Inc. is headquartered in Cupertino, California.
In 1976, Steve Jobs founded Apple Inc.
Tim Cook is the CEO of Apple Inc.
"""

sample_file = Path("sample_document.txt")
sample_file.write_text(sample_text)

print(f"File: {sample_file}")
print(f"Content length: {len(sample_text)} characters")

ingestor = FileIngestor()
file_object = ingestor.ingest_file(sample_file, read_content=True)
print(f"  File name: {file_object.name}")
print(f"  File type: {file_object.file_type}")
print(f"  Content available: {file_object.content is not None}")

📄 Step 2: Parse the Document

After ingesting the file, we need to parse it to extract the text content. DocumentParser.parse_document() returns the extracted text under the "text" key.

In [ ]:
from semantica.parse import DocumentParser

parser = DocumentParser()
parsed_document = parser.parse_document(str(sample_file))

parsed_content = parsed_document.get("text", "")
assert parsed_content.strip(), "Parsing produced no text — check the input file"

print(f"Parsed content length: {len(parsed_content)} characters")
print(f"Preview: {parsed_content[:120]}...")

⛏️ Step 3: Extract Entities and Relations

Now we'll extract entities and relations from the parsed text. NERExtractor identifies people, organizations, locations and dates; RelationExtractor finds relations between those mentions. Both operate on the parsed content from Step 2 — not on a copy of the raw string.

In [ ]:
from semantica.semantic_extract import NERExtractor, RelationExtractor

ner_extractor = NERExtractor()
relation_extractor = RelationExtractor()

mentions = ner_extractor.extract(parsed_content)
relations = relation_extractor.extract(parsed_content, mentions)

print("Entity mentions:")
for mention in mentions:
    print(f"  {mention.text!r:<13} {mention.label:<7} span=[{mention.start_char}:{mention.end_char}]")

print("\nExtracted relations:")
for rel in relations:
    print(f"  {rel.subject.text!r} --{rel.predicate}--> {rel.object.text!r}")

🕸️ Step 4: Build the Knowledge Graph

Using the extracted entities and relations, we construct a knowledge graph with GraphBuilder. Every mention gets a graph ID, and each edge is built from the actual Relation.subject / Relation.object endpoints.

Note

The graph will contain one node per mention, so Apple Inc. appears three times. Merging duplicate mentions into one canonical entity is covered in 07_Building_Knowledge_Graphs.ipynb.

In [ ]:
from semantica.kg import GraphBuilder

entities = []
span_to_id = {}
for i, mention in enumerate(mentions, 1):
    graph_id = f"e{i}"
    span_to_id[(mention.start_char, mention.end_char)] = graph_id
    entities.append({
        "id": graph_id,
        "type": mention.label,
        "name": mention.text,
        "properties": {},
    })

relationships = []
for rel in relations:
    source_id = span_to_id.get((rel.subject.start_char, rel.subject.end_char))
    target_id = span_to_id.get((rel.object.start_char, rel.object.end_char))
    if source_id is None or target_id is None:
        print(f"Skipping relation with unmapped endpoint: "
              f"{rel.subject.text!r} --{rel.predicate}--> {rel.object.text!r}")
        continue
    relationships.append({
        "source": source_id,
        "target": target_id,
        "type": rel.predicate,
        "properties": {},
    })

builder = GraphBuilder()
knowledge_graph = builder.build({"entities": entities, "relationships": relationships})

id_to_name = {entity["id"]: entity["name"] for entity in entities}

print(f"Nodes (entities): {len(knowledge_graph['entities'])}")
for entity in knowledge_graph["entities"]:
    print(f"  {entity['id']}: {entity['name']} ({entity['type']})")

print(f"\nEdges (relationships): {len(knowledge_graph['relationships'])}")
for relationship in knowledge_graph["relationships"]:
    print(f"  {id_to_name[relationship['source']]} "
          f"--{relationship['type']}--> {id_to_name[relationship['target']]}")

edges = {
    (id_to_name[r["source"]], r["type"], id_to_name[r["target"]])
    for r in knowledge_graph["relationships"]
}
assert ("Apple Inc.", "located_in", "Cupertino") in edges
assert ("Tim Cook", "works_for", "Apple Inc.") in edges

📊 Step 5: Visualize and Analyze

Finally, we render the knowledge graph with KGVisualizer and look at its structure. visualize_network() accepts the GraphBuilder result directly and can save an interactive HTML file.

In [ ]:
from semantica.visualization import KGVisualizer

visualizer = KGVisualizer()
fig = visualizer.visualize_network(
    knowledge_graph, output="html", file_path="knowledge_graph.html"
)
print("Saved interactive visualization to knowledge_graph.html")

entity_types = {}
for entity in knowledge_graph["entities"]:
    entity_types[entity["type"]] = entity_types.get(entity["type"], 0) + 1

print("\nEntities by type:")
for entity_type, count in sorted(entity_types.items()):
    print(f"  - {entity_type}: {count}")

relationship_types = {}
for relationship in knowledge_graph["relationships"]:
    relationship_types[relationship["type"]] = (
        relationship_types.get(relationship["type"], 0) + 1
    )

print("\nRelationships by type:")
for relationship_type, count in sorted(relationship_types.items()):
    print(f"  - {relationship_type}: {count}")

fig

🧹 Optional: Clean Up

Run this cell only when you are done with the notebook. Earlier cells read sample_document.txt, so they stay rerunnable until you delete it here.

In [ ]:
for path in [sample_file, Path("knowledge_graph.html")]:
    if path.exists():
        path.unlink()
        print(f"Removed {path}")

Summary

You've built your first knowledge graph, end to end:

  • FileIngestor loaded the sample document
  • DocumentParser returned its text under the "text" key
  • NERExtractor / RelationExtractor produced real mentions and relations from that text
  • GraphBuilder turned them into a graph whose edges come from the actual relation endpoints
  • KGVisualizer rendered the result as an interactive network

Next: merge duplicate mentions with EntityResolver in 07_Building_Knowledge_Graphs.ipynb, or explore graph metrics in the Graph Analytics notebook.