78 votes

Comment obtenir un Token à partir d'un TokenStream Lucene ?

J'essaie d'utiliser Apache Lucene pour la tokénisation, et je suis dérouté par le processus permettant d'obtenir des tokens à partir d'un fichier TokenStream .

Le pire, c'est que je regarde les commentaires dans les JavaDocs qui répondent à ma question.

http://lucene.apache.org/java/3_0_1/api/core/org/apache/lucene/analysis/TokenStream.html#incrementToken%28%29

D'une manière ou d'une autre, une AttributeSource est censé être utilisé, plutôt que Token s. Je suis totalement perdue.

Quelqu'un peut-il expliquer comment obtenir des informations de type jeton à partir d'un TokenStream ?

120voto

Adam Paynter Points 22056

Oui, c'est un peu compliqué (comparé à la bonne vieille méthode), mais ça devrait le faire :

TokenStream tokenStream = analyzer.tokenStream(fieldName, reader);
OffsetAttribute offsetAttribute = tokenStream.getAttribute(OffsetAttribute.class);
TermAttribute termAttribute = tokenStream.getAttribute(TermAttribute.class);

while (tokenStream.incrementToken()) {
    int startOffset = offsetAttribute.startOffset();
    int endOffset = offsetAttribute.endOffset();
    String term = termAttribute.term();
}

Edit : Le nouveau chemin

Selon Donotello, TermAttribute a été déprécié au profit de CharTermAttribute . Selon jpountz (et la documentation de Lucene), addAttribute est plus souhaitable que getAttribute .

TokenStream tokenStream = analyzer.tokenStream(fieldName, reader);
OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);

tokenStream.reset();
while (tokenStream.incrementToken()) {
    int startOffset = offsetAttribute.startOffset();
    int endOffset = offsetAttribute.endOffset();
    String term = charTermAttribute.toString();
}

6 votes

Maintenant, TermAttribute est déprécarisé. Comme je peux le voir, nous pouvons utiliser quelque chose comme CharTermAttributeImpl.toString() au lieu de

6 votes

Vous devez utiliser addAttribute plutôt que getAttribute. Extrait de la javadocs de lucene : "Il est recommandé de toujours utiliser addAttribute(java.lang.Class) même dans les consommateurs de TokenStreams, car vous ne pouvez pas savoir si un TokenStream spécifique utilise réellement un Attribut spécifique" lucene.apache.org/core/old_versioned_docs/versions/3_5_0/api/

1 votes

@jpountz : Merci pour le conseil ! J'ai modifié la réponse en conséquence.

43voto

yegor256 Points 21737

C'est comme ça que ça devrait être (une version propre de la réponse d'Adam) :

TokenStream stream = analyzer.tokenStream(null, new StringReader(text));
CharTermAttribute cattr = stream.addAttribute(CharTermAttribute.class);
stream.reset();
while (stream.incrementToken()) {
  System.out.println(cattr.toString());
}
stream.end();
stream.close();

10 votes

Votre code ne fonctionnait pas correctement jusqu'à ce que j'ajoute un stream.reset() avant la boucle while. J'utilise Lucene 4.0, il se peut donc que ce soit une modification récente. Reportez-vous à l'exemple en bas de cette page : lucene.apache.org/core/4_0_0-BETA/core/org/apache/lucene/

0 votes

J'ai essayé d'éditer pour ajouter l'appel reset(), qui évite un NPE dans Lucene à incrementToken(), mais tous les pairs sauf un ont rejeté l'édition comme incorrecte. La documentation de Lucene indique explicitement que "Le consommateur appelle reset()" avant "Le consommateur appelle incrementToken()" dans le fichier API TokenStream

0 votes

J'ai aussi dû appeler reset() avec Lucene 4.3 donc j'ai pris la liberté de l'ajouter

4voto

Flamingo Points 1107

Pour la dernière version de lucene 7.3.1

    // Test the tokenizer
    Analyzer testAnalyzer = new CJKAnalyzer();
    String testText = "Test Tokenizer";
    TokenStream ts = testAnalyzer.tokenStream("context", new StringReader(testText));
    OffsetAttribute offsetAtt = ts.addAttribute(OffsetAttribute.class);
    try {
        ts.reset(); // Resets this stream to the beginning. (Required)
        while (ts.incrementToken()) {
            // Use AttributeSource.reflectAsString(boolean)
            // for token stream debugging.
            System.out.println("token: " + ts.reflectAsString(true));

            System.out.println("token start offset: " + offsetAtt.startOffset());
            System.out.println("  token end offset: " + offsetAtt.endOffset());
        }
        ts.end();   // Perform end-of-stream operations, e.g. set the final offset.
    } finally {
        ts.close(); // Release resources associated with this stream.
    }

Référence : https://lucene.apache.org/core/7_3_1/core/org/apache/lucene/analysis/package-summary.html

1voto

William Price Points 1324

Il y a deux variantes dans la question du PO :

  1. Qu'est-ce que "le processus d'obtention de jetons à partir d'un TokenStream" ?
  2. "Quelqu'un peut-il expliquer comment obtenir des informations de type jeton à partir d'un TokenStream ?"

Les versions récentes de l Documentation de Lucene pour Token disent (c'est nous qui soulignons) :

REMARQUE : Depuis la version 2.9 ... il est pas nécessaire Il n'est plus nécessaire d'utiliser Token, avec la nouvelle API TokenStream, elle peut être utilisée comme classe de commodité qui implémente tous les attributs, ce qui est particulièrement utile pour passer facilement de l'ancienne à la nouvelle API TokenStream.

Et TokenStream dit son API :

... est passé d'un système basé sur des jetons à un système basé sur des attributs ... la meilleure façon de stocker les informations d'un jeton est d'utiliser des AttributeImpls.

Les autres réponses à cette question couvrent le point 2 ci-dessus : comment obtenir de type jeton des informations provenant d'un TokenStream de la "nouvelle" manière recommandée en utilisant des attributs. En lisant la documentation, les développeurs de Lucene suggèrent que ce changement a été effectué, en partie, pour réduire le nombre d'objets individuels créés à la fois.

Mais comme certaines personnes l'ont fait remarquer dans les commentaires de ces réponses, elles ne répondent pas directement à la question n° 1 : comment obtenir une Token si vous avez vraiment envie/besoin de ce type ?

Avec le même changement d'API qui rend TokenStream un AttributeSource , Token met désormais en œuvre Attribute et peut être utilisé avec TokenStream.addAttribute tout comme les autres réponses montrent pour CharTermAttribute et OffsetAttribute . Ils ont donc bien répondu à cette partie de la question initiale, mais ils ne l'ont pas montrée.

Il est important que, bien que cette approche vous permette d'accéder à Token pendant que vous bouclez, il ne s'agit toujours que d'un seul objet, quel que soit le nombre de jetons logiques dans le flux. Chaque appel à incrementToken() changera l'état de la Token renvoyé par addAttribute Donc si votre but est de construire une collection de différentes Token à utiliser en dehors de la boucle, vous devrez effectuer un travail supplémentaire pour créer un objet de type nouveau Token comme une copie (profonde ?).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X