Tutoriel d'accès au moteur de recherche de TXM par l'interface CQi

CQi est l'API Java et Groovy permettant d'accéder au moteur de recherche, ou de “corpus”, de TXM. Ce tutoriel s'appuie sur des exemples de lignes de code Groovy que l'on peut exécuter facilement depuis TXM. L'API est entièrement définie par la classe Java MemCqiClient (ou AbstractCqiClient - javadoc) de TXM. Chaque méthode de cette classe donne accès à un aspect du moteur de corpus (connexion au moteur, propriétés du moteur, corpus disponibles, appel de requêtes CQL sur un corpus, gestion des résultats de requêtes, index et lexiques du moteur de recherche).

Ce tutoriel reprend de nombreux éléments du document Stefan Evert, "CQi tutorial −− how to run a CQP query", 2000, IMS Stuttgart.

Comme la Javadoc de la classe AbstractCqiClient est TRÈS perfectible, il faut se référer au code C MemCqiServer.c qui implémente ces méthodes pour savoir quelle fonction ou macro de l'API C de CQi est appelée. L'API CQi étant strictement définie dans cqi.h.

Une documentation de l'API CQi est en cours de rédaction à l'occasion de ce tutoriel (en espérant qu'elle alimente la Javadoc un jour).

La documentation de l'API Python CWB.CL du projet cwb-python est intéressante à consulter en complément, ainsi que l'API Perl CWB::CL du package CPAN de même nom. Ces APIs sont construites à partir des mêmes APIs de base CQP avec des variantes de services intéressantes.

Lister tous les corpus présents dans TXM

Nous allons d'abord vérifier que le corpus DISCOURS est présent dans votre TXM.

  1. dans TXM
  2. cliquer dans la barre d'outils sur le bouton Cré[er] un nouveau fichier (Cré[er] un nouveau fichier)
  3. choisir le répertoire des scripts utilisateurs de TXM sur votre machine (”C:\Documents and Settings\<identifiant de l'utilisateur>\TXM\scripts\user” sous Windows 7) et le nom du fichier “cqi.groovy” (vous pouvez choisir un nom différent, mais l'extension doit être '.groovy')
  4. Ajouter les 3 lignes de code Groovy suivantes dans la fenêtre de l'éditeur de texte ayant ouvert le fichier :

    import org.txm.Toolbox
    
    def corpusEngine = Toolbox.getCqiClient()
    
    println corpusEngine.listCorpora().sort()
    
  5. Cliquer sur le bouton Exécuter le script (Control-F11) (Exécuter le script (Control-F11) ) pour exécuter le script
  6. La liste des corpus présents dans votre TXM s'affiche dans la console
  7. Vérifier que le corpus DISCOURS fait partie de la liste

Voici à quoi votre interface de TXM devrait ressembler après l'exécution de ce script :

Copie d'écran de l'exécution du script 'cqi.groovy' dans TXM 0.7.6 sur Linux

Glose

  • la ligne import org.txm.Toolbox déclare la boite à outils donnant accès à toutes les fonctionnalités de TXM aux scripts Groovy (dont l'API CQi)
  • la ligne def corpusEngine = Toolbox.getCqiClient(); associe un accès à l'API CQi (une instance de la classe AbstractCqiClient) à une variable nommée corpusEngine
  • la ligne println corpusEngine.listCorpora().sort() affiche la liste des noms de corpus retournés par la méthode listCorpora de la classe AbstractCqiClient
  • le .sort() permet de trier la liste des noms de corpus alphabétiquement
  • les deux dernières lignes peuvent être remplacées par une seule ligne équivalente println Toolbox.getCqiClient().listCorpora().sort(), ce qui ne nécessite pas de variable intermédiaire (mais est moins lisible pédagogiquement)
  • les lignes sont séparées par une ligne vide pour plus de lisibilité

Lister les propriétés de mots et les structures du corpus DISCOURS

Nous allons maintenant vérifier que le corpus DISCOURS dispose bien des propriétés de mot 'pos' et 'lemma' ainsi que de la structure 's'.

  1. Remplacer par copier/coller les lignes du script Groovy édité dans la fenêtre d'édition du fichier 'cqi.groovy' par les lignes suivantes :

    import org.txm.Toolbox
    
    def corpusEngine = Toolbox.getCqiClient()
    
    println "Positional Attributes : "+corpusEngine.corpusPositionalAttributes("DISCOURS")
    
    println "Structural Attributes : "+corpusEngine.corpusStructuralAttributes("DISCOURS")
    
  2. Cliquer sur le bouton Exécuter le script (Control-F11) pour exécuter le nouveau script
  3. La liste des attributs de position et de structures du corpus DISCOURS s'affiche dans la console

    Exécution de cqi.groovy
    Positional Attributes : [word, id, sid, pid, pos, func, lemma]
    Structural Attributes : [text, text_id, text_loc, text_type, text_date, text_numero, text_base, text_project, s, s_id, p, p_id, txmcorpus, txmcorpus_lang]
    Terminé: 32 ms
    
  4. Vérifier que les propriétés de mot 'pos' et 'lemma' ainsi que la structure 's' sont bien présents

Glose

  • dans CQI :
    • les propriétés de mots sont appelées “attributs de positions” ('positional attributes' en anglais - l'API CQi, comme tout le code Java de TXM est écrit en anglais)
      • les “positions” du corpus correspondent aux “occurrences” de mots. La position numéro 0 correspond au premier mot du corpus, soit la première occurrence d'un mot. Dans le corpus DISCOURS, il s'agit de la forme 'Les' (word), de description morphosyntaxique 'Da-.p-d' (pos) et de lemme 'le' (lemma)
    • les structures et leurs propriétés sont appelées “attributs de structures” ('structural attributes' en anglais)
      • les structures et leurs propriétés sont représentées par un seul mécanisme appelé “attributs de structures” (c'est ce qui explique notamment pourquoi au sein de CQP, les structures ne peuvent pas être récursives).
  • les attributs de positions sont obtenus par la méthode corpusPositionalAttributes de la classe AbstractCqiClient
  • les structures et leurs attributs sont obtenus par la méthode corpusStructuralAttributes

Accéder aux valeurs des propriétés de mots du corpus DISCOURS

Maintenant que nous connaissons les noms des propriétés de mots du corpus DISCOURS, nous pouvons afficher leurs valeurs au fil du corpus.

  1. Remplacer le code Groovy dans la fenêtre de l'éditeur avec les lignes suivantes :

    import org.txm.Toolbox
    
    def corpusEngine = Toolbox.getCqiClient()
    
    def cpos = [0, 1, 2, 3, 4] as int[]
    
    println corpusEngine.cpos2Str("DISCOURS.word", cpos)
    println corpusEngine.cpos2Str("DISCOURS.lemma", cpos)
    println corpusEngine.cpos2Str("DISCOURS.pos", cpos)
    
  2. Cliquer sur le bouton Exécuter le script (Control-F11) pour exécuter le nouveau script
  3. Les valeurs des propriétés des 5 premiers mots du corpus DISCOURS s'affichent dans la console :

    Exécution de cqi.groovy
    [Les, affaires, de, la, France]
    [le, affaire, de, le, France]
    [Da-.p-d, Ncfp, Sp, Da-fs-d, Np.s]
    Terminé: 36 ms
    

Glose

  • la ligne def cpos = [0, 1, 2, 3, 4] as int[] déclare la variable 'cpos' (pour 'c[orpus] pos[ition]') comme contenant un tableau d'entiers de 0 à 4. Comme la position des mots d'un corpus CQP commence à '0', ce tableau contient les adresses des 5 premiers mots du corpus
  • corpusEngine.cpos2Str("DISCOURS.word", cpos) retourne les valeurs de la propriété 'word' des 5 premiers mots du corpus
    • pour faire cela elle procède en deux temps :
      • d'abord elle accède à l'index de la propriété 'word' avec la méthode corpusEngine.cpos2Id("DISCOURS.word", cpos) pour obtenir les codes numériques des valeurs situées à ces positions
      • puis elle accède au lexique de la propriété 'word' pour obtenir les valeurs correspondant à ces codes avec la méthode corpusEngine.id2Str("DISCOURS.word", id) (voir ci-dessous)
  • corpusEngine.cpos2Str("DISCOURS.lemma", cpos) retourne les valeurs de la propriété 'lemma' des 5 premiers mots du corpus
  • corpusEngine.cpos2Str("DISCOURS.pos", cpos) retourne les valeurs de la propriété 'pos' des 5 premiers mots du corpus

Accéder aux lexiques et index des valeurs de propriétés de mots du corpus DISCOURS

Afficher le code numérique de la forme "France" du corpus DISCOURS

Les lexiques de propriétés de mots ('lexicon' dans la terminologie CQP) encodent numériquement leurs différentes valeurs.

Nous allons maintenant afficher le code numérique de la forme “France” dans le corpus DISCOURS.

  1. Remplacer le code Groovy dans la fenêtre de l'éditeur avec les lignes suivantes :

    import org.txm.Toolbox
    
    def corpusEngine = Toolbox.getCqiClient()
    
    println corpusEngine.str2Id("DISCOURS.word", "France")[0]
    
  2. Cliquer sur le bouton Exécuter le script (Control-F11) pour exécuter le nouveau script
  3. Le code de la forme “France” s'affiche dans la console :

    Exécution de cqi.groovy
    4
    Terminé: 24 ms
    

Glose

  • corpusEngine.str2Id("DISCOURS.word", "France")[0] retourne le code numérique de la valeur “France” telle qu'encodée dans le lexique de la propriété 'word' du corpus DISCOURS
  • Le code numérique de la forme “France” est 4 dans ce corpus.

Afficher la fréquence de la forme "France" du corpus DISCOURS

Les lexiques de propriétés de mots encodent la fréquence de leurs différentes valeurs.

Nous allons maintenant afficher la fréquence de la forme “France” dans le corpus DISCOURS.

  1. Remplacer le code Groovy dans la fenêtre de l'éditeur avec les lignes suivantes :

    import org.txm.Toolbox
    
    def corpusEngine = Toolbox.getCqiClient()
    
    println corpusEngine.id2Freq("DISCOURS.word", corpusEngine.str2Id("DISCOURS.word", "France")[0])[0]
    
  2. Cliquer sur le bouton Exécuter le script (Control-F11) pour exécuter le nouveau script
  3. La fréquence de la forme “France” s'affiche dans la console :

    Exécution de cqi.groovy
    428
    Terminé: 26 ms
    

Glose

  • corpusEngine.id2Freq("DISCOURS.word", ...)", "France")[0] retourne la fréquence (le nombre total d'occurrences) de la valeur “France” de la propriété 'word' du corpus DISCOURS. La partie ...)[0] extrait le premier élément du tableau de résultats retourné par la méthode id2Freq (cette méthode est conçue pour interroger plusieurs valeurs de propriétés à la fois).
  • La forme “France” apparait 428 fois dans ce corpus.

Afficher les positions des dix premières occurrences de la forme "France" dans le corpus DISCOURS

Les index de propriétés de mots encodent les positions de leurs différentes valeurs au fil du corpus.

Nous allons maintenant afficher les positions des dix premières occurrences de la forme “France” dans le corpus DISCOURS.

  1. Remplacer le code Groovy dans la fenêtre de l'éditeur avec les lignes suivantes :

    import org.txm.Toolbox
    
    def corpusEngine = Toolbox.getCqiClient()
    
    println corpusEngine.id2Cpos("DISCOURS.word", corpusEngine.str2Id("DISCOURS.word", "France")[0])[0..9]
    
  2. Cliquer sur le bouton Exécuter le script (Control-F11) pour exécuter le nouveau script
  3. Les positions des 10 premières occurrences de la forme “France” du corpus DISCOURS s'affichent dans la console :

    Exécution de cqi.groovy
    [4, 89, 291, 583, 832, 1526, 2230, 2366, 2378, 2666]
    Terminé: 29 ms
    

Glose

  • corpusEngine.id2Cpos("DISCOURS.word", ...) retourne les positions des occurrences du code numérique de l'index de la propriété 'word' dans le corpus DISCOURS
  • corpusEngine.id2Cpos(...)[0..9] retourne les 10 premières positions
  • La forme 'France' apparait en 5ième, 90ième, 292ième, etc. positions.

Afficher les formes correspondant à l'expression régulière "[Ff]ran[cç][aeio].*" dans le corpus DISCOURS

Il est possible d'interroger un lexique pour obtenir les codes numériques d'un ensemble de formes correspondant à un expression régulière.

Et il est bien sûr possible d'obtenir ensuite les valeurs de chaque code.

Nous allons maintenant afficher les formes du corpus DISCOURS correspondant à l'expression régulière ”[Ff]ran[cç][aeio].*”.

  1. Remplacer le code Groovy dans la fenêtre de l'éditeur avec les lignes suivantes :

    import org.txm.Toolbox
    
    def corpusEngine = Toolbox.getCqiClient()
    
    println corpusEngine.id2Str("DISCOURS.word", corpusEngine.regex2Id("DISCOURS.word", "[Ff]ran[cç][aeio].*"))
    
  2. Cliquer sur le bouton Exécuter le script (Control-F11) pour exécuter le nouveau script
  3. Les formes du corpus DISCOURS correspondant à l'expression régulière s'affichent dans la console

    Exécution de cqi.groovy
    [France, Français, Françaises, française, français, françaises, franco-allemand, franco-américaines, franco-américaine, franco-allemande, franco-marocains, franco-allemands, franco-britannique]
    Terminé: 28 ms
    

Glose

  • d'abord corpusEngine.regex2Id("DISCOURS.word", "[Ff]ran[cç][aeio].*") retourne les codes numériques des entrées correspondant à l'expression régulière ”[Ff]ran[cç][aeio].*” dans le lexique des formes (word) du corpus DISCOURS
  • ensuite corpusEngine.id2Str("DISCOURS.word"...) retourne les valeurs correspondant aux codes numériques du lexique des formes (word) du corpus DISCOURS

Accéder aux valeurs des propriétés de structures du corpus DISCOURS

Après avoir listé toutes les structures disponibles et leurs propriétés dans le corpus DISCOURS au début de ce tutoriel, nous allons maintenant lister les différentes valeurs possibles de la propriété 'type' de la structure 'text' (la structure 'text' codant les limites des discours de ce corpus, il s'agit donc d'une métadonnée).

  1. Remplacer le code Groovy dans la fenêtre de l'éditeur avec les lignes suivantes :

    import org.txm.Toolbox
    
    def corpusEngine = Toolbox.getCqiClient()
    
    println ((0..corpusEngine.attributeSize("DISCOURS.text_type")-1).collect { it ->
    	corpusEngine.struc2Str("DISCOURS.text_type", [it] as int[])[0]
    }.sort().unique())
    
  2. Cliquer sur le bouton Exécuter le script (Control-F11) pour exécuter le nouveau script
  3. Les différentes valeurs de la propriété 'type' de la structure 'text' du corpus DISCOURS s'affichent dans la console :

    Exécution de cqi.groovy
    [Allocution radiotélévisée, Conférence de presse, Entretien radiotélévisé]
    Terminé: 35 ms
    

Glose

  • l'expression 0..corpusEngine.attributeSize("DISCOURS.text_type")-1 déclare l'intervalle des entiers entre 0 et le nombre total (-1) de valeurs prises par la propriété 'type' de cette structure dans le corpus DISCOURS
  • .collect { it -> ... } retourne la liste de tous les résultats de l'application du calcul suivant pour chaque entier de cet intervalle
  • corpusEngine.struc2Str("DISCOURS.text_type", [it] as int[])[0] calcule la valeur prise par la propriété 'type' pour une entrée donnée
  • .sort().unique() retourne la liste alphabétiquement triée des différentes valeurs possibles

Exécuter une requête CQL sur le corpus DISCOURS et utiliser les résultats

Nous allons maintenant utiliser le moteur de recherche CQP pour rechercher toutes les séquences de la forme <lemme “je” suivi d'un verbe> et lister les 10 lemmes de verbes les plus fréquents dans cette position. Pour pouvoir ne lister que les verbes, nous les ciblons au sein de la requête avec l'opérateur '@'.

  1. Remplacer le code Groovy dans la fenêtre de l'éditeur avec les lignes suivantes :

    import org.txm.Toolbox
    
    byte CQI_CONST_FIELD_TARGET = (byte) 0x00
    
    def corpusEngine = Toolbox.getCqiClient()
    
    corpusEngine.cqpQuery("DISCOURS", "RES1", "'je' @[pos='V.*']")
    
    def matches_target_lemma = corpusEngine.cpos2Str("DISCOURS.lemma", corpusEngine.dumpSubCorpus("DISCOURS:RES1", CQI_CONST_FIELD_TARGET, 0, corpusEngine.subCorpusSize("DISCOURS:RES1")-1))
    
    println matches_target_lemma.countBy { it }.sort { -it.value }.take(10)
    
  2. Cliquer sur le bouton Exécuter le script (Control-F11) pour exécuter le nouveau script
  3. La liste des 10 lemmes les plus fréquents s'affiche dans la console

    Exécution de cqi.groovy
    [croire:36, vouloir:25, être:22, pouvoir:18, dire:13, aller:11, parler:8, devoir:7, faire:5, penser:5]
    Terminé: 61 ms
    

Glose

  • la ligne byte CQI_CONST_FIELD_TARGET = (byte) 0x00 déclare un nouveau type de donnée CQi pour accéder aux positions d'occurrences ciblées (elle ne sera plus utile à partir de TXM 0.7.8)
  • la ligne corpusEngine.cqpQuery("DISCOURS", "RES1", "'je' @[pos='V.*']") appelle le moteur de recherche CQP pour rechercher la requête <'je' @[pos='V.*']> dans le corpus DISCOURS en sauvegardant le résultat dans le sous-corpus RES1
    • dans la requête, l'opérateur '@' sert à cibler la position du verbe dans les résultats
  • la ligne def matches_target_lemma = corpusEngine.cpos2Str("DISCOURS.lemma", corpusEngine.dumpSubCorpus("DISCOURS:RES1", CQI_CONST_FIELD_TARGET, 0, corpusEngine.subCorpusSize("DISCOURS:RES1")-1)) calcule la liste des lemmes correspondant aux positions ciblées dans les résultats
    • corpusEngine.dumpSubCorpus("DISCOURS:RES1", CQI_CONST_FIELD_TARGET, 0, corpusEngine.subCorpusSize("DISCOURS:RES1")-1)) récupère les positions ciblées dans le résultat RES1
    • corpusEngine.cpos2Str("DISCOURS.lemma", ...) récupère les lemmes des positions retournées
  • la ligne println matches_target_lemma.countBy { it }.sort { -it.value }.take(10) compte les lemmes, les trie par fréquence décroissante et ne garde que les 10 premiers
    • .countBy { it } compte les lemmes
    • .sort { -it.value } trie les lemmes par fréquence décroissante
    • .take(10) ne garde que les 10 premiers

Afficher les longueurs de phrases du corpus DISCOURS

Afficher le nombre de phrases du corpus DISCOURS

Nous allons d'abord vérifier le nombre de phrases du corpus DISCOURS, c'est à dire le nombre de structures 's'.

  1. Mettre à jour le code Groovy dans la fenêtre de l'éditeur avec les lignes suivantes :

    import org.txm.Toolbox
    
    def corpusEngine = Toolbox.getCqiClient()
    
    printf("Nombre de phrases du corpus DISCOURS = %d\n", corpusEngine.attributeSize("DISCOURS.s"))
    
  2. Cliquer sur le bouton Exécuter le script (Control-F11) pour exécuter le nouveau script
  3. Le nombre de structures 's' du corpus DISCOURS s'affiche dans la console

    Exécution de cqi.groovy
    Nombre de phrases du corpus DISCOURS = 3427
    Terminé: 23 ms
    

Glose

  • le nombre de phrases est obtenu par le calcul de la taille de l'index de l'attribut de structure 's' du corpus DISCOURS dont le nom global CQi est DISCOURS.s avec la méthode attributeSize
  • la méthode 'printf' permet de formater la ligne affichée (alors que la méthode 'print' se contente d'afficher son argument). Le premier argument définit le format où '%d' demande l'affichage d'un entier (le nombre de phrases calculé dans le second argument) et '\n' demande un saut de ligne (à la fin de la ligne)

Afficher les longueurs de phrases

Nous allons maintenant afficher le nombre de mots par phrase.

  1. Mettre à jour le code Groovy dans la fenêtre de l'éditeur avec les lignes suivantes :

    import org.txm.Toolbox
    
    def corpusEngine = Toolbox.getCqiClient()
    
    printf("start\tend\tlength\n")
    
    for (i in 0..corpusEngine.attributeSize("DISCOURS.s")-1) {
    
     (start, end) = corpusEngine.struc2Cpos("DISCOURS.s", i)
    
     printf("%d\t%d\t%d\n", start, end, end-start+1)
    
    }
    
  2. Cliquer sur le bouton Exécuter le script (Control-F11) pour exécuter le nouveau script
  3. Les positions et longueurs des phrases s'affichent dans la console

    Exécution de cqi.groovy
    start	end	length
    0	13	14
    14	16	3
    17	23	7
    24	35	12
    36	50	15
    51	58	8
    59	78	20
    79	97	19
    98	105	8
    ...
    104983	104988	6
    104989	105001	13
    105002	105106	105
    105107	105118	12
    105119	105156	38
    105157	105182	26
    105183	105190	8
    Terminé: 176 ms
    

Glose

  • la ligne printf("start\tend\tlength\n") affiche la ligne suivante (le code '\t' correspond à la tabulation, voir le Formateur Java) :
    start	end	length
    
  • la ligne for (i in 0..corpusEngine.attributeSize("DISCOURS.s")-1) { commence une boucle de 0 au nombre de structures 's' du corpus DISCOURS moins 1. c'est-à-dire qu'elle va itérer autant de fois qu'il y a de phrases. Le numéro d'itération sera stocké dans la variable i, qui prendra donc successivement les valeurs 0, 1, 2, etc.
  • la position du premier mot (start) et du dernier mot (end) de chaque phrase sont obtenus avec la méthode struc2Cpos et stockées dans les variables start et end
  • la longueur de la phrase est calculée en soustrayant la position du dernier mot de la phrase avec celle du premier et en ajoutant 1 (ce qui correspond au calcul end-start+1)

Accéder aux index d'alignement du corpus UNO

à faire

public/tutoriel_cqi.txt · Dernière modification: 2017/11/09 20:21 par slh@ens-lyon.fr