Guide des analyseurs Lucene

1. Vue d'ensemble

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

Nous avons brièvement mentionné les analyseurs dans notre tutoriel d'introduction.

Dans ce didacticiel, nous aborderons les analyseurs couramment utilisés, comment construire notre analyseur personnalisé et comment attribuer différents analyseurs pour différents champs de document .

2. Dépendances de Maven

Tout d'abord, nous devons ajouter ces dépendances à notre pom.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ée ici.

3. Lucene Analyzer

Les analyseurs Lucene ont divisé le texte en jetons.

Les analyseurs se composent principalement de jetons et de filtres. Différents analyseurs se composent 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 communs

Maintenant, jetons un coup d'œil à quelques analyseurs Lucene couramment utilisés.

4.1. Analyseur standard

Nous allons commencer par le StandardAnalyzer qui est l'analyseur le plus couramment utilisé:

private static final String SAMPLE_TEXT = "This is baeldung.com Lucene Analyzers test"; @Test public void whenUseStandardAnalyzer_thenAnalyzed() throws IOException { List result = analyze(SAMPLE_TEXT, new StandardAnalyzer()); assertThat(result, contains("baeldung.com", "lucene", "analyzers","test")); }

Notez que StandardAnalyzer peut reconnaître les URL et les e-mails.

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

4.2. StopAnalyzer

Le StopAnalyzer se compose de LetterTokenizer, LowerCaseFilter et StopFilter:

@Test public void whenUseStopAnalyzer_thenAnalyzed() throws IOException { List result = analyze(SAMPLE_TEXT, new StopAnalyzer()); assertThat(result, contains("baeldung", "com", "lucene", "analyzers", "test")); }

Dans cet exemple, le LetterTokenizer divise le texte par des caractères autres que des lettres , tandis que le StopFilter supprime les mots vides de la liste de jetons.

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

4.3. SimpleAnalyzer

SimpleAnalyzer se compose de LetterTokenizer et d'un LowerCaseFilter :

@Test public void whenUseSimpleAnalyzer_thenAnalyzed() throws IOException { List result = analyze(SAMPLE_TEXT, new SimpleAnalyzer()); assertThat(result, contains("this", "is", "baeldung", "com", "lucene", "analyzers", "test")); }

Ici, SimpleAnalyzer n'a pas supprimé les mots vides . Il ne reconnaît pas non plus les URL.

4.4. WhitespaceAnalyzer

Le WhitespaceAnalyzer utilise uniquement un WhitespaceTokenizer 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", "baeldung.com", "Lucene", "Analyzers", "test")); }

4.5. KeywordAnalyzer

Le KeywordAnalyzer tokenizes entrée en un seul jeton:

@Test public void whenUseKeywordAnalyzer_thenAnalyzed() throws IOException { List result = analyze(SAMPLE_TEXT, new KeywordAnalyzer()); assertThat(result, contains("This is baeldung.com Lucene Analyzers test")); }

Le KeywordAnalyzer est utile pour les champs tels que les identifiants et les codes postaux.

4.6. Analyseurs de langues

Il existe également des analyseurs spéciaux pour différentes langues comme EnglishAnalyzer , FrenchAnalyzer et SpanishAnalyzer :

@Test public void whenUseEnglishAnalyzer_thenAnalyzed() throws IOException { List result = analyze(SAMPLE_TEXT, new EnglishAnalyzer()); assertThat(result, contains("baeldung.com", "lucen", "analyz", "test")); }

Ici, nous utilisons la EnglishAnalyzer qui consiste StandardTokenizer , StandardFilter , EnglishPossessiveFilter , LowerCaseFilter , StopFilter et PorterStemFilter .

5. Analyseur personnalisé

Ensuite, voyons 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, nous utiliserons le générateur CustomAnalyzer pour construire notre analyseur à partir de tokenizers et de filtres prédéfinis :

@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("Baeldung.com", "Lucen", "Analyz", "Test")); }

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

Dans le deuxième exemple, nous allons créer le même analyseur en étendant la classe abstraite Analyzer et en remplaçant la méthode createComponents () :

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 tokenizer ou filtre personnalisé et l'ajouter à notre analyseur personnalisé si nécessaire.

Now, let's see our custom analyzer in action – we'll use InMemoryLuceneIndex in this example:

@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

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

First, we need to define our analyzerMap to map each analyzer to a specific field:

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

We mapped the “title” to our custom analyzer and the “body” to the EnglishAnalyzer.

Next, let's create our PerFieldAnalyzerWrapper by providing the analyzerMap and a default Analyzer:

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

Now, let's test it:

@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

We discussed popular Lucene Analyzers, how to build a custom analyzer and how to use a different analyzer per field.

Le code source complet peut être trouvé sur GitHub.