API Java e REST: come posso verificare la presenza di duplicati prima di inserire il record?

4

Sto sviluppando un'applicazione in Java per analizzare e caricare record da un CSV a un database online, tramite un'API REST.

Pur essendo sicuro che non ci siano record duplicati in ogni file CSV, non posso essere sicuro che ogni file CSV sia stato elaborato una sola volta (* vedi chiarimenti sotto), quindi ho bisogno di verificare la presenza di duplicati prima di inserire.

[CHIARIMENTO] Non riesco a implementare una soluzione controllando che ogni file CSV sia stato elaborato una sola volta. I file CSV contengono record di transazioni bancarie scaricati da una banca. Pertanto, so che ogni singolo file CSV non contiene duplicati. Tuttavia, è possibile scaricare più file CSV per lo stesso intervallo di date, o per intervalli di date sovrapposti, ecc., Quindi è necessario verificare la presenza di duplicati a livello di transazione anziché a livello di file.

Purtroppo non ho alcun controllo sul database di back-end e posso utilizzare solo i metodi disponibili tramite l'API. Ciò significa le solite soluzioni che utilizzano SQL (ad esempio questa domanda ) non sono adatti.

Metodi disponibili da API ( link ):

  • listTransactions

  • editTransaction

  • insertTransaction

Metodi disponibili ma probabilmente non pertinenti:

  • listProjects

  • listWriteProjects

  • getBalance

  • getTags

  • NewProject

  • deleteProject

  • listTagTransactions

  • deleteTransaction

  • listCurrencies

  • userData

Non è un enorme database: solo quattro colonne e qualche migliaio di record.

Sembra che la mia unica opzione sia quella di iterare su ogni record da inserire e confrontarlo con ogni record del database:

get ListOfRecordsInDb from database using listRecords(). Store in HashMap,
    local database or similar data structure??

for each record to be inserted,
    iterate over ListOfRecordsInDb, checking none of them match 
       the record to be inserted
    if no match found, insert record

Questo sembra molto inefficiente. Ci sono altre opzioni? In caso contrario, qual è il modo più efficiente per confrontare migliaia di record, utilizzando Java?

Risposte a commenti / domande:

What happens if you call insertTransaction with a transaction that already exists? Does it duplicate it or does it fail?

La transazione è stata inserita correttamente come duplicato

Does the CSV file have an "id" column?

No. Le colonne disponibili sono Data, Descrizione, Quantità e Saldo. La combinazione di questi rende ogni record unico, quindi potrei potenzialmente creare un ID basato su questi.

Does listRecords() allow pagination, or can it only return all of the records?

Restituisce solo i record, in formato XML.

    
posta Lydia Ralph 17.06.2015 - 14:33
fonte

3 risposte

4

I cannot be sure that each CSV file has only been processed once...

Potresti voler tentare di risolvere la tua domanda gestendola prima. Se ho capito bene, il nocciolo del tuo problema non sembra essere una singola transazione duplicata (dato che hai menzionato "So per certo che non ci sono record duplicati in ogni file CSV"), ma per evitare un'elaborazione duplicata per file.

Quindi, puoi considerare l'aggiunta di qualche tipo di logica di stato nella tua applicazione Java che sa se un file è stato elaborato calcolando e memorizzando il suo checksum, ad es. il suo hash MD5 . Una volta che hai un checksum corrispondente, sai che c'è una buona probabilità che il file sia stato elaborato in precedenza. Puoi eseguire ulteriori verifiche, ad esempio ispezionando il numero di righe o altri identificatori univoci di ciascun file.

Estendendo ulteriormente questa idea, se ci sono possibilità che la stessa transazione appaia su diversi file CSV, allora l'unica altra opzione, oltre all'aggiornamento dello schema del database per gestire correttamente i duplicati, è di memorizzare tutte le transazioni processate localmente all'interno di Java applicazione. Se possono esserci più istanze della tua applicazione (sullo stesso computer, o attraverso una rete), allora avrai bisogno di un altro database centralizzato per gestirlo, o di una griglia di dati distribuita ... per allora, l'opzione migliore è ancora sul tavolo da disegno per migliorare sul tuo schema di database esistente.

