reading Rappresentare la logica come dati in JSON




reading a json in java (6)

A proposito, IBM DB2 supporta istruzioni logiche codificate in JSON .

Le operazioni booleane sembrano un incrocio tra la soluzione di cHao e Amazon CloudFormation:

{"$and":[{"age":5},{"name":"Joe"}]}

Le operazioni di confronto mi sembrano simili a SQL traslitterato. (Invece del movimento di Amazon o Russellg o cHao verso un albero sintattico astratto).

{"age":{"$lt":3}}

Per ragioni aziendali, è necessario esternalizzare alcune logiche condizionali in file esterni: preferibilmente JSON.

Un semplice scenario di filtro può essere gestito aggiungendo un nodo come segue:

"filter": [
  {
    "criteria": "status",
    "value": "open",
    "condition": "=="
  }
]

Più condizioni potrebbero essere gestite da valori aggiuntivi nella matrice.

"filter": [
  {
    "criteria": "status",
    "value": "open",
    "condition": "=="
  },
  {
    "criteria": "condition2",
    "value": "value2",
    "condition": "=="
  }
]

Tuttavia, diventa un po 'di confusione quando gestiamo condizioni complesse che coinvolgono AND o OR.

Domanda: esiste un formato standardizzato (o anche ampiamente accettato) per rappresentare tale logica all'interno di JSON? Come lo faresti se dipendesse da te?

NOTA: la prima risposta è stata resa una wiki modificabile in modo che possa essere migliorata da chiunque ne abbia la sensazione.


Se devi implementarlo usando il JSON standard, consiglierei qualcosa di simile alle "S-espressioni" di Lisp. Una condizione può essere un oggetto semplice o una matrice la cui prima voce è l'operazione logica che le unisce.

Per esempio:

["AND",
    {"var1" : "value1"},
    ["OR",
        { "var2" : "value2" },
        { "var3" : "value3" }
    ]
]

rappresenterebbe var1 == value1 AND (var2 == value2 OR var3 == value3) .

