Leitfaden für Lucene-Analysatoren

1. Übersicht

Lucene Analyzer werden zum Analysieren von Text beim Indizieren und Durchsuchen von Dokumenten verwendet.

In unserem Einführungs-Tutorial haben wir Analysatoren kurz erwähnt.

In diesem Tutorial werden häufig verwendete Analysatoren erläutert, wie Sie unseren benutzerdefinierten Analysator erstellen und wie Sie verschiedene Analysatoren für verschiedene Dokumentfelder zuweisen .

2. Maven-Abhängigkeiten

Zuerst müssen wir diese Abhängigkeiten zu unserer pom.xml hinzufügen :

 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 

Die neueste Lucene-Version finden Sie hier.

3. Lucene Analyzer

Lucene Analyzer teilen den Text in Token auf.

Analysatoren bestehen hauptsächlich aus Tokenisierern und Filtern. Verschiedene Analysatoren bestehen aus verschiedenen Kombinationen von Tokenisierern und Filtern.

Um den Unterschied zwischen häufig verwendeten Analysegeräten zu demonstrieren, verwenden wir die folgende Methode:

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; }

Diese Methode konvertiert einen bestimmten Text mit dem angegebenen Analysator in eine Liste von Token.

4. Gemeinsame Lucene-Analysatoren

Schauen wir uns nun einige häufig verwendete Lucene-Analysegeräte an.

4.1. StandardAnalyzer

Wir beginnen mit dem StandardAnalyzer , dem am häufigsten verwendeten Analysator:

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")); }

Beachten Sie, dass der StandardAnalyzer URLs und E-Mails erkennen kann.

Außerdem werden Stoppwörter entfernt und die generierten Token in Kleinbuchstaben geschrieben.

4.2. StopAnalyzer

Der StopAnalyzer besteht aus LetterTokenizer, LowerCaseFilter und StopFilter:

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

In diesem Beispiel teilt der LetterTokenizer Text durch Nicht-Buchstaben-Zeichen, während der StopFilter Stoppwörter aus der Token-Liste entfernt.

Im Gegensatz zum StandardAnalyzer kann StopAnalyzer jedoch keine URLs erkennen.

4.3. SimpleAnalyzer

SimpleAnalyzer besteht aus LetterTokenizer und einem 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")); }

Hier hat der SimpleAnalyzer keine Stoppwörter entfernt. Es erkennt auch keine URLs.

4.4. WhitespaceAnalyzer

Der WhitespaceAnalyzer verwendet nur einen WhitespaceTokenizer, der Text durch Whitespace-Zeichen aufteilt:

@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

Der KeywordAnalyzer tokenisiert die Eingabe in ein einzelnes Token:

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

Der KeywordAnalyzer ist nützlich für Felder wie IDs und Postleitzahlen.

4.6. Sprachanalysatoren

Es gibt auch spezielle Analysatoren für verschiedene Sprachen wie EnglishAnalyzer , FrenchAnalyzer und SpanishAnalyzer :

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

Hier verwenden wir den EnglishAnalyzer, der aus StandardTokenizer , StandardFilter , EnglishPossessiveFilter , LowerCaseFilter , StopFilter und PorterStemFilter besteht .

5. Benutzerdefinierter Analysator

Als nächstes wollen wir sehen, wie wir unseren benutzerdefinierten Analysator erstellen. Wir werden denselben benutzerdefinierten Analysator auf zwei verschiedene Arten erstellen.

Im ersten Beispiel verwenden wir den CustomAnalyzer- Builder, um unseren Analysator aus vordefinierten Tokenisierern und Filtern zu erstellen :

@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")); }

Unser Analysator ist EnglishAnalyzer sehr ähnlich , aktiviert jedoch stattdessen die Token.

Im zweiten Beispiel erstellen wir denselben Analyzer, indem wir die abstrakte Analyzer- Klasse erweitern und die Methode createComponents () überschreiben :

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); } }

Wir können auch unseren benutzerdefinierten Tokenizer oder Filter erstellen und ihn bei Bedarf unserem benutzerdefinierten Analysator hinzufügen.

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.

Den vollständigen Quellcode finden Sie auf GitHub.