Leitura lista extremamente grande 134 milhões de linhas

21 respostas Resolvido
F

Pessoal.
Estou fazendo um processo recursivo para trabalhar em cima de valores de uma lista. Apesar de extremamente grande, cada linha ou objeto contem informações relativamente pequenas.
Problemas que enfrento e gostaria da ajuda de voces:
1-Primeiro problema que estou enfrentando e na leitura desses arquivos. A partir de um arquivo com 100 mil linhas, o processo ja chora na hora da leitura
2-Seria a melhor forma de pesquisar. Tenho linho sobre o HashMap. Seria a melhor opção neste casos?

Se alguém puder contribuir com a sua sábia e valiosa experiencia, ficarei eternamente grato.

21 Respostas

esmiralha

Você precisa guardar todas as 360 milhões de linhas em memória ao mesmo tempo?

F

Nao necessariamente.
Pode fazer uma busca em disco mesmo. Caso seja possível poderia me falar como?

Trabalho com uma ferramenta, desenvolvida em Java, que ao acompanhar o processo, vejo que ela cria uma lista com os index e uma lista com o valores. Acredito que a lista de index aponte para a lista de valo. Enfim, apenas para exemplificar o que também pode acontecer.

Pode ser tanto em disco quando em memória. As suas menores lista, mas que sao mais consultadas, gostaria de deixar em memoria. A ultima lista que e menor acessada eu nao vejo problemas de deixar em disco. Se nao for possível seleciono apenas 1 para memorias e as outras em disco.

Obrigado!

pfk66
rmendes08

A maneira mais simples de indexar esses registros em disco é inserí-los em um banco de dados. A outra opção é você implementar o seu próprio índice. De qualquer maneira, não ficou muito claro o seu problema. Ok, você tem um arquivo grande com muitos registros, mas o que exatamente é demorado no seu processo ? Carrregá-los todos para a memória ? Executar buscas ?

F

Olá, muito obrigado pela resposta. Acredito que a mesma faca parte da solução da qual procuro, mas será praticamente a última parte(desculpe a indelicadeza ,mas, a escrita às vezes nos faz parecer rude).
O que procuro de momento, é saber qual seria a melhor forma para trabalha com estas litas. Hashmap ou percorrer a lista comparando valores utilizando mecanismos para otimizar a pesquisa ?
Atualmente o que estou fazendo e separar as listas em 3 categorias e ordenalas pela chave que utilizarei para pesquisa . Sempre que eu faço um busca vejo se o valor que quero é maior ou menor ao último procurando, assim, consigo dividir a lista ao meio fazendo com que evite percorrer toda lista .
Obrigado e desculpe me por qualquer coisa .

rmendes08

Carregar tudo para a memória, de maneira geral, são soluções mais simples e mais performáticas. O problema é se você tem memória disponível para comportar tudo. Em muitos casos, simplesmente alocar mais memória não é uma opção.

F

Mendes, obrigado .
Hoje o que mais demora, com uma massa de 10 milhões, é propriamente o processo de busca recuvisa. bem provável por conta da forma com que a faço, não ser a melhor. Atualmente, percorro todo o meu registro a busca de um valor . Tentei ingressar uma forma de otimização porém, mesmo assim, ficou bem lento .
Você acredita que aplicar hashmap conseguiria otimizar a minha busca?
Máquina não é problema(pelo menos assim julgo) pois temos uma maquina de 32 corea e 120gb de ram(desenvolvimento).

F

Então Mendes, poderia dar uma dica de qual melhor maneira?
Você acredita que trabalhando junto com um banco de dados, seria a melhor opção? Mesmo tento o i/o!?
Hashmap, tenho ouvido muito sobre ele. ajuda em alguma coisa?

M

Pesquise sobre algoritmos de ordenação .
busca binária pode ajudar na localização pelo dado mas o ideal que esses registros estivessem em um banco de dados.

pfk66

Usando SSD a performance é quase a mesma que ler da memória.

rmendes08

Ajuda muito! Porém, para usar o HashMap você tem que definir uma chave que seja única para cada registro. Imagine que você tenha um base de clientes e cada um tem o cpf. Se você armazenar em uma lista, a busca por cpf seria assim:

Cliente buscaPorCpf(Integer cpf, List<Cliente> clientes){
    for(Cliente c : clientes){
        if(c.getCpf().equals(cpf){
            return c;
        }
    } 
}

Porém, usando a HashMap a operação é feita em tempo constante:

Cliente buscarPorCpf(Integer cpf, HashMap<Integer,Cliente> clientesPorCpf){
    return clientesPorCpf.get(cpf);
}

Assim, caso você tenha memória disponível, uma alternativa é carregar todos os dados para uma HashMap no início do processamento e sempre recuperá-los através da chave única.

esmiralha

Umas perguntas para você pensar aí…

Com frequência os dados do arquivo grande são alterados?
Você processa esse arquivo sequencialmente como se fosse um lote de transações ou você usa ele como um banco de dados para fazer busca por chave, inserções, deleções e alterações?
Se você busca por chaves, as chaves são mutáveis ou imutáveis? São artificiais ou naturais? Se são naturais, qual o tipo de dados?

drsmachado

As informações que você passou são bem restritas. Por exemplo, não sabemos em que tipo de ambiente esse teu sistema está sendo executado, se como standalone ou como aplicação web.
Na empresa onde trabalho, temos várias necessidades, dentre elas, o processamento real time de inúmeros pacotes de dados para a aplicação de regras que mudam de acordo com N parâmetros.
Estas regras são todas carregadas em cache (coherence, no caso), pois as aplicações rodam em um weblogic. É óbvio que o cenário não é tão radical quanto o que você aprensenta, mas, esta seria uma ótima sugestão de alternativa, trabalhar com cacheamento destes dados.
Este cacheamento pode ser feito utilizando uma combinação parecida com a que apresentei, weblogic + coherence, ou se isso não for ideal, utilizando-se de um banco de dados nosql (como o mongodb).
Aliás, você informa que trabalha com recursividade e que, aparentemente, esta é a razão da lentidão. Como o @rmendes08 disse, carregar os dados em memória pode ser complicado, ainda mais se não houver um ambiente propício para isto (memória limitada, por exemplo). Outra coisa, o custo de ler em disco é sempre alto…

A

Pra ser honesto eu ainda nao entendi o problema que está tentando resolver.

Você disse que precisa carregar esse arquivo em memória e fazer buscas recursivas nele, mas nao explicou o problema em si.

Qual o tamanho total do arquivo? Cabe na memória física?
Que tipo de pesquisa você faz no conteúdo do arquivo? Quando essas pesquisas acontecem? (É um request online de um usuário?)
Por que essas informaçoes existem num arquivo hoje em dia? Poderia usar algum outro tipo de data storage?

F

Srs. @AbelBueno @drsmachado @esmiralha @rmendes08 , primeiramente obrigado pelas resposta.
Vou tentar colocar o cenário que está apresentando e o que eu tentarei fazer, para que todos tenham uma ideia.

Na empresa foi modelado, ao meu ver, de forma errônea, um relaciomaneto de produtos para que quando alterado o código do fornecedor um registro de elo entre eles e inserido e um relacionamento com chaves distintas é criado, conforme exemplo abaixo:

Supomos que temos este produto, Feijão, cadastrado em nossa base, da seguinte forma:

Se no próximo mês o nosso fornecedor, por algum motivo inusitado, alterar o NU_FORNECEDOR (que seria como um numero do produto na base de dados do fornecedor) eu não realizo apenas uma nova inclusão. Eu realizo o seguinte:

1 - Altero o NU_ESTADO E NU_CASO PARA 1 E 5

2- Crio um novo registro onde onde NU_ESTADO e NU_CASO sejam 3 e 2 mantendo o NU_COD_INTERNO

3- Cria-se um novo registro onde este terá a informação mais atual do produto com NU_ESTADO E NU_CASO sendo 1 e 1. Temos o seguinte resultado:

Observem que, quando tenho o relacionamento entre os códigos 1 e 5 com 3 e 2, utiliza-se o NU_COD_INTERNO como chave de relacionamento e, quando tenho relacionamento entre 3 e 2, utiliza-se NU_FORNECEDOR como chave de relacionamento.

Imaginem agora que este código pode sofrer alteracoes, como já vimos aqui, 16 vezes!

Em um exemplo de modificação de 3 vezes teremos nosso produto assim:

Objetivo do projeto:
Criar uma tabela de relaciomaneto inserindo todos os códigos que algum dia foram o mais atual do produto e criar uma coluna com os código atuais e anteriores.

O que consegui fazer, mas gostaria de melhorar a mais performance, foi criar uma lista assim:

Freqüência:
Procedimento será realizado uma vez por mês e , necessariamente, todos os registros devem ser lidos novamente.

Tamanho:
Temos aproximadamente 355 milhões de registro que serao divididos em 3 grupos utilizando o NU_ESTADO e NU_CASO para alocação em cada tabela.

Crescimento:
Crescimento médio de 30 mil registros mês.

Infra:
Contamos com uma maquina com 8 CPU em um total de 32 cores 120GB de memória hd SSD

Funcionamento:
Objetivo e rodar o processo localmente, standalone, para evitar para uma integração com outro servidor uma vez que o servidor e exclusivo para o software de integração. Interagir essa maquina com outra implicaria em procedimento de abertura de regra de firewall logo, preferimos deixar tudo centralizado uma vez que teremos durante este processo, a maquina com todos os seus recursos exclusivos para o processo. Contamos um um SQL Server 2016 com alta capacidade de comunicação.

Próximos passos:

Seguindo a ideia @pfk66, estou realizando os seguintes procedimento:

  • Realizados:

  • 1- Em uma ferramenta de integração de dados, ja separei os códigos em grupos de 1e5 , 3e2 e 1e1 permanecendo com os registro que apenas, e apenas, tenham relacionamento entre eles pois, a base tem muito lixo.

  • Em andamento:

  • 1- Jogando as informações extraídas para o SQL SERVER 2016 criando index pelas chaves. Apesar de repertisem, quando separamos em grupos, as mesmas tornam-se únicas em cada tabela.

Espero que as explicações possam ter tiradas as dúvidas e obrigado mais uma vez.

F

Fala pessoal, boa tarde.

Resultado da aplicação sugerida pelo @pfk66

A media de insert dentro do banco de dados, ficou em 1,33 por segundo, não estou armazenando em disco.

Levando em consideração que estou fazendo em cima de 133.680.412 registros (depois que fiz o pre-tratamento) e que estou falando em um I5 3.74 com apenas 8 de ram, acredito que no servidor real fique mais rápido porém nao o suficiente

Considerações finais:
A tabela 3 , que é a mandatória , com 47.073.366 registros, nessa verificade de 1.33 p/segundo demorará 1 ano e 1 mes para fazer com todos os registros. Nao irá me atender.

Tamanhos reais tabelas:
Tabela 1 = 39533669
Tabela 2 = 47073377
Tabela 3 = 47073366

Próximos passos:
Vou colocar uns 32GB de ram na minha maquina
Colocar o todos os registros em memória e realizarei o HashMap.

Aguardam próximos resultados!
Abraços e obrigado a todos mais uma vez.

cviniciusm

Olá,

Conhece o Apache Spark ?

Introdução ao Apache Spark

Apache Spark: Processando grafos com Big Data

rmendes08

E qual é a tabela que vai ser percorrida ? Coloque o algoritmo do processamento (em alto nível, por favor). De qualquer maneira, processar 355 milhões de linhas vai demorar um bocado mesmo.

F

@cviniciusm obrigado pela dica. Irei estudar mais.

F

Hoje acredito que encontrei uma solução viável, que foi a utilização do HashMap.
Com ele, todo o processamento do 133.680.412 de linhas, executou em menos de 10 minutos.

O problema que estava tendo nos meu teste é a concessão de memoria máxima para a maquina virtual do java e a própria quantidade de memoria que eu tenho em meu computador. O processo consome em media 13GB de memória porem, fico extremamente rápido.

Vou realizar mais testes amanha na empresa e depois ponho a resposta aqui.

O exemplo que postei no dia Out 8, às 12:06, retrata exatamente o meu problema.

Vou tentar modificar alguma coisa mas e bem trabalhoso mudar todos os campos porém, me comprometo em colocar o tempo e da um print do resultado para que todos tenham também a solução em mãos,

F
Solucao aceita

Pessoal, fim do mistério.

Conseguir roda o processo apenas no ambiente de produção, onde tenho 120GB de ram.

Utilizei o HashMap todo o processo envolvendo as 133 milhões de linhas demorou menos de 10 minutos.
Ocupou uma memória violenta, mais precisamente 21GB(apesar dos arquivos em si terem apenas 3.5GB)

Agradeço a todos a atenção dada e dicas. Coloco-me a disposição para eventuais problemas.

Atenciosamente,

Felipe Cabral.

Criado 6 de outubro de 2016
Ultima resposta 13 de out. de 2016
Respostas 21
Participantes 8