Algoritmo per determinare le transazioni tra serie di dati settimanali?


9

Sto cercando di sviluppare un piccolo strumento di reportistica (con backend sqlite). Posso descrivere al meglio questo strumento come un libro mastro di "transazione". Quello che sto cercando di fare è tenere traccia delle "transazioni" dall'estratto settimanale dei dati:

  • "new" (o aggiungi): la risorsa è nuova per la mia app poiché la mia app potrebbe non aver monitorato questa risorsa in precedenza poiché non è stata vista tramite estratti.
  • "aggiornamento" (o hit) - c'è un uso recente di quella risorsa, aggiorna il periodo di conservazione di un'altra settimana.
  • "elimina" (o rilascia): questo elemento non è stato utilizzato dall'ultimo rapporto (facoltativo, ma sarebbe utile avere un grafico delle variazioni settimanali della domanda di risorse).

Tutto quello che ho è un estratto settimanale di dati (file flat delimitato da pipe) proveniente da un sistema di archiviazione / gestione dei record legacy su cui non ho alcun controllo.

Ogni riga può essere distillata sostanzialmente per questo:
resource_id | resource info | customer_id | customer_info

Dati di esempio:

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

L'obiettivo è semplificare la segnalazione di risorse che non sono state utilizzate per X-mesi (in base all'ultimo hit). C'è un periodo di conservazione in cui le risorse sono conservate per facilitare l'accesso se sono popolari. Una risorsa che non ha visto l'uso per 18 mesi è contrassegnata per l'archiviazione a lungo termine altrove.

Questo deve essere un problema comune. Ti chiedi se esiste un algoritmo generico per determinare cosa c'è di nuovo / uguale / rimosso tra set di dati (db vs. ultimo estratto)?

Risposte:


1

Bene, la tua risposta è ... Sì. C'è un semplice algoritmo che puoi implementare che non richiede nulla di tutto ciò. È un algoritmo di valore attuale netto. È facile da implementare e tutto ciò che richiede alla fine del database è che tu stampi i dati settimanali e scrivi una semplice query e una piccola funzione ricorsiva o per il ciclo, o potresti fare una di quelle altre soluzioni.

