Like x Full-Text Search do Postgres
2
0

Like x Full-Text Search do Postgres

Descubra os detalhes da nossa mudança do ilike para Full-Text Search do Postgres, uma solução mais robusta e eficiente.

Matt Montenegro
5 min
2
0

PingTech - #2 | Nova versão do canal 🏴‍☠️
Escrito por Daniel Bastos.

Além das alterações visuais no novo canal da Pingback, fizemos várias mudanças internas significativas para aprimorar a funcionalidade e a eficiência da plataforma.

Vamos mergulhar nos detalhes técnicos dessas alterações?

Neste artigo, vou detalhar as limitações anteriores de nossa busca utilizando a função ilike do Postgres e explicar por que escolhemos migrar para o Full-Text Search, uma solução mais robusta e eficiente.

Juntos vamos explorar as mudanças técnicas que fizemos e como elas vão tornar sua experiência na nossa plataforma ainda melhor.

Email image

O problema com a busca ilike no Postgres

Anteriormente, a busca em nosso canal era realizada usando a função ilike do Postgres. Embora essa abordagem funcione para comparações de padrão de string sem diferenciar maiúsculas de minúsculas, ela tem várias desvantagens:

  • Performance: o ilike realiza uma busca sequencial na tabela, o que significa que ele verifica cada linha em busca de uma correspondência.
  • Limitações na busca: usávamos ilike apenas para buscar títulos, o que significa que o conteúdo real dos textos não era considerado nas buscas.
  • Flexibilidade: o ilike é limitado a comparações de string literal.

A solução: Full-Text-Search do Postgres

A Pingback funcionava com ilike, por isso nossa busca era extremamente imprecisa e muito pouco performática.

Então decidimos buscar ferramentas, e novas tecnologias que fizesse isso de uma forma mais performática. No final optamos por implementar o recurso full-text-search do próprio Postgres, pois era o que possuímos mais domínio sobre. Esta decisão trouxe várias melhorias:

Performance aprimorada

O Full-Text Search utiliza indexação especializada (TSVECTOR e TSQUERY), tornando as buscas mais rápidas e eficientes, mesmo em grandes volumes de dados.

Maior precisão

Ele entende a estrutura e a semântica do texto, resultando em correspondências mais relevantes. Palavras são convertidas em lexemas, e a busca é realizada nessa forma normalizada, reduzindo falsos positivos.

Flexibilidade e recursos avançados

Com o Full-Text Search, é possível buscar palavras com raízes similares, considerar sinônimos e até mesmo atribuir diferentes pesos a diferentes partes do texto (como dar mais importância ao título do que ao corpo do texto).

Suporte a operadores

Ele permite o uso de operadores de busca, como AND, OR e NOT, proporcionando buscas mais complexas e refinadas.

A migração para o Full-Text Search não apenas acelerou nossas buscas, mas também as tornou mais precisas e flexíveis.

Esta mudança foi fundamental para continuar oferecendo uma experiência de usuário de alta qualidade em nosso canal.

Mas como funciona esse Full-Text-Search?

Diferentemente do ilike, que compara strings de forma literal e não é otimizado para grandes volumes de dados, o Full-Text Search do Postgres utiliza um sistema de indexação especializado para tornar as buscas mais rápidas e eficientes. Confira como ele funciona:

Indexação

Antes de tudo, o Full-Text Search começa com a indexação do conteúdo.

O texto é quebrado em palavras, que são então convertidas em lexemas utilizando dicionários.

Esses lexemas são representações normalizadas das palavras, desconsiderando variações como tempos verbais, plural/singular, entre outros. Esse processo é armazenado em um tipo de dado chamado TSVECTOR.

Aqui na Pingback utilizamos um trigger para fazer essa indexação:

CREATE OR REPLACE FUNCTION update_issue_search_column()RETURNS TRIGGER AS $$BEGIN NEW._search := setweight(to_tsvector('pg_catalog.portuguese', NEW.title), 'A') || setweight(to_tsvector('pg_catalog.portuguese', NEW.issue::text), 'B'); RETURN NEW;END;$$ LANGUAGE plpgsql;CREATE TRIGGER "Issues_vector_update"BEFORE INSERT OR UPDATE ON "Issues"FOR EACH ROW EXECUTE PROCEDURE update_issue_search_column();

Este código faz o seguinte:

  • A função update_issue_search_column é chamada sempre que um registro é inserido ou atualizado.
  • Ele atualiza a coluna _search com um TSVECTOR que combina o título (com um peso mais alto) e o conteúdo do texto.
  • A trigger "Issues_vector_update" garante que a função seja chamada automaticamente.

Consulta

O PostgreSQL fornece várias funções para auxiliar na construção de consultas Full-Text Search. Uma delas, especialmente útil para lidar com consultas inseridas por usuários, é a websearch_to_tsquery.

Esta função é projetada para aceitar strings de busca no estilo de mecanismos de busca da web, como Google. Por exemplo, se um usuário inserir uma string de consulta como "texto exato" termo1 termo2 -termo3, a função irá tratar essa string de maneira inteligente, considerando a frase "texto exato" como uma busca de frase exata, incluindo termo1 e termo2 como termos de busca positivos e excluindo registros que contêm termo3.

Exemplo de como usá-lo em uma query:

SELECT * FROM "Issues"WHERE "Issue"."_search" @@ websearch_to_tsquery('pg_catalog.portuguese', '${searchTermAntiInjection}');

Neste exemplo, a função websearch_to_tsquery transforma a string de busca inserida pelo usuário em uma consulta otimizada (TSQUERY). O operador @@ é usado para verificar se há uma correspondência entre o conteúdo indexado (TSVECTOR) e a consulta (TSQUERY).

Ranking

O Full-Text Search também possui a capacidade de classificar os resultados com base na relevância. Isso é feito através de funções como ts_rank, que avaliam quão bem o conteúdo corresponde à consulta, permitindo que os resultados mais relevantes sejam retornados primeiro.

Aqui está um exemplo da utilização do ts_rank:

SELECT * FROM "Issues"WHERE "Issue"."_search" @@ websearch_to_tsquery('pg_catalog.portuguese', '${searchTermAntiInjection}')ORDER BY ts_rank("Issue"."_search", websearch_to_tsquery('pg_catalog.portuguese', '${searchTermAntiInjection}')) DESC;

Embora estejamos cientes de que tecnologias dedicadas de busca, como Algolia e ElasticSearch, são amplamente reconhecidas como soluções de ponta para buscas em texto completo, decidimos continuar com o Postgres.

Nossa decisão se baseou no fato de que, para o nosso volume de dados e requisitos de busca, o Postgres tem se mostrado mais do que capaz.

Ele oferece tempos de resposta rápidos e resultados de busca de alta qualidade, eliminando a necessidade de incorporar e manter uma tecnologia de busca adicional.

Com isso, queremos reiterar nosso compromisso em fornecer uma experiência de usuário de alta qualidade sem comprometer a eficiência e a performance.

Espero que estas informações técnicas tenham proporcionado uma visão clara das otimizações que fizemos em nosso canal. Como sempre, estamos abertos a feedback e sugestões.

Até a próxima!

Equipe PingTech. 🏴‍☠️ 🏓