JobTech Taxonomy API

The JobTech Taxonomy API is a REST API for the JobTech Taxonomy Database. The JobTech Taxonomy Database contains terms or phrases used at the Swedish labour market.

Endpoints

  • GraphiQL is a query language for APIs, and a server-side runtime for executing queries.
  • Swagger UI visualize and interact with the API's resources without having any of the implementation logic in place.

Open Source

The JobTech Taxonomy API is provided under the EPL-2.0 license.

Copyright © 2024 JobTech

Overview

This is the documentation for the JobTech Taxonomy API. The purpose of the JobTech Taxonomy is to act as a common language for labour market related systems. The JobTech Taxonomy API is used to access the JobTech Taxonomy.

Contact has information on how to reach us with questions, suggestions and problems. It also contains information on where the project source code can be found.

Explore has information on entrypoints that enables an interactive exploration of the Taxonomy.

Understanding the Taxonomy contains information about what the Taxonomy is, what it contains and how it is supposed to work.

Using the Taxonomy contains information about the technical aspects of working with the Taxonomy, including some GraphQL examples.

Explore

The taxonomy can be found at https://taxonomy.api.jobtechdev.se or accessed via one of the entrypoints listed below.

The Taxonomy Atlas

The Taxonomy Atlas is a more human friendly way to take a look at what can be found in the Taxonomy.

There is an interactive visualisation that displays part of the graph behind the Taxonomy.

GraphiQL

An interactive GraphiQL entrypoint where GraphQL queries can be written and tested is available.

There is also a chapter on how to use GraphQL in this book.

REST API

There is a Swagger UI endpoint where the REST API can be tested.

Other things

For more software from the team who brought you the Taxonomy API, check out our other open software and APIs at taxonomy-dev.

Or take a look at what the other JobTechDev teams are up to on the JobTechDev GitLab instance.

Contact Information

Open Source

The JobTech Taxonomy API is an Open Source project and the source code can be found at https://gitlab.com/arbetsformedlingen/taxonomy-dev/backend/jobtech-taxonomy-api.

Reporting an issue

If you have found a problem or have an idea on how to improve the software create an issue.

JobTechDev Forum

For technical questions about the Taxonomy API contact us at https://forum.jobtechdev.se.

Specifically the Taxonomy forum section.

Mail

Questions about the content of the Taxonomy database, about Jobtech, about the API in general are best emailed to jobtechdev@arbetsformedlingen.se.

If you have questions about the implementation and have a mail account at Arbetsförmedlingen, you can send an email directly to taxonomy-dev@arbetsformedlingen.se.

Introduction

Exploring the Taxonomy via GraphQL

The best way to understand the Jobtech Taxonomy is to explore the data via the GraphQL endpoint. Here's a collection of example queries.

All Taxonomy Environments

graph BT
ON-->|substitutability|ON
ON(occupation-name) -->|broader| S4(ssyk-level-4)
S4 -->|broader| S3(ssyk-level-3)
S3 -->|broader| S2(ssyk-level-2)
S2 -->|broader| S1(ssyk-level-1)
S4-->|broader|OF(occupation-field)
OC(occupation-collection)-->|related|ON
I4(isco-level-4)-->|related|S4
K(keyword)-->|related|ON
S(skill)-->|related|I4
S-->|broader|SH(skill-headline)

M(municipality)-->|broader|REGION
COUNTRY(country)-->|broader|CONTINENT(continent)
REGION(region)-->|broader|COUNTRY
	

SNI2(sni-level-2)-->|broader|SNI1(sni-level-1)


SF4(sun-education-field-4)-->|broader|SF3(sun-education-field-3)
SF3-->|broader|SF2(sun-education-field-2)-->|broader|SF1(sun-education-field-1)

SL3(sun-education-level-3)-->|broader|SL2(sun-education-level-2)-->|broader|SL1(sun-education-level-1)

D(driving-license)-->D

ED(employment-duration)

ET(employment-type)

UF(unemployment-fund)

WT(wage-type)

L(language)
LL(language-level)

WTE(worktime-extent)

Terminology

The Taxonomy Database contains terms or phrases used at the Swedish labour market. These are called concepts in the database. Each concept has a unique concept-id, a preferred-label and a type. We aim to use the terminology of SKOS Simple Knowledge Organization System Reference by the World Wide Web Consortium.

Here's an explanation of some of the terminology:

TermDefinitionExample
ConceptA concept can be viewed as an idea or notion, a unit of thoughtData/IT
TypeThe type of a conceptOccupation field
Preferred labelThe preferred label for a conceptKey account manager
Alternative labelAn alternative name of a concept, can be displayed externallyKAM
DefinitionThe explanation of a conceptWorking with system development, programming or maintenance of systems and networks

Some concepts include extra attributes like alternative-labels and ssyk-code-2012.

The content of the Taxonomy Database is constantly improved and updated by the JobTech editorial team. New versions of the database will be released at regular intervals. However the data is immutable, none of the concepts are deleted in the Taxonomy Database. A concept that is considered outdated is attributed with a deprecated flag, but it is still available in the API from some endpoints.

Occupation-name concepts

Definition

A definition is needed here.

Description

An occupation name concept is a detailed occupational designation, tied to groups on the fourth level of both the SSYK and the ISCO structures. The ISCO connection is primarily maintained in order to ensure interoperability with the Eures portal, while the SSYK connection is used more frequently in many implementations on the labour market.

The occupation name concepts aim at representing a language used and recognized by the industries and its employers on the labour market. In order to ensure this, the team that manages them attempts to collect as much information as possible from external sources, such as industry experts, , when curating the concepts,

On alternative labels, job titles and keywords

Occupational titles can have the attribute alternative-labels. They can also have connections to other types of concepts, such as job-title and keyword.

The attribute alternative-labels is only used in cases where an obvious synonym or abbreviation for the concept exists. For example, the occupation-name concept Museichef/Museidirektör. In many cases these concepts have the different terms connected to the alternative-labels attribute separated with a "/" in their preferred-label, but not always.

Unlike alternative-labels, a job-title is an own, separate, concept that has a different scope than a occupation-name concept. A job title that is linked to a occupation-name concept should therefore not be seen as a synonym. For example, consider the term Länsmuseichef, which is connected to Museichef/Museidirektör, but due to its narrower scope is represented as a job-title instead of an alternative-label.

Concepts classified as keyword often constitute a broad concept, or domain, that a multitude of occpupation-name concepts can be linked to. For instance, see Law.

Managed by

Team Redaktionen at Jobtech, Arbetsförmedlingen.

Purpose

The occupation-name concepts at Arbetsförmedlingen have a long history. As long as some form of digital matching has been conducted, occupation-name concepts, or their previous equivalents, have been necessary. They provide a terminology that aims to reflect the language of the labour market, with more frequent update intervals than the SSYK structure. The classification can be used for job matching, creating resumes, categorizing job ads, career guidance, etc.

Concepts that are deemed outdated are given the deprecated attribute to indicate that they should no longer be used. Concepts are however never removed from the database and can always be queried through the Taxonomy API, despite of deprecation.

Governance

Updates of the occupation-name concepts are performed continuously, and may occur in each new version of the Taxonomy. Generally the updates are performed as the need arises, and may be initiated in a number of ways:

  • through user (such as employers, job seekers, or consumers of Taxonomy) feedback

  • through research (carried out by the editorial team in charge of the Taxonomy)

  • through changes in governing documents (such as for teachers and nursing assistants)

  • through systematic reviews of the whole set of concepts (such as when mapping to ESCO)

Collaborations

Above all, it is through collaboration with industry representatives that good quality in the occupation-name concepts is achieved.

A representative is often tied to an employers organisation or a union within a particular industry. It could also be someone working at university or governmental agency or another type of organisation with knowledge on a specific domain on the labour market.

Such collaborations are however not always possible. In these cases the Editorial team makes an assessment on whether a concept should be updated or created. As a basis for the assessment, job ads and other descriptive texts related to the term at hand are often consulted.

Quality level

Quality is defined here in relation to how well a concept is anchored within an organization representing the industry in which the concept is relevant. The quality-level attribute of an occupation-name concept can be expressed using three different levels:

Level 1. Includes level 3 and/or 2, and: the update is done in consultation with a national actor, such as an employer and industry organization, professional board, education board, or government authority, see the document. New concepts and relocation of existing ones in the SSYK structure are done in consultation with Statistiska Centralbyrån (SCB).

Level 2. Includes level 3 and: the update is done in consultation with an employer or a recruiter. New concepts and relocation of existing ones in the SSYK structure are done in consultation with SCB.

Level 3. The update is done as a result of own research, i.e. through consulting job ads, websites related to the current concept, etc. New concepts and relocation of existing ones in the SSYK structure are done in consultation with SCB.

The quality-levelattribute is unique for occupation-name concepts. Do note however that currently only a subset of all occupation-name concepts makes use of the attribute.

Update frequency

The occupation-name concepts are continuously updated as new versions of the Taxonomy are published, approximately once every other month.

The updates that come with a new version do not cover the entire range of concepts, but instead focus on individual concepts and additions, name changes, deprecations, or changes regarding connections to other concepts.

For detailed information on each version's changes, please consult the taxonomy-version-history repo.

Standards

SKOS

SKOS (Simple Knowledge Organization System Reference) is used to describe how a concept relates to other concepts within and outside of its own terminology:

skostaxonomy
skos:narrowernarrower
skos:broaderbroader
skos:relatedrelated
skos:exactMatchexact-match
skos:narrowMatchnarrow-match
skos:broadMatchbroad-match
skos:closeMatchclose-match

The SKOS mapping relations (relations containing "match" ) are used to represent relations to concepts within another taxonomy or terminology, e.g. ESCO-occupations.

SKOS is also used in the Taxonomy to define concepts:

skostaxonomy
skos:prefLabelpreferred-label
skos:altLabelalternative-labels
skos:hidden-labelhidden-labels

Relations to other types of concepts in the Taxonomy

An occupation-name concept may be related to a number of other concept types within the Taxonomy, such as:

concept typerelation type
job-titlerelated
keywordrelated
esco-occupationsee mapping relations
ssyk-level-4broader
isco-level-4broader
occupation-namesubstituted-by/substitutability

Constraints

  • Most occupation-name concepts lack definitions (work in progress), the definition attribute is therefore generally populated with the same term as the preferred-label
  • Not all concepts are up to date

Graph-QL examples

Below examples can be tested through our Graphi-QL GUI.

SSYK-level-4 groups with occupation-name concepts

query MyQuery {
  concepts(type: "ssyk-level-4") {
    id
    type
    preferred_label
    ssyk_code_2012
    narrower(type: "occupation-name") {
      id
      type
      preferred_label
      alternative_labels
    }
  }
}
query MyQuery {
  concepts(type: "occupation-name") {
    id
    type
    preferred_label
    alternative_labels
    related(type: ["keyword", "job-title"]) {
      id
      type
      preferred_label
    }
  }
}

Occupation-name concepts with mapped ESCO occupations

query MyQuery {
  concepts(type: "occupation-name") {
    id
    type
    preferred_label
    alternative_labels
    exact_match(type: "esco-occupation") {
      id
      type
      preferred_label
    }
    broad_match(type: "esco-occupation") {
      id
      type
      preferred_label
    }
    narrow_match(type: "esco-occupation") {
      id
      type
      preferred_label
    }
    close_match(type: "esco-occupation") {
      id
      type
      preferred_label
    }
  }
}