Se si preferisce la brevità rispetto alla consistenza, si potrebbe anche consentire a un oggetto di avere proprietà multiple, che sarebbero implicitamente affiancate da un AND. Ad esempio, { "a": "b", "c": "d" } sarebbe equivalente a ["AND", { "a": "b" }, { "c": "d" }] . Ma ci sono casi (come nell'esempio) in cui la precedente sintassi non può rappresentare fedelmente la condizione come scritta; avresti bisogno di trucchi aggiuntivi come la traduzione della condizione o l'utilizzo di nomi di proprietà fittizie. La seconda sintassi dovrebbe sempre funzionare.


La mia collega ha suggerito questa possibile soluzione:

"tutte le condizioni OR sarebbero un array mentre le condizioni AND sarebbero oggetti,

Ad esempio, OR può corrispondere a qualsiasi oggetto nell'array:

[
  {
    "var1":"value1"
  },
  {
    "var2":"value2"
  },
  {
    "var3":"value3"
  }
]

E sarebbe

{ 
  "var1":"val1",
  "var2":"val2",
  "var3":"val3"
}

La logica può essere implementata con "logicOp": "Operatore" su un "set": ["a", "b" ...] Per l'esempio di cHau:

"var": {
         "logicOp": "And",
         "set": ["value1",
                 {
                    "LogicOp": "Or",
                    "set": ["value2", "value3"]
                 }
              ]
       }

Ad esempio, possono esserci anche altri attributi / operazioni per il set

"val": { "operators": ["min": 0, "max": 2], "set": ["a", "b", "c"] } 

Per una domenica con due scoop di uno o più tipi di gelato, 1 condimenti e whipcream

"sunday": {
            "icecream": { 
                          "operators": [ "num": 2,
                                        "multipleOfSingleItem": "true"],
                          "set": ["chocolate", "strawberry", "vanilla"]
                        },
            "topping": {
                          "operators": ["num": 1],
                          "set": ["fudge", "caramel"]
                       },
            "whipcream": "true"
          }

Si prega di controllare (JSL) [ https://www.npmjs.com/package/lib-jsl ]. Sembra adattarsi alla descrizione fornita.

Ecco un esempio:

var JSL = require('lib-jsl');

var bugs = [
    [{ bug : { desc: 'this is bug1 open', status : 'open' } }],
    [{ bug : { desc: 'this is bug2 resolved', status : 'resolved' } }],
    [{ bug : { desc: 'this is bug3 closed' , status : 'closed' } }],
    [{ bug : { desc: 'this is bug4 open', status : 'open' } }],
    [{ bug : { desc: 'this is bug5 resolved', status : 'resolved' } }],
    [{ bug : { desc: 'this is bug6 open', status : 'open' } }],

    [   { workInProgress : '$bug'},
        { bug : '$bug'},
        { $or : [
            { $bind : [ '$bug', { status : 'open'} ] },
            { $bind : [ '$bug', { status : 'resolved'} ] }
        ] }
    ]
];
var query = [{workInProgress : '$wip'}]
var transform = '$wip'
var jsl = new JSL ({
    rules : bugs,
    query : query,
    transform : transform
});
var retval = jsl.run();
console.log(JSON.stringify(retval, null,2));

La risposta è:

[
  {
    "desc": "this is bug1 open",
    "status": "open"
  },
  {
    "desc": "this is bug2 resolved",
    "status": "resolved"
  },
  {
    "desc": "this is bug4 open",
    "status": "open"
  },
  {
    "desc": "this is bug5 resolved",
    "status": "resolved"
  },
  {
    "desc": "this is bug6 open",
    "status": "open"
  }
]

Il lavoro principale è svolto dalla query definita nella regola workInProgress:

[   { workInProgress : '$bug'},
    { bug : '$bug'},
    { $or : [
        { $bind : [ '$bug', { status : 'open'} ] },
        { $bind : [ '$bug', { status : 'resolved'} ] }
    ] }
]

Questa regola può essere letta come:

Per soddisfare la query con workInProgress, definiamo una variabile {workInProgress : '$bug'} , che poi procederemo per corrispondere a tutti i bug nel database usando la parte successiva della regola {bug : '$bug'} . Questa parte corrisponde a tutti i bug in quanto la forma dell'oggetto (le sue chiavi: 'bug') corrispondono ai record di bug nel database. La regola chiede inoltre alla variabile $ bug di essere vincolata da $ (ed) ai pattern contenenti valori di stato rilevanti (aperti e chiusi) all'interno di $ o. Solo quei record di bug il cui valore di stato in $ bug soddisfa tutte le parti del corpo della regola che si qualificano per il risultato.

Il risultato viene infine trasformato utilizzando la specifica di trasformazione: transform : '$wip' che richiede letteralmente una matrice di tutti i valori restituiti nella variabile $ wip della query.


Avevo bisogno di un formato che avrebbe:

  1. Supporta confronti diversi dall'uguaglianza.
  2. Lascia che le variabili appaiano in qualsiasi posizione, non solo rispetto alle letterali.
  3. Sii coerente, conciso, sicuro ed estensibile.

Così ho creato un formato che sto chiamando JsonLogic . Una regola è un oggetto JSON, con l'operatore nella posizione della chiave e uno o un array di argomenti nella posizione del valore. (Ispirato dalle funzioni di Amazon CloudFormation ). Qualsiasi argomento può essere un'altra regola, quindi puoi costruire una logica arbitrariamente profonda.

Ho anche scritto due parser per questo: JsonLogic per JavaScript e JsonLogic per PHP .

L'esempio di cHao sarebbe scritto come

{ "and", [
    {"==", [ {"var" : "var1"}, "value1" ]},
    { "or", [
        {"==", [ {"var" : "var2"}, "value2" ]},
        {"==", [ {"var" : "var3"}, "value3" ]}
    ]}
]}

var è l'operatore per ottenere una proprietà dell'oggetto "data", passata con l'oggetto "regola" al parser, ad esempio:

jsonLogic(
    {"==", [{"var":"filling"}, "apple"]}    // rule, is this pie apple?
    {"filling":"apple", "temperature":100}  // data, a pie I'm inspecting
);
// true

Ci sono molti più operatori possibili (maggiori di, non-uguali, in-array, ternari, ecc.) Ed entrambi i parser sono disponibili su GitHub (con test unitari e documentazione).





design