Open anapaulagomes opened 4 years ago
@anapaulagomes temos algum exemplo de busca que está lenta?
Como pode ser visto nesse post: https://findwork.dev/blog/optimizing-postgres-full-text-search-in-django/, a forma mais performática em se tratando de full text search com postgres é usando um campo específico para armazenar o search vector e usar um índice GIN ou GiST.
O projeto já segue essas práticas, como poder ver aqui https://github.com/andrewsmedina/maria-quiteria/blob/main/datasets/models.py#L65 e aqui https://github.com/andrewsmedina/maria-quiteria/blob/main/datasets/models.py#L70
Rodando local as queries de busca tem executado bem rapidamente (é possível verificar isso usando o debug toolbar) e imprimindo a query e o explain da query podemos ver que o índice e o campo com o serch vector estão sendo utilizados:
(Pdb) print(queryset.query)
SELECT "datasets_gazette"."id", "datasets_gazette"."created_at", "datasets_gazette"."updated_at", "datasets_gazette"."crawled_at", "datasets_gazette"."crawled_from", "datasets_gazette"."notes", "datasets_gazette"."date", "datasets_gazette"."power", "datasets_gazette"."year_and_edition", "datasets_gazette"."is_legacy" FROM "datasets_gazette" INNER JOIN "datasets_file" ON ("datasets_gazette"."id" = "datasets_file"."object_id" AND ("datasets_file"."content_type_id" = 8)) WHERE "datasets_file"."search_vector" @@ plainto_tsquery(portuguese::regconfig, Secretaria Municipal da Fazenda) ORDER BY "datasets_gazette"."date" DESC NULLS LAST, "datasets_gazette"."id" DESC
(Pdb) print(queryset.explain())
Sort (cost=52.33..52.33 rows=1 width=212)
Sort Key: datasets_gazette.date DESC NULLS LAST, datasets_gazette.id DESC
-> Nested Loop (cost=40.28..52.32 rows=1 width=212)
-> Bitmap Heap Scan on datasets_file (cost=40.00..44.02 rows=1 width=4)
Recheck Cond: (search_vector @@ '''secret'' & ''municipal'' & ''fazend'''::tsquery)
Filter: (content_type_id = 8)
-> Bitmap Index Scan on datasets_fi_search__52321c_gin (cost=0.00..40.00 rows=1 width=0)
Index Cond: (search_vector @@ '''secret'' & ''municipal'' & ''fazend'''::tsquery)
-> Index Scan using datasets_gazette_pkey on datasets_gazette (cost=0.28..8.30 rows=1 width=212)
Index Cond: (id = datasets_file.object_id)
Se em produção a pesquisa está com problemas de performance, eu penso em duas hipóteses:
@anapaulagomes essas hipóteses fazem sentido? Como proceder aqui?
O @andrewsmedina descobriu que o índice não está funcionando corretamente em produção (na verdade, não está funcionando). Dado que vamos mudar a infra em breve (🙏🏽), vamos deixar como está por hora e revisitar essa issue quando a migração for feita (#134).
@anapaulagomes Com a mudança de infra feita, cê acha que podemos avaliar a performance dessa busca?
Sim, tudo já foi migrado. 🚀 Pode checar se funciona local e depois na Absam (a galera do canal #infraestrutura do nosso Discord pode dar mais informações e eu posso ajudar com as credenciais tb). @geraldo-castro
Configurei o pghero hoje. Vou deixar alguns dias rodando por lá e posto os resultados aqui. Nesse PR habilito os campos que estavam causando gargalos: https://github.com/DadosAbertosDeFeira/maria-quiteria/pull/401.
cc @turicas @cuducos
As otimizações iniciais que eu sugeriria já estão feitas (popular o vetor em segundo plano numa coluna dedicada e criar o índice do tipo GIN nessa coluna), mas talvez dê pra melhorar a forma como o Django Admin faz as buscas (pode ser que o ordering
do model, por exemplo, esteja influenciando em não usar o índice que existe). Proponho o seguinte:
EXPLAIN
. Isso pode ser feito de 2 formas:
Notas: no caso de colocar tudo na coluna do vetor de busca:
- É possível adicionar pesos diferentes aos dados de cada coluna (exemplo: peso maior para o sumário e menor para o texto que vem do Tika)
- Precisarão ser alteradas as classes
ModelAdmin
, o management commandsearch_vector
e criar uma migração de dados pra re-popular a coluna com os novos dados em produção- O comando de indexação ficará mais lento por conta do join entre modelo especializado e arquivo correspondente, mas creio que isso não será um impeditivo. Nesse caso o comando precisaria só atualizar os registros que foram afetados com o resultado do crawler, então a quantidade de registros atualizados não deve ser muito grande.
Saiu um artigo hoje falando um pouco sobre esse tópico. Deixando o link aqui pra caso alguem queira entender mais/ganhar mais contexto. 🤗
Atualmente as bases de dados do painel tem usado a busca simples, que é mais lenta e cara em termos computacionais. Já temos uma busca com full-text search mas pode ser mais rápida e apresentar resultados mais satisfatórios ao buscar no conteúdo dos arquivos.