Guía de analizadores Lucene

1. Información general

Los analizadores Lucene se utilizan para analizar texto al indexar y buscar documentos.

Mencionamos brevemente los analizadores en nuestro tutorial introductorio.

En este tutorial, discutiremos los analizadores de uso común, cómo construir nuestro analizador personalizado y cómo asignar diferentes analizadores para diferentes campos de documentos .

2. Dependencias de Maven

Primero, necesitamos agregar estas dependencias a nuestro 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 última versión de Lucene se puede encontrar aquí.

3. Analizador de Lucene

Los analizadores de Lucene dividen el texto en tokens.

Los analizadores consisten principalmente en tokenizadores y filtros. Los diferentes analizadores constan de diferentes combinaciones de tokenizadores y filtros.

Para demostrar la diferencia entre los analizadores de uso común, usaremos este método siguiente:

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

Este método convierte un texto dado en una lista de tokens usando el analizador dado.

4. Analizadores de Lucene comunes

Ahora, echemos un vistazo a algunos analizadores Lucene de uso común.

4.1. Analizador estándar

Comenzaremos con StandardAnalyzer, que es el analizador más utilizado:

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

Tenga en cuenta que StandardAnalyzer puede reconocer URL y correos electrónicos.

Además, elimina las palabras vacías y pone en minúsculas los tokens generados.

4.2. StopAnalyzer

El StopAnalyzer consiste en LetterTokenizer, LowerCaseFilter y StopFilter:

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

En este ejemplo, LetterTokenizer divide el texto por caracteres que no son letras, mientras que StopFilter elimina las palabras vacías de la lista de símbolos .

Sin embargo, a diferencia de StandardAnalyzer , StopAnalyzer no puede reconocer las URL.

4.3. SimpleAnalyzer

SimpleAnalyzer consta de LetterTokenizer y 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")); }

Aquí, SimpleAnalyzer no eliminó las palabras vacías . Tampoco reconoce las URL.

4.4. Analizador de espacios en blanco

El WhitespaceAnalyzer usa solo un WhitespaceTokenizer que divide el texto por caracteres de espacio en blanco:

@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

El KeywordAnalyzer tokenizes de entrada en un único 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")); }

El KeywordAnalyzer es útil para campos como los identificadores y códigos postales.

4.6. Analizadores de idiomas

También hay analizadores especiales para diferentes idiomas como EnglishAnalyzer , FrenchAnalyzer y SpanishAnalyzer :

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

En este caso, estamos usando la EnglishAnalyzer que consiste en StandardTokenizer , StandardFilter , EnglishPossessiveFilter , LowerCaseFilter , StopFilter y PorterStemFilter .

5. Analizador personalizado

A continuación, veamos cómo construir nuestro analizador personalizado. Construiremos el mismo analizador personalizado de dos formas diferentes.

En el primer ejemplo, usaremos el constructor CustomAnalyzer para construir nuestro analizador a partir de tokenizadores y filtros predefinidos :

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

Nuestro analizador es muy similar a EnglishAnalyzer , pero en su lugar, capitaliza los tokens.

En el segundo ejemplo, crearemos el mismo analizador ampliando la clase abstracta Analyzer y anulando el método 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); } }

También podemos crear nuestro tokenizador o filtro personalizado y agregarlo a nuestro analizador personalizado si es necesario.

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.

El código fuente completo se puede encontrar en GitHub.