Key Concepts¶
LinkingTK models Entity Alignment, Entity Linking, Word Sense Disambiguation
and Word Sense Alignment as the same underlying problem: matching
Entity objects from one dataset to
another. Four kinds of component cooperate to do that — a Linker drives
the whole process, calling on a Blocker to narrow the search space, a
Source to reach a dataset too large to load in full, and a Matcher
to turn scored candidates into final links.
Linkers¶
A BaseLinker implements one task's
matching logic behind a single method:
def link(
self,
dataset1: list[Entity],
dataset2: list[Entity] | EntitySource,
graph: Graph = None,
blocking: BlockingStrategy = DEFAULT_BLOCKING,
) -> list[AlignmentResult]:
...
It takes two entity datasets, an optional supporting graph, and a
Blocker, and returns one
AlignmentResult per predicted
link — a source_id → target_id pair with a confidence score. Linkers
range from simple baselines
(StringSimilarityLinker)
to classical-ML classifiers
(FeatureClassifierLinker),
knowledge-graph-embedding and deep-learning methods for EA
(linkingtk.algorithms.ea), transformer-based WSD
(linkingtk.algorithms.wsd), and LLM-backed linkers and re-rankers
(LlmBaseLinker,
LlmRerankerLinker).
Internally, most linkers score candidate pairs and then hand the scores to
a Matcher to resolve into final results.
Blockers¶
A BlockingStrategy generates
candidate pairs before any scoring happens, cutting the full
dataset1 × dataset2 cross-product down to a smaller set worth comparing:
def candidate_pairs(
self, dataset1: list[Entity], dataset2: list[Entity] | EntitySource
) -> Iterable[tuple[Entity, Entity]]:
...
The default is ExactMatch, which
pairs entities sharing an identical label.
LabelOverlap and
EmbeddingSimilarityBlocker
rank candidates by a graded similarity instead of requiring an exact
match, keeping only the top few per source entity.
Evaluator.evaluate_blocking
scores a blocking pass on its own, independent of any downstream linker.
Sources¶
An EntitySource stands in for a
dataset2 too large — or already indexed elsewhere — to materialize as a
plain list[Entity]. Instead of enumerating the whole target set, a
linker or blocker queries it per mention:
def search(self, query: str, top_k: int = 10) -> list[Entity]: ...
def get(self, entity_id: str) -> Entity | None: ...
Concrete sources wrap external targets such as WordNet
(WnEntitySource), live Wikipedia
and Wikidata
(WikipediaEntitySource,
WikidataEntitySource),
and a local FAISS index
(VectorIndexEntitySource).
Not every BlockingStrategy supports an EntitySource — one that needs to
enumerate the whole target set to build an index raises TypeError
instead; ExactMatch and LabelOverlap do support it, querying
dataset2.search(...) directly.
CachingEntitySource wraps any
source to memoize search/get calls, worthwhile for HTTP-backed or
otherwise slow sources.
Matchers¶
A Matcher takes a linker's scored
candidates and resolves them into the final AlignmentResult list:
def match(
self, candidates_by_source: dict[str, list[tuple[str, float]]]
) -> list[AlignmentResult]:
...
GreedyMatcher — the default —
picks each source entity's highest-scoring candidate independently, so two
sources may end up matched to the same target.
OptimalMatcher instead finds
a single globally optimal one-to-one assignment via the Hungarian
algorithm, which can outperform greedy matching when two sources'
individually-best candidate is the same target. Linkers that produce a
scored candidate map accept a matching argument to choose between them —
e.g. StringSimilarityLinker(matching=OptimalMatcher()).
Where to go next¶
- Getting Started — install the package and run these four pieces together end-to-end.
- Examples — task-specific linkers built on these same interfaces.
- API Reference — full docs for every public class and function.