modifica

Per capovolgere le cose, le altre considerazioni da esaminare in , se cambiare lo schema del database per gestire i duplicati è interamente non pensarci nemmeno quasi impossibile , è valutare la quantità di dati che l'applicazione Java dovrà elaborare in un determinato momento e la velocità della connessione tra il database e l'applicazione.

Nell'estremità inferiore, supponiamo che l'applicazione stia elaborando solo 10 record per file, calcolando la media di un file all'ora. La connessione di rete è molto buona, diciamo quasi come accedere a un database ospitato localmente. In questo caso, non penso che l'impatto sulle prestazioni derivi in gran parte dal dover interrogare tutti i record.

All'estremo opposto, l'applicazione dovrebbe leggere file di transazioni di migliaia di righe ogni 10 secondi e la connessione di rete è estremamente negativa, ad esempio impiegando un minuto per interrogare tutti i record. In questo caso, si hanno maggiori dubbi sull'elaborazione dei file in modo rapido e in questo modo è possibile suggerire di modificare lo schema del database. :)

Quindi, se tutto va bene nel caso di livello inferiore, quale sarebbe un modo efficace per confrontare un set di dati relativamente grande con un set di input più piccolo per i duplicati? Ti suggerisco di eseguire il marshalling del payload XML che ottieni in HashSet . Inoltre, spero che tu abbia una classe di dominio Transaction con metodi hashCode() e equals() correttamente implementati. Una potenziale soluzione di Java 8 sarebbe quindi:

// assuming your database records are marshalled into currentSet
inputSet.stream().filter(v -> !currentSet.contains(v))
                    .forEach( /* these are the new records to send to the database */);

Inoltre, l'elefante nella stanza: inserimenti simultanei. Ci sarà? Se sì, come intendi gestirlo allora?

    
risposta data 18.06.2015 - 02:22
fonte
2

Considerando che hai affermato che si tratta di API REST, pensa che ogni chiamata all'API comporterà un certo traffico di rete, dove si applicano la latenza e il tempo di trasferimento. Quindi direi meno chiamate all'API che fai (memorizza i risultati in memoria per cercare), meglio è.

Tuttavia, quando lavori con l'API, non sempre hai una scelta: se l'API stessa non è ben progettata, o non progettata per scopi come il tuo in mente, potresti non avere altra scelta che fare come hai detto .

Inoltre, considera che un servizio remoto (API REST) può essere utilizzato contemporaneamente da molti utenti, il che significa che caricare tutti i risultati in memoria o DB locale, per elaborarli in un secondo momento, può causare problemi perché i dati remoti sono cambiati in nel frattempo.

Temo che la mia non sia una risposta adeguata alla tua domanda, poiché credo che una risposta adeguata possa essere data solo a condizione che tu prima documenti bene quali sono le chiamate API disponibili, i loro input e output, ma puoi beneficiare da questi pochi suggerimenti, spero.

    
risposta data 17.06.2015 - 17:14
fonte
2

Ti stanno schiacciando in entrambe le direzioni, con input ingannevoli e un back-end difficile. In un mondo ideale, sfiderai alcuni di questi vincoli, ma ho l'impressione che non andrai da nessuna parte.

L'algoritmo che descrivi sembra la tua unica opzione, anche se penso che possa essere migliorata un po '.

  1. Elenco chiamateTransazioni e archivia tutte le transazioni in un HashSet
  2. Fai scorrere il file CSV:
    1. Se la linea si trova in HashSet, ignora
    2. Altrimenti, insertTransaction

Solo poche migliaia di righe, penso sia accettabile chiamare listTransactions ogni volta che qualcuno carica un CSV. Se il database fosse più grande dovresti considerare di creare il tuo database, che rispecchia il back-end di REST, unicamente allo scopo di evitare duplicati.

Una cosa che non capisco, anche se non è rilevante, è come l'API REST può avere un editTransaction quando le transazioni non hanno un ID.

Modifica - ok, anche se il file CSV non ha ID, il servizio REST di back-end ha un ID.

    
risposta data 19.06.2015 - 12:31
fonte

Leggi altre domande sui tag