Mappe nidificate e chiavi combinate

5

nel progetto al momento sto lavorando abbiamo avuto tre diversi tipi di prezzi a seconda dell'età dell'utente (adulto, bambino, ecc ...). Quindi abbiamo avuto sul DB una tabella simile a questa:

PRICES
type     Amount
A         20
B         15
C         ..
D         ..

All'inizio avevamo solo 4 diversi tipi di prezzi, quindi nel codice avevamo qualcosa di simile a questo:

Map<String, BigDecimal> prices = new HashMap<String, BigDecimal>();

Dove le chiavi erano il tipo di prezzo.

Recentemente, hanno aggiunto una nuova regola aziendale che aggiunge 3 sottotipi a ogni tipo di prezzo, quindi ora abbiamo qualcosa di simile a questo:

PRICES
type   subtype  Amount
A          1      20
A          2      15
A          3      ..
B          1      ..
B          2      ..
...        ..     ..

Quale delle seguenti due opzioni ritieni sia meglio e perché?

Mappe nidificate

Map<String, Map<String, BigDecimal>> prices;

dove le chiavi sono il tipo di prezzo e il sottotipo:

prices.get(type).get(subtype);

Tasti combinati

La stessa mappa dell'originale:

Map<String, BigDecimal> prices;

E concatena le chiavi per indicizzare i diversi prezzi:

prices.get(type+"_"+subtype);
    
posta mario595 16.07.2014 - 15:16
fonte

4 risposte

4

Entrambe le chiavi nidificate e combinate hanno i loro posti. bowmore fornisce un argomento pro per le chiavi composite e un argomento di conflitto per le mappe nidificate. Permettetemi di fornire la fedele opposizione:

I tasti mappa compositi funzionano alla grande quando stai cercando uno specifico elemento conosciuto.

Le mappe nidificate funzionano bene quando è necessario trovare rapidamente tutte le varianti, i tipi ei sottotipi di tipo A. Ad esempio, scegliendo A (rispetto a B, C, ...) potrebbe essere il primo passo in un albero decisionale . Una volta che l'utente o l'algoritmo o qualsiasi cosa scelga A, allora è necessario conoscere solo i sottotipi di A, e B..Z o B..ZZZZZ non contano più.

Ora hai a che fare con una struttura di ricerca molto stretta ed efficiente per la ricerca secondaria. Se provi a farlo con i tasti compositi, finisci per eseguire una scansione completa della tabella a la [ (key, value) for (key, value) in prices.items() if key.startswith('A') ] . Questa è non un'operazione efficiente e sarà lenta se la mappa è troppo grande.

Le mappe nidificate funzionano bene anche quando il numero di livelli di nidificazione può aumentare. La struttura del problema è già stata estesa da type a (type, subtype) . C'è qualche possibilità che il prossimo giro abbia bisogno di (type, subtype, variation) o (type, subtype, version) ? In tal caso, un approccio di mappatura nidificato può essere esteso in modo pulito. Questo, comunque, è un vantaggio stilistico, di secondo ordine, soprattutto rispetto al vantaggio "easy subsearch" sopra.

    
risposta data 17.07.2014 - 21:58
fonte
3

Evita mappe nidificate. Sono più difficili da ridimensionare e portano a un codice molto prolisso e difficile da leggere con tutte le dichiarazioni generiche annidate in corso.

Ancora più importante, Maps in Java tende a consumare molta memoria. La compilazione di una mappa con ancora più mappe non farà che aggravare il problema del consumo di memoria.

Infine, una mappa che usa le chiavi composite è più facile da ragionare.

L'uso dei tasti compositi ti semplificherà la vita nei casi più tipici, tuttavia alcune cose saranno più difficili. Ad esempio, ottenendo tutti i prezzi per un componente chiave specifico, ma è più probabile che si invii i risultati direttamente dal database anziché distillarli dalla mappa.

    
risposta data 17.07.2014 - 19:00
fonte
0

Entrambe le opzioni non sono buone secondo me. Dì cosa succede se la logica di business cambia di nuovo in modo da avere un altro sottotipo?

Quello che ti suggerisco di fare è il seguente:

  1. Utilizza una chiave surrogata per una chiamata alla tabella Type questa tabella sarà simile a Type(INT auto_inc id, VARCHAR(255) name, VARCHAR(255) desc, INT status, etc)
  2. Nella tua tabella Price usa la chiave esterna nella tabella Type sopra in modo che assomigli a Price(INT type_id, INT price)
  3. Assicurati di NON supportare l'eliminazione di un tipo. Contrassegni semplicemente un tipo come inactive perché i riferimenti penzolanti renderebbero la cancellazione un vero mal di testa

Ora, la logica utente e aziendale può aggiungere qualsiasi combinazione di sottotipo di tipo nello schema. Quello che dovrebbero fare è semplicemente creare una nuova riga nella tabella Type e cambiare name e / o desc nella vecchia tabella.

Nel tuo caso, l'utente dovrebbe rinominare il tipo A per digitare A_1 , aggiungere un nuovo tipo chiamato A_2 e impostare un nuovo prezzo per A_2 come 15

    
risposta data 16.07.2014 - 19:48
fonte
0

Questo non ha a che fare con "quale implementazione è la migliore" e più con "quale astrazione dovrei lavorare con".

Sia la chiave composita che la mappa delle mappe hanno i loro punti di forza e le loro debolezze, tutte presenti nel dominio delle prestazioni (ad esempio, utilizzo di velocità / memoria). Non differiscono nella loro funzionalità: entrambi prendono due valori e restituiscono il valore "put" precedentemente impostato.

Poiché sono equivalenti dal punto di vista funzionale, la prima cosa che dovresti fare è astrarre su di loro. Non preoccuparti di quale è meglio. Creare un'interfaccia DoubleKeyedMap con tutti i metodi necessari su di essa e utilizzarla nel codice. Quindi scrivi qualunque implementazione tu possa scrivere più velocemente e semplicemente andare avanti.

SOLO una volta che hai scritto la tua applicazione e hai scoperto che l'implementazione della tua chiave composita non filtra la prima chiave molto velocemente, o che la mappa delle mappe sta prendendo troppa memoria se dovessi andare e ottimizzare.

L'ottimizzazione prematura è la radice di tutti i mali. Non astrarre è peggio.

    
risposta data 28.09.2016 - 11:24
fonte

Leggi altre domande sui tag