Crea bucket unici per il flusso di entità in base ai vincoli sugli attributi di entità

2

Ho stream (grandezza 10s di milioni) di entità, ad esempio Item che è modellato come segue:

class Item {
 String id;
 Double price;
 Double profitPercentage;
 Country originCountry;
 Country destinationCountry;
 ...
}

Tutti gli attributi di questa entità sono ben definiti e sono limitati alle informazioni relative ai prezzi + ai metadati.

Vorrei dare a un utente la possibilità di creare bucket, che non sono altro che una serie di vincoli sull'attributo (ad es. price > 1000, originCountry == Country.USA, profitPercentage tra 5 e 20), ma con la condizione che un'entità non possa cadere in due bucket (lo stesso dovrebbe essere rilevato quando viene effettuato un tentativo di creare un Bucket in conflitto tra loro).

Anche le operazioni su ciascun tipo di entità sono ben definite, ad es. Il doppio può essere utilizzato solo nei confronti (>, <, =, intervallo), Paese (che rappresenta logicamente un membro di un insieme di valori ben definito) in alcuni set ecc.)

Ciò è dovuto principalmente al fatto che ciascun bucket è associato a un'azione automatizzata, come il pagamento, il rifiuto o il rimborso, e la risoluzione delle azioni sovrapposte non è banale.

L'ovvia soluzione a questo problema è consentire all'utente di definire priorità sui bucket creati (implica che più bucket possano corrispondere a una data entità), ma è una cosa che vorrei evitare, poiché richiede che non ci possa mai essere due bucket aventi la stessa priorità e tale eventualità non riuscirebbe in fase di esecuzione.

Sto cercando soluzioni che potrebbero essere utilizzate per rilevare i conflitti durante il tempo di creazione, ma non ho idea di dove cominciare. Altri hanno suggerito una sorta di SMT Solver (Z3 era raccomandato), ma non sono consapevole che sia del tutto fattibile.

    
posta Hav3n 07.04.2016 - 10:53
fonte

2 risposte

1

Se sei abbastanza fortunato da avere a che fare solo con le congiunzioni (logiche e non) e senza disgiunzioni (o s), controllare se un segmento introdotto di recente entra in conflitto / formalmente si interseca con quelli già definiti, potrebbe non essere così difficile come sembra.

Ad esempio, puoi sempre normalizzare le definizioni del loro elenco di vincoli dopo, ad esempio, l'ordine lessicografico del corresp. i nomi degli attributi e quindi non dovrebbe essere troppo difficile capire perché, ad esempio,

(originCountry == Country.USA, price > 1000, profitPercentage between 5 and 20, ...)

in effetti è in conflitto con

((unconstrained originCountry), price > 1500, profitPercentage between 0 and 10, ...)

ma non con

((unconstrained originCountry), price > 1000, profitPercentage > 20, ...)

In sostanza, per due di queste tuple, a vs b:

data

(constraint-a-1, ... , constraint-a-N)

e

(constraint-b-1, ... , constraint-b-N)

(dove N è il numero di attributi, prezzo, profitPercentage, ecc.)

l'intersezione sarà vuota se c'è una i in 1..N, dove constraint-a-i non si interseca con constraint-b-i.

Presumibilmente, alcuni (attributo non vincolato) si interseca sempre con se stesso o con qualsiasi (vincolo sullo stesso attributo).

Ma, probabilmente, mi sono perso qualcosa.

'Spero che questo aiuti.

    
risposta data 23.10.2016 - 10:43
fonte
0

Penso che ci siano un paio di opzioni da considerare:

  1. crea secchi disgiunti, come suggerisci tu. Questo crea il problema del controllo, se i bucket sono davvero disgiunti.
  2. esegui i bucket, come suggerisci, ma esegui tutti i test su tutti gli articoli e contrassegna quelli per la gestione speciale, per i quali vengono attivate più regole (ad esempio, utilizza l'ispezione manuale).
  3. Il filtro dei pacchetti Linux ha una tabella di condizioni con priorità che vengono eseguite una dopo l'altra. Alcune azioni potrebbero terminare l'elaborazione, dopo che alcune altre azioni di elaborazione continuano (pensare al logging). C'è la possibilità di chiamare ad altri tavoli. Vedi man iptables
  4. Utilizza un albero decisionale per creare un unico insieme deterministico di regole.

Se avessi scelto (1), probabilmente dovresti farlo (2) in ogni caso, per controllare l'algoritmo di controllo.

Dal punto di vista dell'utente (1) e (2) potrebbe essere percepito come complesso dopo un po 'di tempo, perché perché (il diavolo) ottengo un errore di controllo, se sono certo che due bucket non sono gli stessi? (ti consigliamo di evitare i messaggi di errore criptici e probabilmente dare alcuni esempi).

(3) è ragionevole, ma posso dirti che ci vorrà un po 'di tempo per abituarsi. Il debugging potrebbe non essere così bello, a meno che non si accerti che l'implementazione lo supporti. Penserei che questo consenta di gestire il più grande insieme di regole. Questa è sicuramente la soluzione più pratica che ha superato la prova del tempo e ha attraversato più iterazioni, prima di arrivare a quello che è ora.

(4) impone una determinata logica nella decisione e probabilmente richiederà 2-3 tentativi per farlo correttamente (come iniziare da zero con una condizione diversa nella radice dell'albero). Ragionare al riguardo dal punto di vista dell'utente potrebbe essere più semplice. Potrebbe non essere la soluzione migliore, se le regole sono granulose e l'albero diventa grande.

A seconda delle dimensioni del set di regole, sceglierei (3) o (4).

Tutte queste opzioni potrebbero richiedere un'attenta riflessione e una buona strategia su come distribuire, se si utilizzano più istanze parallele nel flusso di input.

    
risposta data 18.09.2017 - 23:38
fonte

Leggi altre domande sui tag