Algoritmo para determinar transações entre séries semanais de dados?


9

Estou tentando desenvolver uma pequena ferramenta de relatório (com back-end sqlite). Posso descrever melhor essa ferramenta como um razão de "transação". O que estou tentando fazer é acompanhar as "transações" da extração semanal de dados:

  • "novo" (ou adicionar) - o recurso é novo no meu aplicativo, pois ele pode não ter rastreado esse recurso antes, pois não foi visto por meio de extrações.
  • "update" (ou hit) - há um uso recente desse recurso, atualize o período de retenção por mais uma semana.
  • "excluir" (ou soltar) - esse item não foi utilizado desde o último relatório (opcional, mas seria bom ter um gráfico das alterações semana a semana na demanda por recursos).

Tudo o que tenho é uma extração semanal de dados (arquivo simples delimitado por canal) proveniente de um sistema legado de arquivamento / gerenciamento de registros sobre o qual não tenho controle.

Cada linha pode ser destilada para basicamente isso:
resource_id | resource info | customer_id | customer_info

Dados de amostra:

10| Title X       | 1 | Bob
11| Another title | 1 | Bob
10| Title X       | 2 | Alice

O objetivo é facilitar o relatório de recursos que não são usados ​​por X-meses (com base no último hit). Há um período de retenção em que os recursos são mantidos para facilitar o acesso, se populares. Um recurso que não é utilizado há 18 meses está marcado para arquivamento de longo prazo em outros lugares.

Este deve ser um problema comum. Querendo saber se existe um algoritmo de uso geral para determinar o que há de novo / o mesmo / removido entre os conjuntos de dados (db vs. última extração)?

Respostas:


1

Bem, sua resposta é ... Sim. Existe um algoritmo simples que você pode implementar que não requer nada disso. É um algoritmo de valor presente líquido. É fácil de implementar e tudo o que é necessário no final do banco de dados é que você marca os dados semanais e escreve uma consulta simples e uma pequena função recursiva ou loop, ou você pode fazer uma dessas outras soluções.

VPL = PV- (PV (CP / T) ou o Novo Valor Presente é igual ao Valor Presente multiplicado pelo Período Atual (meses desde a última entrada) dividido pelo Prazo (por exemplo, 18 meses) quando o valor do recurso cai para 0, é o valor atual líquido está gasto.

Se você me der um lang, você quer que eu publique o código aqui em uma edição


A linguagem não é tão importante. Ruby ou C ++, se eu tivesse que escolher. Se você pode escrever um algoritmo em HTML 4.0 Strict, você será meu herói. Brincando sobre a última parte :)
Swartz

Estaria interessado em ver o código. Ruby ou C ++. Obrigado.
Swartz

0

Se você estiver mantendo as atualizações em um back-end do SQLite, poderá transformar a atualização semanal em uma nova tabela e compará-la com os dados arquivados com consultas, antes de mesclá-la.

Exemplo de uso do SQL para localizar novas inclusões em uma tabela: /programming/2077807/sql-query-to-return-differences-between-two-tables

Se um campo no seu banco de dados armazena a data da transação, basta consultar todos os usuários que realizaram transações nos últimos 18 meses. Em seguida, o arquivo é apenas o banco de dados completo. Como alternativa, você pode consultar todos os usuários que não o fizeram, extrair os dados e descartá-los. As atualizações são todas as linhas com carimbo de data e hora desta semana.


Melhor, é uma solução centrada em dados, pelo menos, mas ainda é um exagero
J-Boss

Por enquanto, estou usando um sqlite, pois é fácil começar. Poderia facilmente mudar para o MySQL (ou PostgreSQL). Se o uso de um back-end sem SQL renderia alguma coisa para tornar esse trabalho ainda melhor, eu sou todo ouvidos.
Swartz

Bem, meu pensamento era principalmente que você está convertendo para linhas em um banco de dados de qualquer maneira . Se você não precisar executá-lo de vários processos simultaneamente, acho que não deseja mudar para algo mais pesado que o SQLite.
Davislor

Não há necessidade de processamento simultâneo. Mas preciso armazenar os dados sobre recursos em algum lugar. Um banco de dados SQL parecia uma boa opção. No entanto, não há nada que me impeça de carregar dados em qualquer tipo de dados para processar deltas. Tudo o que quero ao final de cada extração é descobrir o que há de novo, o que permaneceu o mesmo e o que desapareceu. Eu posso descobrir como atualizar registros conforme necessário a partir desta informação.
Swartz

Depois de analisar os dados e colocá-los no banco de dados, provavelmente é mais fácil escrever uma consulta do que implementar um algoritmo. Dito isso, se você quiser codificá-lo, o algoritmo que você quer é definir a diferença e há uma implementação no C ++ STL que você pode usar para fazê-lo em uma única linha depois de colocar os dois conjuntos de dados no contêiner de sua escolha, provavelmente a Vector.
Davislor 5/09/15

0

Idéia alternativa:

  1. Analise sua lista de transações em algum tipo de estrutura de dados, como uma matriz. (Em C ++, pense Vectore em Java ArrayList,.)

  2. Execute uma consulta no seu back-end SQL, como por exemplo, SELECT DISTINCT customer_id FROM Transactions ORDER BY customer_ide empacote os IDs de clientes distintos classificados em um conjunto old. Se você fizer exatamente o mesmo com uma WHEREcláusula que separa as transações antigas e novas, poderá pular a etapa 3.

  3. Obtenha os IDs de clientes exclusivos das novas atualizações em uma estrutura de dados separada, em ordem classificada. Existem algumas estruturas de dados que você pode usar para obter uma estrutura de dados new,. A ordenação por inserção em uma lista com vínculo duplo é muito simples, mas o uso de uma hashtable intermediária seria executado em tempo quase linear ou, se você estiver classificando a matriz original de qualquer maneira, é fácil obter uma configuração disso.

  4. Tome a diferença definida new- oldusando a biblioteca padrão do seu idioma favorito. Seu idioma favorito possui esse algoritmo em sua biblioteca padrão?

