Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Prototipo funcional] data-processing e Associação AMA exoonero #44

Merged
merged 5 commits into from
Dec 13, 2023

Conversation

Winzen
Copy link
Contributor

@Winzen Winzen commented Sep 29, 2023

PR referente as Issues #43 #40

Essa não é uma versão final e busca passar por varias revisões.
O protótipo foca em sondar possíveis problemas, dar molde para uma versão final e limpa.
Ele já consegui segmentar os diários da AMA e chegar ao ponto final do processamento dos diários .

Objetivos inicias e principais

  • Segmentar Diarios dentro do storage(Separados por id e suas datas).
  • Fazer o registros dos metadados dos diarios segmetados.
  • Fazer a indexação dos diarios segmetados com elasticsearch.

Passos a serem adicionados e melhorados.

  • Criar verificador no registro dos metadados para evitar duplicados. ➡️ Parte a modificar
  • Verificar melhor formar de tratar duplicadas.(Naturalmente o projeto já evita que elas sejam adicionadas. Porém, ele levanta um erro e para o processo)
  • Colocar um tratador de erro caso ele não consiga pegar territory_id. ➡️ Parte a modificar
  • Verificar porque aparamente ele não esta conseguindo processar todos os pdfs de uma vez
  • Criar self.url, self.file_raw_txtcorretamente usando o get_file_endpoint().➡️ Parte a modificar
  • Atualização da documentação.
    • Como conectar querido-diario e data-processing(lembrar de falar do csv)
    • Configurar ambiente no windons(wsl)
  • Verificar se está com um consumo excessivo de ram

Obs: Logo estarei colocando a explicação, caminho tomado pelo protótipo para concluir o processamento e limpa o Readme do repositório.

@ogecece ogecece added the melhoria New feature or request label Oct 3, 2023
Copy link
Contributor

@Jefersonalves Jefersonalves left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Winzen, obrigado pelo submissão do PR.
Parabéns por ter conseguido chegar em um protótipo funcional!
Olhei brevemente o código e apontei alguns pontos de melhoria, peço que avalie se as sugestões fazem sentido pra você. Também levantei alguns questionamentos, responda quando possível

