Guide des analyseurs Lucene

Guide des analyseurs Lucene

1. Vue d'ensemble

Les analyseurs Lucene sont utilisés pour analyser du texte lors de l'indexation et de la recherche de documents.

Nous avons brièvement mentionné les analyseurs dans nosintroductory tutorial.

Dans ce didacticiel,we’ll discuss commonly used Analyzers, how to construct our custom analyzer and how to assign different analyzers for different document fields.

2. Dépendances Maven

Tout d'abord, nous devons ajouter ces dépendances à nospom.xml:


    org.apache.lucene
    lucene-core
    7.4.0


    org.apache.lucene
    lucene-queryparser
    7.4.0


    org.apache.lucene
    lucene-analyzers-common
    7.4.0

La dernière version de Lucene peut être trouvéehere.

3. Analyseur Lucene

Lucene Analyzers divise le texte en jetons.

Analyzers mainly consist of tokenizers and filters. Différents analyseurs sont constitués de différentes combinaisons de jetons et de filtres.

Pour démontrer la différence entre les analyseurs couramment utilisés, nous utiliserons la méthode suivante:

public List analyze(String text, Analyzer analyzer) throws IOException{
    List result = new ArrayList();
    TokenStream tokenStream = analyzer.tokenStream(FIELD_NAME, text);
    CharTermAttribute attr = tokenStream.addAttribute(CharTermAttribute.class);
    tokenStream.reset();
    while(tokenStream.incrementToken()) {
       result.add(attr.toString());
    }
    return result;
}

Cette méthode convertit un texte donné en une liste de jetons à l'aide de l'analyseur donné.

4. Analyseurs Lucene courants

Voyons maintenant quelques analyseurs Lucene couramment utilisés.

4.1. StandardAnalyzer

Nous allons commencer par leStandardAnalyzer qui est l’analyseur le plus couramment utilisé:

private static final String SAMPLE_TEXT
  = "This is example.com Lucene Analyzers test";

@Test
public void whenUseStandardAnalyzer_thenAnalyzed() throws IOException {
    List result = analyze(SAMPLE_TEXT, new StandardAnalyzer());

    assertThat(result,
      contains("example.com", "lucene", "analyzers","test"));
}

Notez que lesStandardAnalyzer peuvent reconnaître les URL et les e-mails.

En outre, il supprime les mots vides et les minuscules des jetons générés.

4.2. StopAnalyzer

LeStopAnalyzer se compose deLetterTokenizer, LowerCaseFilter etStopFilter:

@Test
public void whenUseStopAnalyzer_thenAnalyzed() throws IOException {
    List result = analyze(SAMPLE_TEXT, new StopAnalyzer());

    assertThat(result,
      contains("example", "com", "lucene", "analyzers", "test"));
}

Dans cet exemple,LetterTokenizer splits le texte par des caractères non alphabétiques, tandis queStopFilter supprime les mots vides de la liste de jetons.

Cependant, contrairement auxStandardAnalyzer,StopAnalyzer n'est pas capable de reconnaître les URL.

4.3. SimpleAnalyzer

SimpleAnalyzer se compose deLetterTokenizer et d'unLowerCaseFilter:

@Test
public void whenUseSimpleAnalyzer_thenAnalyzed() throws IOException {
    List result = analyze(SAMPLE_TEXT, new SimpleAnalyzer());

    assertThat(result,
      contains("this", "is", "example", "com", "lucene", "analyzers", "test"));
}

Ici, lesSimpleAnalyzern'ont pas supprimé les mots vides. Il ne reconnaît pas non plus les URL.

4.4. WhitespaceAnalyzer

LeWhitespaceAnalyzer utilise uniquement unWhitespaceTokenizer qui divise le texte par des espaces:

@Test
public void whenUseWhiteSpaceAnalyzer_thenAnalyzed() throws IOException {
    List result = analyze(SAMPLE_TEXT, new WhitespaceAnalyzer());

    assertThat(result,
      contains("This", "is", "example.com", "Lucene", "Analyzers", "test"));
}

4.5. KeywordAnalyzer

LeKeywordAnalyzer tokenise l'entrée en un seul token:

@Test
public void whenUseKeywordAnalyzer_thenAnalyzed() throws IOException {
    List result = analyze(SAMPLE_TEXT, new KeywordAnalyzer());

    assertThat(result, contains("This is example.com Lucene Analyzers test"));
}

LeKeywordAnalyzer  est utile pour les champs comme les identifiants et les codes postaux.

4.6. Analyseurs de langues

Il existe également des analyseurs spéciaux pour différents langages tels queEnglishAnalyzer,FrenchAnalyzer etSpanishAnalyzer:

