Terrorist Organizations - Technical Reference¶
This page documents the technical implementation of the terrorist organizations use case.
Architecture¶
use_cases/terrorist_orgs/
├── __init__.py # Use case registration
├── data/ # FTM JSON Lines files
│ ├── us_state_terrorist_orgs.ftm.json
│ ├── gb_proscribed_orgs.ftm.json
│ └── au_listed_terrorist_orgs.ftm.json
├── ontology/
│ ├── followthemoney.ttl # FTM ontology
│ └── extensions/
│ └── custom_relations.ttl # HAS_ALIAS extension
├── evaluation_questions.json # Full evaluation set (70q)
└── evaluation_questions_curated.json # Curated set (40q)
Components¶
Parser¶
The terrorist_orgs use case reuses the FTM parser from the anticorruption use case:
# use_cases/terrorist_orgs/__init__.py
from use_cases.anticorruption.parser import FTMParser, FTMEntity
Parser = FTMParser
FTM Parser Features¶
The FTMParser class handles FollowTheMoney JSON Lines format:
class FTMParser(BaseParser):
"""Parser for FollowTheMoney JSON Lines files."""
def parse_all(self) -> Iterator[FTMEntity]:
"""Parse all .ftm.json files in data directory."""
for file in self.data_dir.glob("*.ftm.json"):
with open(file) as f:
for line in f:
entity = json.loads(line)
yield FTMEntity.from_dict(entity)
FTM Entity Structure¶
Each FTM entity has this structure:
{
"id": "NK-c6rsgFRyrcFxF2xZdx4uq4",
"schema": "Organization",
"properties": {
"name": ["Hamas"],
"alias": ["Islamic Resistance Movement", "Harakat al-Muqawama al-Islamiya"],
"topics": ["sanction", "crime.terror"],
"programId": ["US-FTO219"]
},
"referents": []
}
ID Resolution¶
FTM entities reference each other by ID. The parser resolves these to human-readable names:
# Without resolution:
"entity": "NK-c6rsgFRyrcFxF2xZdx4uq4"
# With resolution (default):
"entity": "Hamas"
Properties resolved: - entity (Sanction target) - owner, asset (Ownership) - director, organization (Directorship) - holder, person, relative, associate
Episode Builder¶
The episode builder converts FTM entities to markdown for Graphiti:
# use_cases/anticorruption/episode_builder.py
def build_ftm_episode_content(entity: FTMEntity) -> str:
"""Build markdown episode from FTM entity."""
lines = [
f"# FollowTheMoney Entity: {entity.get_name()}",
"",
"## Entity Metadata",
f"- **Schema Type**: {entity.schema}",
f"- **Status**: Target of investigation",
"",
"## Properties",
]
for prop, values in entity.properties.items():
if values:
value_str = ", ".join(str(v) for v in values)
lines.append(f"- **{prop.title()}**: {value_str}")
return "\n".join(lines)
Episode Output Example¶
# FollowTheMoney Entity: Hamas
## Entity Metadata
- **Schema Type**: Organization
- **Status**: Target of investigation
## Properties
- **Name**: Hamas
- **Alias**: Islamic Resistance Movement, Harakat al-Muqawama al-Islamiya
- **Topics**: sanction, crime.terror
- **Program Id**: US-FTO219
## Entity Context
This is an organization entity representing Hamas.
Ontology¶
The use case uses the FollowTheMoney ontology with extensions:
Base Ontology¶
followthemoney.ttl defines:
- Entity classes: Person, Organization, Company, LegalEntity, etc.
- Relationship classes: Ownership, Directorship, Membership, Sanction
- Properties: name, alias, jurisdiction, incorporationDate, etc.
HAS_ALIAS Extension¶
# ontology/extensions/custom_relations.ttl
@prefix ftm: <https://followthemoney.tech/ns#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
ftm:HAS_ALIAS a owl:ObjectProperty ;
rdfs:label "HAS_ALIAS" ;
rdfs:comment "Links an entity to an alternative name or identifier" ;
rdfs:domain ftm:Thing ;
rdfs:range ftm:Thing .
Registration¶
The use case is registered in __init__.py:
# use_cases/terrorist_orgs/__init__.py
from use_cases.anticorruption.parser import FTMParser, FTMEntity
from aletheia.core.ontology import GenericOntologyLoader
from aletheia.core.episodes import register_episode_builder
from use_cases.anticorruption.episode_builder import build_ftm_episode_content
Parser = FTMParser
Ontology = GenericOntologyLoader
DATA_DIR = "use_cases/terrorist_orgs/data"
ONTOLOGY_DIR = "use_cases/terrorist_orgs/ontology"
register_episode_builder(
"terrorist_orgs",
build_ftm_episode_content,
source_description="Multi-Authority Terrorist Organizations (US, UK, Australia)",
)
Data Pipeline¶
OpenSanctions (.ftm.json)
│
▼ [FTMParser]
FTMEntity objects
│
▼ [Episode Builder]
Markdown episodes
│
▼ [Graphiti]
Knowledge Graph
│
├──► Nodes: Organization, Sanction, PublicBody, Person
└──► Edges: SANCTION, HAS_ALIAS, RELATES_TO, MENTIONS
Graph Schema¶
Node Types¶
| Type | Count | Description |
|---|---|---|
| Organization | ~285 | Terrorist organizations |
| Sanction | ~181 | Designation records |
| PublicBody | 4 | Designating authorities |
| Person | ~5 | Named individuals |
| Address | ~7 | Associated locations |
| Episodic | ~427 | Source episodes |
Edge Types¶
| Type | Count | Description |
|---|---|---|
| MENTIONS | ~1162 | Episode → Entity |
| RELATES_TO | ~306 | General relationships |
| SANCTION | ~161 | Authority → Organization |
| HAS_ALIAS | ~155 | Organization → Alias |
Designating Authorities¶
| Authority | Program ID | Jurisdiction |
|---|---|---|
| US State Department | US-FTO219 | United States |
| UK Home Office | UK-PROSCRIBED | United Kingdom |
| Attorney-General of Australia | AU-TERROR | Australia |
| Australia Home Affairs | AU-TERROR | Australia |
Evaluation Questions¶
Question Format¶
{
"questions": [
{
"id": "q1",
"question": "What alias is used for al-Shabaab?",
"answer": "al-Hijra",
"answer_aliases": ["Al-Hijra", "al Hijra"],
"type": "alias_lookup"
}
]
}
Question Type Distribution (Curated)¶
| Type | Count | % |
|---|---|---|
| entity_existence | 9 | 22.5% |
| alias_lookup | 8 | 20% |
| entity_description | 8 | 20% |
| authority_specific | 6 | 15% |
| multi_hop | 4 | 10% |
| cross_jurisdiction | 3 | 7.5% |
| historical_name | 2 | 5% |
Configuration¶
Environment Variables¶
# Database
FALKORDB_HOST=localhost
FALKORDB_PORT=6379
# LLM
OPENAI_API_KEY=sk-...
# Embeddings (optional)
EMBEDDING_PROVIDER=local
EMBEDDING_MODEL=BAAI/bge-small-en-v1.5
Search Configuration¶
For optimal retrieval:
from graphiti_core.search.search_config import (
SearchConfig,
NodeSearchConfig,
EdgeSearchConfig,
)
config = SearchConfig(
node_config=NodeSearchConfig(
search_methods=[NodeSearchMethod.cosine_similarity, NodeSearchMethod.bfs],
reranker=NodeReranker.rrf,
bfs_max_depth=2,
),
edge_config=EdgeSearchConfig(
search_methods=[EdgeSearchMethod.cosine_similarity, EdgeSearchMethod.bfs],
reranker=EdgeReranker.rrf,
),
limit=15,
)
Extending the Use Case¶
Adding New Data Sources¶
- Download FTM data from OpenSanctions
- Place
.ftm.jsonfile indata/directory - Rebuild graph with
--reset
Adding Custom Relationships¶
- Create extension TTL file in
ontology/extensions/ - Define new ObjectProperty
- Rebuild ontology graph
- Rebuild knowledge graph
Adding Evaluation Questions¶
Add questions to JSON file:
{
"id": "q_new",
"question": "Your question?",
"answer": "Expected answer",
"type": "question_type"
}
Run evaluation to validate.