Occupation structure (with Arbetsförmedlingen's occupation-fields)

query MyQuery {
  concepts(type: "occupation-field") {
    id
    type
    preferred_label
    narrower(type: "ssyk-level-4") {
      id
      type
      preferred_label
      ssyk_code_2012
      narrower(type: "occupation-name") {
        id
        type
        preferred_label
        alternative_labels
      }
    }
  }
}

SSYK level 4

Definition

The SSYK structure's fourth and most detailed level.

Description

SYK level 4 groups (see SCB's documentation), play an important role in many contexts, not least within the Employment Service's handling of occupations related to forecasting, statistics and analysis. In the Taxonomy, the SSYK level 4 groups are used as hubs to which many other concepts are linked, including occupation name concepts and skills.

The SSYK structure is managed by SCB (Statistics Sweden). Concerning its fourth level, Arbetsförmedlingen, together with SCB, decided upon a slightly modified version for use primarily in matching. In this documentation, that version is called Af-SSYK. The variant is largely identical to the structure's regular fourth level, but differs in some groupings, namely managerial ones.

Note that conventionally within Arbetsförmedlingen a group belonging to the SSYK structure's fourth level is called "occupation group/yrkesgrupp" or "yrkesmall".

The latter actually refers to a collection of concepts showcasing occupation-name concepts together with skills, by using their relations to an SSYK level 4 group. Within the core operations of Arbetsförmedlingen, these templates are well established and are primarily used as a reference when working with job seekers.

All SSYK level 4 are attributed with an ssyk-code-2012, which denotes their four-digit SSYK codes. In addition, they also have a definition, definition, which was created when SSYK-2012 was developed. The attributes included in the SSYK level 4 groups generally do not change. Changes only occur in cases such as spelling errors. But changes concerning definition, label, etc., that could result in the scope or description of a SSYK level 4 group being changed, do not occur.

The following is an example on how an SSYK level 4 group can be defined:

{
  "data": {
    "concepts": [
      {
        "id": "DJh5_yyF_hEM",
        "preferred_label": "Mjukvaru- och systemutvecklare m.fl.",
        "definition": "Analyserar, designar och utvecklar IT-system eller delar av system. Utformar och utvecklar lösningar för programvara, applikationer, system och databaser.",
        "type": "ssyk-level-4",
        "ssyk_code_2012": "2512"
      }
    ]
  }
}

Relations to other concept types

SSYK level 4 concepts are related to a number of other concept types. Below is an illustration on how those relations are defined within in the Taxonomy.

graph TD;
A --narrower--> B
A --related--> C
D --narrower--> A
E --narrower--> A
A --related--> F
    A("ssyk level 4");
    B("occupation-name concept");
    C("skill");
    D("occupation-field")
    E("ssyk level 3")
    F("forecast occupation")

Occupation name concepts

An occupation-name concepts must always be linked to one (and only one) SSYK level 4 group. Given that they are more detailed than SSYK level 4 groups, it is generally the case that there are links from a SSYK level 4 group to several occupation name concepts. Connections between SSYK level 4 groups and occupation-name concepts are defined with the narrower relation.

Skills

Generally spekaing, the same principle applies to skills, but there are a number of exceptions. Most skills are linked to one or more SSYK level 4 groups, but in instances where the skills are so generally defined that they could be applicable in almost all groups, they are not linked to any. Read more about skill concepts and general competences in the documentation on skills. Skill concepts are linked to the SSYK level 4 groups with the relation type related. The reason why related is used and not narrower, as with occupation name concepts, is that a skill's relationship to a SSYK level 4 group is not as clearly defined.

Occupation fields

In addition to being the most detailed level in the SSYK structure, SSYK level 4 is part of a separate hierarchy, developed by Arbetsförmedlingen, where occupation field constitutes the highest level and occupation-name the lowest, see example below.

graph TD;
A --narrower--> B
B --narrower--> C
    subgraph "occupation field"
    A("Data/IT");
    end
    subgraph "ssyk level 4 group"
    B("2512 - Mjukvaru- och systemuvecklare m.fl.");
    end
    subgraph "occupation name concept"
    C("Backend-utvecklare");
    end

Forecast occupations

Please note that forecast occupations are being replaced with barometer occupations.

Another example of concepts associated with SSYK level 4 groups is Forecast Occupations, which can consist of one or more such connections.

Governance

Given that they are static and owned by SCB, the SSYK level 4 concepts do not require much management from the Arbetsförmedlingen. However, the connections to the concepts are continuously updated. For example, when a new occupation-name concept or skill is created, or when any of them changes SSYK level 4 group..

GraphQL examples

The queries below can be tested through our GraphiQL interface.

Get all SSYK level 4 groups

query MyQuery {
  concepts(type: "ssyk-level-4") {
    id
    preferred_label
    type
    definition
    ssyk_code_2012
  }
}
query MyQuery {
  concepts(type: "ssyk-level-4") {
    id
    preferred_label
    type
    definition
    ssyk_code_2012
    narrower(type: "occupation-name") {
      id
      preferred_label
      type
    }
  }
query MyQuery {
  concepts(type: "ssyk-level-4") {
    id
    preferred_label
    type
    definition
    ssyk_code_2012
    related(type: "occupation-name") {
      id
      preferred_label
      type
    }
  }
}

SSYK

Definition

SSYK, or Standard for Swedish Occupational Classification, is a hierarchical structure used to describe the Swedish labor market. SSYK is owned by Statistics Sweden (SCB) but the Swedish Public Employment Service (Arbetsförmedlingen) uses a variant with a number of modifications at the fourth level. More information about the variant can be found in the section on Af-SSYK below.

Description

SSYK is a directory and classification of occupations. SSYK aims to make visible occupations that exist in the labor market. At the same time, SSYK serves as a structure for international reporting of data related to the Swedish labor market.

The current version of SSYK, SSYK-2012, is developed by, among others, the SCB (Statistics Sweden) and Arbetsförmedlingen, based on the international precursor ISCO (International Standard Classification of Occupations).

In the SSYK structure, occupations have been divided and grouped into four levels. The most comprehensive level consists of ten broad occupational areas. Each occupational area forms a hierarchy that becomes more occupational-specific the further down you go. The diagrams below explain both how the SSYK structure is generally constructed, and what a selected part of it might look like.

graph TD;
    A(occupation field/one digit level) -->|narrower| B(main group/two digit level)
    B -->|narrower| C(occupation group/three digit level)
    C -->|narrower| D(unit group/four digit level)

graph TD;
    A(2 - Yrken med krav på fördjupad högskolekompetens) -->|narrower| B(26 - Yrken med krav på fördjupad högskolekompetens inom juridik, kultur och socialt arbete m.m.)
    B -->|narrower| C(261 - Jurister)
    C -->|narrower| D(2611 - Advokater)

Af-SSYK

Arbetsförmedlingen employs a modified version of the SSYK structure's fourth level, information about it can be found here.

SSYK level 4

Information on how Arbetsförmedlingen uses the fourth level of SSYK can be found here.

Regarding naming conventions

Often, and not least within Arbetsförmedlingen, the term "ccupation group" is used to refer to what is referred to in the SSYK structure as "unit group". In the Taxonomy, these groupings are called SSYK level 4 (or ssyk-level-4 in the database and API). In the same spirit, the term "occupation field" is used to refer to collections of SSYK level 4 groups, when in the SSYK structure the same label is used to designate the top node in the hiearchy.

Af-SSYK

Definition

Arbetsförmedlingen's adaptation of the fourth level of the SSYK structure.

Description

Af-SSYK is a modified version of the fourth level of the official edition of the SSYK structure.

The modifications consist of merging and removal of a number of SSYK level 4 groups. Affected groups, and how they can be translated between Af-SSYK and the official version of SSYK level 4, can be found here.

All SSYK level 4 groups concerning managerial occupations have been affected in such a way that the representations of levels of management from the official version of SSYK is not used in Af-SSYK. For each managerial occupation, there are two such levels. Broadly speaking, the first level (codes ending with 1, e.g. 1311) denotes middle managers (manager over managers), whereas the second one (codes ending with 2, e.g. 1312) denotes managers at a more operative level. In Af-SSYK, these two codes are merged into one: 1310. The same patterns applies to all managerial codes (with SSYK codes starting with 1).

The four groups regarding undersköterskor in the official SSYK codes have been translated to two in Af-SSYK (only 5321 and 5323 are used).

The groups referring to local farm manufacturing and elected officials, 7619 and 4430, are not used in Af-SSYK. Even though the codes can describe occupations, the decision was made to exclude them as the objects classified within them are not subject to recruitment.

Purpose

Af-SSYK was developed at the same time as SSYK-2012. The reasoning behind Af-SSYK was that certain SSYK level 4 groups were not considered relevant in a matching context. This applies, for example, to all manager codes, where the distinction of management level is not used.

Uppdateringsförfarande

The Af-SSYK is updated in conjunction with the update of the official SSYK structure (currently SSYK-2012).

Job titles

Definition

A title that refers to a specific job.

Description

A job title can be seen as a variation of an occupation-name (LINK) concept. The job title is usually more specific, sometimes even specific to a certain organization, and not as widely accepted (in terms of the broader labour market) as the occupation-name concept to which it is linked. A job title should not be seen as a direct synonym for an occupation-name concept (for synonymization, the attribute alternative-labels is used instead).

The example below shows how a job title relates to an occupation-name concept (LINK).

graph LR;
B --related--> A
    subgraph "occupation-name concept" 
    A("Journalist")
    end
    subgraph "job title"
    B("Allmänreporter");
    end

A job title is always connected to an occupation-name (LINK) concept with the relation-type (LINK) related.

Purpose

The job titles attempts to broaden the language used to represent occupations in the Taxonomy. The idea is to capture variations of a concept and link the job title to it. In this way, a basis is created for building end-user services that allows for a broader spectrum of words that can guide the user towards a fitting occupation-name (link) concept.

Governance

A majority of the job titles originates in the synonym dictionary used by JobAd enrichments. Terms from the dictionary have been evaluated before being created and tied to an occupation-name (LINK) concept in the Taxonomy.

In order to assess whether a certain concept is more suitable as a job title or as an occupation-name (LINK) concept, consideration is taken of how widely accepted the concept appears to be by looking at various sources on the internet and job advertisements. The level of detail of the concept can also be helpful in the assessment, as a concept that is too specific is often more suitable as a job title.

Connections to the synonym dictionary

Please note that there is no actual reference/link between the job title in the Taxonomy and the concept in the synonym dictionary. The job titles taken from the synonym list have simply been created in the Taxonomy as their own, independent concepts, and it is only through their preferred-label that they can be matched to corresponding concepts in the synonym list. However, it is not guaranteed that the preferred-label is exactly the same as the corresponding designation in the synonym list, as there are cases where the title needed to be adapted to the naming conventions in the Taxonomy.

Job titles and keywords

Just like job titles, keywords are terms that can be used to refer to occupation-name (LINK) concepts. There are however a number of characteristics that separates them:

  • keywords can be connected to multiple types of concepts, wheras job titles can only be connected to occupation-name concepts (LINK).
  • job titles are much more specific than keywords
  • a job title usually only refers to one occupation-name concept (LINK), whereas a keywords is usually related to a number of concepts

Below are a number of examples depicting the differences.

Regarding job titles:

Regarding keywords:

Please note that only a limited number of relationships are shown above, for example Avlopp and Järnväg are related to many more occupation name concepts (LINK).

GraphQL examples

The queries below can be tested through our GraphiQL interface.

All occupation-name concepts with relations to job titles

query MyQuery {
  concepts(type: "occupation-name") {
    id
    preferred_label
    type
    related (type: "job-title"){
      id 
      preferred_label
      type
    }
  }
}


Keyword

Definition

A broad concept, often referring to a larger, not necessarily occupation-specific, phenomenon or area.

Description

Keywords are terms used to refer to other concepts. A keyword can describe, for example, an area or a phenomenon that may be related to one or more occupation name concepts. Search terms are often broad, with connections to many other concepts. An example is the concept of Juridik, which is connected to a large number of concepts within the field of law. Search terms can also be linked to employment types and educational fields (within SUN2020). The example below shows how a search term relates to different occupation name concepts.

Below is an example on how a keyword related to a number of different occupation name concepts.

graph LR;
B --related--> A
B --related--> C
B --related--> D
    subgraph "occupation-name concept" 
    A("Ambulanssjuksköterska")
    C(Ambulanssjukvårdare)
    D("Sjuktransportör")
    end
    subgraph "keyword"
    B("Ambulans");
    end

Keywords are always connected to occupation name concepts with the relation type related.

Keywords and job titles

Just like keywords, job titles are terms that can be used to refer to occupation name concepts. There are however a number of characteristics that separates them:

  • keywords can be connected to multiple types of concepts, wheras job titles can only be connected to occupation-name concepts (LINK).
  • job titles are much more specific than keywords
  • a job titles usually only refers to one occupation-name concept (LINK), whereas a keyword is usually related to a number of concepts

Below are a number of examples depicting the differences.

Regarding job titles:

Regarding keywords:

Please note that only a limited number of relationships are shown above, for example Avlopp and Järnväg are related to many more occupation name concepts (LINK).

Graph-QL examples

The queries below can be tested through our GraphiQL interface.

All occupation-name concepts with relations to keywords

query MyQuery {
  concepts(type: "occupation-name") {
    id
    preferred_label
    type
    related (type: "keyword"){
      id 
      preferred_label
      type
    }
  }
}

Occupation field

Definition

Broad groupings of SSYK-4 groups, according to likeness of work being done within in them, e.g. "construction", "Data/IT", "health services", etc.

Description

An occupation field, for example Data/IT, contains a number of thematically related SSYK-4 groups. Among the SSYK-4 groups within Data/IT, you will find, among others, 2511 - System Analysts and IT Architects, etc. and 2512 - Software and System Developers, etc.

The fields are primarily used to help users navigate the occupational structure in order to find an occupation-name concept when, for instance, creating a job posting or a CV.

The example below describes the relationship between occupation field, SSYK-4 group, and occupation-name concept.

graph TD;
A --narrower--> B
B --narrower--> C

    subgraph "occupation field"
    A("Data/IT");
    end
    subgraph "ssyk 4 group"
    B("2512 - Mjukvaru- och systemuvecklare m.fl.");
    end
    subgraph "occupation-name concept"
    C("Backend-utvecklare");
    end

Governance

The occupational fields are owned by Arbetsförmedlingen, with the Jobtech unit responsible for managing them.

Updates

The occupational fields are rarely updated. However, there are instances where an SSYK level 4 group changes its affiliation with an occupational field, but only if the original affiliation has been deemed wholly incorrect. Such scenarios are usually initiated by feedback from users of services or applications integrated with Taxonomy.

In cases where there is equally good argumentation that the original affiliation is correct, the SSYK-4 group is not moved.

Restrictions

The restriction of only being able to link an SSYK level 4 group to one occupation field can lead to users having difficulty finding occupation-name concepts that thematically could belong to two (or more) occupational fields. For example, the occupation-name concept CIO, which through its connection to the SSYK level 4 group 1310 - IT Managers inherits the affiliation to the occupational area Chefer och verksamhetsledare. Even though this connection is correct, the occupation-name concept could just as well be considered to belong to the occupational field Data/IT. However, for all SSYK level 4 groups that describe managerial professions, the connection to the occupational area Chefer och verksamhetsledare applies.

GraphQL examples

The queries below can be tested through our GraphiQL interface.

Get the complete occupational structure

query MyQuery {
  concepts(type: "occupation-field") {
    id
    preferred_label
    definition
    type
    narrower(type: "ssyk-level-4") {
      id
      preferred_label
      type
      ssyk_code_2012
      narrower(type: "occupation-name") {
        id
        preferred_label
        type
      }
    }
  }
}

Skills

Definition

A broadly used concept referring to a requirement to carry out a specific job.

definition needs reviewing

Description

Presently, skills in the Taxonomy are vaguely defined and lack the structure necessary to adequately categorize them. A skill in the Taxonomy can be a number of things. For instance, it can come in the form of a formal qualification (such as a diploma), a technology (such as Bluetooth) a software (such as Ms Excel), or formalized prerequisites to carry out a specific job such as licences and certificates, among other things.

A skill is generally expressed using a single term, but can it also be complemented with another term following a comma with the intention of narrowing or specifying its scope (see, for instance, Grafikprogram, undervisning). Other variants of expressing skills within the Taxonomy also exist. Notably they do not follow any formalised pattern such as the descriptive statements of learning outcomes.

The skill tree consists of two levels of concepts, in which concepts on the more detailed level are attributed with the type skill, each with a broader relation to a skill-headline concept:

graph TD;

B --narrower--> A
    A("skill-headline")
    B("skill"); 

Furthermore, skills are generally related to one or more SSYK level 4 groups. These connections should be seen as suggestions on skills that could be combined with occupation-name concepts within the group, without declaring their importance for them (for instance the strength of the relationship). Skills belonging to Yrkesövergripande kompetenser however are not related to any SSYK level 4 groups, since they are intended to be applicable in all of them.

Note that work is being done to connect skills to occupation-name concepts as well.

Skills within the taxonomy are not connected to the skills or traits listed in jobad-enrichment's synonym dictionary.

Below is an exhaustive look at how the Taxonomy skills relate to other concept types:

graph LR;

B --broader--> A
B --exact-match--> C
B --narrow-match--> C
B --broad-match--> C
B --close-match--> C
B --related --> E
B --related-->D
    A("skill-headline")
    B("skill"); 
    C("esco-skill")
    D("ssyk-level-4")
    E("skill-collection")

Connections to ESCO

According to the EURES regulation, each memberstate within the union is tasked to map its national classifications of skills and occupations to ESCO. In the Taxonomy, each mapping is represented as one of the following relations (also, see graph above):

Some skills, however, are not mapped but are instead tagged with the attribute no-esco-relation, meaning no relation to any concept in the external classification could be found. For instance, the skill Villkorad läkemedelsanvändning:

{
    "id": "RBpz_aSt_vhm",
    "preferred_label": "Villkorad läkemedelsanvändning",
    "type": "skill",
    "no_esco_relation": true,
    "uri": "http://data.jobtechdev.se/taxonomy/concept/RBpz_aSt_vhm"
}

Visit the chapter ESCO-skills for more information.

A note on skills in job ads

In job ads, Taxonomy skills are accepted but used very sparsely. This is due to a lack of support for skills in the service providing an integrated solution for recruiters to send their ads to Arbetsförmedlingen. This solution answers for the vast majority of ads.

Notes on the future of skills in the Taxonomy

Please note that:

  • the skill structure is subject to change in the future
  • work is being done to connect skills to occupation-name concepts

As of now, no timeframe has been established for carrying out the changes listed above.

GraphQL examples

The queries below can be tested through our GraphiQL interface.

Get skill structure

query MyQuery {
  concepts(type: "skill-headline") {
    id
    preferred_label
    type
    narrower(type: "skill") {
      id
      preferred_label
      type
    }
  }
}
query MyQuery {
  concepts(type: "ssyk-level-4") {
    id
    preferred_label
    type
    ssyk_code_2012
    related(type: "skill") {
      id
      preferred_label
      type
    }
  }
}

Get skill mappings to ESCO

query MyQuery {
  concepts(type: "skill") {
    id
    preferred_label
    type
    no_esco_relation
    exact_match(type: "esco-skill") {
      id
      preferred_label
      type
      esco_uri
    }
    broad_match(type: "esco-skill") {
      id
      preferred_label
      type
      esco_uri
    }
    narrow_match(type: "esco-skill") {
      id
      preferred_label
      type
      esco_uri
    }
    close_match(type: "esco-skill") {
      id
      preferred_label
      type
      esco_uri
    }
  }
}

Generic skills

Definition

Generic skill should be understood as skill that can be applied throughout the labor market and is based on an individual's psychological functioning. It is about action potential in the form of desirable behavior at work and not about characteristics or how someone "is" privately.

Description

The generic skills terminology is the result of a project carried out by Arbetsförmedlingen. For more information, please consult the project's report. This report serves as the main documentation for this terminology and should be read before making use of the terminology.

Below we will touch briefly upon how generic skills are represented in the Taxonomy.

Generic skills in the Taxonomy

The generic skills structure is represented in the Taxonomy as follows:

graph TD;
A --narrower--> B
B --narrower--> C

    A(skill-group)
    B(generic-skill-group)
    C(generic-skill)

Each skill description is found through the definition attribute, and additional labels to the most detailed concepts are found through alternative_labels.

Presently, the structure stands isolated from other concepts within the Taxonomy, meaning there are no relations to other concept types such as skills or SSYK level 4 groups.

GraphQL examples

The queries below can be tested through our GraphiQL interface.

Get generic skill structure

query MyQuery {
  concepts(type: "skill-group") {
    id
    preferred_label
    definition
    type
    narrower(type: "generic-skill-group") {
      id
      preferred_label
      definition
      type
      narrower(type: "generic-skill") {
        id
        preferred_label
        alternative_labels
        definition
        type
      }
    }
  }
}

ESCO-skills

Definition

According to the ESCO definition, ESCO applies the same definition of "skill" as the European Qualifications Framework (EQF). According to this, "skill" means the ability to apply knowledge and use know-how to complete tasks and solve problems.

Description

ESCO is a common EU classification of occupations and skills, akin to Jobtech Taxonomy. The concepts in ESCO are translated into all official EU languages, aswell as some additional ones such as Arabic, and serve as a hub for interoperability between classifications on a national and European level.

The member states of the EU are bound by the Eures Directive to either create mappings between ESCO and their national occupational and skill structures, or to fully implement ESCO. The main purpose with the mapping is to enrich CVs and job ads sent to EURES with references (URIs) to the concepts in ESCO to which mappings from a national skill or occupation used in the CV or job ad has been created. In Sweden, we chose to map occupation name concepts and skills to corresponding concept types in ESCO. The mappings between the concept structures are made available via Jobtech Taxonomy. Member states' mapping tables are published on the ESCO website.

Skills in ESCO distinguish between concepts related to skills and concepts related to knowledge. The skills are partly based on O*Net and the Canadian skills and knowledge glossary and are attributed with a "closeness indicator", either essential or optional, in relation to ESCO occupations to which they are deemed to be connected.

When comparing the skill concepts classified within the Taxonomy with ESCOs classification, it is apparent that ESCO represent skills at a more detailed level while skills in the Taxonomy are fewer and generally broader.

Concepts in ESCO are identified using persistent URIs, for example: http://data.europa.eu/esco/skill/1605025e-a179-421f-8f35-5b07d182a6b2.

ESCO-skills in the Taxonomy

The Taxonomy represents all ESCO skills as their own concepts. Mappings to the Taxonomy skills are represented as mapping relations according to SKOS. URIs to the ESCO concepts are found through the esco-uri attribute.

The example below shows what such a concept might look like in the Taxonomy. Note that there is an additional attribute to represent URIs (uri). This attribute can be used by external sources to reference concepts within the Taxonomy.

{
    "id": "oFJV_raT_EUx",
    "preferred_label": "webbanalys",
    "type": "esco-skill"
    "esco_uri": "http://data.europa.eu/esco/skill/1605025e-a179-421f-8f35-5b07d182a6b2",
    "uri": "http://data.jobtechdev.se/taxonomy/concept/oFJV_raT_EUx",
}

Although ESCO skills are incorporated in the Taxonomy, the ESCO skill structure (hierachical levels above) is not.

Mappings

The different types of mapping relations can be found in the relations chapter. An ESCO skill can be mapped towards one or more Taxonomy skill concepts, and vice versa.

In ESCO, there are nearly 14000 skills, while the number of skill concepts in the Taxonomy is around 6000. Since the ESCO skills are also more detailed, a majority of the mappings uses the broad-match relation, i.e., the Taxonomy skill is broader than the ESCO skill.

In the following example, however, the inverse is true. Here, the ESCO skill webbanalys has been mapped to the skills Konverteringsoptimering and Google Analytics using the narrow-match relation, implying that the Taxonomy skill concepts are more detailed.

graph TD;
    A(webbanalys) -->|narrow-match| B(Google Analytics)
    A -->|narrow-match| C(Konverteringsoptimering)

Managing the mappings

The mapping has been carried out, and is managed, by the editorial team at the Jobtech Unit within Arbetsförmedlingen.

Due to the fact that all skills need to be mapped to one or more ESCO skills, new mappings are constantly being added as new skills emerge or become deprecated. Therefore, it is to be expected that each new Taxonomy version will involve some changes in regards to the mappings to some, usually a lesser, extent.

The mappings are determined through manual analysis and with adherance to the ESCO's instructions.

ESCO-skills without mappings

For certain ESCO skills, the assessment has been that mapping to one or more competency concepts has not been possible. In addition to these concepts not having any mapping relationships, they have a special attribute, no-esco-relation, to more easily distinguish them from the mapped concepts. See, for instance, the concept utvärdera sin egen miljöpåverkan.

{
    "id": "FcHd_Pat_syt",
    "preferred_label": "utvärdera sin egen miljöpåverkan",
    "esco_uri": "http://data.europa.eu/esco/skill/2aaad52d-599e-4e77-a681-bbc236825821",
    "uri": "http://data.jobtechdev.se/taxonomy/concept/FcHd_Pat_syt",
    "type": "esco-skill",
    "no_esco_relation": true
}

ESCO versions

With each release of a new ESCO version, the upcoming Taxonomy version is updated with any changes to the ESCO skills.

Presently, however, ESCO versions are not explicitly represented in the Taxonomy.

The mapping subsytem can however be used to target specific ESCO versions.

GraphQL examples

The queries below can be tested through our GraphiQL interface.

Get all skill mappings

query MyQuery {
  concepts(type: "skill") {
    id
    preferred_label
    uri
    type
    broad_match (type: "esco-skill"){
      id
      preferred_label
      esco_uri
      type
    }
    narrow_match (type: "esco-skill"){
      id
      preferred_label
      esco_uri
      type
    }
    exact_match (type: "esco-skill"){
      id
      preferred_label
      esco_uri
      type
    }
    close_match (type: "esco-skill"){
      id
      preferred_label
      esco_uri
      type
    }
  }
}

ESCO-occupations

Definition

Please consult the ESCO definition.

Description

ESCO is a common EU classification of occupations and skills, akin to Jobtech Taxonomy. The concepts in ESCO are translated into all official EU languages, aswell as some additional ones such as Arabic, and serve as a hub for interoperability between classifications on a national and European level.

The member states of the EU are bound by the Eures Directive to either create mappings between ESCO and their national occupational and skill structures, or to fully implement ESCO. The main purpose with the mapping is to enrich CVs and job ads sent to EURES with references (URIs) to the concepts in ESCO to which mappings from a national skill or occupation used in the CV or job ad has been created. In Sweden, we chose to map occupation name concepts and skills to corresponding concept types in ESCO. The mappings between the concept structures are made available via Jobtech Taxonomy. Member states' mapping tables are published on the ESCO website.

Occupations in ESCO are structured according to ISCO (International Standard Classification of Occupations), the international standard for classifying occupations. Occupation-name concepts in the Swedish Public Employment Service's classification are structured according to SSYK (Swedish standard for occupational classification), which is based on ISCO.

Concepts in ESCO are identified using persistent URIs, for example: http://data.europa.eu/esco/skill/1605025e-a179-421f-8f35-5b07d182a6b2.

ESCO-occupations in the Taxonomy

The Taxonomy represents all ESCO occupations as their own concepts. Mappings to the Taxonomy occupations are represented as mapping relations according to SKOS. URIs to the ESCO concepts are found through the esco-uri attribute.

The example below shows what such a concept might look like in the Taxonomy. Note that there is an additional attribute to represent URIs (uri). This attribute can be used by external sources to reference concepts within the Taxonomy.

{
    "id": "v2kx_tST_Zy2",
    "preferred_label": "kemist",
    "type": "esco-occupation",
    "esco_uri": "http://data.europa.eu/esco/occupation/0d93706d-32fd-4de3-aa08-be1003e325da",
    "uri": "http://data.jobtechdev.se/taxonomy/concept/v2kx_tST_Zy2"
}

Mappings

The different types of mapping relations can be found in the relations chapter. An ESCO occupation can be mapped towards one or more Taxonomy occupation-name concepts, and vice versa.

The example below shows the ESCO occupation kemist and some of its mappings to occupation-name concepts.

graph TD;
    A(kemist) -->|narrow-match| B(Materialkemist)
    A(kemist) -->|narrow-match| C(Organisk kemist)
    A -->|exact-match| D(Kemist)

Managing the mappings

The mapping has been carried out, and is managed, by the editorial team at the Jobtech Unit within Arbetsförmedlingen.

Due to the fact that all occupation-name concepts need to be mapped to one or more ESCO occupations, new mappings are constantly being added as new occupation-name concepts emerge or become deprecated. Therefore, it is to be expected that each new Taxonomy version will involve some changes in regards to the mappings to some, usually a lesser, extent.

The mappings are determined through manual analysis and with adherance to the ESCO's instructions.

ESCO versions

With each release of a new ESCO version, the upcoming Taxonomy version is updated with any changes to the ESCO skills.

Presently, however, ESCO versions are not explicitly represented in the Taxonomy.

The mapping subsytem can however be used to target specific ESCO versions.

GraphQL examples

The queries below can be tested through our GraphiQL interface.

Get all occupation mappings

query MyQuery {
  concepts(type: "occupation-name") {
    id
    preferred_label
    uri
    type
    broad_match (type: "esco-occupation"){
      id
      preferred_label
      esco_uri
      type
    }
    narrow_match (type: "esco-occupation"){
      id
      preferred_label
      esco_uri
      type
    }
    exact_match (type: "esco-occupation"){
      id
      preferred_label
      esco_uri
      type
    }
    close_match (type: "esco-occupation"){
      id
      preferred_label
      esco_uri
      type
    }
  }
}

Skill collection

Definition

A skill collection is a specific categorization of skills, independent from the skill structure.

Description

Skill collections are created to address the need for categorizations of skills beyond the groupings that already exist in the skill structure. They enable flexibility in terms of non-hierarchical categorizations of the skills within the Taxonomy.

A skill collection is represented as its own concept in the Taxonomy, see for example Kompetensbegrepp med grön koppling, but can also be seen as a kind of metadata for the skills that are linked to the collection.

Skill collections based on ESCO

The editorial team at JobTech, within the Swedish Public Employment Service, has conducted a mapping of ESCO's green and digital skills against the skills in the Taxonomy. The mapping has been done according to ESCO's method description. The work has primarily been conducted manually, with some AI-generated suggestions for relevant mappings. The process was such that based on the descriptions available for ESCO's skill concepts, assessments were made regarding suitable mappings to the Taxonomy skills.

To map concepts in national classifications against concepts in ESCO, mapping relations are used to describe how well the meanings of the concepts correspond. The four distinct relations express when a concept (1) is broader, (2) is more narrow, (3) is an exact match (4) is a close match. Some examples of relations based on the mapping of green ESCO skills:

The first row in the table above reads as follows: for the skill Berggrundsgeologi there is a relation to the more general/broader ESCO skill geologi. The definition of the ESCO skill is therefore broader than the meaning of the Taxonomy skill. The reverse relationship also applies between the concepts, that is, the definition of the skill Berggrundsgeologi is narrower than the definition of the ESCO skill geologi.

For Avfallsteknik, there is a relation to the more specialized/narrower ESCO skill utveckla förfaranden för avfallshantering. Thus, the definition of the ESCO skill is narrower than the definition of the Taxonomy skill.

For Miljökonsekvensanalys, there is a relation to the corresponding ESCO skill bedöma miljöpåverkan. The concepts are expressed differently but are considered to have the same meaning.

Jordbruksturism, is closely matched to the ESCO skill tillhandahålla tjänster inom landsbygdsturism. It is assessed that there are parts of the definition of each concept that correspond to each other, such as certain tasks, but also parts that do not correspond.

From the mapping, it is apparent that it is common for several ESCO skills to be mapped against one or more broader Taxonomy skills. An example of this is the Taxonomy skill Avfallsteknik, which is mapped towards twenty different ESCO skills. This is an expected result since there is a relatively large difference in detail level between Taxonomy skills and ESCO skills.

The collections

The skill collections based on ESCO are as follows:

Skills related to the skill collection Kompetenser med grön koppling or Kompetenser med digital koppling are mapped to one, or several, ESCO skills that have been classified as either green or digital.

In the example below, the skill Miljökonsekvensanalys illustrates how the mapping (exact-match) to a green ESCO skill, in this case bedöma miljöpåverkan, results in the skill being linked to the skill collection Kompetenser med grön koppling. The exact same principle applies to the skill collection Kompetenser med digital koppling.

graph LR;
B --related--> A
B --exact-match--> C
C --related--> D
    subgraph "skill-collection" 
    A("Kompetenser med grön koppling")
    end
    subgraph "skill"
    B("Miljökonsekvensanalys");
    end
    subgraph "esco-skill"
    C("bedöma miljöpåverkan");
    end
    subgraph "esco-skill-collection"
    D("Gröna ESCO-kompetenser");
    end

GraphQL examples

Below examples can be tested through our Graphi-QL GUI.

Get all skill collections

query MyQuery {
  concepts(version: "next", type: "skill-collection") {
    id
    preferred_label
    definition
    type
  }
}

Get all skills with green mappings

We base the query on yXbD_NTH_ijE, which is the concept-id for the skill collection Kompetenser med grön koppling, and query for all skills that have a related relation to the collection.

query MyQuery {
  concepts(id: "yXbD_NTH_ijE") {
    id
    preferred_label
    type
    related(type: "skill"){
      id
      preferred_label
      type
    }
  }
}

Get all skills with digital mappings

We base the query on 4Jty_HpK_a3Q, which is the concept-id for the skill collection Kompetenser med digital koppling, and query for all skills that have a related relation to the collection.

query MyQuery {
  concepts(id: "4Jty_HpK_a3Q") {
    id
    preferred_label
    type
    related(type: "skill"){
      id
      preferred_label
      type
    }
  }
}

Relations

Definition

Types of relations found between concepts within the Taxonomy.

Description

Relations in the Taxonomy database are expressed as edges between different concepts. Essentially, the various relation types are based on SKOS and inherit the properties described there. Local relation types have also been defined as needed.

Relation types

A complete list of existing types of relations can be found through the Taxonomy API.

Please note that some relation types are not included in the list from the Taxonomy API. Relation types that are inverses of each other are not explicitly expressed in the Taxonomy database. For example, broader is used but not narrower. However, if a broader relationship exists from concept A to concept B, then the narrower relationship is implicitly present between concept B and concept A.

In the example below, the relationship between the occupation name concept Dancer and the SSYK-4 group Choreographers and dancers has been defined as broader.

graph TB;
    subgraph "explicit relation" 
    A --broader--> B
    A("Dansare (occupation-name concept)")
    B("Koreografer och dansare (ssyk-level-4 concept)");
    end

Since narrower acts as an inverse of broader, such a relation is present implicitly from the other direction.

graph TB;
    subgraph "implicit relation" 
    B --narrower--> A
    A("Dansare (occupation-name concept)")
    B("Koreografer och dansare (ssyk-level-4 concept)");
    end 

When using the Taxonomy API, both relation types are valid, see:


query MyQuery {
  concepts(id: "euJP_wxo_skF") {
    id
    preferred_label
    type
    broader (id: "gmRr_7tt_eHj") {
      id
      preferred_label
      type
    }
  }
}

and:


query MyQuery {
  concepts(id: "gmRr_7tt_eHj") {
    id
    preferred_label
    type
    narrower (id: "euJP_wxo_skF") {
      id
      preferred_label
      type
    }
  }
}

SKOS

A majority of the relation types in the Taxonomy have their origin in SKOS. The properties of the relationship types, as defined in SKOS, also apply in the Taxonomy. See links in the table below for more information.

taxonomyskos
broaderskos:broader
narrowerskos:narrower
relatedskos:related
exact-matchskos:exactMatch
broad-matchskos:broadMatch
close-matchskos:closeMatch
narrow-matchskos:narrowMatch

Mapping relations

The mapping relations referenced in SKOS are used to define relations between classifications:

taxonomyskos
exact-matchskos:exactMatch
broad-matchskos:broadMatch
close-matchskos:closeMatch
narrow-matchskos:narrowMatch

The mapping relations are primarily found between concepts in the Taxonomy and ESCO (e.g. between skills and ESCO skills).

Other relation types

Additionally, there are a number of relation types that are specific to the Taxonomy. These are listed below.

substitutability

The substitutability relation can be expressed between two occupation-name concepts, and can be of either high or low. The levels are set in the substitutability-percentage attribute, where low corresponds to 25 and high to 75.

A high substitutability-percentage indicates a high degree of similarity in work tasks carried out in the two occupation-name concepts. In terms of recruitment, the two concepts may be deemed as close to, albeit not fully, interchangable.

A low substitutability-percentage indicates some degree of similarity in work tasks carried out in the two occupation-name concepts. In terms of recrutiment, some education or training may be needed in order to bridge the gap between the two concepts.

A substitutability relation should be seen as an indication that there are apparent similarities between two occupation-name concepts. The relation set is, however, neither exact nor all-encompassing. The relations should be viewed as common sense-classification, as they do not rely on an actual classification of work tasks. A relation might be created as a result from a discussion with a stakeholder/industry expert or through researching sources describing the two occupation-name concepts at hand.

Substitutability is an example of a non-symmetric type of relationship. This means that a relation from occupation-name A to occupation-name B does not imply a relation from occupation-name B to occupation-name A, i.e., the reverse. This may seem illogical considering that the relation is based on a similarity in work tasks between two occupation-name concepts. This is because the relations are derived from a recruitment perspective, where the reasoning has been that the substituted occupation-name-concept (in relation to the occupation-name-concept that an employer specifies in an ad) to a high or some degree could potentially be suitable for the advertised position. In a digital matching context, it then becomes possible to broaden the pool of job seekers considered for the advertised position. The idea is perhaps more easily illustrated with an example.

In the case of Läkemedelskonsulent and Läkare, there is a substitutability relation (low) from Läkare to Läkemedelskonsulent, but not the other way around. The assessment has been that some of the knowledge that a Läkare possesses can be transferred to the context in which a Läkemedelskonsulent finds carries out their work, and that when recruiting a Läkemedelskonsulent, it could be possible to broaden the search to include job seekers registered as Läkare.

The same reasoning cannot be applied the other way around however, since we cannot assume that the Läkemedelskonsulent has a medical licence.

possible-combinations

Relations labeled possible-combinations are used solely to show possible combinations of education level (sun-education-level-2) and education field (sun-education-field-3) concepts, primarily when registering a job seeker's highest education, but also for representing educational requirements in job ads.

The relations are based on mappings, provided by SCB (Statistics Sweden) between the two SUN structures (field and education), and are based on information about how actual educations are coded.

If no relation exists between a sun-education-level-2 and sun-education-field-3 concept, combining the two is not possible.

unlikely-combinations

Relations labeled as unlikely-combinations are used solely to show possible combinations of education level (sun-education-level-2) and education field (sun-education-field-3) concepts, primarily when registering a job seeker's highest education, but also for representing educational requirements in job ads.

The relations are based on mappings, provided by SCB (Statistics Sweden) between the two SUN structures (field and education), and are based on information about how actual educations are coded.

A combination that is unlikely means that there are educations coded with it, albeit very few. The idea of representing this information in the Taxonomy is so that users can build interface solutions that inform the end user (for example, the job seeker) that the chosen combination should only be used in special cases.

On relations and deprecation

Presently, there is no support for deprecation in regards to relations. This means that a removed relation cannot be traced (other than in logs) in versions after the removal occurred.

When a concept is deprecated, we make sure that its relations are not removed so that when interacting with the Taxonomy, it should be possible to look up a deprecated concept and see how it previously related to other concepts.

Swedish Standard Classification of Education (SUN)

Definition

Hierarchical nomenclature describing education in terms of educational level and educational field.

Description

Svensk utbildningsklassifkation (SUN) is used for classifying education. SUN provides the conditions for producing comparable statistics and analysis of population, education and the Swedish education system, both nationally and internationally. SUN consists of two classifications: one describing education level and another describing education field.

SUN in the Taxonomy

There are two versions of the SUN structures implemented in the Taxonomy. In version 1, SUN2000 is still used. The new classification, SUN2020, is present in versions after it

Looking at SUN2020, the two structures are represented with the type(s) sun-education-level-{n} and sun-education-field-{n}, nbeing a variable expressing a number from 1 to 3 for education levels and 1 to 4 for education fields. The number signifies a hierachical level. For instance, concepts with the type sun-education-field-1 are found on the least detailed level of the education field structure.

Each concept is attributed with a statistically significant SUN code. The name of this attribute differs between concepts in the two structures. Concepts in the level structure carry the SUN code in the sun-education-level-code-2020 attribute and concepts in the field structure in the sun-education-field-code-2020 attribute.

The hierarchical relations within the structures are expressed with broader (or, inversely, narrower) relations.

See GraphQL examples for examples on how to query the Taxonomy for SUN concepts.

Keywords

A list of keywords, provided and maintained by SCB, tied to educational fields at their most detailed level has been implemented in the Taxonomy.

These concepts can be utilized for helping end users find suitable sun-education-field-4 concepts.

See for instance the following example, in which the string "kostvetenskap" is supplied as input.

query MyQuery {
  concepts(type: "keyword", preferred_label_contains: "kostvetenskap") {
    id
    preferred_label
    type
    related (type: "sun-education-field-4"){
      id
      preferred_label
      type
      sun_education_field_code_2020
    }
  }
}

To which, presently (version 22), the response will look like this:

{
  "data": {
    "concepts": [
      {
        "id": "qptt_gUa_Ln9",
        "preferred_label": "Kostvetenskap",
        "type": "keyword",
        "related": [
          {
            "id": "zFUS_WCq_uHh",
            "preferred_label": "Biokemi, toxikologi, farmakologi och nutrition",
            "type": "sun-education-field-4",
            "sun_education_field_code_2020": "421b"
          }
        ]
      }
    ]
  }
}

Special relations

To describe the feasability of combining a sun-education-level-2 concept and a sun-education-field-3concept, two special relation types have been created. You can read more on them in the following chapters:

All relations included, the SUN structures, can be illustrated as follows:

graph LR;

A --broader--> B
B --broader--> C

    A("sun-education-level-3");
    B("sun-education-level-2");
    C("sun-education-level-1");

D --broader--> E
E --broader--> F
F --broader--> G

    D("sun-eduation-field-4")
    E("sun-eduation-field-3")
    F("sun-eduation-field-2")
    G("sun-eduation-field-1")

    H("keyword")

B --possible-combinations--> E
B --unlikely-combinations--> E
H <--related--> D

Governance

SUN is managed by Statistics Sweden (SCB). The implementation at Arbetsförmedlingen is handled by the editorial team at Jobtech.

GraphQL examples

Below examples can be tested through our Graphi-QL GUI.

Get entire SUN level structure

query MyQuery {
  concepts(type: "sun-education-level-1") {
    id
    preferred_label
    type
    sun_education_level_code_2020
    narrower(type: "sun-education-level-2") {
      id
      preferred_label
      type
      sun_education_level_code_2020
      narrower(type: "sun-education-level-3") {
        id
        preferred_label
        type
        sun_education_level_code_2020
      }
    }
  }
}

Get SUN level structure with SUN field combinations

query MyQuery {
  concepts(type: "sun-education-level-1") {
    id
    preferred_label
    type
    sun_education_level_code_2020
    narrower(type: "sun-education-level-2") {
      id
      preferred_label
      type
      sun_education_level_code_2020
      possible_combinations(type: "sun-education-field-3") {
        id
        preferred_label
        type
        sun_education_field_code_2020
      }
      unlikely_combinations(type: "sun-education-field-3") {
        id
        preferred_label
        type
        sun_education_field_code_2020
      }
      narrower(type: "sun-education-level-3") {
        id
        preferred_label
        type
        sun_education_level_code_2020
      }
    }
  }
}

Get SUN field structure with keywords

query MyQuery {
  concepts(type: "sun-education-field-1") {
    id
    preferred_label
    type
    sun_education_field_code_2020
    narrower(type: "sun-education-field-2") {
      id
      preferred_label
      type
      sun_education_field_code_2020
      narrower(type: "sun-education-field-3") {
        id
        preferred_label
        type
        sun_education_field_code_2020
        narrower(type: "sun-education-field-4") {
          id
          preferred_label
          type
          sun_education_field_code_2020
          related(type: "keyword") {
            id
            preferred_label
            type
          }
        }
      }
    }
  }
}

Swedish Standard Industrial Classification (SNI)

Definition

Standard för svensk näringsgrensindelning, SNI, is primarily a statistical standard used to classify units such as companies and workplaces based on their economic activities. The standard is based on the international precursor NACE.

Description

The SNI classification contains concepts representing divisions of industries on a five level hierarchy. This taxonomy follows the SCB documentation.

Se below graph on how the structure is represented in the Taxonomy.

graph TD;
A --narrower--> B
B --narrower--> C
C --narrower--> D
D --narrower--> E
    A(sni level 1)
    B(sni level 2)
    C(sni level 3)
    D(sni level 4)
    E(sni level 5)

Governance

The structure is owned an managed by Statistiska centralbyrån (SCB). Arbetsförmedlingen uses it as-is, with no modifications.

GraphQL examples

The queries below can be tested through our GraphiQL interface.

Get SNI structure

query MyQuery {
  concepts(type: "sni-level-1") {
    id
    preferred_label
    definition
    sni_level_code_2007
    uri
    narrower (type: "sni-level-2"){
      id
      preferred_label
      definition
      sni_level_code_2007
      uri
      narrower(type: "sni-level-3") {
        id
        preferred_label
        definition
        sni_level_code_2007
        uri
        narrower(type: "sni-level-4") {
          id
          preferred_label
          definition
          sni_level_code_2007
          uri
          narrower(type: "sni-level-5") {
            id
            preferred_label
            definition
            sni_level_code_2007
            uri
          }
        }
      }
    }
  }
}

Language

Definition

Languages classified within the Taxonomy, in accordance with ISO 639-2 and partly ISO 639-3.

Description

The language taxonomy lists natural languages like Engelska and Nederländska.

The language taxonomy is primarily based on ISO 639-2 (for which it should have full coverage), and uses the terms translated into Swedish by SIS. Where certain needs have been identified there are languages from the ISO 639-3 series present as well. These are included to be able to distinguish between certain dialects, primarily for using interpretation services.

Note, however, that the full ISO 639-3 classification has not been implemented in the Taxonomy.

A language within the Taxonomy can have a number of attributes, representing ISO-specific codes as well as URIs to open language repositories such as ISO and Glottolog.

There are three attributes denoting ISO codes: iso_639_1_2002, iso_639_2_1998 and iso_639_3_2007. These codes pertains to the version of the standard in which they are present.

For instance, the Kurdish language Kurmanji is only present in ISO 639-3, and is therefore only attributed with a iso_639_3_2007 code:

{
    "id": "nTYu_SG6_CNa",
    "preferred_label": "Kurdiska - Kurmanji",
    "definition": "Kurmanji",
    "uri": "http://data.jobtechdev.se/taxonomy/concept/nTYu_SG6_CNa",
    "iso_uri": "https://iso639-3.sil.org/code/kmr",
    "glottolog_uri": "https://glottolog.org/resource/languoid/id/nort2641",
    "iso_639_1_2002": null,
    "iso_639_2_1998": null,
    "iso_639_3_2007": "KMR"
}

Afrikaans is present in both ISO 639-1 and ISO 639-2 and is thus attributed with codes from both series.

{
    "id": "vitY_dty_VbD",
    "preferred_label": "Afrikaans",
    "definition": "Afrikaans",
    "uri": "http://data.jobtechdev.se/taxonomy/concept/vitY_dty_VbD",
    "iso_uri": "https://iso639-3.sil.org/code/afr",
    "glottolog_uri": "https://glottolog.org/resource/languoid/id/afri1274",
    "iso_639_1_2002": "AF",
    "iso_639_2_1998": "AFR",
    "iso_639_3_2007": null
}

The language Bemba is present in ISO 639-2 but not in ISO 639-1:

{
    "id": "nc4p_BwA_2HH",
    "preferred_label": "Bemba",
    "definition": "Bemba",
    "uri": "http://data.jobtechdev.se/taxonomy/concept/nc4p_BwA_2HH",
    "iso_uri": "https://iso639-3.sil.org/code/bem",
    "glottolog_uri": "https://glottolog.org/resource/languoid/id/bemb1257",
    "iso_639_1_2002": null,
    "iso_639_2_1998": "BEM",
    "iso_639_3_2007": null
}

If the ISO 639-3 code is identical to the ISO 639-2 code, only the latter is present. Maybe we should look into amending this.

Regarding dialects

The Taxonomy does not distinguish between language and dialect. Language concepts are represented as a flat structure, attributed with the type language, see GraphQL example below.

Interpreter languages

Please consult the language collection chapter for information on interpreter languages.

Governance

The languages are managed by the editorial team at the Jobtech unit within Arbetsförmedlingen.

Languages classified in ISO 639-3 may be added when specific needs arise.

GraphQL examples

The queries below can be tested through our GraphiQL interface.

Get all languages

query MyQuery {
  concepts(type: "language") {
    id
    preferred_label
    definition
    uri
    iso_uri
    glottolog_uri
    iso_639_1_2002
    iso_639_2_1998
    iso_639_3_2007
  }
}

Language collections

Definition

Collections of languages, developed for a specific purpose.

Description

The language collections are developed and managed by the editorial team at the Jobtech unit at Arbetsförmedlingen.

A language collection is represented in the Taxonomy as a concept relating to a number of language concepts.

Interpreter language

The Interpreter language collection is a collection of languages that the Arbetsföremdlingen can order interpretation for, and contains a subset of all languages in Taxonomy.

The collection is developed by Arbetsförmedlingen, together with an organisation delivering interpretation services.

Governance

The list of interpretation languages may be updated if an agreement is made with the interpretation providers contracted to Arbetsförmedlingen about adding additional languages.

GraphQL examples

The queries below can be tested through our GraphiQL interface.

Get all language collections

query MyQuery {
  concepts(type: "language-collection") {
    id
    preferred_label
    definition
    type
  }
}

Get interpreter languages with metadata

query MyQuery {
  concepts(id: "ngh6_UjL_9bg") {
    id
    preferred_label
    definition
    type
    narrower {
      id
      preferred_label
      definition
      type
      glottolog_uri
      iso_uri
      wikidata_uri
      iso_639_1_2002
      iso_639_2_1998
      iso_639_3_2007
    }
  }
}

Barometer occupations

Definition

A barometer occupation is a collection of occupation-name concepts used for aggregating data for labour market information, such as prognosis and regional assessments of the current situation for a specific occupational cluster.

Description

The Swedish Public Employment Service has changed the method for making occupational forecasts. The new method provides assessments of current job opportunities and the recruitment situation within occupations, both at the regional and national level. In addition to a current assessment, there is also a forecast of how the demand for labor within each barometer occupation is expected to develop over a five-year period.

A barometer occupation is tied to one or more occupation-name concepts, often within a single SSYK level 4 group. There are however cases in which a barometer occupation is tied to occupation-name concepts belonging to different SSYK level 4 groups.

graph LR;
B --related--> A
    A("occupation-name")
    B("barometer-occupation");
    

The composition of a barometer occupation can change over time, with new occupation-name concepts being added or deprecated. New barometer occupations may also be added.

The dataset

The dataset concerning the barometer occupations is useful for all organizations that offer services in career and educational guidance and want to help their target groups make well-informed decisions. Actors who want deeper insights into the labor market also benefit from the dataset.

Before using the dataset, please consult the following documents:

Governance

The barometer occupations, together with the dataset, are managed by the Analytics Department at Arbetsförmedlingen.

GraphQL examples

The queries below can be tested through our GraphiQL interface.

query q {
  concepts(type: "barometer-occupation") {
    id
    preferred_label
    related(type: "occupation-name") {
      id
      preferred_label
      type
    }
  }
}

Prognosyrken

Please note that forecast occupations have, since April 2024, been replaced. The new occupations used for forecasting are called barometer occupations.

Definition

A forecast occupation describes the competitive position of one or more combined SSYK level 4 groups in the labor market.

Description

A forecast occupation is tied to one or more SSYK level 4 groups in the Taxonomy with the related relation. A forecast occupation is never directed at a lower level in the SSYK structure.

Governance

The forecast occupations are managed by the Analytics Department at Arbetsförmedlingen.

Updates

The composition of a forecast occupation can change over time, with new SSYK level 4 groups being added or removed from it. New forecast occupations may also be added.

GraphQL examples

The queries below can be tested through our GraphiQL interface.

Get all forecast occupations

query MyQuery {
  concepts(type: "forecast-occupation") {
    id
    preferred_label
    type
    related(type: "ssyk-level-4") {
      id
      preferred_label
      type
      ssyk_code_2012
    }
  }
}

Work descriptions

Definition

Concepts that describe conditions at a workplace or the nature of a job, usually in terms of working environment.

Description

The work descriptions are managed by Arbetsförmedlingen. The descriptions consist of concepts that are categorized under a number of classifications.

The concepts are intended to be used, among other things, to describe workplaces or as a complement to a occupation-name concept, for example when describing a previous employment in a CV.

To the greatest extent possible, the concepts follow language that has already been defined by trusted sources, for example through legislative texts (see employment type) or by Arbetsmiljöverket (Swedish Work Environment Authority) (see workplace environment).

Employment duration

Employment-duration denotes the length of an advertised employment. For instance, Tills vidare and 3 månader - upp till 6 månader.

These concepts can be found primarily in job ads.

Workplace environment

The term workplace environment refers to workplace specific descriptions regarding the work environment or a workplace's conditions. For example, if it involves beredskapstjänst or höghöjdsarbete.

Worktime extent

Worktime extent, describes the amount of time a specific job offers, either full-time or part-time.

These concepts are mainly used in job advertisements.

Wage type

Wage type refers to the type of wage on offer for a specific job, for instance rörlig ackords- eller provisionslön.

These concepts are mainly used in job advertisements.

Employment type

Employment type, refers to concepts that have been defined as types of employment in the Lagen om anställningsskydd (LAS), for example Tillsvidareanställning.

These concepts are mainly used in job advertisements.

Self employment type

Self-employment type refers to concepts that can be used to describe such employments that cannot be defined formally as employment types. For example, Franchisetagare.

Occupation experience year

Occupation-experience-year describes a job seeker's experience (in time) in conjunction with a specific occupation-name concept. For instance, 2-4 års erfarenhet or Ingen erfarenhet.

These concepts primarily occurs in descriptions of a job seeker's qualifications, for example in CVs.

Employment variety

Employment variety acts as a top node for both employment-type and self-employment-type concepts, and may refer to either, forming a two level hierarchy.

GraphQL examples

The queries below can be tested through our GraphiQL interface.

Get all employment varieties

query MyQuery {
  concepts(type: "employment-variety") {
    id
    preferred_label
    definition
    type
    narrower {
      id
      preferred_label
      definition
      type
    }
  }
}

Geography

Definition

Geographical Areas classified within the Taxonomy.

Description

The database contains a four-level taxonomy of geographical areas. Like the occupation and skill taxonomy, the concepts are related to each other in a hierarchical structure:

graph TD;
A --narrower--> B
B --narrower--> C
C --narrower--> D
    A("continent")
    B("country")
    C("region")
    D(municipality)

Continents

The top geographic type lists all continents in the world, including Antarctica. The taxonomy is based on the UN standard for continents. Classified with this type, there is also the concept Hela världen (this concept pragmatically targets some use case within Arbetsförmedlingen).

Countries

The second type in this taxonomy contains all countries, according to ISO standard for countries. Each country in this level has a parent continent in the top level.

Regions

The third type is simply called region and contains all regions within the EU with a “NUTS code” (See Eurostat for information about NUTS). In Sweden the regions correspond to “län”. Every region is mapped to a specific parent country in the second level in the taxonomy.

Please note that there are two versions of the NUTS level three attribute within the Taxonomy: nuts_level_3_code_2013 and nuts_level_3_code_2021. Here, the latter one is recommended since some regions have been updated since the previous version.

Municipalities

The fourth type of the geographic areas contains the Swedish municipalities. Each municipality is mapped to a specific parent region in the above level.

Note that this level is not applicable on areas outside of Sweden.

Regarding Swedish areas

When querying for regions and municipalities in Sweden, the concept-id for Sweden, i46j_HmG_v64, needs to be specified at the top level. From there, you can make use of the geographical hierarchy to include the related regions and municipalities. See the GraphQL-example below.

Please note that there are two attributes concerning region specific codes for these regions: nuts_level_3_code_2021, adhering to the EU-standard and national_nuts_level_3_code_2019, specifying the Swedish "länskod". The Swedish "kommunkod" is found through the lau_2_code_2015 attribute.

GraphQL examples

The queries below can be tested through our GraphiQL interface.

Get all continents and countries

query MyQuery {
  concepts(type: "continent") {
    id
    preferred_label
    definition
    type
    narrower (type: "country"){
      id
      preferred_label
      type
      iso_3166_1_alpha_2_2013
      iso_3166_1_alpha_3_2013
    }
  }
}

Get all EU-regions

query MyQuery {
  concepts(id: "HstV_nCB_W2i") {
    id
    preferred_label
    definition
    type
    narrower (type: "country"){
      id
      preferred_label
      type
      iso_3166_1_alpha_2_2013
      iso_3166_1_alpha_3_2013
    }
  }
}

Get all Swedish municipalities

query MyQuery {
  concepts(id: "i46j_HmG_v64") {
    id
    preferred_label
    definition
    type
    iso_3166_1_alpha_2_2013
    iso_3166_1_alpha_3_2013
    narrower (type: "region"){
      id
      preferred_label
      type
      nuts_level_3_code_2021
      national_nuts_level_3_code_2019
      narrower(type: "municipality") {
        id
        preferred_label
        type
        lau_2_code_2015
      }
    }
  }
}

Driving Licence

Definition

Swedish driving licences in accordance with Transportstyrelsen and EU.

Description

This single type schema contains driving license categories in Sweden, according to EU standard, and the description and limitation of each license.

Implicit licences

All but the “lowest” ranked license also contain relations to the licenses that are implicit within that level. The A2 licence, for instance, is implicitly related to AM and A1. These are lower level licenses for scooters that you are automatically allowed to drive if you carry the A2 license. See theGraphQL-example on how to query these relations.

GraphQL examples

The queries below can be tested through our GraphiQL interface.

Get driving licences

query MyQuery {
  concepts(type: "driving-licence") {
    id
    preferred_label
    short_description
    driving_licence_code_2013
    definition
    type
  }
}

Get implicit driving licences

query MyQuery {
  concepts(type: "driving-licence") {
    id
    preferred_label
    short_description
    driving_licence_code_2013
    definition
    type
    narrower {
      id
      preferred_label
      short_description
      driving_licence_code_2013
      definition
      type
    }
  }
}

Versions

Definition

Publically avaliable instances of the Taxonomy.

Description

Versions in the Taxonomy are expressed as integers, starting at 1. For current Taxonomy version, see Querying Taxonomy versions below.

Versions are not tied to certain types of changes. Any change, such as the adding and deprecating of concepts, as well as updating of labels and relations, etc., may occur in each new version: all versions are "major" in this sense.

For a comprehensive look at changes that have occurred in each previous Taxonomy version, see the taxonomy version history repo.

New versions of the Taxonomy are published roughly every third month, but with no set frequency.

Querying Taxonomy versions

A list containing all published Taxonomy versions can be found through:

curl -X 'GET' \
  'https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/versions' \
  -H 'accept: application/json'

Or simply:

https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/versions

The last item in the list is the most recently published version.

A Taxonomy query can be parameterized with a specific version if needed, for instance:

query MyQuery {
  concepts(type: "occupation-name", version: 2) {
    id
    preferred_label
    type
  }
}

When the version parameter is omitted, the response defaults to the one most recently published.

Scenarios

Definition

Identified events related to the management of concepts, that may be of interest to consumers of Taxonomy.

Description

Each new version of the Taxonomy consists of changes regarding concepts and their relations. Below, a number of such changes are accounted for. The list is not exhaustive but accounts for such scenarios that have been frequently asked about.

Deprecation

A concept attributed as deprecated signifies it as being outdated and that we advise against using it. Often such a concept is related to another concept of the same type through the replaced-by relation. This relation acts as a recommendation to use that concept instead.

Concepts that are deprecated are never removed from the database and can be retrieved from the Taxonomy-API if needed.

Note that queries to the Taxonomy does not include deprecated concepts per default. For the inclusion of such concepts, the include_deprecated parameter must be set to true when querying the API.

Replaced by

In various applications within Arbetsförmedlingen, there have long been an embedded logic regarding deprecated concepts. For instance, if an occupation-name concept becomes deprecated with a replaced-by reference, the concept that the reference points to is automatically used instead of the deprecated one.

The replaced-by reference may only point to one other concept, primarily with regard to the paragraph above.

Occupation-name concepts

An occupation-name concept becomes depreacted with a replaced-by reference

There are several situations that can lead to a concept becoming deprecated and replaced by a new or another already existing concept. For example, it could be that a new concept with a broader scope replaces the previous concept.

In the example below, the concept Dansare, show has been deprecated and replaced by the broader concept Dansare:

Example: deprecated with replaced-by:

graph LR;
    A --replaced-by--> B
    subgraph "new concept" 
        B(Dansare);
        end
    subgraph "deprecated concept" 
        A("Dansare, show")
        end

Through Graph-ql, you can get the concepts through the following query:

query MyQuery {
  concepts(include_deprecated: true, id: "saUi_aP6_zhU") {
    id
    preferred_label
    type
    replaced_by {
      id
      preferred_label
      type
    }
  }
}

When the labels for two or more concepts have been deemed to represent the same concept, the concepts can be merged. In the example below, Familjepedagog has been merged into one concept together with Familjebehandlare.

Example: deprecated with replaced-by:

graph LR;
    A --replaced-by--> B
    subgraph "new concept" 
        B(Familjebehandlare/Familjepedagog);
        end
    subgraph "deprecated concept" 
        A("Familepedagog")
        end

Through Graph-ql, you can get the concepts through the following query:

query MyQuery {
  concepts(include_deprecated: true, id: "TChs_6ci_gJQ") {
    id
    preferred_label
    type
    replaced_by {
      id
      preferred_label
      type
    }
  }
}


Occupation-name concept is deprecated without reference

There are cases where occupation-name concepts are marked as deprecated without being referred to another concept. Primarily, this occurs when a single concept needs to be split into two or more distinct ones. Since the replaced-by reference is restricted to only one other concept, no such reference is made when it can potentially be pointed at multiple.

Example: deprecated with no replaced-by reference:

graph TD;
    subgraph "new concepts" 
        B(Kock, storhushåll);
        C(Kock, a la carte)
        end
    subgraph "deprecated concepts" 
        A("Kock")
        end

Occupation-name concept changes SSYK level 4 group

Each occupation-name concept is related to one (and only one) SSYK-4 group. In instances where an occupation-name concept is deemed to be related to the wrong SSYK-4 group, it can be moved to a more suitable one. In the example below, the job title Assistant University Lecturer has been moved from the SSYK-4 group Biträdande universitetslektor to Verkställande direktörer m.fl. The job title was likely mistakenly read as "principal" instead of "lecturer".

See the following query in Graph-ql:

query MyQuery {
  concepts(version: "1", include_deprecated: true, id: "dvXH_mwD_9KU") {
    id
    preferred_label
    type
    broader(type: "ssyk-level-4") {
      id
      preferred_label
      ssyk_code_2012
      type
    }
  }
}

In version 1 of the Taxonomy, the response is:

{
  "data": {
    "concepts": [
      {
        "id": "dvXH_mwD_9KU",
        "preferred_label": "Biträdande universitetslektor",
        "type": "occupation-name",
        "broader": [
          {
            "id": "3i4a_Ufc_qpp",
            "preferred_label": "Verkställande direktörer m.fl.",
            "ssyk_code_2012": "1120",
            "type": "ssyk-level-4"
          }
        ]
      }
    ]
  }
}

Whereas versions 2 and later returns the following:

{
  "data": {
    "concepts": [
      {
        "id": "dvXH_mwD_9KU",
        "preferred_label": "Biträdande universitetslektor/Biträdande högskolelektor",
        "type": "occupation-name",
        "broader": [
          {
            "id": "cYCo_PxY_zQd",
            "preferred_label": "Universitets- och högskolelektorer",
            "ssyk_code_2012": "2312",
            "type": "ssyk-level-4"
          }
        ]
      }
    ]
  }
}

Occupation-name concept changes its preferred-label

If a concept's preferred-label changes in such a way that it implies a change in the concept's meaning, it should instead be made deprecated with a reference to a new concept with the new preferred-label. For instance in the case of misspellings or changes of cosmetic nature, an update of a concept's preferred-label may be warranted.

Design principles

The Jobtech Taxonomy database never deletes any data. Internally it just adds all changes to the database as an ever increasing event log. Concepts that shouldn't be used anymore gets flagged with a deprecated flag and will not be exposed via the API unless specifically asked for. The API allows it's consumers to choose what version of the database they want to retrieve data from which allows the consumers to become eventually consistent, instead of forcing a big bang of the usage.

Example of changes endpoint

[  
  {
    "taxonomy/event-type": "CREATED",
    "taxonomy/new-concept": {
      "taxonomy/definition": "Big data analyst/Stordata-analytiker",
      "taxonomy/preferred-label": "Big data analyst/Stordata-analytiker",
      "taxonomy/id": "Ggze_QQS_jZi",
      "taxonomy/type": "occupation-name"
    },
    "taxonomy/version": 2
  },
  {
    "taxonomy/event-type": "DEPRECATED",
    "taxonomy/latest-version-of-concept": {
      "taxonomy/id": "3vQv_E4Q_wjK",
      "taxonomy/type": "occupation-name",
      "taxonomy/definition": "Trafikpedagog",
      "taxonomy/preferred-label": "Trafikpedagog"
    },
    "taxonomy/version": 2
  }
]

Architectural overview

Architectural overview

Systems overview

Systems overview

Mappings - Currently 78% LIES!

Problem

In several use cases a user want to be able to query for a concept in the JobTech Taxonomy and receive a record or ID corresponding to some external data collection or structure.

Currently the JobTech Taxonomy have some support for this, but not in a generalised way that allows versioned mappings. The workaround for this is to add fields with versioned names. But this makes it hard to describe how the fields are related and each new version requires a new field.

To be able to represent generalised mappings in a datalog database system.

Reasoning

The mapping is separated into a mapping description and a collection of edges that defines the mapping.

Mapping Description

A mapping is represented by a mapping entity with the required :mapping.mapping/type attribute set to the keyword :mapping. Future work may define further keywords that may be used to represent different kind of mappings.

Additional optional attributes for a mapping entity are:

  • family (i.e. "EURES") Describing that the mapping belongs to a related collection of mappings.
  • name (i.e. "ESCO") Describing that the mapping is a specific type of mapping.
  • version (i.e. "1.0.9") For mappings that may change over versions.
  • description (i.e. "Some informative text.") For the API to present to users.
  • url (i.e. "https://example.com") A link to further information.
  • testing (i.e. "alpha") If the mapping is not yet finalised.
  • bi-directional (i.e. false) If the mapping is not trivially reversible.

Other mathematical properties of the mapping could be added. Such as if it is a total mapping of every entity in the JobTech Taxonomy or not, how it behaves together with other mappings and similar.

The only required property of the mapping entity is that it has an entity ID. The rest are arbitrary and depend on the use case. The mapping should however have a type attribute that designates it as a mapping.

This type may be implemented as a concept-type if this can be done without affecting the semantics of the concept entity. It could also be implemented as a new attribute signalling that it is separate from the core JobTech Taxonomy data.

Mapping Edges

Every edge in the mapping is defined by an edge entity. An edge entity has a collection of mapping entities under which it is valid. It also has a source and a target attribute that references entities in the database. Where the source is mapped to target according to descriptions in the mapping entity.

An edge entity can be valid under multiple mapping entities.

Usage

First create a mapping entity for the collection that is to be mapped. Then, for each source entity that needs to be mapped add an edge entity and a target entity. An alternative is to update valid existing edges.

To find the desired mapping target for a given concept a query would first find the entity ID of the mapping, then query for edges from the concepts entity id that are valid under that mapping.

Schema

The following schema covers the functionality of the mapping subsystem.

Mappings

The mapping definitions must contain :mapping.mapping/type. The other attributes are optional.

[{:db/ident :mapping.mapping/type
  :db/doc "Indicates that the entity is a mapping description and gives it a type."
  :db/valueType :db.type/keyword
  :db/cardinality :db.cardinality/one}
 {:db/ident :mapping.mapping/organisation
  :db/doc "The organisation providing the target mapping."
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/one}
 {:db/ident :mapping.mapping/family
  :db/doc "The family of mappings this mapping belongs to."
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/one}
 {:db/ident :mapping.mapping/name
  :db/doc "The name of this mapping."
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/one}
 {:db/ident :mapping.mapping/uri
  :db/doc "A link to a description of the mapping."
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/one}
 {:db/ident :mapping.mapping/description
  :db/doc "A description of the mapping."
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/one}
 {:db/ident :mapping.mapping/version
  :db/doc "The verison of a mapping."
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/one}
 {:db/ident :mapping.mapping/taxonomy-version
  :db/doc "The Taxonomy verison of a specific mapping."
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/one}
 {:db/ident :mapping.mapping/slug
  :db/doc "The Taxonomy API route slugs that identifies one or more mappings."
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/many}]

Edges

[{:db/ident :mapping.edge/mapping
  :db/doc "The mappings under which an edge is valid."
  :db/valueType :db.type/ref
  :db/cardinality :db.cardinality/many}
 {:db/ident :mapping.edge/source
  :db/doc "The source entity of an edge."
  :db/valueType :db.type/ref
  :db/cardinality :db.cardinality/one}
 {:db/ident :mapping.edge/target
  :db/doc "The target entity of an edge."
  :db/valueType :db.type/ref
  :db/cardinality :db.cardinality/one}]

External

[{:db/ident :mapping.external/source-attribute
  :db/doc "The source identifying attribute, or :id/db for entity-id."
  :db/valueType :db.type/keyword
  :db/cardinality :db.cardinality/one}
 {:db/ident :mapping.external/target-attribute
  :db/doc "The target identifying attribute, or :id/db for entity-id."
  :db/valueType :db.type/keyword
  :db/cardinality :db.cardinality/one}
 {:db/ident :mapping.external/attribute-mapping
  :db/doc "Attributes that should be taken from the source or target and added to the response. The tuple takes :source or :target, a database attribute and the name it should be given in the output map."
  :db/valueType :db.type/tuple
  :db/tupleTypes [:db.type/keyword :db.type/keyword :db.type/keyword]
  :db/cardinality :db.cardinality/many}
               ;; Created target entities
 {:db/ident :mapping.external/id
  :db/doc "Provides a string that represents an external ID."
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/one}
 {:db/ident :mapping.external/uri
  :db/doc "Provides a string that represents an URI to an external resource for the mapping target."
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/one}
 {:db/ident :mapping.external/key-value-data
  :db/doc "Key-value data that should be added to the target entity."
  :db/valueType :db.type/tuple
  :db/tupleTypes [:db.type/keyword :db.type/string]
  :db/cardinality :db.cardinality/many}
 {:db/ident :mapping.external/annotations
  :db/doc "Annotations relating to the external target entity."
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/many}]

Example

The database

As an example we set up a database that contains the following schema.

[{:db/ident :local-id
  :db/doc "Local identifier for the entity."
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/one
  :db/unique :db.unique/identity}
 {:db/ident :occupation
  :db/doc "Occupation of the entity."
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/one}
 {:db/ident :annotation
  :db/doc "Annotations for the entity."
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/many}
 {:db/ident :remote-id
  :db/doc "Remote identifier for the entity."
  :db/valueType :db.type/string
  :db/cardinality :db.cardinality/one
  :db/unique :db.unique/identity}]

And fill it with this data describing roles, actors and extras who have played roles in film adaptions of the novel Treasure Island by Robert Luis Stevenson.

[{:remote-id "NOT MAPPED"}
 {:local-id "Presenter"
  :occupation "Disembodied Voice of the Narrative"}
 {:remote-id "Walt Disney"}
 {:local-id "Hispaniola"
  :annotation "This is the fictional ship!"}
 {:remote-id "Hispaniola"
  :annotation "This is the actual boat!"}
 {:local-id "Long John Silver"
  :occupation "Mighty Pirate!"}
 {:remote-id "Robert Newton"
  :annotation ["An irrelevant fact."
               "And another one."]
  :occupation "Not A Scientist Actually"}
 {:remote-id "L. Charles"
  :occupation "Actor!"}
 {:remote-id "Eddie Izzard"}
 {:local-id "Captain Smollett"}
 {:remote-id "Basil Sydney"}
 {:remote-id "Fred Tooze"}
 {:remote-id "Philip Glenister"}
 {:local-id "Jim Hawkins"}
 {:remote-id "Bobby Driscoll"}
 {:remote-id "Michael Croudson"}
 {:remote-id "Toby Regbo"}
 {:local-id "Just This Guy, You Know"
  :occupation "Galactic President"}]

Now we have a database with information, but it lacks relations. Who played what and when?

Mappings

Treasure Island (1950)

{:mapping
 {:type :default
  :organisation "The Mighty Pirates"
  :family "Epics"
  :name "Skattkammarön"
  :version "1950"
  :taxonomy-version "23"
  :description "En film om en skattkammare på en ö."
  :uri "https://www.imdb.com/title/tt0043067/"}
 :config
 {:source
  {:id :local-id
   :include
   {:occupation :role}}
  :target
  {:id :remote-id
   :mapping :remote-id
   :include {:occupation :occupation}}}
 :data
 {:edges
  [["Presenter" "Walt Disney"]
   ["Hispaniola" "Hispaniola"]
   ["Long John Silver" "Robert Newton"]
   ["Long John Silver" "L. Charles"]
   ["Captain Smollett" "Basil Sydney"]
   ["Captain Smollett" "Fred Tooze"]
   ["Jim Hawkins" "Bobby Driscoll"]
   ["Jim Hawkins" "Michael Croudson"]]}}

Treasure Island (2021)

{:mapping
 {:type :default
  :organisation "The Mighty Pirates"
  :family "Epics"
  :name "Skattkammarön"
  :version "2012"
  :taxonomy-version "23"
  :description "En helt ny film om en skattkammare på en ö."
  :uri "https://www.imdb.com/title/tt1820723/"}
 :config
 {:source
  {:id :local-id}
  :target
  {:id :remote-id
   :mapping :remote-id}}
 :data
 {:targets [{:db/id "not-mapped"
             :mapping.external/id "N/A"
             :mapping.external/annotations
             ["This is source has no mapping."]
             :mapping.external/key-value-data
             [[:label "Not Mapped"]]}]
  :edges [["Presenter" {:db/id "not-mapped"}]
          ["Hispaniola" "Hispaniola"]
          ["Long John Silver" "Eddie Izzard"]
          ["Captain Smollett" "Philip Glenister"]
          ["Jim Hawkins" "Toby Regbo"]]}}

Updatable mappings and edges

If there is a new EURES ESCO v. 2.0.0-alpha under test and the edge is valid under this new version the update could be encoded as follows:

{:id <eures_esco_v_2.0.0-alpha_entity_id>
 :family "EURES"
 :name "ESCO"
 :testing "This is just for internal exploration ..."
 :version "2.0.0-alpha"
 :bi-directional false}
{:source <source_entity_id>
 :target <target_entity_id>
 :mapping [ <eures_esco_v_1.0.9_entity_id>
            <eures_esco_v_2.0.0-alpha_entity_id> ]}

Introduction

The JobTech Taxonomy API gives access to different taxonomies like occupation names, skills and SSYK, SNI etc.

REST API

How the REST API works is described by an OpenAPI specification. This is used to generate an overview with examples for the API and this can be accessed at the JobTech Taxonomy API Swagger UI page.

GraphQL API

The Taxonomy API can be accessed using GraphQL and this can be tested at the JobTech Taxonomy API GraphiQL UI.

More about how the GraphQL API can be used is found in the chapter on GraphQL.

Getting started

The JobTech Taxonomy API is divided into four sections GraphQL, Main, Specific Types and Suggesters.

The GraphQL section is the most modern approach to fetch data from the API and is the recommended way of fetching data from the API. Our long term goal is to be able to replace all other endpoints with the GraphQL endpoint. With the GraphQL end point you can fetch concepts (words) and their relations to other concepts.

The Main section contains the core functionalities of the API like retrieving concepts (words) from different taxonomies. It also has endpoints helping you to track and react to changes in the taxonomies.

The Specific Types section contains typed endpoints for taxonomies that has specific fields like statistical codes for SSYK and SNI.

The Suggesters section contains endpoints that helps end users finding values from the taxonomies when they are creating structured data based on the taxonomies. There is an autocomplete endpoint that suggest concepts that can assist users creating CVs or job ads.

Status

About SLA, to see statistics on our actual uptime to get a realistic idea on our availability. See this page Uptime statistics

Our commitment is that the Jobtech Taxonomy API will be operating during office hours. If you are in need of a higher uptime you should implement a fall back solution with a local copy of the Jobtech Taxonomy.

API Changes

There are two ways to get notified when changes occur in the Taxonomy API. The first is to subscribe to our API RSS feed, and the second is to register a user on https://forum.jobtechdev.se/ and subscribing to the API changes topic.

Versions

The content of the taxonomies is constantly being updated and changes are released in a controlled manner.

Warning

In order to fetch version 1 of the Taxonomy you have to add the query parameter "version" and set it to "1".

https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?id=tHZB_LJU_8LG&version=1

[
  {
    "taxonomy/id": "tHZB_LJU_8LG",
    "taxonomy/type": "occupation-name",
    "taxonomy/definition": "Barnsjuksköterska, mottagning/vårdcentral",
    "taxonomy/preferred-label": "Barnsjuksköterska, mottagning/vårdcentral",
    "taxonomy/relations": {
      "taxonomy/broader": 2,
      "taxonomy/narrower": 0,
      "taxonomy/related": 2,
      "taxonomy/substitutability-to": 6,
      "taxonomy/substitutability-from": 7
    }
  }
]

If you don't add the query parameter "version" to your request you will always get the latest version of the Taxonomy.

https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?id=tHZB_LJU_8LG

[
  {
    "taxonomy/id": "tHZB_LJU_8LG",
    "taxonomy/type": "occupation-name",
    "taxonomy/definition": "Barnsjuksköterska, mottagning/Barnsjuksköterska, vårdcentral",
    "taxonomy/preferred-label": "Barnsjuksköterska, mottagning/Barnsjuksköterska, vårdcentral",
    "taxonomy/relations": {
      "taxonomy/broader": 2,
      "taxonomy/narrower": 0,
      "taxonomy/related": 2,
      "taxonomy/substitutability-to": 6,
      "taxonomy/substitutability-from": 7
    }
  }
]

Authentication

No authentication is needed for read access of published versions.

Endpoints

Below we only show the URLs. If you prefer the curl command, you type it like:

curl "{URL}" -H "accept: application/json"

Main Endpoints

/v1/taxonomy/main/concept/types

This endpoint will list all available types in the taxonomies

v1/taxonomy/main/relation/types

This endpoint will list all available relation types in the taxonomies.

The broader / narrower relation is for hierarchical relations.

The related relation is a non specific relation like a keyword that is related to an occupation name.

The substitutability relation is for showing related occupations that can substitute one another. For example, if an employer wants to hire a “Barnmorska, förlossning" but can't find any they can do a search for a "Barnmorska, vårdavdelning/BB-avdelning" instead. The substitutability-percentage will show how well the occupation can substitute another occupation.

/v1/taxonomy/main/concepts

This endpoint will let you retrieve concepts from different taxonomies.

Example List all Skill headlines
https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?type=skill-headline

This request will fetch all concepts of type skill headline.

Example Relations
https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?related-ids=xAWr_WYq_JPP%20Uj5W_dft_Ssg&relation=narrower

This request will fetch concepts that has a narrower relation from the concepts “Databaser” and “Operativsystem”.

Example 2. Multiple types
https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?type=ssyk-level-1%20ssyk-level-2%20ssyk-level-3

This request will fetch concepts of types ssyk-level-1 ssyk-level-2 and ssyk-level-3

/v1/taxonomy/main/graph

This endpoint will list relations between two types of concepts in the taxonomies. It’s main use case is to be able to build tree views of the taxonomy. It will also list extra metadata on the relations.

Example Tree view Occupation Field, ssyk-level-4, occupation-name
https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/graph?edge-relation-type=broader&source-concept-type=occupation-name&target-concept-type=ssyk-level-4

https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/graph?edge-relation-type=broader&source-concept-type=ssyk-level-4&target-concept-type=occupation-field

With the help of these two request you can build a tree view bottom up of the occupation-name -> ssyk-level-4 -> occupation-field hierarchy

Example Occupation name substitutability
https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/graph?edge-relation-type=substitutability&source-concept-type=occupation-name&target-concept-type=occupation-name&limit=10

This request will fetch occupation names that has a substitutability relation to each other. For example, if an employer wants to hire a “Barnmorska, förlossning" but can’t find any they can instead use information from this endpoint to search for a "Barnmorska, vårdavdelning/BB-avdelning". The substitutability-percentage will show how well the occupation can substitute another occupation.

/v1/taxonomy/main/changes

This endpoint will list all changes that have occurred to the taxonomies. It’s a list of events of the types CREATED, DEPRECATED and UPDATED.

You can use it to be able to react to changes in the taxonomies. For example if a job seeker is subscribing to job recommendations based on a specific occupation name and that occupation name becomes deprecated, this endpoint will contain information that the deprecation occurred so you can inform the job seeker to update their search profile.

/v1/taxonomy/main/replaced-by-changes

This endpoint will list all deprecated concepts that has been replaced by another newer concept.

/v1/taxonomy/main/versions

This endpoint will list all published versions of the taxonomies.

GraphQL endpoint

GraphQL is a modern query language for APIs that is especially useful for fetching multiple related resources at once in a single request. Since this taxonomy consists of highly inter-related concepts, GraphQL is a naturally fitting instrument for building complex queries that require only a single round-trip to server.

GraphiQL is an interactive GraphQL explorer that helps you browse the taxonomy and build queries interactively. It is accessible on this page.

GraphiQL

You can learn GraphQL, as well as taxonomy dataset and terms, using interactive Explorer UI that shows all available options and allows to build queries by selecting from them. You can read Docs to learn about our schema and meanings of different concept fields.

GraphQL endpoint for programmatic access — /v1/taxonomy/graphql — is also documented on the Swagger API page, so once you've finished building your GraphQL query in GraphiQL, you can use query's text as a query parameter to see how curl commands or urls will look like, for example:

https://taxonomy.api.jobtechdev.se/v1/taxonomy/graphql?query=query%20SwedishMunicipalities%20%7B%20%20%20concepts%28id%3A%20%22i46j_HmG_v64%22%29%20%7B%20%20%20%20%20id%20%20%20%20%20preferred_label%20%20%20%20%20regions%3A%20narrower%20%7B%20%20%20%20%20%20%20id%20%20%20%20%20%20%20type%20%20%20%20%20%20%20preferred_label%20%20%20%20%20%20%20municipalities%3A%20narrower%20%7B%20%20%20%20%20%20%20%20%20id%20%20%20%20%20%20%20%20%20type%20%20%20%20%20%20%20%20%20preferred_label%20%20%20%20%20%20%20%7D%20%20%20%20%20%7D%20%20%20%7D%20%7D

Example Fetch Swedish regions and municipalities (län and kommuner) in one request

query MyQuery {
  concepts(id: "i46j_HmG_v64") {
    id
    preferred_label
    type
    narrower {
      id
      preferred_label
      type
      narrower {
        id
        preferred_label
        type
      }
    }
  }
}

Example Fetch ssyk-level-4 and occupation-name based on occupation-field Data/IT

query MyQuery {
  concepts(type: "occupation-field", id: "apaJ_2ja_LuF") {
    id
    preferred_label
    type
    narrower(type: "ssyk-level-4"){
      id
      preferred_label
      type
      narrower(type: "occupation-name") {
        id
        preferred_label
        type
      }
    }
  }
}
query MyQuery {
  concepts(id: "rQds_YGd_quU") {
    id
    preferred_label
    type
    broader(type: "ssyk-level-4") {
      id
      preferred_label
      type
      related(type: "skill"){
          id
          preferred_label
          type
      }
    }
  }
}

Example Fetch Standard för svensk näringsgrensindelning (SNI) taxonomy

query MyQuery {
  concepts(type: "sni-level-1"){
    id
    preferred_label
    type
    sni_level_code_2007
    narrower(type: "sni-level-2"){
      id
      preferred_label
      type
      sni_level_code_2007
    }
  }
}

Specific Endpoints

These endpoint acts like the /v1/taxonomy/main/concepts but will also display specific metadata on the concepts like ssyk or country codes.

Example Fetch SSYK codes for all levels

https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/ssyk?type=ssyk-level-1%20ssyk-level-2%20ssyk-level-3%20ssyk-level-4

Suggesters Endpoints

/v1/taxonomy/suggesters/autocomplete

This endpoint is to help end users to find concepts in the taxonomies.

Example Autocomplete programming languages starting on “sc”

https://taxonomy.api.jobtechdev.se/v1/taxonomy/suggesters/autocomplete?query-string=sc&type=skill&relation=narrower&related-ids=ShQw_McG_oti

With this request you can autocomplete programming languages starting on the letter “sc”

https://taxonomy.api.jobtechdev.se/v1/taxonomy/suggesters/autocomplete?query-string=lastb&type=occupation-name%20keyword

https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?related-ids=d68E_e74_a59&relation=related

Let's say a user wants to find jobs as a “Lastbilsförare” and starts typing the word “lastb”.

We make a first request to this endpoint also limiting the result to occupation-name and keyword. The response contains the concept “Lastbilsförare” but not as an occupation-name but as a keyword.

If the user show interest in the word “Lastbilsförare” we can make another request for related occupation names with the /v1/taxonomy/main/concepts endpoint.

Results

The results of your queries will be in edn, transit+messagepack or transit+json or JSON.

Successful queries will have a response code of 200 and give you a result set that consists of:

...

Errors

Unsuccessful queries will have a response code of:

HTTP Status codeReasonExplanation
400Bad RequestSomething wrong in the query
401UnauthorizedYou are not using a valid API key (private endpoints only)
500Internal Server ErrorSomething wrong on the server side

Diagrams

Here is a diagram over the types in the taxonomies and what relations they have to each other. The "broader" relation always has an implicit "narrower" relation in the opposite direction. The "related" relation always has an implicit "related" relation in the opposite direction.

Taxonomy Types and Relations

Convert between Old and New Taxonomy ids

If you need to convert data that contains ids from the old taxonomy service you can use these APIs to convert between old and new Taxonomy ids:

Please be aware of that occupation-group, municipality, region are not using the legacyDatabase id but statistical codes, like SSYK, länskod, kommunkod.

Also note that "driving license", is named "driving licence", in the the new taxonomy API

Taxonomy + Ontology

The Job market Ontology is being merged with the JobTech Taxonomy. This is an ongoing task. The values of the Ontology will become either new concepts, alternative labels or keywords and all identifiers will be replaced with Jobtech Taxonomy identifiers where it's applicable.

Ontology files

A file dump of the Ontology can be downloaded here: Ontology Files

Tutorials

Under this section, we collect tutorials for using the Taxonomy API in various ways.

Using the Taxonomy from Python

This is a tutorial on how to use the Taxonomy API from Python. We will be using the Requests library to make HTTP requests. Start by installing it, and then, in a new script, import it:

import requests

The GraphQL API is arguably the easiest API to use. You may want to have a look at the GraphQL documentation along with this tutorial.

We will be talking against a server at the following address:

host = "https://taxonomy.api.jobtechdev.se"

and in order to display results, we will import a pretty printing module.

import pprint
pp = pprint.PrettyPrinter(width=41, compact=True)

Querying versions using GraphQL

The taxonomy has several versions. Let's start by querying what versions there are:

response = requests.get(host + "/v1/taxonomy/graphql", params={"query": """query MyQuery {
  versions {
    id
  }
}"""})

version_data = response.json()["data"]["versions"]
print("Last three versions:")
pp.pprint(version_data[-3:])

Output:

Last three versions:
[{'id': 20}, {'id': 21}, {'id': 22}]

Let's pick out the latest version:

latest_version = max([x["id"] for x in version_data])

pp.pprint(latest_version)

Output:

22

Querying concepts using GraphQL

If we want to, we can modify our query to include concept data from every version. To keep things concise, we will limit ourselves to the latest version and only pick two concepts. Note that we pass in a separate json-coded map with variables.

import json

query = """query MyQuery($version:VersionRef) {
  versions(from: $version, to: $version) {
    id
    concepts(limit: 2) {
      id
      preferred_label
    }
  }
}"""

variables = json.dumps({"version": "21"})

response = requests.get(
    host + "/v1/taxonomy/graphql",
    params={"query": query, "variables": variables})
    
pp.pprint(response.json())

and we get

Output:

{'data': {'versions': [{'concepts': [{'id': 'ghs4_JXU_BYt',
                                      'preferred_label': 'Planeringsarkitekt/Fysisk '
                                                         'planerare'},
                                     {'id': 'GPNi_fJR_B2B',
                                      'preferred_label': 'Inredningsdesigner'}],
                        'id': 21}]}}

We could also have approached this by directly querying the concepts:

query = """query MyQuery($version: VersionRef) {
  concepts(version: $version, limit: 2) {
    id
    preferred_label
  }
}"""

response = requests.get(
    host + "/v1/taxonomy/graphql",
    params={"query": query, "variables": variables})

pp.pprint(response.json())

and we get

Output:

{'data': {'concepts': [{'id': 'ghs4_JXU_BYt',
                        'preferred_label': 'Planeringsarkitekt/Fysisk '
                                           'planerare'},
                       {'id': 'GPNi_fJR_B2B',
                        'preferred_label': 'Inredningsdesigner'}]}}

What concepts are returned differ from query to query.

Querying concept types using GraphQL

To see what concept types there are in the latest version we can do

query = """query MyQuery {
  concept_types {
    id
    label_en
  }
}"""

response = requests.get(host + "/v1/taxonomy/graphql", params={"query": query})
concept_types = response.json()["data"]["concept_types"]
n = len(concept_types)
print(f"There are {n} concept types in the latest version")
print("Here are some:")
pp.pprint(concept_types[0:3])

We only print three concept types.

Output:

There are 52 concept types in the latest version
Here are some:
[{'id': 'occupation-experience-year',
  'label_en': 'Occupation experience '
              '(time)'},
 {'id': 'forecast-occupation',
  'label_en': 'Forecast occupation'},
 {'id': 'occupation-field',
  'label_en': 'Occupation field'}]

but we can also look at the concept types for a specific version:

query = """query MyQuery($version:VersionRef) {
  concept_types(version: $version) {
    id
    label_en
  }
}"""

variables = json.dumps({"version": "1"})
response = requests.get(host + "/v1/taxonomy/graphql", params={"query": query, "variables": variables})
n = len(response.json()["data"]["concept_types"])
print(f"There are {n} concepts in the first version.")

Output:

There are 36 concepts in the first version.

Understanding versions with GraphQL and Python

The taxonomy has multiple versions to help track changes and maintain backward compatibility. We can start by retrieving all the version ids. Just as in the introduction, we use the Requests library. We start with some imports and some definitions:

import json
import requests
import pprint
pp = pprint.PrettyPrinter(width=41, compact=True)
host = "https://taxonomy.api.jobtechdev.se"

def graphql_get(query, variables):
    response = requests.get(host + "/v1/taxonomy/graphql",
                            params={"query": query, "variables": json.dumps(variables)})
    return response.json()

The function graphql_get is a helper function to keep the rest of this code concise.

We can use it to get all versions:

version_data = graphql_get("""query MyQuery {
  versions {
    id
  }
}""", {})

versions = [x["id"] for x in version_data["data"]["versions"]]
versions.sort()

pp.pprint(versions)

Output:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]

Let's query the number of concepts per version:

query = """query MyQuery($version: VersionRef) {
  concepts(include_deprecated: true, version: $version) {
    id
    deprecated
    preferred_label
    replaces {
      id
    }
    replaced_by {
      id
    }
  }
}"""

version_concepts = {}

for v in versions:
    cdata = graphql_get(query, {"version": v})
    concepts = cdata["data"]["concepts"]
    version_concepts[v] = {c["id"]:c for c in concepts}
    n = len(concepts)

print(f"Loaded {len(version_concepts)} versions.")
print("Number of concepts per version: ")
pp.pprint([len(version_concepts[v]) for v in versions])

Output:

Loaded 22 versions.
Number of concepts per version: 
[14715, 18227, 18361, 18406, 18418,
 21365, 24291, 26352, 26352, 26546,
 28560, 41130, 41179, 41436, 41816,
 41960, 41960, 41998, 42227, 42584,
 44942, 45647]

We see that the number of concepts increase with every version if we count both deprecated and non-deprecated concepts. We would expect that the set of concepts in the last version is the set of all concepts ever seen:

all_ids = {k for concepts in version_concepts.values()
           for k in concepts.keys()}
last_ids = {k for k in version_concepts[versions[-1]].keys()}

print("Equal" if last_ids == all_ids else "Not equal")

Output:

Equal

It would be interesting to study the history of every concept. We will create a map from every concept id to its value in every version:

concept_histories = {concept_id:{v:cs[concept_id]
                                 for v,cs in version_concepts.items()
                                 if concept_id in cs}
                     for concept_id in all_ids}

There are for sure going to be some concepts that have been deprecated. We will start by looking at concepts that have not been replaced by any other concepts. To filter the concepts, we write two helper functions has_deprecated and has_replaced_by.


def map_has_value(m, pred):
    for k, v in m.items():
        if pred(v):
            return True
    return False


def has_deprecated(history):
    return map_has_value(history, lambda concept: concept["deprecated"])

def has_replaced_by(history):
    return map_has_value(history, lambda concept: 0 < len(concept["replaced_by"]))
    
histories_of_interest = [(concept_id, history)
                         for concept_id, history in concept_histories.items()
                         if has_deprecated(history) and not(has_replaced_by(history))]

(concept_id, history) = histories_of_interest[0]

exist_versions = [v for v in versions if v in history]
deprecated_in_versions = [v for v in exist_versions if history[v]["deprecated"]]

label = history[exist_versions[0]]["preferred_label"]

print(f"Have a look at concept {concept_id} with first label {label}")
print(f"It exists in versions {exist_versions}")
print(f"It is marked as deprecated in {deprecated_in_versions}")

Output:

Have a look at concept Tgsx_o7B_Tpo with first label Musik
It exists in versions [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
It is marked as deprecated in [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]

The above concept does not have any replacements (as its replaced_by value is always empty). Let's look at an example where replaced_by has a value:

histories_of_interest = [(concept_id, history)
                         for concept_id, history in concept_histories.items()
                         if has_deprecated(history) and has_replaced_by(history)]

(concept_id, history) = histories_of_interest[0]

exist_versions = [v for v in versions if v in history]
deprecated_in_versions = [v for v in exist_versions if history[v]["deprecated"]]

import itertools

replaced_by_id_version_pairs = [(r["id"],v) for v,concept in history.items() for r in concept["replaced_by"]]
groups = itertools.groupby(replaced_by_id_version_pairs, lambda kv: kv[0])
replaced_by_id_version_map = {id:[p[1] for p in pairs]
                              for id, pairs in groups}

label = history[exist_versions[0]]["preferred_label"]

print(f"Have a look at concept {concept_id} with first label {label}")
print(f"It exists in versions {exist_versions}")
print(f"It is marked as deprecated in {deprecated_in_versions}")
print("It has been replaced by")
for id, versions in replaced_by_id_version_map.items():
    print(f" * Concept {id} in versions {versions}")

Output:

Have a look at concept AWt8_idw_DYJ with first label Odlare av trädgårds- och jordbruksväxter, frukt och bär
It exists in versions [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
It is marked as deprecated in [13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
It has been replaced by
 * Concept Wv97_wRL_3LS in versions [13, 14, 15, 16, 17, 18, 19, 20, 21, 22]

It would be interesting to take a look at a replacement concept.

(rid, rversions) = next(iter(replaced_by_id_version_map.items()))
rconcept = concept_histories[rid][rversions[0]]
pp.pprint(rconcept)

Output:

{'deprecated': False,
 'id': 'Wv97_wRL_3LS',
 'preferred_label': 'Odlare av '
                    'trädgårds- och '
                    'jordbruksväxter '
                    'samt djuruppfödare '
                    'blandad drift',
 'replaced_by': [],
 'replaces': [{'id': 'AWt8_idw_DYJ'}]}

Let's also see if it does indeed replace the previous concept:


replaces_id_set = {c["id"] for c in rconcept["replaces"]}
print(f"Is it true that {rid} replaces {concept_id}? {concept_id in replaces_id_set}")

Output:

Is it true that Wv97_wRL_3LS replaces AWt8_idw_DYJ? True

Hopefully, you will understand how versions and deprecation works now.

Using the main API

In addition to the GraphQL API previously shown, there are also several endpoints under the HTTP path /v1/taxonomy/main. This tutorial will show you how you can access them from Python.

Let's start with some imports and definitions:

import json
import requests
import pprint
pp = pprint.PrettyPrinter(width=41, compact=True)
host = "https://taxonomy.api.jobtechdev.se"

We will start by quering the versions:

version_data = requests.get(host + "/v1/taxonomy/main/versions").json()
version_data.sort(key=lambda x: x["taxonomy/timestamp"])

def disp_version(v):
    version = v["taxonomy/version"]
    timestamp = v["taxonomy/timestamp"]
    print(f"Version {version} published at {timestamp}")

print("First version:")
disp_version(version_data[0])

print("Last version:")
disp_version(version_data[-1])

version_ids = [v["taxonomy/version"] for v in version_data]

print("Version ids:")
pp.pprint(version_ids)

Output:

First version:
Version 1 published at 2021-03-05T13:38:02.440Z
Last version:
Version 22 published at 2024-02-21T16:16:00.195Z
Version ids:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]

There is also a /v1/taxonomy/main/concepts endpoint. Let's look at one of the concepts from that endpoint. We put the limit parameter to one.

Many endpoints accept a version parameter to specify a version and if it is omitted, the endpoint will default to delivering data from the latest version. In the following example, we omit the version parameter:

concepts = requests.get(host + "/v1/taxonomy/main/concepts",
                        params={"limit": 1}).json()
pp.pprint(concepts)

Output:

[{'taxonomy/alternative-labels': ['Fysisk '
                                  'planerare',
                                  'Planeringsarkitekt'],
  'taxonomy/definition': 'Planeringsarkitekt/Fysisk '
                         'planerare',
  'taxonomy/id': 'ghs4_JXU_BYt',
  'taxonomy/preferred-label': 'Planeringsarkitekt/Fysisk '
                              'planerare',
  'taxonomy/type': 'occupation-name'}]

We can also pick out exactly one concept at a specific version:

concept_id = concepts[0]["taxonomy/id"]
latest_version_id = version_ids[-1]

concept = requests.get(host + "/v1/taxonomy/main/concepts",
                       params={"id": concept_id, "version": latest_version_id}).json()

pp.pprint(concept)

Output:

[{'taxonomy/alternative-labels': ['Fysisk '
                                  'planerare',
                                  'Planeringsarkitekt'],
  'taxonomy/definition': 'Planeringsarkitekt/Fysisk '
                         'planerare',
  'taxonomy/id': 'ghs4_JXU_BYt',
  'taxonomy/preferred-label': 'Planeringsarkitekt/Fysisk '
                              'planerare',
  'taxonomy/type': 'occupation-name'}]

We can list all the types. By default

types_data = requests.get(host + "/v1/taxonomy/main/concept/types",
                          params={"version": latest_version_id}).json()

print("The first 5 types:")
pp.pprint(types_data[0:5])

Output:

The first 5 types:
['barometer-occupation', 'continent',
 'country', 'driving-licence',
 'employment-duration']

That's it. We have now seen some of the most useful endpoints of the main taxonomy API.

REST API

The REST API exposes endpoints for querying and updating concepts i Taxonomy. The Swagger page is accessible on this URL:

https://taxonomy.api.jobtechdev.se/v1/taxonomy/swagger-ui/index.html

REST API Examples

The Swagger page of the REST API can be found here:

https://taxonomy.api.jobtechdev.se/v1/taxonomy/swagger-ui/index.html

It is a good starting point for exploring the capabilities of the REST API.

Requesting all Swedish regions

In this example, we want to use the legacy API to obtain all regions in Sweden. We will be using two endpoints to accomplish that:

In the first step, we will figure out the concept id of Sweden using the first endpoint. In the second step, we will use the second endpoint to query regions in Sweden.

Start by visiting the Swagger page of the API at

https://taxonomy.api.jobtechdev.se/v1/taxonomy/swagger-ui/index.html

Step 1: Obtaining the concept id of Sweden

The specific endpoint that we are going to use to obtain the concept id of Sweden has the following Swagger URL:

https://taxonomy.api.jobtechdev.se/v1/taxonomy/swagger-ui/index.html#/Specific%20Types/get_v1_taxonomy_specific_concepts_country

Click on the Try it out button. Then click execute. You will see a long list of all countries in the latest version of the taxonomy. The URL of the request is

https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/country

In order to only obtain Sweden in the result list, set the preferred-label parameter to be Sverige. The corresponding URL is

https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/country?preferred-label=Sverige

and we obtain the result

[
  {
    "taxonomy/type": "country",
    "taxonomy/definition": "Sverige",
    "taxonomy/id": "i46j_HmG_v64",
    "taxonomy/iso-3166-1-alpha-3-2013": "SWE",
    "taxonomy/iso-3166-1-alpha-2-2013": "SE",
    "taxonomy/preferred-label": "Sverige"
  }
]

with Sweden having the concept id i46j_HmG_v64.

Step 2: Obtaining all regions in Sweden

Visit the Swagger page for regions and click on the button Try it out:

https://taxonomy.api.jobtechdev.se/v1/taxonomy/swagger-ui/index.html#/Specific%20Types/get_v1_taxonomy_specific_concepts_region

Then click on the button Execute which will return all regions in the world. For instance, we will obtain the following region in the result set:

{
  "taxonomy/type": "region",
  "taxonomy/definition": "Erzincan",
  "taxonomy/id": "CsrW_6th_DKs",
  "taxonomy/preferred-label": "Erzincan"
}

The corresponding URL can be found under Request URL in the Swagger UI: https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/region

We want to restrict the set of regions to the set of concepts being narrower to the concept with id i46j_HmG_v64 that represents Sweden. In order to do that, set the relation parameter to be narrower and the related-ids parameter to be i46j_HmG_v64. Then execute the request. The corresponding URL is

https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/region?related-ids=i46j_HmG_v64&relation=narrower

and the results will now only contain Swedish regions, such as

{
  "taxonomy/type": "region",
  "taxonomy/definition": "Kalmar län",
  "taxonomy/id": "9QUH_2bb_6Np",
  "taxonomy/national-nuts-level-3-code-2019": "08",
  "taxonomy/nuts-level-3-code-2013": "SE213",
  "taxonomy/preferred-label": "Kalmar län"
}

Requesting all occupations fields

To request all concepts of type occupation-field from the REST API, start by taking a look at the Swagger page:

https://taxonomy.api.jobtechdev.se/v1/taxonomy/swagger-ui/index.html

The /v1/taxonomy/main/concepts endpoints can be used to obtain concepts of a specific type. Click on the Try it out button and fill in the type parameter to be occupation-field. Then click Execute. You will obtain a list of occupation fields from the latest version, such as

{
  "taxonomy/type": "occupation-field",
  "taxonomy/definition": "Exempel på arbetsuppgifter: \r\n\r\nKlipper och behandlar hår.\r\n\r\nUtför ansikts-, spa- och kroppsbehandlingar eller fotvård. \r\n\r\nMasserar kroppens mjukdelsvävnader.",
  "taxonomy/id": "Uuf1_GMh_Uvw",
  "taxonomy/preferred-label": "Kropps- och skönhetsvård"
}

The corresponding URL is https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?type=occupation-field .

In order to obtain the occupation fields for a specific version, set the version parameter to the version you want, e.g. 22. The corresponding URL is https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?type=occupation-field&version=22.

Requesting specific sun-education-level concepts

Assume we want to request specific concepts of type sun-education-level that have the attribute sun-education-level-code-2000 being either 1, 2, 3, 4, 5 or 6 for version 1 of the Taxonomy. Start by visiting the Swagger page:

https://taxonomy.api.jobtechdev.se/v1/taxonomy/swagger-ui/index.html

Go to the endpoint /v1/taxonomy/specific/concepts/sun-education-level and click on Try it out. Fill in the the following fields:

  • version should have value 1.
  • sun-education-level-code-2000 should have either 1, 2, 3, 4, 5 or 6.

The API does not support comma-separated values for the sun-education-level-code-2000 field. You will have to make a separate query for each of the possible values. For the value sun-education-level-code-2000 being 1, we have the URL

https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/sun-education-level?version=1&sun-education-level-code-2000=1

and the results

[
  {
    "taxonomy/type": "sun-education-level-1",
    "taxonomy/definition": "Förgymnasial utbildning kortare än 9 år",
    "taxonomy/id": "hxDt_SD3_1qX",
    "taxonomy/sun-education-level-code-2000": "1",
    "taxonomy/preferred-label": "Förgymnasial utbildning kortare än 9 år"
  }
]

All URL for sun-education-level-code-2000 being either 1, 2, 3, 4, 5 or 6 are:

GraphQL

GraphQL is a query language for APIs that provides a flexible alternative to REST. It allows clients to request precisely the data they need, reducing unnecessary data transfer and multiple requests. This efficiency is particularly useful in querying taxonomy data, where different applications might need varying levels of detail from the same dataset.

Using curl it is quite easy to query the GraphQL endpoints of the taxonomy and save the response in a JSON document. Save the query in a file (in the example below example.graphql is chosen) and call the desired endpoint.

# Get 5 occupation names.
query occupation_names {
  concepts(type: "occupation-name", limit: 5) {
    preferred_label
  }
}
curl --data-urlencode query@example.graphql --get https://taxonomy.api.jobtechdev.se/v1/taxonomy/graphql

The command above should produce output similar to the following JSON.

{
  "data": {
    "concepts": [
      { "preferred_label": "Planeringsarkitekt/Fysisk planerare" },
      { "preferred_label": "Inredningsdesigner" },
      { "preferred_label": "Utvecklingsingenjör, elkraft" },
      { "preferred_label": "Beräkningsingenjör, el-tele" },
      { "preferred_label": "Mjukvaruutvecklare" }
    ]
  }
}

Comparison between REST API and GraphQL API

The table below highlights how common data fetching tasks can be accomplished using either a REST API or a GraphQL API.

Use REST API When:

You need simple, fixed endpoints for specific tasks, such as getting a list of items or details of a single item. You want a straightforward approach to access or modify resources. The operation is focused on a single type of request or a specific, well-defined resource.

Use GraphQL API When:

You need to gather various related pieces of data in a single request, avoiding multiple API calls. You want the flexibility to adjust queries dynamically, asking for only the data you need. You need to fetch interconnected data, such as getting a concept along with its related concepts and changes, in one go.

This table and summary illustrate when each approach is most useful, with specific examples of GraphQL queries highlighting its ability to handle complex and nested data in a single request.

RequestREST APIGraphQL API
Fetch a list of all occupationsGET taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?type=occupation-name'query AllOccupations { concepts(type: "occupation-name") { id preferred_label type } }
Fetch a specific occupation by IDGET taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?id=occupation-id&type=occupation-namequery specificOccupation { concepts(id: "occupation-id") { id preferred_label type } }
Fetch detailed information about a concept, including related concepts and hierarchyNot feasible in REST without multiple requestsquery ComplexQuery { concepts(id: "concept-id") { id preferred_label type broader { id preferred_label } narrower { id preferred_label } related { id preferred_label } } }

Examples

Fetch tree of occupation-field -> ssyk-level-4 -> occupation-name in version 1.

query occupations {
  concepts(type: "occupation-field", version: "1") {
    id
    preferred_label
    type
    narrower(type: "ssyk-level-4") {
      id
      preferred_label
      type
      narrower(type: "occupation-name") {
        id
        preferred_label
        type
      }
    }
  }
}

Fetch regions and municipalities.

query MyQuery {
  concepts(id: "i46j_HmG_v64") {
    id
    preferred_label
    type
    narrower {
      id
      preferred_label
      type
      narrower {
        id
        preferred_label
        type
      }
    }
  }
}

Fetch related skills to occuaption-name Mjukvaruutvecklare.

query MjukvaruutvecklareSkillsQuery {
  concepts(id: "rQds_YGd_quU") {
    id
    preferred_label
    type
    broader(type: "ssyk-level-4") {
      id
      preferred_label
      type
      related(type: "skill") {
        id
        preferred_label
        type
      }
    }
  }
}

Fetch all changes that has happend to the concept "Utvecklingsingenjör, el-tele".

query MyQuery {
  changelog(id: "Qzzb_67o_n2P") {
    event: __typename
    user
    comment
    timestamp
    concept {
      id
      type
      preferred_label
    }
    ... on Updated {
      changes {
        attribute
        old_value
        new_value
      }
    }
  }
}

Playground

GraphiQL Playground is a tool that lets you easily interact with a GraphQL API in your browser. It provides an interface where you can:

Write and Run Queries: Type your GraphQL queries and click "Run" to see the results.
Explore the API: Use the built-in explorer to browse available data types and fields.
Test Data Changes: Besides fetching data, you can also test mutations to change data.
Use Variables: Add dynamic values to your queries and set custom headers if needed.

This tool helps you quickly understand and test how a GraphQL API works.

Libraries

To reduce application complexity, improve stability and availability it can be useful to access the Taxonomy using one of the provided libraries. These libraries are build by performing standard queries against the default production endpoint and packaging the result into libraries that are deployed into the appropriate package managers.

Here is an overview of the queries used for the platforms concerned.

.NET

The .NET Taxonomy contains a subset of the taxonomy presented in library form consumable from .NET.

Country

Country

query region_country_continent {
  concepts(type: "country", include_deprecated: true) {
    id
    deprecated
    preferred_label
    iso_3166_1_alpha_3_2013
    iso_3166_1_alpha_2_2013
  }
}

Language

Language

query language {
  concepts(type: "language", include_deprecated: true) {
    id
    type
    deprecated
    preferred_label
    iso_639_1_2002
    iso_639_2_1998
    iso_639_3_2007
  }
}

Region

Region

query region_country_continent {
  concepts(type: "region", include_deprecated: true) {
    id
    deprecated
    preferred_label
    nuts_level_3_code_2021
    national_nuts_level_3_code_2019
    broader(type: "country", include_deprecated: true) {
      id
    }
  }
}

Occupation name to ESCO ID

Occupation name to ESCO ID

# This needs to confirm to the ESCO ID Selection algorithm to be valid.
query occupation_name_to_esco {
  concepts(type: "occupation-name", include_deprecated: true) {
    id
    preferred_label
    type
    no_esco_relation
    exact_match {
      id
      esco_uri
      preferred_label
      type
    }
    broad_match {
      id
      esco_uri
      preferred_label
      type
    }
    broader {
      id
      esco_uri
      preferred_label
      type
    }
    narrow_match {
      id
      esco_uri
      preferred_label
      type
    }
    close_match {
      id
      esco_uri
      preferred_label
      type
    }
  }
}

Skill to ESCO ID

Skill to ESCO ID

query skill_to_esco {
  concepts(type: "skill", include_deprecated: true) {
    id
    preferred_label
    type
    no_esco_relation
    exact_match {
      id
      esco_uri
      preferred_label
      type
    }
    broad_match {
      id
      esco_uri
      preferred_label
      type
    }
    broader {
      id
      esco_uri
      preferred_label
      type
    }
    narrow_match {
      id
      esco_uri
      preferred_label
      type
    }
    close_match {
      id
      esco_uri
      preferred_label
      type
    }
  }
}

Taxonomy versions

Every time modifications are made to the taxonomy, those modifications are released in the form of a version. The released versions form a linear history of the taxonomy with every version being identified by an integer. The first version is 1 and every new version is assigned a version number that is an increment by one from the previous version number. The last released version as of this writing is version 22.

The various API endpoints optionally provide a version parameter in order to explicitly specify which version of the taxonomy to use. If the version parameter is not specified, it will by default be assumed that the last published version is requested. A good reason for explicitly providing a version parameter is to make sure that a system that uses the taxonomy works exactly the same irrespective of updates made to the taxonomy.

Concepts in the taxonomy are never deleted from one version to the next. Instead they become deprecated. By default, the API will not return deprecated concepts from a given version–but it does exist in the database. If a deprecated concept has been replaced by some other concept, there will be a relation of type replaced-by from the deprecated concept to the new concept.

Versions in the GraphQL API

Visit the interactive page https://taxonomy.api.jobtechdev.se/v1/taxonomy/graphiql to explore the GraphQL API. To list available versions, use the following query:

query MyQuery {
  versions {
    id
    timestamp
  }
}

which will return a json-encoded response with data about versions:

{
  "data": {
    "versions": [
      {
        "id": 1,
        "timestamp": "2021-03-05T13:38:02.440Z"
      },
      
      ...

      {
        "id": 22,
        "timestamp": "2024-02-21T16:16:00.195Z"
      }
    ]
  }
}

In order to query a concept from a specific version, specify the version parameter in the query. For example, the following query will get the concept with id AWt8_idw_DYJ from version 10:

query MyQuery {
  concepts(version: 10, id: "AWt8_idw_DYJ") {
    id
    preferred_label
  }
}

and return the following result:

{
  "data": {
    "concepts": [
      {
        "id": "AWt8_idw_DYJ",
        "preferred_label": "Odlare av trädgårds- och jordbruksväxter, frukt och bär"
      }
    ]
  }
}

But if we request the same concept in version 14, that is

query MyQuery {
  concepts(version: 14, id: "AWt8_idw_DYJ") {
    id
    preferred_label
  }
}

we get an empty result. However, this does not mean that the concept does not exist in version 14: It only means that it has been deprecated. In order to get the concept in version 14, set the include_deprecated parameter to true:

query MyQuery {
  concepts(version: 14, id: "AWt8_idw_DYJ", include_deprecated: true) {
    id
    preferred_label
    replaced_by {
      id
    }
  }
}

Note that we also include the field replaced_by. We obtain the following result:

{
  "data": {
    "concepts": [
      {
        "id": "AWt8_idw_DYJ",
        "preferred_label": "Odlare av trädgårds- och jordbruksväxter, frukt och bär",
        "replaced_by": [
          {
            "id": "Wv97_wRL_3LS"
          }
        ]
      }
    ]
  }
}

From this result, we read that in version 14, the concept with id Wv97_wRL_3LS is meant to be used instead of the concept with id AWt8_idw_DYJ.

Versions in the REST API

In order to get a list of all published versions, send a GET request to the following address: https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/versions

It will return a list of versions and timestamps in json-format:

[{"taxonomy/version":1,"taxonomy/timestamp":"2021-03-05T13:38:02.440Z"},

 ...
 
 {"taxonomy/version":22,"taxonomy/timestamp":"2024-02-21T16:16:00.195Z"}]

Many of the REST endpoints accept a version parameter. Here is an example where we request concept with id AWt8_idw_DYJ and version 10:

https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?id=AWt8_idw_DYJ&version=10

The response will have the following json-coded body:

[
  {
    "taxonomy/type": "forecast-occupation",
    "taxonomy/definition": "Ett prognosyrke beskriver en eller fler ihopslagna yrkesgruppers konkurrensläge på arbetsmarknaden. Ett prognosyrke riktas aldrig mot en lägre nivå i SSYK-strukturen än SSYK 4 men kan däremot bestå av en eller fler SSYK grupper på 4 eller 3 siffernivå. \n\nDetta prognosyrke består av följande SSYK 4-grupper: \n·\t6112 - Trädgårdsodlare\n·\t6111 - Odlare av jordbruksväxter, frukt och bär",
    "taxonomy/id": "AWt8_idw_DYJ",
    "taxonomy/preferred-label": "Odlare av trädgårds- och jordbruksväxter, frukt och bär"
  }
]

However, if we request a later version, say 14, with address https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?id=AWt8_idw_DYJ&version=14, we will get an empty result: []. The reason for that is that in version 14, the concept with id AWt8_idw_DYJ has been deprecated and, by default, will not be returned by the API. To get the data of this concept, specify the included-deprecated parameter to be true: https://taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?id=AWt8_idw_DYJ&include-deprecated=true&version=14. This will return the concept with id AWt8_idw_DYJ in version 14:

[
  {
    "taxonomy/type": "forecast-occupation",
    "taxonomy/definition": "Ett prognosyrke beskriver en eller fler ihopslagna yrkesgruppers konkurrensläge på arbetsmarknaden. Ett prognosyrke riktas aldrig mot en lägre nivå i SSYK-strukturen än SSYK 4 men kan däremot bestå av en eller fler SSYK grupper på 4 eller 3 siffernivå. \n\nDetta prognosyrke består av följande SSYK 4-grupper: \n·\t6112 - Trädgårdsodlare\n·\t6111 - Odlare av jordbruksväxter, frukt och bär",
    "taxonomy/id": "AWt8_idw_DYJ",
    "taxonomy/replaced-by": [
      {
        "taxonomy/id": "Wv97_wRL_3LS",
        "taxonomy/definition": "Ett prognosyrke beskriver en eller fler ihopslagna yrkesgruppers konkurrensläge på arbetsmarknaden. Ett prognosyrke riktas aldrig mot en lägre nivå i SSYK-strukturen än SSYK 4 men kan däremot bestå av en eller fler SSYK grupper på 4 eller 3 siffernivå.\n\nDetta prognosyrke består av följande SSYK 4-grupper:\n\n·\t6130 - Växtodlare och djuruppfödare, blandad drift\n·\t6112 - Trädgårdsodlare\n·\t6111 - Odlare av jordbruksväxter, frukt och bär",
        "taxonomy/type": "forecast-occupation",
        "taxonomy/preferred-label": "Odlare av trädgårds- och jordbruksväxter samt djuruppfödare blandad drift"
      }
    ],
    "taxonomy/preferred-label": "Odlare av trädgårds- och jordbruksväxter, frukt och bär",
    "taxonomy/deprecated": true
  }
]

Note the presence of the key "taxonomy/replaced-by". It means that in version 14, the concept has been replaced by another concept with id Wv97_wRL_3LS.

Summary

In both the GraphQL API and the REST API, a version parameter can be provided in order to get data from a specific version. Concepts are never deleted from the taxonomy, they are only deprecated. To include deprecated concepts, use the include_deprecated parameter in the GraphQL API and the included-deprecated query parameter in the REST API. In the GraphQL API, include the replaced_by field in a concept query to see which concept replaces a deprecated concept. In the REST API, deprecated concepts will contain the taxonomy/replaced-by key listing any concept that replaces the returned concept.

A Taxonomy of One's Own

Should you wish to experiment with the content of the taxonomy or set up a private local copy go to https://gitlab.com/arbetsformedlingen/taxonomy-dev/backend/jobtech-taxonomy-api and take a look at the development documentation.