Memorizza espressione condizionale nel database

3

Abbiamo un'applicazione che consente agli utenti di immettere condizionali nella forma bound op x op bound2 , la memorizziamo come una stringa e quindi la analizziamo in fase di esecuzione per valutarla.

È una quantità decente di lavoro, per una dichiarazione condizionale molto limitata.

Stiamo cercando un modo per serializzare e quindi valutare condizioni complesse, con almeno un livello di complessità dell'intervento di commutazione.

Ho visto in questa domanda Come serializzare e deserializzare l'espressione lambda in F #? che in f # puoi semplicemente serializzare un lambda (e presumo che ci sia un modo per ottenere un lambda da una stringa di testo), ma:

  1. Dobbiamo farlo in Java
  2. So che possiamo compilare il codice java al volo e renderlo "sicuro" eliminando le parole chiave e non consentendo cose come System. ma anche se non è un incubo per la sicurezza, è proibitivamente computazionalmente costoso da fare migliaia di volte.

Qualcuno sa di un linguaggio piccolo là fuori il cui interprete può fare solo le basi (condizionali, cicli, assegnazione delle variabili) ed essere eseguito in / come java, o in qualsiasi modo per eseguire quei tipi di espressioni così come sono definiti in fase di runtime e devono essere persistenti.

Aggiornamento: Per essere chiari, la funzionalità minima di cui ho bisogno è una catena if else. Non ho solo bisogno di valutare una condizione. L'unica condizione è ciò che ho già.

    
posta soandos 17.01.2017 - 14:58
fonte

2 risposte

3

Potresti anche creare un linguaggio di espressione davvero semplice e quindi valutarlo al volo. Le espressioni sono alberi, quindi possono essere serializzate come XML, JSON, espressioni s o qualunque cosa tu preferisca. Per esempio. a + b * c potrebbe essere espresso in JSON come ["+", "a", ["*", "b", "c"]] . È anche molto facile scrivere un valutatore per tale albero.

Una catena if come:

if a then x 
else if b then y
else if c then z
else q

Potrebbe essere espresso in Json come:

["if", "a", "x", ["if", "b", "y", ["if", "c", "z", "q"]]]

Un interprete in pseudocodice:

def eval(args):
  operator = args[0]
  if operator=="+":
    return eval(args[1]) + eval(args[2])
  elif operator =="*":
    return eval(args[1]) * eval(args[2])
  elif operator=="<":
    return eval(args[1]) < eval(args[2])
  elif operator=="if":
    if (eval(arg[1])):
        return eval(arg[2]) 
    else:
        return eval(arg[3])

E così via ...

Ovviamente, non appena aggiungete lambda o funzioni, diventa molto più complesso, e quindi consiglierei di usare un motore di scripting off-the-shelf. Ma se hai solo bisogno di supportare espressioni, potrebbe essere più semplice scrivere semplicemente la tua scala di valutazione.

    
risposta data 17.01.2017 - 20:48
fonte
1

"Condizioni, cicli, assegnazione variabile" è già sufficiente per consumare quantità arbitrarie di CPU, a meno che tu non stia attento.

Se tutto ciò che serve è solo espressioni aritmetiche , è facile scrivere un interprete per loro, con alcune operazioni / funzioni predefinite. È anche facile capire il tempo di esecuzione dell'espressione, perché non può avere cicli.

Se fossi nei tuoi panni e avessi bisogno di un linguaggio di scripting completo di Turing, la prima cosa che farei sarebbe evitare di far girare il mio.

Java 6 ha introdotto un'API di scripting . C'è un'implementazione JavaScript per questo. C'è anche Mozilla Rhino implementazione JavaScript in Java.

Per quanto posso dire, entrambe le implementazioni consentono di limitare lo spazio dei nomi iniziale del programma JS in modo che le strutture non passate esplicitamente non siano accessibili.

Poi c'è LuaJ che implementa la VM Lua in JVM, con il controllo dell'esecuzione più fine / sandbox previsto da Lua.

Potresti anche considerare Groovy, Jython e JRuby, ma questi devono essere significativamente più pesanti e più difficili da sandbox. O forse potresti prendere in considerazione Golo (nessuna idea di sandboxing).

In ogni caso, eseguirò uno script in un thread separato e ucciderò qualsiasi script che impiega più tempo di un tempo assegnato per l'esecuzione.

Vorrei anche esaminare i modi per tenere traccia e limitare la quantità di allocazioni di heap provenienti da tale thread, ma ciò sembra impossibile in Java.

Se considerazioni di prestazioni rigorose / protezione DoS erano importanti, probabilmente eseguirò LuaJ, o forse anche una C Lua VM tramite JNI, e controllerò completamente la quantità di CPU e RAM disponibili e mostrerò solo un (piccolo) proxy a gli oggetti da scrivere.

    
risposta data 17.01.2017 - 20:05
fonte

Leggi altre domande sui tag