Calcolo della distanza e normalizzazione dei dati

6

Sto progettando un sistema che deve riportare la distanza di base tra i codici postali. Utilizzerà l'API Google Distance Matrix ma desidero memorizzare nella cache i risultati nel database in modo che più richieste per gli stessi punti di dati non generino chiamate API duplicate.

Una classe base Distance potrebbe essere simile a questa:

Unastrutturadatidibaseperlacachepotrebbeesseresimileaquesta:

Dal momento che non sto utilizzando dettagli a grana fine relativi alle modifiche a causa di strade a senso unico o autostrade divise, interscambi, ecc., quindi non mi importa se sto ricevendo i dati dal punto A a punto B o dal punto B al punto A. Ma non sono sicuro di come esprimerlo con la completa normalizzazione nel database. Con questa chiave primaria, sarebbe perfettamente legale per la stessa distanza esistere in due righe separate, cioè

var row1 = new Distance("00001", "00002");
var row2 = new Distance("00002", "00001");

Probabilmente sarebbe una buona idea per me richiedere un parametro SortedList nel costruttore, ma c'è un modo per progettarlo dal lato del database per imporre la piena normalizzazione?

    
posta lorddev 29.07.2013 - 03:07
fonte

4 risposte

1

Ho ricevuto una risposta da Tony su Google+ che mi ha aiutato molto. La chiave non è di buttare via l'idea della normalizzazione, ma semplicemente di superare il concetto di due colonne (zip1 + zip2) come chiave primaria - che era, per qualche motivo, il concetto con cui ho iniziato. Invece, usiamo una tabella relazionale che associa le due posizioni, senza preoccuparsi di quale ordine entrino.

La tabella relazionale esegue il mapping di due zip a un RouteId , quindi la tabella Routes conterrà i dati relativi alla distanza e alla data memorizzata nella cache.

    
risposta data 30.07.2013 - 03:52
fonte
7

Se la posizione è rappresentata da un codice postale (bene per i casi in cui la maggior parte delle stime di distanza sono all'interno di una tolleranza per lo stesso codice postale), allora imporre un vincolo CHECK sui campi Zip1 e Zip2 che Zip1 = < Zip2.

Ovviamente questo impone un onere corrispondente alla logica del middleware per capire che la convenzione per assicurare un solo record sta mettendo il più piccolo zipcode in Zip1. Questo è principalmente un problema per INSERIRE le righe, poiché le query possono essere agnostiche su quale campo sia il primo, ovvero WHERE (Zip1 = myZip1 e Zip2 = myZip2) OPPURE (Zip1 = myZip2 e Zip2 = myZip1).

Tuttavia, la normalizzazione non viene violata conservando entrambi gli ordini nella chiave composta. Utilizza qualcosa di meno del doppio del numero di record, ma sembra che siano file piuttosto piccole, quindi non sono sicuro di poter giustificare la complessità logica per motivi di efficienza (men che meno in termini di velocità).

    
risposta data 29.07.2013 - 03:27
fonte
2

In base alle Domande frequenti su questo codice postale , ci sono circa 43.000 codici postali negli Stati Uniti. La cifra fluttua di un paio di migliaia all'anno. Nota che il valore restituito da distance(zip1, zip2) può cambiare nel tempo probabilmente a causa di nuove costruzioni stradali, modifiche ai limiti del codice postale, ecc.

Se si memorizzano i valori di ritorno indefinitamente, è possibile concludere con 43.000 ^ 2 (circa 1,8 miliardi) di valori. In tal caso, evitare gli inversi (zip2, zip1) ha senso.

Se lasci scadere i tuoi record della cache (conservali per un giorno? una settimana? un mese?), allora potrebbe essere più sensato non preoccuparsi delle inversioni.

Finché non stai codificando per dispositivi mobili o incorporati, lo spazio su disco è davvero economico.

    
risposta data 29.07.2013 - 16:41
fonte
0

Considera l'allontanamento dalla normalizzazione. Per ogni allontanamento da una delle forme normali, c'è un'anomalia corrispondente da superare. Per 2NF fino a 5NF le anomalie sono generalmente nell'area della ridondanza dannosa.

Ciò che rende dannoso questo tipo di ridondanza è la possibilità che il database contenga fatti contraddittori tra loro e, pertanto, produca risultati errati. Devi programmare in modo tale che queste contraddizioni non si verifichino.

Per il lavoro di routine su database, è solitamente meglio normalizzare e quindi evitare la contraddizione che cercare di fare attenzione con gli aggiornamenti.

Ma se dovessi portare questa linea di ragionamento fino alla sua conclusione logica, non faresti mai alcun tipo di cacheing. Una cache contiene sempre dati ridondanti per i dati sottostanti che memorizza nella cache. Ogni volta che si costruisce una cache, è necessario proteggersi dalla cache fornendo risultati non più validi. La programmazione per far fronte alla ridondanza dannosa coinvolge lo stesso tipo di pensiero disciplinato.

Alla fine della giornata, puoi decidere di normalizzare dopo tutto. Ma non trattare la normalizzazione come una sorta di Santo Graal. Non lo è.

C'è un'alternativa. Ogni volta che aggiungi un punto dati alla cache, disponi i dati in modo che zip1.lt.Zip2. Ogni volta che si effettua una ricerca, sistemare le due cerniere allo stesso modo. È un po 'più aritmetico, ma potrebbe battere l'aggiunta di ogni punto due volte.

    
risposta data 29.07.2013 - 13:56
fonte

Leggi altre domande sui tag