As outras coisas que você deseja fazer são definitivamente consultas SQL depois de atualizar seu banco de dados de transações.

Nota na etapa 3: considere a natureza dos seus dados. Suponha que seu arquivo de texto liste pedidos cronologicamente e, em uma semana típica, muitos clientes iniciantes recebem um novo customer_idem ordem crescente. Suponha que a maioria dos outros pedidos seja de um pequeno número de clientes fiéis fiéis, com menos customer_id. Então suas entradas já são classificadas principalmente. Um tipo de inserção em que você tenta inserir baixo customer_idna frente de uma lista com vínculo duplo e alto customer_idna parte de trás, nessa situação, teria um bom desempenho na prática.


11
Estou mais interessado nas novas / mesmo / atualizados recursos em vez de clientes. Mas sim, a ideia seria a mesma.
Swartz

0

Pelo que entendi da sua pergunta, você realmente possui resource_id (+ info) e "lista" de cliente (id + info).

Assim, você pode manter facilmente a Lista de clientes por recurso e verificar o último nó em cada lista do recurso (para saber o horário da última operação; basta adicionar o campo de data ao seu cliente no código)

Eu não estou familiarizado com SQL, portanto, dou meu exemplo com HashMape List, mas tenho certeza de que é a mesma idéia:, HashMap <Resource, List<Customer>>quando Resourcedeve conter resourceID como chave e Customerdeve conter ID do cliente, informações e data da operação.

Com essa idéia, você pode conhecer facilmente o último tempo de operação e modificar qualquer recurso (adicionar \ remover recurso \ cliente).


0

Se você estiver usando um banco de dados SqLite, se adicionar a data do lote também como uma coluna da tabela,

10| Title X       | 1 | Bob    | 2015-03-01
11| Another title | 1 | Bob    | 2015-03-01
...............................
10| Title X       | 1 | Alice  | 2015-03-05

seria muito fácil usar um SQL para obter os recursos não utilizados no último número X de dias

Select distinct r.ResourceID from Resources r
where not exists (SELECT julianday('now') - julianday(r.DateUpdated)) < X

Eu não testei o SQL, mas deve lhe dar uma idéia


0

Da postagem original, parece que os dados que estão sendo ingeridos não possuem um campo para indicar a data / hora da transação, e presumo que o arquivo seja ingerido com frequência, em uma programação diária, horária etc.

Eu lidaria com isso adicionando uma coluna de carimbo de data / hora SQL que é gerada automaticamente no nível do banco de dados ou pelo código que extrai os dados e insere no banco de dados. Em seguida, você coloca um índice nessa coluna de carimbo de data e hora e termina com ele. Deixe o mecanismo de banco de dados fazer o trabalho de responder com eficiência à pergunta "quantas transações não ocorreram desde esse momento" ou "quantas entre esse período e esse período".

Em seguida, você agende um trabalho para consultar e calcular os diferenciais sobre os quais deseja relatar. Transações "novas" são transações que não têm nenhum registro no banco de dados anterior à data em que você está solicitando "novas desde". Registros antigos são aqueles que não têm transações desde a data limite.


-2

Não é para isso que servem as HashTables? Se tudo o que você deseja fazer é manter registros de quais recursos foram usados ​​nos últimos meses e excluir recursos que não foram acessados ​​nos últimos 18 meses, você poderá usar um HashTable em que a Chave é o resource_id e o valor é o data do último acesso.

Para arquivar os registros com mais de 18 meses, você pode percorrer todos os registros na tabela de hash e apenas remover (ou mover) esses registros específicos. (você pode fazer isso semanalmente quando o relatório chegar)


Por que a necessidade do HashTable se estou armazenando coisas no banco de dados? Eu posso fazer atualizações nos registros db. Estou mais interessado em um caso: pegue dois conjuntos de dados, descubra as diferenças (o que é adicionado, permanece o mesmo, excluído) entre os dois conjuntos. Como uma técnica HashTable ajudaria a encontrar registros novos e "removidos"?
Swartz

Se as tabelas são indexadas no banco de dados, elas também são basicamente HashTables nos bastidores. Se você tiver 2 tabelas, cada uma representando um conjunto de dados, poderá obter seus registros novos e removidos fazendo algumas junções externas. Consulte isto para referência: i.stack.imgur.com/pxUO3.png . Verifique se você possui índices na coluna resource_id e ela deve ser bem rápida. Se você tivesse que implementar isso do zero, acho que o HashTables ainda seria o caminho a seguir, pois você pode procurar / inserir / excluir no tempo amortizado O (1). Não consigo pensar em uma maneira mais eficiente de fazer isso.
Adrian Buzea

3
Existem estruturas de dados melhores que lidam com o envelhecimento, sem as etapas extras de amontoar isso em uma tabela de hash.

Gostaria de mencionar alguns?
Adrian Buzea

@Snowman - Eu gostaria de poder-se taxa que mais algumas vezes, eu vou ter enfaticamente concordam em este comentário
J-Boss
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.