Introdução ao Lucene

Introdução ao Lucene
Nesta lição, entenderemos o funcionamento por trás de um dos mecanismos de pesquisa de texto completo mais poderosos, Apache Lucene. Com o Apache Lucene, podemos usar as APIs que ela expõe em muitas linguagens de programação e cria os recursos de que precisamos. Lucene é um dos mecanismos mais poderosos no qual o Elasticsearch é construído em. Antes de começarmos com um aplicativo que demonstra o funcionamento do Apache Lucene, entenderemos como o Lucene funciona e muitos de seus componentes. Vamos começar.

Por que o Lucene é necessário?

A pesquisa é uma das operações mais comuns que realizamos várias vezes ao dia. Esta pesquisa pode ser em várias páginas da web que existem na web ou em um aplicativo de música ou em um repositório de código ou uma combinação de todos esses. Pode -se pensar que um simples banco de dados relacional também pode suportar a pesquisa. Isto está certo. Bancos de dados como o MySQL suportam pesquisa de texto completo. Mas e quanto à web ou aplicativo de música ou repositório de código ou uma combinação de todos esses? O banco de dados não pode armazenar esses dados em suas colunas. Mesmo se isso aconteceu, levará uma quantidade inaceitável de tempo para executar a pesquisa neste grande.

Um mecanismo de pesquisa em texto completo é capaz de executar uma consulta de pesquisa em milhões de arquivos de uma só vez. A velocidade na qual os dados estão sendo armazenados em um aplicativo hoje é enorme. Executar a pesquisa de texto completo nesse tipo de volume de dados é uma tarefa difícil. Isso ocorre porque as informações necessárias podem existir em um único arquivo de bilhões de arquivos mantidos na web.

Como o Lucene funciona?

A pergunta óbvia que deve vir à sua mente é: como Lucene é tão rápido na execução de perguntas de pesquisa de texto completo? A resposta para isso, é claro, é com a ajuda de índices que cria. Mas, em vez de criar um índice clássico, Lucene faz uso de Índices invertidos.

Em um índice clássico, para cada documento, coletamos a lista completa de palavras ou termos que o documento contém. Em um índice invertido, para cada palavra em todos os documentos, armazenamos qual documento e posicionar. Este é um algoritmo de alto padrão que facilita muito a pesquisa. Considere o seguinte exemplo de criação de um índice clássico:

Doc1 -> "this", "é", "simples", "Lucene", "amostra", "clássico", "invertido", "index"
Doc2 -> "Running", "Elasticsearch", "Ubuntu", "Update"
Doc3 -> "RabbitMQ", "Lucene", "Kafka", "", "Spring", "Boot"

Se usarmos o índice invertido, teremos índices como:

Este -> (2, 71)
Lucene -> (1, 9), (12,87)
Apache -> (12, 91)
Estrutura -> (32, 11)

Os índices invertidos são muito mais fáceis de manter. Suponha que, se queremos encontrar o Apache em meus termos, terei respostas imediatamente com índices invertidos, enquanto com a pesquisa clássica será executada em documentos completos que podem não ter sido possíveis para executar em cenários em tempo real.

Lucene Workflow

Antes que o Lucene possa realmente pesquisar os dados, ele precisa executar etapas. Vamos visualizar estas etapas para uma melhor compreensão:

Lucene Workflow

Como mostrado no diagrama, é isso que acontece no Lucene:

  1. Lucene é alimentado com os documentos e outras fontes de dados
  2. Para cada documento, Lucene primeiro converte esses dados em texto sem formatação e, em seguida, os analisadores convertem esta fonte em texto sem formatação
  3. Para cada termo no texto simples, os índices invertidos são criados
  4. Os índices estão prontos para serem pesquisados

Com este fluxo de trabalho, o Lucene é um mecanismo de pesquisa de texto completo muito forte. Mas esta é a única parte que Lucene cumpre. Precisamos realizar o trabalho sozinho. Vejamos os componentes da indexação necessários.

Componentes Lucene

Nesta seção, descreveremos os componentes básicos e as classes básicas do Lucene usadas para criar índices:

  • Diretórios: Um índice Lucene armazena dados no sistema de arquivos normais Directoies ou na memória se precisar de mais desempenho. É completamente a escolha dos aplicativos para armazenar dados onde quiserem, um banco de dados, a RAM ou o disco.
  • Documentos: Os dados que alimentamos para o motor Lucene precisam ser convertidos em texto simples. Para fazer isso, criamos um objeto de documento que representa essa fonte de dados. Mais tarde, quando executamos uma consulta de pesquisa, como resultado, obteremos uma lista de objetos de documentos que satisfazem a consulta que passamos.
  • Campos: Os documentos são preenchidos com uma coleção de campos. Um campo é simplesmente um par de (nome, valor) Unid. Portanto, ao criar um novo objeto de documento, precisamos preenchê -lo com esse tipo de dados emparelhados. Quando um campo é invertidamente indexado, o valor do campo é tokenizado e está disponível para pesquisa. Agora, enquanto usamos campos, não é importante armazenar o par real, mas apenas o indexado invertido. Dessa forma, podemos decidir quais dados são pesquisáveis ​​e não são importantes para serem salvos. Vejamos um exemplo aqui:

    Indexação de campo

    Na tabela acima, decidimos armazenar alguns campos e outros não são armazenados. O campo do corpo não é armazenado, mas indexado. Isso significa que o email será devolvido como resultado quando a consulta para um dos termos para o conteúdo do corpo for executada.

  • Termos: Termos representa uma palavra do texto. Os termos são extraídos da análise e tokenização dos valores dos campos, assim O termo é a menor unidade em que a pesquisa é executada.
  • Analisadores: Um analisador é a parte mais crucial do processo de indexação e pesquisa. É o analisador que coereça o texto simples em tokens e termos para que eles possam ser pesquisados. Bem, essa não é a única responsabilidade de um analisador. Um analisador usa um tokenizer para fazer tokens. Um analisador também realiza as seguintes tarefas:
    • Stemming: um analisador converte a palavra em uma haste. Isso significa que 'flores' é convertida para a palavra -tronco 'flor'. Então, quando uma busca por 'flor' é executada, o documento será devolvido.
    • Filtragem: um analisador também filtra as palavras de parada como 'the' 'é' ​​etc. Como essas palavras não atraem nenhuma dúvida para ser executada e não são produtivas.
    • Normalização: esse processo remove sotaques e outras marcas de personagens.

    Esta é apenas a responsabilidade normal do StandardAnalyzer.

Exemplo de aplicativo

Usaremos um dos muitos arquétipos Maven para criar um projeto de amostra para o nosso exemplo. Para criar o projeto, execute o seguinte comando em um diretório que você usará como espaço de trabalho:

Arquétipo de MVN: Gerate -dgroupid = COM.Linuxhint.Exemplo -DartifactId = lh -luceneexample -DarchetyPeartifactId = maven -arcetype -quickstart -dinteractiveMode = false

Se você estiver executando o Maven pela primeira vez, levará alguns segundos para realizar o comando GERATE, porque o Maven precisa baixar todos os plug -ins e artefatos necessários para fazer a tarefa de geração. Aqui está a aparência da saída do projeto:

Configuração do projeto

Depois de criar o projeto, fique à vontade para abri -lo no seu IDE favorito. O próximo passo é adicionar dependências maven apropriadas ao projeto. Aqui está o pom.Arquivo XML com as dependências apropriadas:



org.apache.Lucene
Lucene-core
4.6.0


org.apache.Lucene
Lucene-Analyzers-Common
4.6.0

Finalmente, para entender todos os frascos que são adicionados ao projeto quando adicionamos essa dependência, podemos executar um comando Maven simples, que nos permite ver uma árvore de dependência completa para um projeto quando adicionamos algumas dependências a ele. Aqui está um comando que podemos usar:

Dependência de MVN: árvore

Quando executamos este comando, ele nos mostrará a seguinte árvore de dependência:

Finalmente, criamos uma classe SimpleIndexer que é executada

pacote com.Linuxhint.exemplo;
importar java.io.Arquivo;
importar java.io.FileReader;
importar java.io.Ioexception;
importação org.apache.Lucene.análise.Analisador;
importação org.apache.Lucene.análise.padrão.StandardAnalyzer;
importação org.apache.Lucene.documento.Documento;
importação org.apache.Lucene.documento.StoredField;
importação org.apache.Lucene.documento.Campo de texto;
importação org.apache.Lucene.índice.Indexwriter;
importação org.apache.Lucene.índice.IndexwriterConfig;
importação org.apache.Lucene.loja.Fsdirectory;
importação org.apache.Lucene.util.Versão;
classe pública SimpleIndexer
String final estática privada IndexDirectory = "/Users/Shubham/Somewhere/LH-Luceneexample/Index";
String final estática privada DIRTOBEIndexed = "/Users/Shubham/Somewhere/LH-Luqueneexample/Src/Main/Java/com/Linuxhint/Exemplo";
public static void main (string [] args) lança exceção
Arquivo indexdir = novo arquivo (indexDirectory);
Arquivo datadir = novo arquivo (DIRTOBEIndexed);
SimpleIndexer Indexer = new SimpleIndexer ();
int numindexed = indexador.índice (indexdir, datadir);
Sistema.fora.println ("Total Files Indexed" + numIndexed);

Private Int Index (arquivo indexdir, arquivo datadir) lança a ioexception
Analisador analisador = new StandardAnalyzer (versão.Lucene_46);
IndexWriterConfig Config = new IndexWriterConfig (versão.Lucene_46,
analisador);
Indexwriter indexwriter = new indexwriter (fsdirectory.aberto (indexdir),
configuração);
Arquivo [] arquivos = datadir.listfiles ();
para (Arquivo F: Arquivos)
Sistema.fora.println ("arquivo de indexação" + f.getCanonicalPath ());
Documento doc = new document ();
Doc.Add (novo TextField ("Content", New FileReader (F)));
Doc.Add (novo StoredField ("nome do arquivo", f.getCanonicalPath ()));
IndexWriter.addDocument (doc);

int numIndexed = indexwriter.maxdoc ();
IndexWriter.fechar();
retornar numIndexed;

Neste código, acabamos de fazer uma instância do documento e adicionamos um novo campo que representa o conteúdo do arquivo. Aqui está a saída que obtemos quando executamos este arquivo:

Indexação do arquivo/usuários/shubham/side/lh-luceneexample/src/main/java/com/linuxhint/exemplo/simplesindexer.Java
Total de arquivos indexados 1

Além disso, um novo diretório é criado dentro do projeto com o seguinte conteúdo:

Dados de índice

Analisaremos o que todos os arquivos são criados nesses índices em mais lições para vir ao Lucene.

Conclusão

Nesta lição, analisamos como o Apache Lucene funciona e também fizemos um exemplo simples de aplicativo que foi baseado em maven e java.