Pular para conteúdo

Módulo: Typesense Local

Ambiente de desenvolvimento local para busca full-text e vetorial.

Módulo Migrado

Os scripts de sincronização com Typesense foram migrados para o repositório data-platform. O repositório typesense foi arquivado.

Novo repositório: github.com/destaquesgovbr/data-platform

Visão Geral

O Typesense é usado para busca full-text e vetorial no portal. Em desenvolvimento local, você pode usar Docker Compose para rodar uma instância local.

flowchart LR
    PG[(PostgreSQL)] -->|Sync| SC[data-platform CLI]
    SC -->|Upsert| TS[(Typesense Local)]
    TS -->|Busca| PO[Portal Dev]

Quick Start

1. Subir Typesense com Docker

# Criar docker-compose.yml
cat > docker-compose.yml << 'EOF'
version: '3.8'

services:
  typesense:
    image: typesense/typesense:0.25.2
    container_name: typesense
    ports:
      - "8108:8108"
    environment:
      - TYPESENSE_API_KEY=xyz
      - TYPESENSE_DATA_DIR=/data
    volumes:
      - typesense-data:/data
    restart: unless-stopped

volumes:
  typesense-data:
EOF

docker compose up -d

2. Verificar se está rodando

curl http://localhost:8108/health
# Resposta: {"ok":true}

3. Carregar dados (via data-platform)

# No diretório data-platform
data-platform sync-typesense --start-date $(date -v-7d +%Y-%m-%d)

4. Testar busca

curl "http://localhost:8108/collections/news/documents/search?q=economia&query_by=title" \
  -H "X-TYPESENSE-API-KEY: xyz"

Sincronização com PostgreSQL

A sincronização agora lê do PostgreSQL (fonte de verdade) e escreve no Typesense.

CLI do data-platform

# Sync incremental (últimos N dias)
data-platform sync-typesense --start-date YYYY-MM-DD

# Sync completo (todos os registros)
data-platform sync-typesense --full-sync

Fluxo Interno

# src/data_platform/jobs/typesense/sync_job.py
def sync_typesense(start_date: date = None, full_sync: bool = False):
    """Sincroniza PostgreSQL → Typesense."""
    # 1. Conectar ao PostgreSQL
    # 2. Conectar ao Typesense
    # 3. Buscar notícias (com embeddings)
    # 4. Converter para schema Typesense
    # 5. Upsert em batches de 5000
    pass

Schema da Collection

O schema inclui campos para busca vetorial:

schema = {
    "name": "news",
    "fields": [
        # Identificação
        {"name": "unique_id", "type": "string"},
        {"name": "agency", "type": "string", "facet": True},
        {"name": "agency_name", "type": "string", "facet": True},

        # Conteúdo
        {"name": "title", "type": "string"},
        {"name": "url", "type": "string"},
        {"name": "image", "type": "string", "optional": True},
        {"name": "content", "type": "string"},
        {"name": "summary", "type": "string", "optional": True},

        # Datas
        {"name": "published_at", "type": "int64", "sort": True},

        # Classificação original
        {"name": "category", "type": "string", "optional": True, "facet": True},
        {"name": "tags", "type": "string[]", "optional": True},

        # Temas (enriquecimento Cogfy)
        {"name": "theme_l1_code", "type": "string", "optional": True, "facet": True},
        {"name": "theme_l1_label", "type": "string", "optional": True, "facet": True},
        {"name": "theme_l2_code", "type": "string", "optional": True, "facet": True},
        {"name": "theme_l2_label", "type": "string", "optional": True},
        {"name": "theme_l3_code", "type": "string", "optional": True, "facet": True},
        {"name": "theme_l3_label", "type": "string", "optional": True},
        {"name": "most_specific_theme_code", "type": "string", "optional": True, "facet": True},
        {"name": "most_specific_theme_label", "type": "string", "optional": True},

        # Embedding para busca vetorial
        {
            "name": "content_embedding",
            "type": "float[]",
            "num_dim": 768,
            "optional": True
        },
    ],
    "default_sorting_field": "published_at"
}

Busca Vetorial

O Typesense em produção suporta busca semântica via embeddings:

# Busca vetorial (requer embedding da query)
curl -X POST "http://localhost:8108/multi_search" \
  -H "X-TYPESENSE-API-KEY: xyz" \
  -d '{
    "searches": [{
      "collection": "news",
      "q": "*",
      "vector_query": "content_embedding:([0.1, 0.2, ...], k:10)"
    }]
  }'

API do Typesense

Verificar saúde

curl http://localhost:8108/health

Listar collections

curl http://localhost:8108/collections \
  -H "X-TYPESENSE-API-KEY: xyz"

Ver estatísticas da collection

curl http://localhost:8108/collections/news \
  -H "X-TYPESENSE-API-KEY: xyz"

Busca simples

curl "http://localhost:8108/collections/news/documents/search?q=economia&query_by=title,content" \
  -H "X-TYPESENSE-API-KEY: xyz"

Busca com filtros

curl "http://localhost:8108/collections/news/documents/search?\
q=*&\
query_by=title,content&\
filter_by=agency:gestao&\
sort_by=published_at:desc&\
per_page=10" \
  -H "X-TYPESENSE-API-KEY: xyz"

Busca por tema

curl "http://localhost:8108/collections/news/documents/search?\
q=*&\
query_by=title&\
filter_by=theme_l1_code:01&\
sort_by=published_at:desc" \
  -H "X-TYPESENSE-API-KEY: xyz"

Configuração no Portal

.env.local

TYPESENSE_HOST=localhost
TYPESENSE_PORT=8108
TYPESENSE_PROTOCOL=http
TYPESENSE_API_KEY=xyz
TYPESENSE_COLLECTION_NAME=news

Cliente TypeScript

import Typesense from "typesense"

const client = new Typesense.Client({
  nodes: [{
    host: "localhost",
    port: 8108,
    protocol: "http",
  }],
  apiKey: "xyz",
})

Troubleshooting

Container não inicia

# Ver logs
docker compose logs typesense

# Verificar porta em uso
lsof -i :8108

# Reiniciar
docker compose down && docker compose up -d

Erro de conexão

Error: connect ECONNREFUSED 127.0.0.1:8108

Solução: Verificar se container está rodando:

docker ps | grep typesense

Busca não retorna resultados

  1. Verificar se há dados:
curl http://localhost:8108/collections/news \
  -H "X-TYPESENSE-API-KEY: xyz"
  1. Recarregar dados:
data-platform sync-typesense --start-date $(date -v-7d +%Y-%m-%d)

Reset completo

# Parar e remover volumes
docker compose down -v

# Subir novamente
docker compose up -d

# Recarregar dados
data-platform sync-typesense --full-sync

Comparação: Local vs Produção

Aspecto Local Produção
Host localhost IP interno GCP
Porta 8108 8108
API Key xyz Secret Manager
Dados Últimos N dias Dataset completo
Embeddings Opcional Incluídos
Persistência Volume Docker Disco persistente
Fonte de dados PostgreSQL PostgreSQL

Performance

Requisitos mínimos

  • RAM: 2GB (4GB recomendado para dataset completo)
  • Disco: 5GB para dados
  • CPU: 2 cores

Otimização local

# Carregar menos dados para desenvolvimento
data-platform sync-typesense --start-date $(date -v-3d +%Y-%m-%d)

Arquivos Principais (data-platform)

Componente Localização
TypesenseClient src/data_platform/typesense/client.py
TypesenseIndexer src/data_platform/typesense/indexer.py
SyncJob src/data_platform/jobs/typesense/sync_job.py