chore: mover documentação para pasta docs e ignorar no git
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
.env
|
.env
|
||||||
|
docs/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
*$py.class
|
*$py.class
|
||||||
|
|||||||
@@ -1,407 +0,0 @@
|
|||||||
# Tipos de Atuação Disponíveis no Elasticsearch (AtuaCAPES)
|
|
||||||
|
|
||||||
> Mapeamento completo dos tipos de atuação encontrados no índice `atuacapes` do Elasticsearch CAPES
|
|
||||||
|
|
||||||
## Visão Geral
|
|
||||||
|
|
||||||
Este documento lista todos os tipos de atuação (`atuacoes.tipo`) disponíveis no índice Elasticsearch do sistema AtuaCAPES, identificados através da análise do código implementado e da documentação do projeto.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Tipos de Atuação Implementados
|
|
||||||
|
|
||||||
### Componente A - Coordenação CAPES
|
|
||||||
|
|
||||||
| Tipo | Descrição | Boost | Pontuação Base |
|
|
||||||
|------|-----------|-------|----------------|
|
|
||||||
| `Coordenação de Área de Avaliação` | Coordenadores ativos (CA, CAJ, CAJ-MP, CAM) | 10 | 200-100 pts |
|
|
||||||
| `Histórico de Coordenação de Área de Avaliação` | Coordenadores históricos (mandatos encerrados) | 5 | 200-100 pts |
|
|
||||||
|
|
||||||
**Subtipos identificados em `dadosCoordenacaoArea.tipo`:**
|
|
||||||
- `Coordenador de Área` (CA) - Base: 200 pts
|
|
||||||
- `Coordenador Adjunto` (CAJ) - Base: 150 pts
|
|
||||||
- `Coordenador Adjunto de Mestrado Profissionalizante` (CAJ-MP) - Base: 120 pts
|
|
||||||
- `Coordenador de Câmara Temática` (CAM) - Base: 100 pts
|
|
||||||
|
|
||||||
### Componente C - Consultoria
|
|
||||||
|
|
||||||
| Tipo | Descrição | Boost | Pontuação Base |
|
|
||||||
|------|-----------|-------|----------------|
|
|
||||||
| `Consultor` | Registro de consultoria ativa ou histórica | 2 | 150 pts (ativo) |
|
|
||||||
| `Histórico de Consultoria` | Consultorias encerradas | 1 | 100 pts (histórico) |
|
|
||||||
|
|
||||||
**Valores de `situacaoConsultoria`:**
|
|
||||||
- `Atividade Contínua` - Consultor Ativo
|
|
||||||
- `Ativo` - Consultor Ativo
|
|
||||||
- Outros valores ou com `inativacaoSituacao` preenchido = Histórico
|
|
||||||
|
|
||||||
### Componente D - Premiações
|
|
||||||
|
|
||||||
| Tipo | Descrição | Boost | Pontuação |
|
|
||||||
|------|-----------|-------|-----------|
|
|
||||||
| `Premiação Prêmio` | Prêmio recebido | 3 | 60-180 pts |
|
|
||||||
| `Avaliação Prêmio` | Participação em avaliação/comissão | 2 | 2-115 pts |
|
|
||||||
| `Inscrição Prêmio` | Inscrição em prêmio | 1 | 1-2 pts |
|
|
||||||
|
|
||||||
**Níveis de Premiação:**
|
|
||||||
|
|
||||||
#### Nível 1 - Grande Prêmio CAPES
|
|
||||||
- `dadosPremiacaoPremio.premiacao`: "Grande Prêmio"
|
|
||||||
- Pontuação: 150 + 50 = 200 pts (limitado a 180)
|
|
||||||
|
|
||||||
#### Nível 1 - Prêmio CAPES de Tese (PCT)
|
|
||||||
- `dadosPremiacaoPremio.premio`: "PCT"
|
|
||||||
- `dadosPremiacaoPremio.premiacao`: "Prêmio" (+25) ou "Menção Honrosa" (+15)
|
|
||||||
- Pontuação base: 100 pts (máx 150 pts)
|
|
||||||
|
|
||||||
#### Nível 2 - Institucionais
|
|
||||||
- Interfarma, Vale-CAPES, etc.
|
|
||||||
- Base: 30 pts
|
|
||||||
- Prêmio: +20 pts / Menção: +10 pts
|
|
||||||
- Máximo: 60 pts
|
|
||||||
|
|
||||||
#### Nível 3 - Autoinscrição
|
|
||||||
- CDTDN, Vínculos Familiares, etc.
|
|
||||||
- Base: 10 pts
|
|
||||||
- Prêmio: +5 pts / Menção: +3 pts
|
|
||||||
- Máximo: 20 pts
|
|
||||||
|
|
||||||
### Outros Tipos Identificados
|
|
||||||
|
|
||||||
| Tipo | Descrição | Uso no Ranking |
|
|
||||||
|------|-----------|----------------|
|
|
||||||
| `Evento` | Participação em eventos SAE | Sim - bônus consultoria |
|
|
||||||
|
|
||||||
**Campos relacionados a eventos:**
|
|
||||||
- `dadosEvento.consultorResponsavel`: "Sim" ou "Não"
|
|
||||||
- Eventos recentes (últimos 2 anos): bonus para consultoria ativa
|
|
||||||
- Responsável por evento: +5 pts por vez (máx 25)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Estrutura de Dados por Componente
|
|
||||||
|
|
||||||
### Coordenação CAPES
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"tipo": "Coordenação de Área de Avaliação",
|
|
||||||
"inicio": "01/01/2020",
|
|
||||||
"fim": null,
|
|
||||||
"dadosCoordenacaoArea": {
|
|
||||||
"tipo": "Coordenador de Área",
|
|
||||||
"areaAvaliacao": {
|
|
||||||
"id": 123,
|
|
||||||
"nome": "CIÊNCIAS AMBIENTAIS"
|
|
||||||
},
|
|
||||||
"inicioVinculacao": "01/01/2020",
|
|
||||||
"fimVinculacao": null,
|
|
||||||
"colegio": [
|
|
||||||
{"nome": "Colégio de Ciências Exatas, Tecnológicas e Multidisciplinar"}
|
|
||||||
],
|
|
||||||
"portaria": "123/2020",
|
|
||||||
"ies": {
|
|
||||||
"nome": "Universidade Federal do Brasil",
|
|
||||||
"sigla": "UFB"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Consultoria
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"tipo": "Consultor",
|
|
||||||
"inicio": "15/03/2018",
|
|
||||||
"fim": null,
|
|
||||||
"dadosConsultoria": {
|
|
||||||
"situacaoConsultoria": "Atividade Contínua",
|
|
||||||
"inicioSituacao": "15/03/2018",
|
|
||||||
"inativacaoSituacao": null,
|
|
||||||
"ies": {
|
|
||||||
"nome": "Universidade Federal do Brasil",
|
|
||||||
"sigla": "UFB"
|
|
||||||
},
|
|
||||||
"areaConhecimentoPos": [
|
|
||||||
{
|
|
||||||
"areaAvaliacao": {
|
|
||||||
"nome": "CIÊNCIAS AMBIENTAIS"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"areaPesquisa": [
|
|
||||||
{"descricao": "Mudanças Climáticas"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Premiações
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"tipo": "Premiação Prêmio",
|
|
||||||
"dadosPremiacaoPremio": {
|
|
||||||
"nomePremio": "Prêmio CAPES de Tese",
|
|
||||||
"premio": "PCT",
|
|
||||||
"premiacao": "Prêmio",
|
|
||||||
"ano": 2022,
|
|
||||||
"areaConhecimento": {
|
|
||||||
"areaAvaliacao": {
|
|
||||||
"nome": "CIÊNCIAS AMBIENTAIS"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"papelPessoa": "Autor"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Participação em Prêmios
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"tipo": "Avaliação Prêmio",
|
|
||||||
"dadosParticipacaoPremio": {
|
|
||||||
"tipo": "Membro de Comissão",
|
|
||||||
"premio": "PCT",
|
|
||||||
"ano": 2023,
|
|
||||||
"comissao": {
|
|
||||||
"nome": "Comissão Julgadora",
|
|
||||||
"tipo": "Avaliação"
|
|
||||||
},
|
|
||||||
"areaAvaliacao": {
|
|
||||||
"nome": "CIÊNCIAS AMBIENTAIS"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Eventos
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"tipo": "Evento",
|
|
||||||
"inicio": "10/05/2023",
|
|
||||||
"fim": "15/05/2023",
|
|
||||||
"dadosEvento": {
|
|
||||||
"consultorResponsavel": "Sim",
|
|
||||||
"nome": "Seminário de Avaliação",
|
|
||||||
"tipo": "Presencial"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Query de Agregação - Descobrir Todos os Tipos
|
|
||||||
|
|
||||||
Para descobrir todos os tipos de atuação disponíveis no índice:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"size": 0,
|
|
||||||
"aggs": {
|
|
||||||
"tipos": {
|
|
||||||
"nested": {"path": "atuacoes"},
|
|
||||||
"aggs": {
|
|
||||||
"tipos_unicos": {
|
|
||||||
"terms": {
|
|
||||||
"field": "atuacoes.tipo.keyword",
|
|
||||||
"size": 100
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Mapeamento de Tipos vs. Componentes de Pontuação
|
|
||||||
|
|
||||||
| Componente | Tipos Relacionados | Pontuação Máxima |
|
|
||||||
|------------|-------------------|------------------|
|
|
||||||
| **A - Coordenação CAPES** | `Coordenação de Área de Avaliação`<br>`Histórico de Coordenação de Área de Avaliação` | 450 pts (CA) |
|
|
||||||
| **B - Coordenação PPG** | *Não existe no ES - usar Oracle* | 180 pts |
|
|
||||||
| **C - Consultoria** | `Consultor`<br>`Histórico de Consultoria`<br>`Evento` (bônus) | 230 pts |
|
|
||||||
| **D - Premiações** | `Premiação Prêmio`<br>`Avaliação Prêmio`<br>`Inscrição Prêmio` | 180 pts |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Campos Faltantes / Limitações
|
|
||||||
|
|
||||||
### Não Disponíveis no Elasticsearch
|
|
||||||
|
|
||||||
1. **Coordenação de Programa (PPG)**
|
|
||||||
- Não existe tipo `atuacoes.tipo` para coordenação de programa
|
|
||||||
- Fonte alternativa: Oracle `SUCUPIRA_PAINEL.VM_COORDENADOR`
|
|
||||||
|
|
||||||
2. **Nota do PPG**
|
|
||||||
- Não disponível em `dadosGestaoPrograma`
|
|
||||||
- Fonte alternativa: Oracle `VM_PROGRAMA_SUCUPIRA.DS_CONCEITO`
|
|
||||||
|
|
||||||
3. **Dados detalhados de Câmara Temática**
|
|
||||||
- Inferido pelo campo `dadosCoordenacaoArea.tipo` ou `nome`
|
|
||||||
- Pode haver imprecisão na classificação
|
|
||||||
|
|
||||||
4. **Situação "Falecido"**
|
|
||||||
- Existe `dadosPessoais.anoObito` mas não `situacaoConsultoria="Falecido"`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Implementação no Código
|
|
||||||
|
|
||||||
### Arquivo: `backend/src/infrastructure/elasticsearch/client.py`
|
|
||||||
|
|
||||||
Query principal com boost por tipo:
|
|
||||||
|
|
||||||
```python
|
|
||||||
async def buscar_candidatos_ranking(self, size: int = 1000) -> List[Dict[str, Any]]:
|
|
||||||
query = {
|
|
||||||
"size": size,
|
|
||||||
"query": {
|
|
||||||
"bool": {
|
|
||||||
"should": [
|
|
||||||
# Coordenação CAPES
|
|
||||||
{
|
|
||||||
"nested": {
|
|
||||||
"path": "atuacoes",
|
|
||||||
"query": {
|
|
||||||
"bool": {
|
|
||||||
"should": [
|
|
||||||
{"term": {"atuacoes.tipo": {"value": "Coordenação de Área de Avaliação", "boost": 10}}},
|
|
||||||
{"term": {"atuacoes.tipo": {"value": "Histórico de Coordenação de Área de Avaliação", "boost": 5}}}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"score_mode": "sum"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
# Consultoria
|
|
||||||
{
|
|
||||||
"nested": {
|
|
||||||
"path": "atuacoes",
|
|
||||||
"query": {
|
|
||||||
"bool": {
|
|
||||||
"should": [
|
|
||||||
{"term": {"atuacoes.tipo": {"value": "Consultor", "boost": 2}}},
|
|
||||||
{"term": {"atuacoes.tipo": {"value": "Histórico de Consultoria", "boost": 1}}}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"score_mode": "sum"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
# Premiações
|
|
||||||
{
|
|
||||||
"nested": {
|
|
||||||
"path": "atuacoes",
|
|
||||||
"query": {
|
|
||||||
"bool": {
|
|
||||||
"should": [
|
|
||||||
{"term": {"atuacoes.tipo": {"value": "Premiação Prêmio", "boost": 3}}},
|
|
||||||
{"term": {"atuacoes.tipo": {"value": "Avaliação Prêmio", "boost": 2}}},
|
|
||||||
{"term": {"atuacoes.tipo": {"value": "Inscrição Prêmio", "boost": 1}}}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"score_mode": "sum"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"minimum_should_match": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"_source": ["id", "dadosPessoais", "atuacoes"],
|
|
||||||
"sort": [{"_score": "desc"}]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Arquivo: `backend/src/infrastructure/repositories/consultor_repository_impl.py`
|
|
||||||
|
|
||||||
Extração de tipos:
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Consultoria
|
|
||||||
consultorias = [
|
|
||||||
a for a in atuacoes
|
|
||||||
if a.get("tipo") in ["Consultor", "Histórico de Consultoria"]
|
|
||||||
]
|
|
||||||
|
|
||||||
# Coordenação CAPES
|
|
||||||
coordenacoes = [
|
|
||||||
a for a in atuacoes
|
|
||||||
if a.get("tipo") in [
|
|
||||||
"Coordenação de Área de Avaliação",
|
|
||||||
"Histórico de Coordenação de Área de Avaliação",
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
# Eventos (bônus consultoria)
|
|
||||||
eventos_sae = [
|
|
||||||
a for a in atuacoes
|
|
||||||
if a.get("tipo") == "Evento"
|
|
||||||
]
|
|
||||||
|
|
||||||
# Premiações (todos os tipos são processados genericamente)
|
|
||||||
premiacoes = [
|
|
||||||
a for a in atuacoes
|
|
||||||
if a.get("dadosPremiacaoPremio") or
|
|
||||||
a.get("dadosParticipacaoPremio") or
|
|
||||||
a.get("dadosParticipacaoInscricaoPremio")
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Estatísticas
|
|
||||||
|
|
||||||
### Estimativas de Volume (baseado em documentação)
|
|
||||||
|
|
||||||
| Tipo | Quantidade Estimada |
|
|
||||||
|------|---------------------|
|
|
||||||
| Coordenadores de área (ativos) | ~200 |
|
|
||||||
| Coordenadores históricos | ~322 |
|
|
||||||
| Consultores | ~52.551 |
|
|
||||||
| Premiações | ~63.799 |
|
|
||||||
| **Total de registros com atuações** | **~90.482** |
|
|
||||||
|
|
||||||
### Boost Aplicado
|
|
||||||
|
|
||||||
O boost é usado para priorizar candidatos no score inicial do Elasticsearch:
|
|
||||||
|
|
||||||
| Tipo | Boost | Justificativa |
|
|
||||||
|------|-------|---------------|
|
|
||||||
| Coordenação de Área (ativa) | 10 | Máxima prioridade (200-450 pts) |
|
|
||||||
| Coordenação de Área (histórica) | 5 | Alta prioridade histórica |
|
|
||||||
| Premiação Prêmio | 3 | Mérito significativo |
|
|
||||||
| Consultor | 2 | Base importante |
|
|
||||||
| Avaliação Prêmio | 2 | Participação ativa |
|
|
||||||
| Histórico de Consultoria | 1 | Relevância histórica |
|
|
||||||
| Inscrição Prêmio | 1 | Participação básica |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Notas de Implementação
|
|
||||||
|
|
||||||
1. **Paginação**: Query principal retorna top 1000 candidatos ordenados por score ES
|
|
||||||
2. **Recálculo**: Python recalcula pontuação completa e reordena por pontuação real
|
|
||||||
3. **Cache**: Resultados cacheados por 5 minutos (TTL=300s)
|
|
||||||
4. **Performance**: Primeira requisição ~1m34s, cacheadas ~0.27s
|
|
||||||
5. **Timeout**: 120s para queries ES
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Referências
|
|
||||||
|
|
||||||
- **Documentação**: `/home/fred/projetos/ranking/.claude/rules/ranking-queries-elasticsearch.md`
|
|
||||||
- **Critérios**: `/home/fred/projetos/ranking/.claude/rules/ranking-consultores-capes.md`
|
|
||||||
- **Implementação ES**: `/home/fred/projetos/ranking/backend/src/infrastructure/elasticsearch/client.py`
|
|
||||||
- **Extração**: `/home/fred/projetos/ranking/backend/src/infrastructure/repositories/consultor_repository_impl.py`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Última atualização**: 2025-12-13
|
|
||||||
**Índice Elasticsearch**: `atuacapes` (servidor: `elastic-atuacapes.hom.capes.gov.br:9200`)
|
|
||||||
@@ -1,291 +0,0 @@
|
|||||||
# TOP 10 CONSULTORES - RANKING CAPES
|
|
||||||
|
|
||||||
**Data da Consulta:** 13/12/2025
|
|
||||||
**Base de Dados:** Elasticsearch AtuaCAPES (índice: atuacapes)
|
|
||||||
**Total de Candidatos Analisados:** 100
|
|
||||||
**Critérios:** Sistema de Ranking Integrado CAPES v1.0
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Resumo Executivo
|
|
||||||
|
|
||||||
O ranking foi calculado com base em 4 componentes principais:
|
|
||||||
|
|
||||||
- **Componente A:** Coordenação CAPES (máx 450 pts) - CA, CAJ, CAJ-MP, CAM
|
|
||||||
- **Componente B:** Coordenação de Programa PPG (máx 180 pts) - *Não disponível nesta consulta*
|
|
||||||
- **Componente C:** Consultoria (máx 230 pts)
|
|
||||||
- **Componente D:** Premiações (máx 180 pts)
|
|
||||||
|
|
||||||
**Pontuação Máxima Teórica:** 1.040 pontos
|
|
||||||
**Pontuação Máxima Observada:** 685 pontos (65,9% do máximo)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Top 10 Consultores
|
|
||||||
|
|
||||||
### 1º LUGAR - EDSON APARECIDO MITISHITA
|
|
||||||
**ID:** 519524
|
|
||||||
**Pontuação Total:** 685 pontos
|
|
||||||
|
|
||||||
**Breakdown de Pontuação:**
|
|
||||||
- **Componente A (Coordenação CAPES):** 340 pts
|
|
||||||
- Base: 200 (Coordenador de Área)
|
|
||||||
- Tempo: 90 (9 anos completos)
|
|
||||||
- Áreas Adicionais: 0
|
|
||||||
- Bônus Atualidade: 30 (coordenação ativa)
|
|
||||||
- Retorno: 20 (já coordenou antes)
|
|
||||||
|
|
||||||
- **Componente B (Coordenação PPG):** 0 pts
|
|
||||||
|
|
||||||
- **Componente C (Consultoria):** 165 pts
|
|
||||||
- Base: 100 (histórico)
|
|
||||||
- Tempo: 50 (10+ anos)
|
|
||||||
- Total eventos: 2
|
|
||||||
- Eventos recentes: 0 (último há mais de 2 anos)
|
|
||||||
- Bônus continuidade: 15 (8+ anos consecutivos)
|
|
||||||
|
|
||||||
- **Componente D (Premiações):** 180 pts
|
|
||||||
- Total de premiações: 7
|
|
||||||
|
|
||||||
**Perfil:**
|
|
||||||
- Anos de atuação: 11,3 anos
|
|
||||||
- Status: Inativo (sem eventos recentes)
|
|
||||||
- Veterano: Sim
|
|
||||||
- Área principal: GEOCIÊNCIAS
|
|
||||||
- Coordenações: 3 (incluindo 1 ativa)
|
|
||||||
|
|
||||||
**Destaque:** Possui a maior pontuação no Componente A devido à combinação de coordenação ativa (bônus de 30 pts) + retorno (20 pts) + 9 anos completos de experiência.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2º LUGAR - ANDRE MOREIRA CUNHA
|
|
||||||
**ID:** 45997
|
|
||||||
**Pontuação Total:** 675 pontos
|
|
||||||
|
|
||||||
**Breakdown de Pontuação:**
|
|
||||||
- **Componente A:** 330 pts
|
|
||||||
- Base: 200
|
|
||||||
- Tempo: 100 (10 anos - máximo permitido)
|
|
||||||
- Bônus Atualidade: 30
|
|
||||||
- Retorno: 0 (sem retorno)
|
|
||||||
|
|
||||||
- **Componente C:** 165 pts
|
|
||||||
- **Componente D:** 180 pts (7 premiações)
|
|
||||||
|
|
||||||
**Perfil:**
|
|
||||||
- Anos de atuação: 14,2 anos
|
|
||||||
- Status: Inativo
|
|
||||||
- Área principal: ECONOMIA
|
|
||||||
- Coordenações: 2 (1 ativa)
|
|
||||||
|
|
||||||
**Destaque:** Atingiu o teto máximo de pontuação por tempo (100 pts) no Componente A.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3º LUGAR - FLAVIO AUGUSTO SENRA RIBEIRO
|
|
||||||
**ID:** 7794
|
|
||||||
**Pontuação Total:** 665 pontos
|
|
||||||
|
|
||||||
**Breakdown de Pontuação:**
|
|
||||||
- **Componente A:** 320 pts
|
|
||||||
- Base: 200
|
|
||||||
- Tempo: 100
|
|
||||||
- Áreas Adicionais: 20 (coordenou 2 áreas diferentes)
|
|
||||||
- Bônus Atualidade: 0 (coordenação encerrada)
|
|
||||||
- Retorno: 0
|
|
||||||
|
|
||||||
- **Componente C:** 165 pts
|
|
||||||
- **Componente D:** 180 pts (11 premiações)
|
|
||||||
|
|
||||||
**Perfil:**
|
|
||||||
- Anos de atuação: 14,5 anos
|
|
||||||
- Status: Inativo
|
|
||||||
- Áreas: FILOSOFIA, CIÊNCIAS DA RELIGIÃO E TEOLOGIA
|
|
||||||
- Coordenações: 3 (todas encerradas)
|
|
||||||
|
|
||||||
**Destaque:** Único no top 10 com pontuação por áreas adicionais (coordenou múltiplas áreas). Maior número de premiações entre os 10 primeiros (11 premiações).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 4º ao 10º LUGAR (Empate em 655 pontos)
|
|
||||||
|
|
||||||
Os consultores da 4ª à 10ª posição compartilham a mesma pontuação total de **655 pontos**, com o seguinte padrão:
|
|
||||||
|
|
||||||
**Componente A:** 310 pts
|
|
||||||
- Base: 200
|
|
||||||
- Tempo: 60 (6 anos)
|
|
||||||
- Bônus Atualidade: 30
|
|
||||||
- Retorno: 20
|
|
||||||
|
|
||||||
**Componente C:** 165 pts
|
|
||||||
**Componente D:** 180 pts
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### 4º - CARLOS FREDERICO MARTINS MENCK
|
|
||||||
**ID:** 20912
|
|
||||||
**Área:** CIÊNCIAS BIOLÓGICAS I
|
|
||||||
**Anos:** 14,5 | **Status:** Inativo
|
|
||||||
**Premiações:** 25 (maior número absoluto)
|
|
||||||
**Coordenações:** 2 (1 ativa)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### 5º - MARCELO ALBANO MORET SIMOES GONCALVES
|
|
||||||
**ID:** 5888
|
|
||||||
**Área:** INTERDISCIPLINAR
|
|
||||||
**Anos:** 11,0 | **Status:** Ativo ✓
|
|
||||||
**Premiações:** 9
|
|
||||||
**Eventos recentes:** 2
|
|
||||||
**Coordenações:** 2 (1 ativa)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### 6º - CARLOS PELLESCHI TABORDA
|
|
||||||
**ID:** 15100
|
|
||||||
**Área:** CIÊNCIAS BIOLÓGICAS III
|
|
||||||
**Anos:** 12,6 | **Status:** Inativo
|
|
||||||
**Premiações:** 15
|
|
||||||
**Coordenações:** 2 (1 ativa)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### 7º - CLÁUDIA LUCIA DE MORAES FORJAZ
|
|
||||||
**ID:** 14569
|
|
||||||
**Área:** EDUCAÇÃO FÍSICA, FISIOTERAPIA, FONOAUDIOLOGIA E TERAPIA OCUPACIONAL
|
|
||||||
**Anos:** 14,5 | **Status:** Inativo
|
|
||||||
**Premiações:** 9
|
|
||||||
**Coordenações:** 2 (1 ativa)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### 8º - ALTAIR ANTONINHA DEL BEL CURY
|
|
||||||
**ID:** 8639
|
|
||||||
**Área:** ODONTOLOGIA
|
|
||||||
**Anos:** 12,1 | **Status:** Ativo ✓
|
|
||||||
**Premiações:** 11
|
|
||||||
**Eventos recentes:** 2
|
|
||||||
**Coordenações:** 2 (1 ativa)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### 9º - DEBORA FOGUEL
|
|
||||||
**ID:** 12271
|
|
||||||
**Área:** CIÊNCIAS BIOLÓGICAS II
|
|
||||||
**Anos:** 14,5 | **Status:** Inativo
|
|
||||||
**Premiações:** 7
|
|
||||||
**Coordenações:** 2 (1 ativa)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### 10º - MARCELO TÁVORA MIRA
|
|
||||||
**ID:** 509665
|
|
||||||
**Área:** MEDICINA I
|
|
||||||
**Anos:** 11,3 | **Status:** Ativo ✓
|
|
||||||
**Premiações:** 7
|
|
||||||
**Eventos recentes:** 1
|
|
||||||
**Coordenações:** 2 (1 ativa)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Análise Estatística
|
|
||||||
|
|
||||||
### Distribuição de Pontuação
|
|
||||||
|
|
||||||
| Posição | Pontuação | Diferença para 1º |
|
|
||||||
|---------|-----------|-------------------|
|
|
||||||
| 1º | 685 | - |
|
|
||||||
| 2º | 675 | -10 |
|
|
||||||
| 3º | 665 | -20 |
|
|
||||||
| 4º-10º | 655 | -30 |
|
|
||||||
|
|
||||||
**Média (top 10):** 661 pontos
|
|
||||||
**Desvio padrão:** ~10 pontos
|
|
||||||
|
|
||||||
### Componentes - Análise
|
|
||||||
|
|
||||||
**Componente A (Coordenação CAPES):**
|
|
||||||
- Média: 319 pts (71% do máximo)
|
|
||||||
- Variação: 310-340 pts
|
|
||||||
- Padrão dominante: CA (Coordenador de Área) com coordenação ativa
|
|
||||||
|
|
||||||
**Componente B (Coordenação PPG):**
|
|
||||||
- Todos: 0 pts (dados não disponíveis no Elasticsearch)
|
|
||||||
|
|
||||||
**Componente C (Consultoria):**
|
|
||||||
- Todos: 165 pts
|
|
||||||
- Padrão: Base 100 + Tempo 50 + Bônus continuidade 15
|
|
||||||
- Uniformidade total no top 10
|
|
||||||
|
|
||||||
**Componente D (Premiações):**
|
|
||||||
- Todos: 180 pts (máximo permitido)
|
|
||||||
- Média de premiações: 10,3 por consultor
|
|
||||||
- Variação: 7-25 premiações
|
|
||||||
|
|
||||||
### Perfil dos Líderes
|
|
||||||
|
|
||||||
**Anos de Atuação:**
|
|
||||||
- Média: 12,7 anos
|
|
||||||
- Variação: 11,0 - 14,5 anos
|
|
||||||
- Todos são veteranos (10+ anos)
|
|
||||||
|
|
||||||
**Status de Atividade:**
|
|
||||||
- Ativos: 3 (30%)
|
|
||||||
- Inativos: 7 (70%)
|
|
||||||
|
|
||||||
**Áreas de Conhecimento:**
|
|
||||||
- Ciências Biológicas: 3 consultores
|
|
||||||
- Áreas diversas: 7 consultores
|
|
||||||
|
|
||||||
**Padrão de Coordenação:**
|
|
||||||
- Todos possuem coordenação ATIVA no momento
|
|
||||||
- Todos exceto 1 tiveram retorno à coordenação
|
|
||||||
- Média de 2,3 coordenações por consultor
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Observações Técnicas
|
|
||||||
|
|
||||||
### Limitações da Análise
|
|
||||||
|
|
||||||
1. **Componente B = 0:** O Elasticsearch não contém dados de coordenação de PPG. Esses dados estão no Oracle (SUCUPIRA_PAINEL). Se incluídos, o ranking poderia mudar significativamente.
|
|
||||||
|
|
||||||
2. **Amostra de 100 candidatos:** A query com boost buscou apenas 100 candidatos pré-ordenados pelo Elasticsearch. É possível que candidatos com alta pontuação real estejam fora dessa amostra.
|
|
||||||
|
|
||||||
3. **Dados de Consultoria incompletos:** O campo "áreas" da consultoria retornou vazio para todos os consultores, sugerindo possível problema na extração de dados do Elasticsearch.
|
|
||||||
|
|
||||||
### Critérios de Desempate
|
|
||||||
|
|
||||||
Quando há empate na pontuação total (casos 4º-10º), a ordenação segue a ordem de retorno do Elasticsearch, que não necessariamente reflete um critério definido.
|
|
||||||
|
|
||||||
**Sugestão:** Implementar critério de desempate explícito:
|
|
||||||
1. Componente A (maior)
|
|
||||||
2. Anos de atuação (maior)
|
|
||||||
3. Status ativo (preferencial)
|
|
||||||
4. ID menor (mais antigo no sistema)
|
|
||||||
|
|
||||||
### Validação dos Cálculos
|
|
||||||
|
|
||||||
Os cálculos seguem rigorosamente os critérios definidos em:
|
|
||||||
- `/home/fred/projetos/ranking/.claude/rules/ranking-consultores-capes.md`
|
|
||||||
- `/home/fred/projetos/ranking/.claude/rules/ranking-queries-implementadas.md`
|
|
||||||
|
|
||||||
**Implementação:** `CalculadorPontuacao` em `/home/fred/projetos/ranking/backend/src/domain/services/calculador_pontuacao.py`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Próximos Passos Recomendados
|
|
||||||
|
|
||||||
1. **Integrar dados do Oracle** para calcular Componente B (Coordenação PPG)
|
|
||||||
2. **Expandir amostra** para 1.000+ candidatos para garantir cobertura completa
|
|
||||||
3. **Corrigir extração de áreas** na consultoria
|
|
||||||
4. **Implementar critério de desempate** explícito
|
|
||||||
5. **Validar dados de premiações** (verificar se todas as 7-25 premiações são válidas)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Script de Geração:**
|
|
||||||
`/home/fred/projetos/ranking/backend/scripts/top10_ranking.py`
|
|
||||||
|
|
||||||
**Método de Consulta:**
|
|
||||||
Query Elasticsearch com boost por tipo de atuação (conforme especificação técnica)
|
|
||||||
@@ -1,441 +0,0 @@
|
|||||||
# Queries Implementadas - Sistema de Ranking de Consultores CAPES
|
|
||||||
|
|
||||||
> Documentação das queries efetivamente implementadas no sistema, com regras de pontuação aplicadas.
|
|
||||||
|
|
||||||
## Visão Geral da Arquitetura
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────────────────┐
|
|
||||||
│ FLUXO DE DADOS │
|
|
||||||
├─────────────────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ 1. Elasticsearch (AtuaCAPES) │
|
|
||||||
│ └─> Query com boost por tipo de atuação │
|
|
||||||
│ └─> Retorna top 1000 candidatos pré-ordenados │
|
|
||||||
│ │
|
|
||||||
│ 2. Oracle - Opcional │
|
|
||||||
│ └─> Busca coordenações de PPG por ID_PESSOA │
|
|
||||||
│ │
|
|
||||||
│ 3. Python (Backend) │
|
|
||||||
│ └─> Calcula pontuação completa (A + B + C + D) │
|
|
||||||
│ └─> Reordena por pontuação real │
|
|
||||||
│ └─> Cache por 5 minutos │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Query Principal - Elasticsearch
|
|
||||||
|
|
||||||
### Objetivo
|
|
||||||
Buscar candidatos relevantes para o ranking, priorizando por tipo de atuação usando boost.
|
|
||||||
|
|
||||||
### Query Implementada
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"size": 1000,
|
|
||||||
"query": {
|
|
||||||
"bool": {
|
|
||||||
"should": [
|
|
||||||
{
|
|
||||||
"nested": {
|
|
||||||
"path": "atuacoes",
|
|
||||||
"query": {
|
|
||||||
"bool": {
|
|
||||||
"should": [
|
|
||||||
{"term": {"atuacoes.tipo": {"value": "Coordenação de Área de Avaliação", "boost": 10}}},
|
|
||||||
{"term": {"atuacoes.tipo": {"value": "Histórico de Coordenação de Área de Avaliação", "boost": 5}}}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"score_mode": "sum"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"nested": {
|
|
||||||
"path": "atuacoes",
|
|
||||||
"query": {
|
|
||||||
"bool": {
|
|
||||||
"should": [
|
|
||||||
{"term": {"atuacoes.tipo": {"value": "Consultor", "boost": 2}}},
|
|
||||||
{"term": {"atuacoes.tipo": {"value": "Histórico de Consultoria", "boost": 1}}}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"score_mode": "sum"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"nested": {
|
|
||||||
"path": "atuacoes",
|
|
||||||
"query": {
|
|
||||||
"bool": {
|
|
||||||
"should": [
|
|
||||||
{"term": {"atuacoes.tipo": {"value": "Premiação Prêmio", "boost": 3}}},
|
|
||||||
{"term": {"atuacoes.tipo": {"value": "Avaliação Prêmio", "boost": 2}}},
|
|
||||||
{"term": {"atuacoes.tipo": {"value": "Inscrição Prêmio", "boost": 1}}}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"score_mode": "sum"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"minimum_should_match": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"_source": ["id", "dadosPessoais", "atuacoes"],
|
|
||||||
"sort": [{"_score": "desc"}]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Explicação dos Boosts
|
|
||||||
|
|
||||||
| Tipo de Atuação | Boost | Justificativa |
|
|
||||||
|-----------------|-------|---------------|
|
|
||||||
| Coordenação de Área de Avaliação | 10 | Máxima pontuação (base 200 pts) |
|
|
||||||
| Histórico de Coordenação de Área | 5 | Alta pontuação histórica |
|
|
||||||
| Premiação Prêmio | 3 | 60 pts por premiação |
|
|
||||||
| Consultor | 2 | Base 150 pts se ativo |
|
|
||||||
| Avaliação Prêmio | 2 | 40 pts por avaliação |
|
|
||||||
| Histórico de Consultoria | 1 | Base 100 pts |
|
|
||||||
| Inscrição Prêmio | 1 | 20 pts por inscrição |
|
|
||||||
|
|
||||||
### Estatísticas de Candidatos
|
|
||||||
|
|
||||||
| Tipo | Quantidade no ES |
|
|
||||||
|------|------------------|
|
|
||||||
| Coordenadores de área | 522 |
|
|
||||||
| Consultores | 52.551 |
|
|
||||||
| Premiações | 63.799 |
|
|
||||||
| **Total com atuações relevantes** | **90.482** |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Query Oracle - Coordenação de Programa (PPG)
|
|
||||||
|
|
||||||
### Objetivo
|
|
||||||
Buscar coordenações de programa por ID_PESSOA para calcular o Componente B.
|
|
||||||
|
|
||||||
### Query Implementada
|
|
||||||
|
|
||||||
```sql
|
|
||||||
SELECT
|
|
||||||
c.ID_PESSOA,
|
|
||||||
c.ID_PROGRAMA_SNPG,
|
|
||||||
p.NM_PROGRAMA,
|
|
||||||
p.CD_PROGRAMA_PPG,
|
|
||||||
p.DS_CONCEITO AS NOTA_PPG,
|
|
||||||
p.NM_PROGRAMA_MODALIDADE,
|
|
||||||
aa.NM_AREA_AVALIACAO,
|
|
||||||
c.DT_INICIO_VIGENCIA,
|
|
||||||
c.DT_FIM_VIGENCIA
|
|
||||||
FROM SUCUPIRA_PAINEL.VM_COORDENADOR c
|
|
||||||
INNER JOIN SUCUPIRA_PAINEL.VM_PROGRAMA_SUCUPIRA p
|
|
||||||
ON c.ID_PROGRAMA_SNPG = p.ID_PROGRAMA
|
|
||||||
LEFT JOIN SUCUPIRA_PAINEL.VM_AREA_CONHECIMENTO ac
|
|
||||||
ON p.ID_AREA_CONHECIMENTO_ATUAL = ac.ID_AREA_CONHECIMENTO
|
|
||||||
LEFT JOIN SUCUPIRA_PAINEL.VM_AREA_AVALIACAO aa
|
|
||||||
ON ac.ID_AREA_AVALIACAO = aa.ID_AREA_AVALIACAO
|
|
||||||
WHERE c.ID_PESSOA = :id_pessoa
|
|
||||||
ORDER BY c.DT_INICIO_VIGENCIA
|
|
||||||
```
|
|
||||||
|
|
||||||
### Campos Retornados
|
|
||||||
|
|
||||||
| Campo | Tipo | Uso |
|
|
||||||
|-------|------|-----|
|
|
||||||
| ID_PROGRAMA_SNPG | NUMBER | Identificador único do programa |
|
|
||||||
| NM_PROGRAMA | VARCHAR2 | Nome do programa |
|
|
||||||
| CD_PROGRAMA_PPG | VARCHAR2 | Código do PPG |
|
|
||||||
| NOTA_PPG | VARCHAR2 | Nota CAPES (3-7, A) |
|
|
||||||
| NM_PROGRAMA_MODALIDADE | VARCHAR2 | Acadêmico/Profissional |
|
|
||||||
| NM_AREA_AVALIACAO | VARCHAR2 | Área de avaliação |
|
|
||||||
| DT_INICIO_VIGENCIA | DATE | Início da coordenação |
|
|
||||||
| DT_FIM_VIGENCIA | DATE | Fim (null = ativo) |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Regras de Pontuação Implementadas
|
|
||||||
|
|
||||||
### Componente A - Coordenação CAPES (máx 450 pts)
|
|
||||||
|
|
||||||
**Arquivo**: `backend/src/domain/services/calculador_pontuacao.py`
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Apenas coordenações ATIVAS pontuam
|
|
||||||
coord_atual = next((c for c in coordenacoes if c.periodo.ativo), None)
|
|
||||||
if not coord_atual:
|
|
||||||
return ComponentePontuacao(base=0, tempo=0, extras=0, bonus=0, retorno=0)
|
|
||||||
|
|
||||||
# Valores por tipo
|
|
||||||
base_map = {"CA": 200, "CAJ": 150, "CAJ-MP": 120, "CAM": 100}
|
|
||||||
tempo_max_map = {"CA": 100, "CAJ": 80, "CAJ-MP": 60, "CAM": 50}
|
|
||||||
bonus_atual_map = {"CA": 30, "CAJ": 20, "CAJ-MP": 15, "CAM": 10}
|
|
||||||
|
|
||||||
# Cálculo
|
|
||||||
base = base_map.get(coord_atual.tipo, 0)
|
|
||||||
anos = coord_atual.periodo.anos_decorridos
|
|
||||||
tempo = min(int(anos * 10), tempo_max_map.get(coord_atual.tipo, 0))
|
|
||||||
extras = min(len(coord_atual.areas_adicionais) * 20, 100)
|
|
||||||
bonus = bonus_atual_map.get(coord_atual.tipo, 0) if coord_atual.periodo.ativo else 0
|
|
||||||
retorno = 20 if coord_atual.ja_coordenou_antes else 0
|
|
||||||
```
|
|
||||||
|
|
||||||
**Tabela de Pontuação**:
|
|
||||||
|
|
||||||
| Tipo | Base | Tempo (máx) | Bônus Ativo | Áreas (máx) | Retorno |
|
|
||||||
|------|------|-------------|-------------|-------------|---------|
|
|
||||||
| CA | 200 | 100 (10 pts/ano) | 30 | 100 | 20 |
|
|
||||||
| CAJ | 150 | 80 (10 pts/ano) | 20 | 100 | 20 |
|
|
||||||
| CAJ-MP | 120 | 60 (10 pts/ano) | 15 | 100 | 20 |
|
|
||||||
| CAM | 100 | 50 (10 pts/ano) | 10 | 100 | 20 |
|
|
||||||
|
|
||||||
### Componente B - Coordenação PPG (máx 180 pts)
|
|
||||||
|
|
||||||
```python
|
|
||||||
if not coordenacoes:
|
|
||||||
return ComponentePontuacao(base=0, tempo=0, extras=0, bonus=0)
|
|
||||||
|
|
||||||
base = 70
|
|
||||||
anos_totais = sum(c.periodo.anos_decorridos for c in coordenacoes)
|
|
||||||
tempo = min(int(anos_totais * 5), 50)
|
|
||||||
|
|
||||||
programas_distintos = len({c.id_programa for c in coordenacoes})
|
|
||||||
extras = min((programas_distintos - 1) * 20, 40)
|
|
||||||
|
|
||||||
coord_ativa = any(c.periodo.ativo for c in coordenacoes)
|
|
||||||
bonus = 20 if coord_ativa else 0
|
|
||||||
```
|
|
||||||
|
|
||||||
**Tabela de Pontuação**:
|
|
||||||
|
|
||||||
| Critério | Pontos | Máximo |
|
|
||||||
|----------|--------|--------|
|
|
||||||
| Base (ser coordenador) | 70 | 70 |
|
|
||||||
| Tempo | 5 pts/ano | 50 |
|
|
||||||
| Programas extras | 20 pts/programa | 40 |
|
|
||||||
| Bônus ativo | 20 | 20 |
|
|
||||||
| **TOTAL** | - | **180** |
|
|
||||||
|
|
||||||
### Componente C - Consultoria (máx 230 pts)
|
|
||||||
|
|
||||||
```python
|
|
||||||
if not consultoria:
|
|
||||||
return ComponentePontuacao(base=0, tempo=0, extras=0, bonus=0)
|
|
||||||
|
|
||||||
# Base depende de ter eventos recentes (últimos 2 anos)
|
|
||||||
base = 150 if consultoria.eventos_recentes > 0 else 100
|
|
||||||
|
|
||||||
# Tempo desde primeiro evento
|
|
||||||
anos = (datetime.now() - consultoria.primeiro_evento).days / 365.25
|
|
||||||
tempo = min(int(anos * 5), 50)
|
|
||||||
|
|
||||||
# Extras
|
|
||||||
extras_eventos = min(consultoria.total_eventos * 2, 20)
|
|
||||||
extras_responsavel = min(consultoria.vezes_responsavel * 5, 25)
|
|
||||||
extras_areas = min((len(consultoria.areas) - 1) * 10, 30) if len(consultoria.areas) > 1 else 0
|
|
||||||
extras = extras_eventos + extras_responsavel + extras_areas
|
|
||||||
```
|
|
||||||
|
|
||||||
**Tabela de Pontuação**:
|
|
||||||
|
|
||||||
| Critério | Pontos | Máximo |
|
|
||||||
|----------|--------|--------|
|
|
||||||
| Base (ativo/recente) | 150 | 150 |
|
|
||||||
| Base (histórico) | 100 | 100 |
|
|
||||||
| Tempo | 5 pts/ano | 50 |
|
|
||||||
| Eventos | 2 pts/evento | 20 |
|
|
||||||
| Responsável | 5 pts/vez | 25 |
|
|
||||||
| Áreas extras | 10 pts/área | 30 |
|
|
||||||
| **TOTAL** | - | **230** |
|
|
||||||
|
|
||||||
### Componente D - Premiações (máx 180 pts)
|
|
||||||
|
|
||||||
```python
|
|
||||||
if not premiacoes:
|
|
||||||
return ComponentePontuacao(base=0, tempo=0, extras=0, bonus=0)
|
|
||||||
|
|
||||||
# Pontos por tipo de premiação
|
|
||||||
mapa = {
|
|
||||||
"Premiação Prêmio": 60,
|
|
||||||
"Avaliação Prêmio": 40,
|
|
||||||
"Inscrição Prêmio": 20,
|
|
||||||
}
|
|
||||||
|
|
||||||
total_pontos = sum(mapa.get(p.tipo, 0) for p in premiacoes)
|
|
||||||
total_pontos = min(total_pontos, 180) # Teto
|
|
||||||
|
|
||||||
return ComponentePontuacao(base=total_pontos, tempo=0, extras=0, bonus=0)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Tabela de Pontuação**:
|
|
||||||
|
|
||||||
| Tipo | Pontos | Descrição |
|
|
||||||
|------|--------|-----------|
|
|
||||||
| Premiação Prêmio | 60 | Recebeu prêmio |
|
|
||||||
| Avaliação Prêmio | 40 | Participou de banca/comissão |
|
|
||||||
| Inscrição Prêmio | 20 | Inscreveu trabalho |
|
|
||||||
| **Máximo total** | **180** | - |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Extração de Dados do Elasticsearch
|
|
||||||
|
|
||||||
### Coordenações CAPES
|
|
||||||
|
|
||||||
```python
|
|
||||||
def _extrair_coordenacoes_capes(self, atuacoes: List[Dict[str, Any]]) -> List[CoordenacaoCapes]:
|
|
||||||
coordenacoes = [
|
|
||||||
a for a in atuacoes
|
|
||||||
if a.get("tipo") in [
|
|
||||||
"Coordenação de Área de Avaliação",
|
|
||||||
"Histórico de Coordenação de Área de Avaliação",
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
# Inferir tipo pelo campo 'nome'
|
|
||||||
def _inferir_tipo_coordenacao(coord):
|
|
||||||
nome = coord.get("nome", "").lower()
|
|
||||||
if "câmara" in nome or "camara" in nome:
|
|
||||||
return "CAM"
|
|
||||||
elif "mestrado profissional" in nome:
|
|
||||||
return "CAJ-MP"
|
|
||||||
elif "adjunta" in nome:
|
|
||||||
return "CAJ"
|
|
||||||
else:
|
|
||||||
return "CA"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Consultoria
|
|
||||||
|
|
||||||
```python
|
|
||||||
def _extrair_consultoria(self, atuacoes: List[Dict[str, Any]]) -> Optional[Consultoria]:
|
|
||||||
consultorias = [
|
|
||||||
a for a in atuacoes
|
|
||||||
if a.get("tipo") in ["Consultor", "Histórico de Consultoria"]
|
|
||||||
]
|
|
||||||
|
|
||||||
# Calcula eventos recentes (últimos 2 anos)
|
|
||||||
limite_recente = datetime.now() - timedelta(days=730)
|
|
||||||
eventos_recentes = sum(1 for d in datas_fim if d >= limite_recente)
|
|
||||||
|
|
||||||
# Extrai áreas únicas
|
|
||||||
areas = list({c.get("areaAvaliacao", "N/A") for c in consultorias if c.get("areaAvaliacao")})
|
|
||||||
|
|
||||||
# Conta vezes como responsável
|
|
||||||
vezes_responsavel = sum(1 for c in consultorias if c.get("responsavel", False))
|
|
||||||
```
|
|
||||||
|
|
||||||
### Premiações
|
|
||||||
|
|
||||||
```python
|
|
||||||
def _extrair_premiacoes(self, atuacoes: List[Dict[str, Any]]) -> List[Premiacao]:
|
|
||||||
premiacoes_data = [
|
|
||||||
a for a in atuacoes
|
|
||||||
if a.get("tipo") in [
|
|
||||||
"Premiação Prêmio",
|
|
||||||
"Avaliação Prêmio",
|
|
||||||
"Inscrição Prêmio",
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
for prem in premiacoes_data:
|
|
||||||
pontos = self._calcular_pontos_premiacao(prem.get("tipo", ""))
|
|
||||||
# tipo vem de atuacoes.tipo
|
|
||||||
# nome_premio vem de atuacoes.descricao
|
|
||||||
# ano vem de atuacoes.inicio (parse para extrair ano)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Cache de Ranking
|
|
||||||
|
|
||||||
### Implementação
|
|
||||||
|
|
||||||
```python
|
|
||||||
class RankingCache:
|
|
||||||
def __init__(self, ttl_seconds: int = 300): # 5 minutos
|
|
||||||
self.ttl = ttl_seconds
|
|
||||||
self._cache: List[Consultor] = []
|
|
||||||
self._last_update: Optional[datetime] = None
|
|
||||||
self._loading = False
|
|
||||||
self._lock = asyncio.Lock()
|
|
||||||
|
|
||||||
def is_valid(self) -> bool:
|
|
||||||
if not self._cache or not self._last_update:
|
|
||||||
return False
|
|
||||||
return (datetime.now() - self._last_update).total_seconds() < self.ttl
|
|
||||||
```
|
|
||||||
|
|
||||||
### Performance
|
|
||||||
|
|
||||||
| Métrica | Valor |
|
|
||||||
|---------|-------|
|
|
||||||
| Primeira requisição (cold) | ~1m34s |
|
|
||||||
| Requisições cacheadas | ~0.27s |
|
|
||||||
| TTL do cache | 5 minutos |
|
|
||||||
| Candidatos processados | 1000 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Fluxo Completo de Ranking
|
|
||||||
|
|
||||||
```python
|
|
||||||
async def buscar_ranking(self, limite: int = 100) -> List[Consultor]:
|
|
||||||
# 1. Verificar cache
|
|
||||||
if _ranking_cache.is_valid():
|
|
||||||
return _ranking_cache.get()[:limite]
|
|
||||||
|
|
||||||
async with _ranking_cache._lock:
|
|
||||||
# 2. Double-check cache
|
|
||||||
if _ranking_cache.is_valid():
|
|
||||||
return _ranking_cache.get()[:limite]
|
|
||||||
|
|
||||||
# 3. Buscar candidatos do ES (ordenados por score ES)
|
|
||||||
tamanho_busca = max(limite * 3, 1000)
|
|
||||||
docs = await self.es_client.buscar_candidatos_ranking(size=tamanho_busca)
|
|
||||||
|
|
||||||
# 4. Construir consultores (calcula pontuação completa)
|
|
||||||
consultores = []
|
|
||||||
for doc in docs:
|
|
||||||
consultor = await self._construir_consultor(doc)
|
|
||||||
# _construir_consultor busca dados do Oracle se disponível
|
|
||||||
consultores.append(consultor)
|
|
||||||
|
|
||||||
# 5. Reordenar por pontuação real
|
|
||||||
consultores_ordenados = sorted(
|
|
||||||
consultores, key=lambda c: c.pontuacao_total, reverse=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# 6. Cachear resultado
|
|
||||||
_ranking_cache.set(consultores_ordenados)
|
|
||||||
|
|
||||||
return consultores_ordenados[:limite]
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Limitações Conhecidas
|
|
||||||
|
|
||||||
1. **Cobertura de candidatos**: Buscamos 1000 candidatos do ES. Se alguém com alta pontuação estiver fora do top 1000 do score ES, não aparecerá.
|
|
||||||
|
|
||||||
2. **Oracle opcional**: Se Oracle não estiver disponível (TNS error no Docker), Componente B = 0 para todos.
|
|
||||||
|
|
||||||
3. **Tipos de coordenação**: Inferência pelo campo `nome` pode não ser 100% precisa.
|
|
||||||
|
|
||||||
4. **Datas inconsistentes**: ES usa formatos `dd/MM/yyyy` e `yyyy-MM-dd` misturados.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Arquivos de Implementação
|
|
||||||
|
|
||||||
| Arquivo | Responsabilidade |
|
|
||||||
|---------|------------------|
|
|
||||||
| `backend/src/infrastructure/elasticsearch/client.py` | Query ES com boost |
|
|
||||||
| `backend/src/infrastructure/oracle/client.py` | Query Oracle PPG |
|
|
||||||
| `backend/src/infrastructure/repositories/consultor_repository_impl.py` | Cache e orquestração |
|
|
||||||
| `backend/src/domain/services/calculador_pontuacao.py` | Regras de pontuação |
|
|
||||||
| `backend/src/domain/entities/consultor.py` | Entidades de domínio |
|
|
||||||
Reference in New Issue
Block a user