Guia para analisadores Lucene

Guia para analisadores Lucene

1. Visão geral

Os Analisadores Lucene são usados ​​para analisar texto enquanto indexa e pesquisa documentos.

Mencionamos os analisadores brevemente em nossointroductory tutorial.

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

2. Dependências do Maven

Primeiro, precisamos adicionar essas dependências ao nossopom.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

A versão mais recente do Lucene pode ser encontradahere.

3. Lucene Analyzer

Os Analisadores Lucene dividem o texto em tokens.

Analyzers mainly consist of tokenizers and filters. Analisadores diferentes consistem em combinações diferentes de tokenizers e filtros.

Para demonstrar a diferença entre os analisadores comumente usados, usaremos o seguinte método:

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 converte um determinado texto em uma lista de tokens usando o analisador fornecido.

4. Analisadores Lucene Comuns

Agora, vamos dar uma olhada em alguns analisadores Lucene comumente usados.

4.1. StandardAnalyzer

Começaremos comStandardAnalyzer, que é o analisador mais comumente usado:

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

Observe queStandardAnalyzer pode reconhecer URLs e e-mails.

Além disso, remove palavras de parada e minúsculas os tokens gerados.

4.2. StopAnalyzer

OStopAnalyzer consiste emLetterTokenizer, LowerCaseFilter eStopFilter:

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

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

Neste exemplo,LetterTokenizer s divide o texto por caracteres que não sejam letras, enquantoStopFilter remove palavras de parada da lista de tokens.

No entanto, ao contrário deStandardAnalyzer,StopAnalyzer não é capaz de reconhecer URLs.

4.3. SimpleAnalyzer

SimpleAnalyzer consiste emLetterTokenizer e aLowerCaseFilter:

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

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

Aqui, oSimpleAnalyzer não removeu as palavras de parada. Ele também não reconhece URLs.

4.4. WhitespaceAnalyzer

OWhitespaceAnalyzer usa apenas umWhitespaceTokenizer que divide o texto por caracteres de espaço em branco:

@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

OKeywordAnalyzer tokeniza a entrada em um único 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"));
}

OKeywordAnalyzer  é útil para campos como ids e códigos postais.

4.6. Analisadores de linguagem

Existem também analisadores especiais para diferentes idiomas, comoEnglishAnalyzer,FrenchAnalyzer eSpanishAnalyzer:

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

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

Aqui, estamos usandoEnglishAnalyzer, que consiste emStandardTokenizer,StandardFilter,EnglishPossessiveFilter,LowerCaseFilter,StopFilter ePorterStemFilter.

5. Analisador Personalizado

A seguir, vamos ver como construir nosso analisador personalizado. Vamos construir o mesmo analisador personalizado de duas maneiras diferentes.

No primeiro exemplo,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"));
}

Nosso analisador é muito semelhante aEnglishAnalyzer, mas em vez disso, ele coloca os tokens em maiúscula.

No segundo exemplo,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);
    }
}

Também podemos criar nosso tokenizador ou filtro personalizado e adicioná-lo ao nosso analisador personalizado, se necessário.

Agora, vamos ver nosso analisador personalizado em ação - usaremosInMemoryLuceneIndex neste exemplo:

@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

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

Primeiro, precisamos definir nossoanalyzerMap para mapear cada analisador para um campo específico:

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

Mapeamos o “título” para o nosso analisador personalizado e o “corpo” para o EnglishAnalyzer.

A seguir, vamos criar nossoPerFieldAnalyzerWrapper fornecendoanalyzerMape umAnalyzer padrão:

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

Agora, vamos testar:

@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. Conclusão

Discutimos os populares Analisadores Lucene, como construir um analisador personalizado e como usar um analisador diferente por campo.

O código-fonte completo pode serfound on GitHub.