Hier, j’illustrais comment un thésaurus pouvait aider à configurer un moteur de recherche comme Elasticsearch dans le cas du bilinguisme. Mais ce n’est pas la seule aide qu’un thésaurus peut fournir ! Il y a également moyen d’utiliser les relations thésaurales, et plus particulièrement les termes spécifiques : si vous cherchez sur discrimination, vous serez probablement intéressé par les termes suivants : âgisme, racisme, sexisme, stéréotype, stigmatisation, discrimination.

Le thésaurus

Contrairement à hier, où je n’ai pas utilisé un vrai thésaurus, j’utiliserai le thésaurus Promosanthés pour mes exemples.

Le code

Le script est finalement très proche de l’outil d’hier, à l’exception de la requête SPARQL :

#!/usr/bin/env python

import argparse
import re
from pathlib import Path

from rdflib import Graph


def _stripping_square_bracket(s):
    s = re.sub(r"\[[^\[\]]+]", "", s)

    return s


def _stripping_slashes(s):
    s = s.replace('/', ' ').replace('\\', ' ')

    return s


def _stripping_comma(s):
    s = s.replace(',', '')

    return s


def synonym_cleaning(synonym):
    actions = {
        'lowercase': str.lower,
        'strip_comma': _stripping_comma,
        'strip_square_bracket': _stripping_square_bracket,
        'strip_slashes': _stripping_slashes,
    }

    for action in actions:
        synonym = actions[action](synonym)

    return synonym


def generate_hierarchical(graph, output):
    h = dict()
    qres = graph.query("""
        PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
        PREFIX thesau: <http://hescida.kikirpa.be/thesau/skos/term#>

        SELECT ?term ?prefLab (count(?middle)-1 as ?distance) WHERE {
          ?category skos:prefLabel ?term ;
                    skos:narrower* ?middle .
          ?middle skos:narrower* ?concept .
          ?concept skos:prefLabel ?prefLab .
        }
        GROUP BY ?term ?prefLab
        ORDER BY ?term ?prefLab
    """)
    print(f"We have {len(qres)} results when processing narrower terms.")

    for row in qres:
        if 0 < int(row[2]) < 4:
            term1 = synonym_cleaning(row[0])
            term2 = synonym_cleaning(row[1])
            if term1 in h:
                if 'narrower' in h[term1]:
                    h[term1]['narrower'].append(term2)
                else:
                    h[term1].update({'narrower': [term2]})
            else:
                h[term1] = {'narrower': [term2]}

    with Path(output).open(mode="w") as outfile:
        for k in h:
            terms = {
                term: None for term in list([
                    *h[k].get('narrower', []),
                    k,
                    *h[k].get('broader', [])
                ])
            }
            if len(terms.keys()) > 1:
                outfile.write(f"{k} => {', '.join(terms.keys())}\n")


if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description="Generating synonyms for Elasticsearch based on a SKOS file (Turtle representation)."
    )
    
    parser.add_argument(
        '-s', '--skos',
        help="Specifiy the filename for the SKOS input (Turtle format).",
        required=True
    )
    parser.add_argument(
        '-H', '--hierarchical',
        help="Specifiy the filename where to output hierarchical synonyms.",
        required=False
    )
    args = parser.parse_args()

    graph = Graph().parse(args.skos, format='turtle')
    print(f"We have {len(graph)} nodes.")

    if args.hierarchical:
        generate_hierarchical(graph, args.hierarchical)

J’exécute le script de la manière suivante :

./hierarchical_synonyms.py -s promosanthes.ttl -H promosanthes_synonyms.txt

qui produit l’affichage suivant :

We have 13134 nodes.
We have 9461 results when processing narrower terms.

Et voici des exemples du fichier produit :

abus d'alcool => alcoolemie, binge drinking, abus d'alcool
abus de drogue => overdose, abus de drogue
abus de medicament => pharmacodependance, abus de medicament
.
.
.
etat federal => armee, chambre des representants, commission parlementaire, gouvernement federal, parlement, senat, etat federal
etat matrimonial => divorce, separation, union libre, veuvage, etat matrimonial
ethique => acharnement therapeutique, anonymat, bioethique, code de deontologie, comite d'ethique, consentement aux soins, deontologie, deontologie medicale, droit a la difference, droits de l'usager, droits de la personne, droits du patient, ethique religieuse, eugenisme, euthanasie, exercice illegal de la medecine, experimentation medicale, information du patient, obligation du patient, satisfaction de l'usager, secret medical, secret professionnel, ethique
etude => etude de cohorte, etude exploratoire, etude longitudinale, etude prospective, etude retrospective, etude transversale, etude
.
.
.

Si l’outil génère facilement une liste de 665 synonymes, en tout cas dans le jargon d’Elasticsearch, ce n’est que la première étape pour améliorer la pertinence du moteur de recherche. Il faudra donc encore vérifier que les résultats correspondent aux attentes des usagers, mais ceci est une autre histoire !