@Test
public void whenUseEnglishAnalyzer_thenAnalyzed() throws IOException {
    List result = analyze(SAMPLE_TEXT, new EnglishAnalyzer());

    assertThat(result, contains("example.com", "lucen", "analyz", "test"));
}

Ici, nous utilisons lesEnglishAnalyzer qui se composent deStandardTokenizer,StandardFilter,EnglishPossessiveFilter,LowerCaseFilter,StopFilter etPorterStemFilter.

5. Analyseur personnalisé

Voyons ensuite comment créer notre analyseur personnalisé. Nous allons créer le même analyseur personnalisé de deux manières différentes.

Dans le premier exemple,we’ll use the CustomAnalyzer builder to construct our analyzer from predefined tokenizers and filters:

@Test
public void whenUseCustomAnalyzerBuilder_thenAnalyzed() throws IOException {
    Analyzer analyzer = CustomAnalyzer.builder()
      .withTokenizer("standard")
      .addTokenFilter("lowercase")
      .addTokenFilter("stop")
      .addTokenFilter("porterstem")
      .addTokenFilter("capitalization")
      .build();
    List result = analyze(SAMPLE_TEXT, analyzer);

    assertThat(result, contains("example.com", "Lucen", "Analyz", "Test"));
}

Notre analyseur est très similaire àEnglishAnalyzer, mais il capitalise les jetons à la place.

Dans le deuxième exemple,we’ll build the same analyzer by extending the Analyzer abstract class and overriding the createComponents() method:

public class MyCustomAnalyzer extends Analyzer {

    @Override
    protected TokenStreamComponents createComponents(String fieldName) {
        StandardTokenizer src = new StandardTokenizer();
        TokenStream result = new StandardFilter(src);
        result = new LowerCaseFilter(result);
        result = new StopFilter(result,  StandardAnalyzer.STOP_WORDS_SET);
        result = new PorterStemFilter(result);
        result = new CapitalizationFilter(result);
        return new TokenStreamComponents(src, result);
    }
}

Nous pouvons également créer notre filtre ou notre tokenizer personnalisé et l'ajouter à notre analyseur personnalisé si nécessaire.

Voyons maintenant notre analyseur personnalisé en action - nous utiliseronsInMemoryLuceneIndex dans cet exemple:

@Test
public void givenTermQuery_whenUseCustomAnalyzer_thenCorrect() {
    InMemoryLuceneIndex luceneIndex = new InMemoryLuceneIndex(
      new RAMDirectory(), new MyCustomAnalyzer());
    luceneIndex.indexDocument("introduction", "introduction to lucene");
    luceneIndex.indexDocument("analyzers", "guide to lucene analyzers");
    Query query = new TermQuery(new Term("body", "Introduct"));

    List documents = luceneIndex.searchIndex(query);
    assertEquals(1, documents.size());
}

6. PerFieldAnalyzerWrapper

Enfin,we can assign different analyzers to different fields using PerFieldAnalyzerWrapper.

Tout d'abord, nous devons définir nosanalyzerMap pour mapper chaque analyseur à un champ spécifique:

Map analyzerMap = new HashMap<>();
analyzerMap.put("title", new MyCustomAnalyzer());
analyzerMap.put("body", new EnglishAnalyzer());

Nous avons mappé le "titre" de notre analyseur personnalisé et le "corps" de l'AnglaisAnalyzer.

Ensuite, créons nosPerFieldAnalyzerWrapper en fournissant lesanalyzerMap et unAnalyzer par défaut:

PerFieldAnalyzerWrapper wrapper = new PerFieldAnalyzerWrapper(
  new StandardAnalyzer(), analyzerMap);

Maintenant, testons-le:

@Test
public void givenTermQuery_whenUsePerFieldAnalyzerWrapper_thenCorrect() {
    InMemoryLuceneIndex luceneIndex = new InMemoryLuceneIndex(new RAMDirectory(), wrapper);
    luceneIndex.indexDocument("introduction", "introduction to lucene");
    luceneIndex.indexDocument("analyzers", "guide to lucene analyzers");

    Query query = new TermQuery(new Term("body", "introduct"));
    List documents = luceneIndex.searchIndex(query);
    assertEquals(1, documents.size());

    query = new TermQuery(new Term("title", "Introduct"));
    documents = luceneIndex.searchIndex(query);
    assertEquals(1, documents.size());
}

7. Conclusion

Nous avons discuté des analyseurs Lucene populaires, de la création d’un analyseur personnalisé et de l’utilisation d’un analyseur différent par champ.

Le code source complet peut êtrefound on GitHub.