NPV = PV- (PV (CP / T) o il nuovo valore attuale è uguale al valore attuale moltiplicato per il periodo corrente (mesi dall'ultima immissione) diviso per il termine (ad esempio 18 mesi) quando il valore della risorsa scende a 0 è il valore attuale netto è esaurito.

Se mi dai un lang in cui lo vuoi, posterò il codice qui in una modifica


La lingua non è così importante. Ruby o C ++ se dovessi scegliere. Se riesci a scrivere un algoritmo in HTML 4.0 Strict sarai il mio eroe. Sto scherzando sull'ultima parte :)
Swartz,

Sarebbe interessato a vedere il codice. Rubino o C ++. Grazie.
Swartz,

0

Se si mantengono comunque gli aggiornamenti in un backend SQLite, è possibile trasformare l'aggiornamento settimanale in una nuova tabella e confrontarlo con i dati archiviati con le query, prima di unirli.

Esempio di utilizzo di SQL per trovare nuove aggiunte a una tabella: /programming/2077807/sql-query-to-return-differences-between-two-tables

Se un campo nel tuo DB memorizza la data della transazione, puoi semplicemente interrogare tutti gli utenti che hanno avuto transazioni negli ultimi 18 mesi. Quindi l'archivio è solo il DB completo. In alternativa, puoi interrogare tutti gli utenti che non lo hanno fatto, estrarre i loro dati, quindi rilasciarli. Gli aggiornamenti sono tutti i file con data e ora di questa settimana.


Meglio, è almeno una soluzione incentrata sui dati, ma è ancora eccessiva
J-Boss

Sto usando un sqlite per il momento in quanto è facile iniziare. Potrebbe facilmente passare a MySQL (o PostgreSQL). Se l'utilizzo di un back-end no-SQL non farebbe nulla per rendere questo lavoro ancora migliore, sono tutto a posto.
Swartz,

Bene, il mio pensiero era principalmente che lo stai convertendo in righe in un database comunque . Se non è necessario eseguirlo contemporaneamente da più processi, non penso che si desideri passare a qualcosa di più pesante di SQLite.
Davislor,

Nessuna necessità di elaborazione simultanea. Ma devo archiviare i dati sulle risorse da qualche parte. Un db SQL sembrava una buona scelta, tuttavia non c'è nulla che mi impedisca di caricare i dati in qualsiasi tipo di dati per l'elaborazione dei delta. Tutto quello che voglio alla fine di ogni estrazione è capire cosa c'è di nuovo, cosa è rimasto uguale e cosa è scomparso. Posso capire come aggiornare i record come necessario da queste informazioni.
Swartz,

Dopo aver analizzato i dati e averli inseriti nel database, è probabilmente più semplice scrivere una query che implementare un algoritmo. Detto questo, se vuoi codificarlo, l'algoritmo che vuoi è impostato sulla differenza e c'è un'implementazione nel C ++ STL che puoi usare per farlo in una sola riga dopo aver inserito entrambi i set di dati nel contenitore di la tua scelta, probabilmente a Vector.
Davislor,

0

Idea alternativa:

  1. Analizza il tuo elenco di transazioni in un qualche tipo di struttura di dati, come un array. (In C ++, pensa Vector, e in Java,. ArrayList)

  2. Eseguire una query in SQL backend, come SELECT DISTINCT customer_id FROM Transactions ORDER BY customer_ide imballare le ordinate ID cliente distinte in un set, old. Se fai esattamente la stessa cosa con una WHEREclausola che separa le transazioni vecchie e nuove, puoi saltare il passaggio 3.

  3. Ottieni gli ID cliente univoci dai nuovi aggiornamenti in una struttura di dati separata, in ordine ordinato. Ci sono un paio di strutture di dati è possibile utilizzare per ottenere è in una struttura di dati, new. L'ordinamento di inserzione in un elenco a doppio collegamento è molto semplice, ma l'utilizzo di una tabella hash intermedia verrebbe eseguito in un tempo quasi lineare, o se si ordina comunque l'array originale, ottenere un set da quello è facile.

  4. Prendi la differenza impostata new- oldusando la libreria standard della tua lingua preferita. La tua lingua preferita ha questo algoritmo nella sua libreria standard?

Le altre cose che vuoi fare sono sicuramente le query SQL dopo aver aggiornato il database delle transazioni.

Nota sul passaggio 3: considerare la natura dei dati. Supponiamo che il tuo file di testo elenchi gli ordini in ordine cronologico e, in una settimana tipica, ci siano molti clienti principianti che ricevono un nuovo customer_idordine in ordine crescente. Supponiamo che la maggior parte degli altri ordini provenga da un numero limitato di clienti fedeli, con un numero inferiore customer_id. Quindi i tuoi input sono già in gran parte ordinati. Un ordinamento di inserzione in cui si tenta di inserire in basso customer_idnella parte anteriore di un elenco a doppio collegamento e in alto customer_idnella parte posteriore, in quella situazione, si sarebbe comportato bene nella pratica.


1
Sono più interessato alle risorse nuove / stesse / aggiornate piuttosto che ai clienti. Ma sì, l'idea sarebbe la stessa.
Swartz,

0

Come ho capito dalla tua domanda, hai effettivamente resource_id (+ info) e "list" del cliente (id + info).

Quindi puoi facilmente tenere Elenco dei clienti per risorsa e controllare l'ultimo nodo in ogni elenco sulla risorsa (per conoscere l'ora dell'ultima operazione; devi solo aggiungere il campo della data al tuo cliente nel codice)

Non ho familiarità con SQL, quindi do il mio esempio con HashMape List ma sono sicuro che è la stessa idea:, HashMap <Resource, List<Customer>>quando Resourcedovrebbe contenere CustomerID risorsa come chiave e dovrebbe contenere ID cliente, informazioni e data dell'operazione.

Con questa idea puoi conoscere facilmente l'ultima operazione e puoi modificare qualsiasi risorsa (aggiungi \ rimuovi risorsa \ cliente).


0

Se stai utilizzando un database SqLite, se aggiungi la data del batch anche come colonna della tabella,

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

sarebbe abbastanza facile usare un SQL per ottenere le risorse non utilizzate negli ultimi X giorni

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

Non ho testato l'SQL ma dovrebbe darti un'idea


0

Dal post originale, sembra che i dati ingeriti non abbiano un campo per indicare la data / ora della transazione, e presumo che il file venga ingerito su una base frequente su un programma come giornaliero, orario, ecc.

Gestirei questo aggiungendo una colonna timestamp SQL che è generata automaticamente a livello di database o dal codice che estrae i dati e li inserisce nel DB. Quindi inserisci un indice su quella colonna timestamp e hai finito. Lascia che il motore DB svolga il compito di rendere efficiente la risposta alla domanda "quante transazioni non sono avvenute da allora" o "quante tra questa volta e quella volta".

Quindi si pianifica un lavoro per eseguire una query e calcolare i differenziali su cui si desidera eseguire il report. Le transazioni "nuove" sono transazioni che non hanno alcun record nel DB prima della data in cui si chiede "nuovo da". I vecchi record sono quelli che non hanno transazioni da una data limite.


-2

Non è per questo che HashTables serve? Se tutto ciò che vuoi fare è tenere un registro delle risorse utilizzate negli ultimi mesi ed eliminare le risorse a cui non è stato effettuato l'accesso negli ultimi 18 mesi, puoi utilizzare una HashTable in cui la chiave è la risorsa_id e il valore è il data dell'ultimo accesso.

Per l'archiviazione dei record> 18 mesi è possibile esaminare tutti i record nella tabella hash e rimuovere (o spostare) quei record specifici. (puoi farlo settimanalmente quando arriva il rapporto)


Perché la necessità di HashTable se sto archiviando elementi nel database? Posso fare aggiornamenti ai record db. Sono più interessato a un caso: prendere due set di dati, scoprire le differenze (ciò che viene aggiunto, rimane lo stesso, eliminato) tra i due set. In che modo una tecnica di HashTable può aiutare a trovare record nuovi e "rimossi"?
Swartz,

Se le tabelle sono indicizzate nel database, in pratica sono anche HashTables dietro le quinte. Se hai 2 tabelle, ognuna delle quali rappresenta un set di dati, puoi ottenere i tuoi record nuovi e rimossi eseguendo alcuni join esterni. Vedere questo per riferimento: i.stack.imgur.com/pxUO3.png . Assicurati di avere indici nella colonna resource_id e dovrebbe essere abbastanza veloce. Se dovessi implementare questo da zero, allora penso che HashTables sarebbe ancora la strada da percorrere in quanto puoi fare ricerca / inserimento / cancellazione nel tempo ammortizzato O (1). Non riesco a pensare a un modo più efficiente per farlo.
Adrian Buzea,

3
Esistono strutture dati migliori che gestiscono l'invecchiamento senza i passaggi aggiuntivi di stipare questo in una tabella hash.

Ti va di menzionarne qualcuno?
Adrian Buzea,

@Snowman - Vorrei poter votare un po 'più di volte, avrò solo un forte consenso in questo commento
J-Boss
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.