Building an investing knowledge graph, part 4: building the resolver
Building an investing knowledge graph, part 4: building the resolver Part 3 ended with a question I left open: how does the threshold actually get set, and what happens to the registry when new articles keep coming in? That's what this one covers. The cost of getting it wrong in both directions Before I touch thresholds, it's worth being specific about what failing in each direction costs. A…
Building an Investing Knowledge Graph: Part 4 - The Resolver
The fourth installment of the series on building an investing knowledge graph delves into the resolver component, which tackles the crucial task of determining whether candidate entity mentions refer to the same underlying entity. In Part 3, we left open the question of how the threshold to classify pairs as matches or splits is set, as well as what happens to the registry when new articles are added. This part will address these concerns.
Cost of Wrong Decisions
Before discussing the threshold, it's essential to understand the consequences of making the wrong decision in either direction. A false merge combines two distinct entities into a single node, potentially leading to incorrect inferences about relationships between companies. In the Samsung SDI case from Part 3, a false merge would incorrectly associate battery supply disruptions with the semiconductor business, resulting in a flawed graph.
Conversely, a false split keeps the same entity as two separate nodes, leading to a partial answer and a loss of coverage for the knowledge graph.
Resolving Pairs and the Resolver Endpoint
The resolver service is exposed through the /v1/splink-pairs endpoint, which accepts a list of candidate entity mention strings and returns a score for each pair along with a decision indicating whether the pair should be matched or split. A minimal request example looks like this:
POST /v1/splink-pairs
{
"candidates": [
"Samsung Electronics Co.",
"the largest memory chipmaker in the world",
"Samsung SDI",
"TSMC"
]
}
The response contains a score matrix for pairs that the model considers worth evaluating, not every combination, but only those above a blocking threshold that filters out obviously unrelated pairs before the full model is run. The response includes a decision (match or split) and the canonical entity ID when a match is found. If the match corresponds to a known registry entry, the alias is recorded, while a new pair triggers the addition of the pair to the evidence set for future model updates.
Growing the Registry
As the investing knowledge graph pipeline processes new articles, it extracts entity mentions and sends them through the resolver. Three outcomes are possible: a known alias, an unknown mention that matches an existing entity, or a genuinely new entity. Known aliases are quickly identified without calling the model, while unknown mentions that match existing entities are added to the registry.
Genuinely new entities are assigned a new canonical ID and accumulate evidence over time as future articles mention the same company.
As of now, the registry contains 47,853 resolved entities and 47,883 aliases. Most early entities started as single-mention nodes, but some have merged as more articles confirmed their connection. However, there are likely some nodes that should be split due to incorrect initial decisions. The threshold was initially set more aggressively, but has since been tightened.
Under the Hood: Splink
The resolver is built on the open-source probabilistic record linkage library Splink, which utilizes DuckDB as the computation backend for pair scoring. This approach handles candidate generation and blocking, filtering the space of possible pairs before running the full model. For corporate entity mentions, key features include string similarity on the canonical name, alias coverage, token overlap on co-occurring named entities within the same article, and base rate weighting.
Splink learns feature weights from a labeled set of manually verified matches and non-matches derived from the first two thousand articles. Although the training set is not large, it was sufficient to correctly weight the context features. The service was eventually wrapped into a standalone FastAPI service, allowing other components to call it over HTTP, with a shared registry across callers.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.