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.
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:
Term | Definition | Example |
---|---|---|
Concept | A concept can be viewed as an idea or notion, a unit of thought | Data/IT |
Type | The type of a concept | Occupation field |
Preferred label | The preferred label for a concept | Key account manager |
Alternative label | An alternative name of a concept, can be displayed externally | KAM |
Definition | The explanation of a concept | Working 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-level
attribute 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:
skos | taxonomy |
---|---|
skos:narrower | narrower |
skos:broader | broader |
skos:related | related |
skos:exactMatch | exact-match |
skos:narrowMatch | narrow-match |
skos:broadMatch | broad-match |
skos:closeMatch | close-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:
skos | taxonomy |
---|---|
skos:prefLabel | preferred-label |
skos:altLabel | alternative-labels |
skos:hidden-label | hidden-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 type | relation type |
---|---|
job-title | related |
keyword | related |
esco-occupation | see mapping relations |
ssyk-level-4 | broader |
isco-level-4 | broader |
occupation-name | substituted-by/substitutability |
Constraints
- Most occupation-name concepts lack definitions (work in progress), the
definition
attribute is therefore generally populated with the same term as thepreferred-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
}
}
}
Occupation-name concepts with related job titles and keywords
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
}
}
Get all SSYK level 4 groups with related occupation-name concepts
query MyQuery {
concepts(type: "ssyk-level-4") {
id
preferred_label
type
definition
ssyk_code_2012
narrower(type: "occupation-name") {
id
preferred_label
type
}
}
Get all SSYK level 4 groups with related skill concepts
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:
Job title | Occupation-name |
---|---|
Allmänreporter | Journalist/Reporter |
Industribrandman | Brandman |
Industrilärare | Yrkeslärare |
Regarding keywords:
Keyword | Occupation-name |
---|---|
Avlopp | Avloppstekniker |
Avlopp | Sug- och spolbilsförare |
Järnväg | Fjärrtågklarerare |
Järnväg | Bangårdsoperatör |
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:
Job title | Occupation-name |
---|---|
Allmänreporter | Journalist/Reporter |
Industribrandman | Brandman |
Industrilärare | Yrkeslärare |
Regarding keywords:
Keyword | Occupation-name |
---|---|
Avlopp | Avloppstekniker |
Avlopp | Sug- och spolbilsförare |
Järnväg | Fjärrtågklarerare |
Järnväg | Bangårdsoperatör |
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
}
}
}
Get SSYK level 4 groups with related skills
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.
taxonomy | skos |
---|---|
broader | skos:broader |
narrower | skos:narrower |
related | skos:related |
exact-match | skos:exactMatch |
broad-match | skos:broadMatch |
close-match | skos:closeMatch |
narrow-match | skos:narrowMatch |
Mapping relations
The mapping relations referenced in SKOS are used to define relations between classifications:
taxonomy | skos |
---|---|
exact-match | skos:exactMatch |
broad-match | skos:broadMatch |
close-match | skos:closeMatch |
narrow-match | skos: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}
, n
being 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-3
concept, 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.
Get all barometer occupations with related occupation name concepts
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
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.
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.
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
}
}
}
}
Example Fetch related skills to occupation-name Mjukvaruutvecklare
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”
Example Autocomplete occupation names with related keywords
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 code | Reason | Explanation |
---|---|---|
400 | Bad Request | Something wrong in the query |
401 | Unauthorized | You are not using a valid API key (private endpoints only) |
500 | Internal Server Error | Something 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.
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:
- https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/country
- https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/region
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:
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:
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
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 value1
.sun-education-level-code-2000
should have either1
,2
,3
,4
,5
or6
.
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
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:
- https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/sun-education-level?version=1&sun-education-level-code-2000=1
- https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/sun-education-level?version=1&sun-education-level-code-2000=2
- https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/sun-education-level?version=1&sun-education-level-code-2000=3
- https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/sun-education-level?version=1&sun-education-level-code-2000=4
- https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/sun-education-level?version=1&sun-education-level-code-2000=5
- https://taxonomy.api.jobtechdev.se/v1/taxonomy/specific/concepts/sun-education-level?version=1&sun-education-level-code-2000=6
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.
Request | REST API | GraphQL API |
---|---|---|
Fetch a list of all occupations | GET 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 ID | GET taxonomy.api.jobtechdev.se/v1/taxonomy/main/concepts?id=occupation-id&type=occupation-name | query specificOccupation { concepts(id: "occupation-id") { id preferred_label type } } |
Fetch detailed information about a concept, including related concepts and hierarchy | Not feasible in REST without multiple requests | query 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
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
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
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
# 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
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.