README.md Outdated
Comment on lines 3 to 16
# Objetivos inicias e principais
- [x] Segmentar Diarios dentro do storage(Separados por id e suas datas).
- [x] Fazer o registros dos metadados dos diarios segmetados.
- [x] Fazer a indexação dos diarios segmetados com elasticsearch.
# Passos a serem adicionados e melhorados.
- [x] Criar verificador no registro dos metadados para evitar duplicados. ➡️ [Parte a modificar](https://github.com/Winzen/querido-diario-data-processing/blob/prototype/tasks/gazette_text_extraction.py#L272)
- [ ] Verificar melhor formar de tratar duplicadas.(Naturalmente o projeto já evita que elas seram adicionadas. Porém, ele levanta um erro e para o processo)
- [ ] Colocar um tratador de erro caso ele não consiga pegar territory_id. ➡️ [Parte a modificar](https://github.com/Winzen/querido-diario-data-processing/blob/prototype/tasks/get_territorie_info.py#L5)
- [x] Verificar porque aparamente ele não esta conseguindo processar todos os pdfs de uma vez
- [ ] Criar `self.url` corretamente usando o `get_file_endpoint()`.➡️ [Parte a modificar](https://github.com/Winzen/querido-diario-data-processing/blob/prototype/tasks/diario_municipal.py#L72)
- [ ] Atualização da documentação.
- [ ] Como conectar querido-diario e data-processing(lembrar de falar do csv)
- [ ] Configurar ambiente no windons(wsl)
- [ ] Verificar se está com um consumo excessivo de ram
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acredito que o melhor lugar para documentar as melhorias futuras seja nas Issues. Nesse caso, sugiro formatar essas ideias e abrir novas issues com esse conteúdo

@@ -49,9 +49,12 @@ def _commit_changes(self, command: str, data: Dict = {}) -> None:
cursor.execute(command, data)
self._connection.commit()

def select(self, command: str) -> Iterable[Tuple]:
def select(self, command: str, data: Dict = {}) -> Iterable[Tuple]:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

É estranho um comando de select receber um conjunto de dados para executar. Não seria melhor usar a função de insert?

Comment on lines 13 to 17
municipio = municipio.rstrip().replace('\n', '') # limpeza inicial
# Alguns nomes de municípios possuem um /AL no final, exemplo: Viçosa no diário 2022-01-17, ato 8496EC0A. Para evitar erros como "vicosa-/al-secretaria-municipal...", a linha seguir remove isso.
municipio = re.sub("(\/AL.*|GABINETE DO PREFEITO.*|PODER.*|http.*|PORTARIA.*|Extrato.*|ATA DE.*|SECRETARIA.*|Fundo.*|SETOR.*|ERRATA.*|- AL.*|GABINETE.*)", "", municipio)
self.id = self._computa_id(municipio)
self.nome = municipio
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sugiro separar a lógica de extração do nome do município da classe que representa o município. A regex não é uma característica do município, mas sim um padrão de publicação da associação

self.id = self._computa_id(municipio)
self.nome = municipio

def _computa_id(self, nome_municipio):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def _recupera_id_ibge(self, nome_municipio):

state = state.strip()
name = limpar_name(name)

for territorie in territories:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for territory in territories:

"""
m = hashlib.md5()
while True:
d = file.read(8096)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Algum motivo para esse limite?

Comment on lines 4 to 8
def extrarir_diarios(pdf_text, path_pdf, territories):

diarios = extrair_diarios_municipais(pdf_text, path_pdf, territories)

return diarios
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A função extrair_diarios está atuando como um proxy para extrair_diarios_municipais. Não seria melhor fazer a chamada de forma direta?

gazette, database, storage, index, text_extractor
)

if str(gazette["territory_id"][-4:]).strip() == "0000":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Houve um acordo para as associações terem um territory_id com o sufixo "0000"?


for diario in diarios:

duplicates = seach_for_duplicate(diario, database)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A necessidade de buscar por duplicatas na base surgiu por qual motivo?

Comment on lines 139 to 140
for territorie in database.select(command):
territories.append(format_territories_data(territorie))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

territories = [format_territories_data(territory) for territory in database.select(command)]

Jefersonalves and others added 5 commits December 13, 2023 13:11
- Cria módulo `segmentation` para organizar o código dos segmentadores
- O módulo segue o padrão de classe base e classes derivadas para cada
  segmentador específico
- O primeiro segmentador base é o `AssociationSegmenter` para segmentar
  documentos de associações de municípios
- Uma dataclass para segmentos `GazetteSegment` também foi criada
- Os segmentadores são instanciados por meio de uma fábrica
  `get_segmenter`
Deleta módulo associations para usar o segmentation

Remove arquivo sem uso

Move funções relacionadas aos territórios para um único arquivo

Move arquivo que lida com territórios para o módulo utils

Atualiza referências para o módulo territories

Troca referência para o módulo segmentation

Remove atribuição da url para usar a url da associação

Remove uso dos territórios nos módulos superiores aos de segmentação

Remove tratamento de exceção para nomes errados na limpeza

Refatora forma de obtenção dos dados dos territórios

Corrige type hinting da segmentação da AMA

Adiciona chamada para obter os territórios para os segmentadores

Corrige type hint no módulo segmentation factory

Remove tratamentos específicos de associações do módulo territories

Adapta segmentador da AMA para obter o territory id dos segmentos

Correções no processo de extração

Remove construção da url ao fazer upload do conteúdo dos segmentos
Torna a busca pelos territórios em uma task

Melhora a obtenção de dados do município a partir do nome

Trata erros que ocorreram em diários recentes

Lança exceção ao obter território se este não for encontrado

Faz ajustes para não ser preciso instanciar a database no segmentador

Refatora bifurcação entre diários normais e de associações

Modifica uso de territories e gazette por segmentadores

Territories agora são utilizados por segmentadores por meio de um
atributo de instância criado na inicialização da classe.

Também não parecia necessária a atribuição do objeto `Gazette` à
instância do segmentador, então o objeto passa a ser usado apenas como
argumento na `.get_gazette_segments()` e não mais na inicialização.

Como a instância do segmentador pode ser reutilizada sem problemas, um
padrão de singleton foi utilizado na criação das instâncias.

Corrige segmentação com marcador de início falso

Na edição de 7 de Dezembro de 2023 do diário da Associação dos
Municípios Alagoanos, o diário de Dois Riachos possui o cabeçalho

```
ESTADO DE ALAGOAS

PREFEITURA MUNICIPAL DE EDUCAÇÃO

SECRETARIA MUNICIPAL DE EDUCAÇÃO DE DOIS RIACHOS
```

no meio do texto de um ato. Isso fazia com que a segmentação fosse
engatilhada novamente, resultando em um segmento anterior quase vazio
(praticamente apenas o cabeçalho) e o segmento atual com o nome de
município incorreto ("EDUCAÇÃO").

Agora, a palavra EDUCAÇÃO foi inserida no regex como uma exceção
notável.

Refatora mapeamento de município para python-slugify

Biblioteca já implementa as transformações que usamos e ainda provê
mais funcionalidades. Agora, a chave criada para um município fica em
formato mais clássico de slug ("uf-nome-municipio").

Refatora split_text de al_associacao_municipios

O método `split_text_by_territory()` estava com problemas de extração
incompleta. Ex:

```
      {
        "_index" : "querido-diario",
        "_type" : "_doc",
        "_id" : "7b7ed1557de74c25cff6a04023ed525f",
        "_score" : null,
        "_source" : {
          "id" : 6,
          "territory_name" : "Maribondo",
          "source_text" : "Alagoas , 02 de Outubro de 2023   •   Diário Oficial dos Municípios do Estado de Alagoas   •    ANO XI | Nº 2145",
          "date" : "2023-10-02",
          "edition_number" : "2145",
          "is_extra_edition" : false,
          "power" : "executive_legislative",
          "file_checksum" : "7b7ed1557de74c25cff6a04023ed525f",
          "scraped_at" : "2023-12-11T20:25:43.705771",
          "created_at" : "2023-12-11T20:25:45.500616",
          "processed" : true,
          "file_path" : "2700000/2023-10-02/a4c2994ffab9f0dabc0d2c3ad46436f917d61efb.pdf",
          "file_url" : "https://www-storage.voxtecnologia.com.br?m=sigpub.publicacao&f=9878&i=publicado_91279_2023-09-29_564051d01bafcfea6f84735fc59f4d94.pdf",
          "state_code" : "AL",
          "territory_id" : "2704807",
          "file_raw_txt" : "/2704807/2023-10-02/7b7ed1557de74c25cff6a04023ed525f.txt",
          "url" : "http://google.com/2700000/2023-10-02/a4c2994ffab9f0dabc0d2c3ad46436f917d61efb.pdf"
        },
```

Neste caso, o `source_text` está apenas com o cabeçalho.

Além disso, o código estava um pouco confuso, então uma refatoração foi
realizada para simplificar a segmentação, passando a utilizar mais
`re.split()` ao invés de iterar diretamente linha-a-linha.

Outra consequência dessa mudança é que além de mais segmentos estarem
sendo coletados, os textos dos segmentos refletem o texto original mais
fielmente, pois o tratamento de espaços em branco e quebras de linha não
está sendo feito linha-a-linha no corpo do segmento.

Refatora gazette_text_extraction por conta de associações

O fluxo da task estava um pouco confuso, especialmente na bifurcação
entre arquivo de diário agregado ou diário completo. Essa refatoração
tem como objetivo simplificar esse fluxo e por consequência, assim como
a task, os segmentadores também foram simplificados.

Refatora criação de índices para tasks

Corrige slug na segmentação

Para eliminar a necessidade de exceções por conta de municípios com
alguma palavra separada por espaço em seu nome indevidamente, o slug
agora não utiliza mais um separador e concatena tudo.

Ex:
- al-senador-rui-palmeira  -> alsenadorruipalmeira
- al-senador-rui-palme-ira -> alsenadorruipalmeira
@ogecece ogecece merged commit cc54af2 into okfn-brasil:main Dec 13, 2023
0 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
melhoria New feature or request
Development

Successfully merging this pull request may close these issues.

3 participants