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.