Skip to content

feat: Add wiki entity linking and QID lookup methods - #107

Open
th0rntwig wants to merge 2 commits into
mainfrom
feat/entity-linking
Open

feat: Add wiki entity linking and QID lookup methods#107
th0rntwig wants to merge 2 commits into
mainfrom
feat/entity-linking

Conversation

@th0rntwig

@th0rntwig th0rntwig commented Sep 3, 2026

Copy link
Copy Markdown
Member

Summary

Adds Wikidata entity linking and QID lookup to the wiki API, plus a batch variant of wiki search. Six methods on both WikiAPI and AsyncWikiAPI.

Entity linking resolves a name as it appears in text to a canonical Wikidata QID — "Apple" to Q312 rather than the fruit — so you can ground a mention before reasoning about it. QID lookup then fetches that entity's metadata directly.

New methods

Method Endpoint
search_wiki_batch(queries, ...) POST /v1/wiki/search/batch
link_entity(entity, ...) GET /v1/wiki/link-entity
link_entity_batch(entities, ...) POST /v1/wiki/link-entity/batch
get_entity(qid) GET /v1/wiki/entity/{qid}
get_entity_batch(qids) POST /v1/wiki/entity/batch

The batch forms embed all inputs in one request and run in parallel, so they are considerably cheaper than the equivalent sequence of single calls.

result = sdk.wiki.link_entity(entity="Apple", entity_type="organization")

if result.link_status == "linked":
    print(result.linked_entity.qid)  # "Q312"

Behavior worth knowing

  • Always check link_status before trusting linked_entity. Linking abstains rather than guessing: linked is a confident match, ambiguous means a different entity of the same name scored within ambiguity_margin, and no_match means nothing cleared relevance_threshold. linked_entity is None for no_match, and for ambiguous when allow_ambiguous=False.
  • A missing QID is not an error. get_entity returns found=False with a null entity rather than raising, because callers batch QIDs and need per-QID outcomes. Batch results preserve input order and include misses.
  • entity_types / entity_descriptions align positionally with entities in link_entity_batch and must match in length; use None for individual entries you don't have.
  • QIDs are percent-encoded into the path — a / in a QID would otherwise retarget a different endpoint.

WikidataMetadata

Entity metadata is a typed core (wikipedia_titles, sitelink_count, aliases, …) plus every Wikidata property the API extracts — 227 of them, each typed. The property fields fall into a handful of shapes, modelled as WikidataQidRef, WikidataQuantity, WikidataMonolingualText and WikidataCoordinate.

Almost every property is absent on any given entity — a person has no capital, a city no date_of_birth — so expect None and read defensively. Each field carries its Wikidata property id as a trailing comment, for lookup at wikidata.org/wiki/Property:<id>.

QID-valued fields list every claim, not just the current one. ceo on a company carries former officeholders alongside the incumbent:

metadata.ceo
# [
#   WikidataQidRef(qid="Q5820", label="Steve Jobs",
#                  start_time="+1997-09-16T00:00:00Z",
#                  end_time="+2011-08-24T00:00:00Z", rank="normal"),
#   WikidataQidRef(qid="Q312556", label="Tim Cook",
#                  start_time="+2011-08-24T00:00:00Z", rank="normal"),
# ]

metadata.ceo[1].label       # "Tim Cook"
metadata.ceo[1].end_time    # None — no end_time on this claim

Each entry carries qid and label plus whichever of start_time, end_time, point_in_time and rank that claim has. Most claims carry no temporal qualifier at all, so those attributes are commonly None.

Deciding which entry is current is the caller's judgement from those fields. Wikidata does not reliably mark it: rank is the authoritative signal when an editor has set it, but it is frequently left at normal for every claim, and a missing end_time does not imply currency — an announced successor who has not taken office yet also has none.

Times are ISO-ish strings; quantities are WikidataQuantity(amount, unit_qid, unit_label, …). Read unit_qid/unit_label before comparing quantities across entities — revenue in EUR and USD would otherwise be silently mixed. For social_media_followers there is one claim per account per snapshot, so check platform, account_id and point_in_time before summing.

A few fields are list-shaped but currently return a single entry (population, total_revenue, launch_date, …). They are marked [one entry] inline in the model. The list shape is held open so restoring the full history later is not a breaking change — don't read their length as a count.

The model keeps extra="allow", so a property added server-side still reaches you via model_extra before this SDK is updated to name it. The nested value models allow extras too: the API attaches per-property context keys to entries (for_work_qid on awards, character_role_qid on cast members, and others), and new ones can appear without warning.

Changes to existing API

search_wiki gains include_main_section and has_wikidata. No existing parameter or default changed, so current callers are unaffected.

Tests

tests/test_entity_linking.py45 tests; 135 pass across the suite. Covers request shapes and query serialization, QID path escaping, DTO validation and per-entity ordering, the typed property shapes, and that unknown properties and unknown qualifier keys still reach the caller.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant