Integrando o PHP com Elasticsearch no desenvolvimento de um sistema de busca

Projeto de criação de um sistema de busca usando o framework Symfony e Elasticsearch. A integração com Kibana também é feito de modo remoto com um raspberrypi.

Postado em 19 outubro 2022

Atualizado em 19 outubro 2022



Introdução

Desenvolvimento de um sistema de buscas utilizando o elasticsearch. Elasticsearch é uma ferramenta de buscas, utilizada por grandes empresas coomo shopify, uber e udemy, pelo seu excelente desempenho em questões de velocidade.

Obs: esse projeto foi desenvolvido no MAC. Usuários usando outros tipos de sistema operacional devem ajustar alguns comandos durante o andamento desse projeto.

Composição repositório

Primeiro, iniciaremos um projeto com o framework symfony para agilizar processos essenciais, como roteador, controladores e views.

composer create-project symfony/skeleton:"6.1.*" search-engine
cd search-engine
composer require webapp

Uma vez que o repositório foi instalado com sucesso, podemos começar desenvolvendo o sistema de buscas.

Elaborando os conceitos básicos do sistema de buscas

O framework symfony fornece diversas ferramentas que agilizam a criação de arquivos como controladores e views. Para termos acesso a essas ferramentas, baixamos o Symfony CLI:

brew install symfony-cli/tap/symfony-cli

Uma vez que instalamos a ferramenta acima com sucesso, obtemos a habilidade de criar vários tipos de arquivos através do terminal, economizando tempo.

Para checar os comandos disponíveis, executamos o comando abaixo:

symfony console list make

Em seguida, criamos o controlador:

symfony console make:controller SearchController

O comando acima irá gerar o controlador e o arquivo de visualização web. Para verificarmos o resultado, criamos o servidor local com o comando abaixo:

symfony server:start

Para sabermos qual é o path para o controlador que criamos, executamos o comando abaixo, responsável por imprimir no terminal todos os paths que podemos acessar:

php bin/console debug:router

Já temos um view predefinido pelo symfony como na imagem abaixo:
tela hello controller do symfony

Usando bootstrap para melhorar o visual

Para facilitar mais ainda a administração de recursos, instalamos mais uma extensão e aplicamos.

composer require symfony/webpack-encore-bundle
npm install

Bootstrap é uma biblioteca de front-end com componentes já prontos para utilização. Uma vez que instalamos e importamos o bootstrap, temos acesso a esses componentes.

npm install bootstrap --save-dev

Após instalar o bootstrap, temos que importar-lo em assets/app.js. Antes de importar, também criamos um arquivo sass global em assets/styles/global.scss.

// assets/styles/global.scss
@import "~bootstrap/scss/bootstrap";

Em seguida importamos o arquivo que importa bootstrap para podermos utilizar o bootstrap.

// assets/app.js
import './styles/global.scss';

Caso não haja problemas, concluímos compilando os arquivos css e js com o comando abaixo:

npm run dev

Caso haja erros no comando acima, instalamos o compilador de sass e ativamos carregador de sass.

npm install sass-loader@^13.0.0 sass --save-dev

Ativando o carregador de sass no symfony:

// webpack.config.js
...
// enables Sass/SCSS support
.enableSassLoader() // 

Quando o comando “npm run dev” for executado com sucesso, adicionamos o bootstrap para podermos usar-lo:

// templates/base.html.twig
<body>
    {% form_theme form 'bootstrap_5_layout.html.twig' %}
    ...
</body>	

Assim, finalmente podemos criar um formulário para o sistema de busca.

Criando o formulário no symfony

No symfony existem outras formas de exibir um formulário. Nesse projeto, iremos fazer isso usando o PHP.

Dentro do nosso controlador, modificamos o código dentro da função “index”:

#[Route('/search', name: 'app_search')]
public function index(Request $request): Response
{
    $form = $this->createFormBuilder()
        ->add('keyword', TextType::class, [
            'label' => 'Digite aqui para pesquisar',
            'attr' => [
                'placeholder' => 'Digite aqui para pesquisar',
            ],
            'row_attr' => [
                'class' => 'form-floating',
            ],
        ])
        ->add('submit', SubmitType::class, ['label' => 'Pesquisar'])
        ->getForm();

    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $data = $form->getData();
		// TODO: Integrar após instalar o elasticsearch
    }

    return $this->renderForm('search/search.html.twig', [
        'form' => $form,
    ]);
}

Em seguida, invocamos o formulário da seguinte maneira:

// templates/search/search.html.twig
{{ form(form) }}

Se tudo ocorrer como esperado, teremos o formulário abaixo:
tela de busca symfony

Criando o servidor com Kibana

O kibana pode ser integrado ao elasticsearch para visualizar dados de várias formas analíticas.

Kibana pode ser instalado em um computador e ter acesso aos dados do elasticsearch de forma remota.

O ambiente de kibana pode ser criado de várias maneiras, como virtualização ou em uma máquina física separada. Nesse projeto iremos utilizar uma máquina física, o raspberrypi4.

Instalando kibana no raspberrypi4

A instalação será feita através do SSH.

ssh [email protected]

A arquitetura da máquina deve ser levada em consideração. Se instalarmos a versão errada, não teremos êxito em executar kibana.

pipipi@raspberrypi:/# uname -a
Linux raspberrypi 5.15.61-v8+ #1579 SMP PREEMPT Fri Aug 26 11:16:44 BST 2022 aarch64 GNU/Linux

Instalaremos kibana como escrito no documento oficial. Como vimos acima, a arquitetura da minha máquina é aarch64 debian. Os comandos executados para a instalação de Kibana estão escritos abaixo:

wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg
sudo apt-get install apt-transport-https
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list
sudo apt-get update && sudo apt-get install kibana

Após a instalação, temos que configurar Kibana para permitir acesso remoto, uma vez que vamos fazer o acesso através do raspberrypi.

nano /etc/kibana/kibana.yml
...
server.port: 5601
server.host: "0.0.0.0"

As duas variáveis devem ser o bastante para obtermos acesso remoto ao Kibana. Quando acesso meu raspberrypi através da porta 5601, consigo acessar kibana remotamente sem problemas.
tela kibana antes da integração

Integrando o elasticsearch

Primeiramente, instalaremos o elasticsearch no computador. Nesse projeto estou usando mac, então estarei baixando conforme os documentos oficiais do elasticsearch dizem.

Se tudo ocorrer corretamente, podemos executar o elasticsearch no diretório onde ele se encontra com o comando abaixo:

./bin/elasticsearch

O comando acima estará funcionando no localhost, geralmente na porta 9200. Pelo fato do elasticsearch estar usando o protocolo SSL para segurança, teremos que acrescentar o “s” no protocolo http.

https://localhost:9200/

Na primeira vez que acessamos o endereço acima, será perguntado o usuário e a senha. Para definirmos a senha executamos o seguinte comando no diretório do elasticsearch:

bin/elasticsearch-setup-passwords interactive

Em seguida, teremos que definir senhas para múltiplos usuários já definidos de padrão.

Após definir a senha, podemos acessar o localhost. Se tivermos sucesso, dados em formato Json irão aparecer na tela.

{
  "name" : "xxxxx.local",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "SQcQ2dfa2123qwUxJDVC4Q",
  "version" : {
    "number" : "8.4.3",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "42f05b9372a9fdsafad327899b99a76ee73",
    "build_date" : "2022-10-04T07:17:24.662462378Z",
    "build_snapshot" : false,
    "lucene_version" : "9.3.0",
    "minimum_wire_compatibility_version" : "7.17.0",
    "minimum_index_compatibility_version" : "7.0.0"
  },
  "tagline" : "You Know, for Search"
}

Em seguida, geramos a chave de integração com Kibana executando a instrução abaixo no terminal:

bin/elasticsearch-create-enrollment-token --scope kibana

Um token deve ser imprimido no terminal. Copiamos e colamos esse token no kibana. Uma janela irá abrir perguntando o código de confirmação do Kibana. Podemos obter esse código com o seguinte comando:

journalctl -u kibana.service

Procuraremos por um log parecido com ao de baixo:

Oct 18 15:33:49 raspberrypi kibana[2116]: Your verification code is:  555 234

Copiamos e colamos o código de confirmação no Kibana e finalmente conseguimos acessar a tela de login. Entramos com o usuário chamado “elastic” e com a senha que definimos algumas etapas anteriores.
tela kibana após integrada com elasticsearch

Integrando o symfony com elasticsearch

O elasticsearch já disponibiliza vários repositórios de integração de linguagens de programação. No nosso caso, estamos usando PHP e o framework Symfony, portanto estaremos usando o repositório de elasticsearch para PHP.

Continuando a implementação que tínhamos deixado pela metade, iremos primeiramente instalar a extensão de elasticsearch.

composer require elasticsearch/elasticsearch

Adicionaremos uma nova função no controlador que irá conter o algoritmo responsável por se conectar e pesquisar no elasticsearch a palavra chave que estamos procurando.

private function runElasticSearch(array $data) {
    $client = ClientBuilder::create()
        ->setHosts(['https://localhost:9200'])
        ->setBasicAuthentication('elastic', 'elastic')
        ->setCABundle($_ENV['ELASTIC_HTTP_CA_PATH'])
        ->build();

    // Info API
    return $client->search($data);
}

Antes de começar a procurar os dados, precisamos primeiro adicionar os dados. Por essa razão, precisamos da tela de registro de documentos.

Estaremos adicionando a tela de registro no mesmo controlador da tela de busca. O algoritmo responsável por adicionar dados ao elasticsearch é o mesmo do repositório oficial.

private function indexDocument(array $data): Elasticsearch|Promise {
    $client = ClientBuilder::create()
        ->setHosts(['https://localhost:9200'])
        ->setBasicAuthentication('elastic', 'elastic')
        ->setCABundle($_ENV['ELASTIC_HTTP_CA_PATH'])
        ->build();
    
    return $client->index($data);
}

Na tela de buscas, se obtermos como resultado as informações que adicionamos anteriormente na tela de registro, tivemos sucesso.
resultado de busca symfony e elasticsearch

Porque usar elasticsearch para sistemas de busca?

Elasticsearch permite a busca, registro, apagamento e análise dos dados. O sistema de busca dessa ferramenta é extremamente rápido mesmo com grande volume de dados, chegando quase na velocidade em tempo real.

Porém, elasticsearch não é tão veloz assim no registro de dados. Por essa razão, elasticsearch não substituí banco de dados tradicionais como Mysql e MongoDB, sendo um banco de dados especializado para buscas.

Repositório disponível para visualização

Postagens mais vistas

Os 5 principais componentes do computador

Os 5 principais componentes do computador são a unidade de controle, unidade aritmética e lógica, memória, dispositivo de entrada e dispositivo de saída.

Portas TCP e UDP

A porta é um número de 16 bits que é adicionado no final do endereço IP, insinuando qual aplicativo está vinculado e atuando nessa porta.

LAN

Rede local de computadores (LAN) é um conjunto de computadores ou dispositivos conectados uns aos outros de forma isolada em um pequeno local.

Retornar aos projetos