Como recuperar um grande array em PHP rapidamente? - Stack Overflow em Português
Como recuperar um grande array em PHP rapidamente?
No exemplo abaixo, tenho um array em PHP com cerca de 128.000 registros (verbetes da língua portuguesa) que recuperei de um outro arquivo, e utilizo em algumas aplicações, para comparar os índices como HashMap.
array(128521) {
string(3) "aba"
string(4) "abá"
string(7) "ababás"
Como posso manter salvo esse array para que possa recuperá-lo rapidamente do HD, sem afetar muito o desempenho da aplicação? O foco é disponibilizar o array para as classes que o utilizarão o mais rápido possível.
editada 11/01/14 às 11:55
6.40544 medalhas de ouro2828 medalhas de prata5757 medalhas de bronze
perguntada 11/01/14 às 6:34
4.41744 medalhas de ouro2323 medalhas de prata5252 medalhas de bronze
Fiquei curioso sobre o motivo do voto contra nesta pergunta. O responsável poderia explicar? – bfavaretto♦ 11/01/14 às 13:10
Partilho a curiosidade do @bfavaretto, um voto contra numa pergunta deve sempre ser comentado. Quem vota contra é porque viu algo mal com a pergunta e nesse caso o comentário ajudaria a realizar as melhorias necessárias. – Zuul 11/01/14 às 14:07
Além de opções NoSQL e uma camada de Memcached conforme comentários acima, uma segunda opção seriam motores de busca. Esse tipo de problema possui características que eu trataria com indexação. Você precisará do array inteiro ou apenas consultar determinados vocábulos de acordo com os critérios de busca?
Caso você precise da segunda opção eu usaria uma ferramenta como o Apache Solr ou Elasticsearch para criar um índice dedicado (e.g., índice contendo um tupla [hash / vocábulo]). Índices bem tunados são muito rápidos e já possuem políticas de cache interno inteligentes, capazes de retornar consultas frequentes "instantaneamente" mesmo em um índice com milhões de entradas.
editada 12/01/14 às 21:01
respondida 11/01/14 às 15:32
não entendi o significado de índice dedicado. Você poderia explicar? – Calebe Oliveira 12/01/14 às 1:29
Olá, Calebe, essa é uma sub-área de Recuperação de informação bastante complexa, mas vou tentar explicá-la na melhor maneira possível. Partindo do caso do Google, ele indexa zilhões de documentos (html, pdfs, páginas, imagens, etc), ou seja, quando um crawler da Google encontra um documento ele é pré-processado e as informações relevantes para ele são armazenadas em um índice, de maneira que usuários da Google possam fazer pesquisas e obter resultados "instantâneos". – Anthony Accioly 12/01/14 às 21:08
Nesse sentido, quando você faz uma consulta a plataforma de busca não está batendo diretamente em um dado, e sim em um índice otimizado para responder aquele tipo de busca (seguindo os critérios de ranking que "ordenam" os dados conforme a relevância). O Apache Solr e o Elasticsearch são plataformas de busca com esse objetivo. Em suma, você constrói / modela seus próprios índices, alimenta-os com as informações necessárias e essas ferramentas utilizam a biblioteca Apache Lucene para construir índices eficientes e escaláveis. – Anthony Accioly 12/01/14 às 21:16
Esses ferramentas aguentam muito mais "porrada" que um banco de dados e implementam algoritmos mais específicos do que uma típica ferramenta NoSQL (como por exemplo, motores para enforçar políticas de rankeamento conforme o comentário acima). Além disso, para índices gigantescos (não é o caso do seu), essas ferramentas estão prontas para trabalhar com particionamento, clusterização, etc. Enquanto eu entendo que seu problema atualmente não é nada tão grande; ele tem cor, som e cheiro de recuperação de informação. Um índice específico para vocábulos deve atender suas necessidades. – Anthony Accioly 12/01/14 às 21:26
Certo, entendi, vou pesquisar sobre essas ferramentas, quem sabe elas resolvem meu problema. – Calebe Oliveira 13/01/14 às 1:02
De fato é completamente inviável fazer isso.
128 mil indices em um array, é uma grande quantidade para ser manipulada e/ou comparada.
O ideal é manter tal informação no database e buscá-la baseado em um limíte mínimo de parâmetros.
No mais tenho talvez duas soluções:
Esse array ser mantido como um arquivo físico (qual extensão você desejar, no formato json)
[EDITADO] Idéia
Apenas como complemento, no seu caso, creio que seja melhor criar um arquivo para cada "letra" do alfabeto.
A menos que sua comparação, inclua valores entre o valor do array, por exemplo: ada
girafada (brincadeira, haha)
Com isso creio que a pesquisa, seja mais rápida (em um único arquivo), mas claro, aumentará a quantidade de requisições no servidor, e pra ajudar neste caso, deixe qualquer informação do arquivo inline (minify), para que o tamanho seja reduzido/comprimido ao máximo.
Página em cache (json/xml)
Não gosto e/ou recomendo xml, mas fique à vontade
Ter uma página (rota) do seu sistema/site, que contem esse array também no formato json, porém, tal página ficará em cache pelo tempo determinado por você.
Dessa forma, quando outras aplicações forem acessar a página específica (por exemplo: http://www.examplo.com.br/ptbr.json ou http://www.examplo.com.br/ptbr.php - a extensão em sí não importa, e sim como você vai tratar a requisição), você retorna essa página, que neste caso estará em cache, e não será carregada novamente.
Você usa algum framework? A grande maioria deles já tem um sistema de cache pronto, e uma excelente administração do tipo de extensão/resposta/protocolo da sua requisição/rota.
Alguns links para lhe ajudar
Excelente post sobre cache pelo Thiago Belem: http://blog.thiagobelem.net/criando-um-sistema-de-cache-no-php/
Stack Overflow (em inglês) - apenas pesquisa
Pesquisa padrão do google
respondida 11/01/14 às 12:32
Sim, tenho um sistema de cache. Acredito que acessar o banco é muito mais lento que utilizar um arquivo físico, já que nunca vou buscar com iteração, e sim com Hash. Pensei em serializar, já que este processo é mais rápido que o parsing de JSON. – Calebe Oliveira 11/01/14 às 12:52
@CalebeOliveira Ouvi dizer que o unserialize é mais lento que o json_decode, vale a pena você testar o desempenhos dos dois. – bfavaretto♦ 11/01/14 às 12:55
@CalebeOliveira certamente serializar é uma opção sim. O ideal é você testar a performance, que neste caso não sei lhe dizer ao certo (preciso testar, assim como você). Após verificar a melhor maneira, basta criar um processo (cron talvez), para atualizar esse arquivo de x em x horas, e/ou somente quando houver modificação no database (desta tabela). – Patrick Maciel 11/01/14 às 12:58
@bfavaretto, fiz os testes, o unserialize é mais rápido. @Patrick, é um arquivo estático, não muda. – Calebe Oliveira 11/01/14 às 13:04
Você poderia utilizar uma solução NoSQL para isso, Redis, MongoDB algo que tenha uma performance que lhe atenda. – Flávio H. Ferreira 11/01/14 às 14:04