Creare tabelle con Envision

Creare tabelle con Envision












Home » Risorse » Qui

Il modo più semplice per creare una tabella in Envision consiste nel leggere la tabella da un file flat. Se nessuna delle tabelle di input presenta le proprietà cercate per uno specifico calcolo, è anche possibile creare tabelle ex novo attraverso uno script.


Sintassi generale

La sintassi usata per creare tabelle è racchiusa negli assegnamenti table ed extend:
table T = extend.range(Orders.42)
La parola chiave table (tabella) non dev'essere confusa con il tipo di casella, come in show table (mostra tabella). La tabella T può essere usata nello script come qualsiasi altra tabella caricata a partire da un file.
show table "Number of lines" with sum(T.1)

extend.range()

Il modo più semplice per creare una tabella è usare l'estensione extend.range(): per ogni riga della tabella originale, vengono create e numerate N righe. L'estensione è utile soprattutto se si vogliono introdurre nuove righe nella tabella.

La sintassi è la seguente:
table T = extend.range(Orders.K)
T.Quantity = Orders.Quantity // implicit projection
show table "Line numbers" with T.N, T.Quantity
L'argomento deve essere un numero intero, che può variare da una riga all'altra della tabella originale. Questo ci consente di controllare la granularità del numero di righe da introdurre.

La tabella T è inserita come estensione della tabella originale passata come argomento. Come vediamo alla riga 2 qui sopra, l'assegnamento tra tabelle funziona perché ogni riga in T è ancora associata alla sua controparte originale nella tabella Orders. Il campo T.N è popolato per impostazione predefinita e rappresenta il numero della riga: si comincia con 1 e si procede di 1 unità alla volta.

Attenzione: la funzione extend.range() può generare un numero arbitrariamente elevato di righe. Questa operazione può richiedere molto tempo e, a seconda delle capacità di calcolo assegnate al tuo account Lokad, può anche non concludersi correttamente. Nella pratica, se K supera la media di un numero maggiore di 10, allora extend.range() potrebbe non essere la soluzione adatta al tuo problema.

L'esempio qui sotto mostra come duplicare righe specifiche di una tabella, pur mantenendo il contenuto della tabella originale.
read "/sample" all
expect Grid(*)

table G = extend.range(Grid.Min == 0 ? 2 : 1)
G.Min = Grid.Min // affinity between 'G' and 'Grid'
G.Max = Grid.Max
G.Probability = Grid.Probability
G.Probability = 0 where G.N == 2
show table "My Grid" with Id, G.Probability, G.Min, G.Max

extend.distrib()

Le distribuzioni di Envision sono un potente strumento algebrico, che può essere usato per evitare complicati calcoli di probabilità sulle liste. Ci sono, però, situazioni in cui una semplice lista di probabilità è perfettamente funzionale e, anzi, persino auspicabile. L'estensione di distribuzione extend.distrib() trasforma un vettore di distribuzioni in una tabella, come illustrato dalla sintassi:
table T = extend.distrib(D)
show table "Distribution details" with Id, T.Min, T.Max, T.Probability
L'argomento D deve essere un vettore di distribuzioni, così come prodotto dal motore di previsione probabilistica di Lokad. La tabella T è inserita come estensione alla tabella originale, ossia la tabella implicita Items nello script qui sopra. La tabella T è popolata con tre campi:

  • T.Min: l'integrale estremo più basso del segmento;
  • T.Max: l'integrale estremo più alto del segmento;
  • T.Probability: la somma della distribuzione nell'intervallo considerato.

Malgrado il nome possa suggerire il contrario, il campo Probability rappresenta la somma della distribuzione nell'intervallo restituito.

Per le distribuzioni relativamente compatte, i segmenti hanno una lunghezza pari a 1, quindi T.Min == T.Max. Tuttavia, se la distribuzione raggiungesse valori più elevati, i segmenti di lunghezza pari a 1 finirebbero per generare anche milioni di righe, diventando così ingestibili. Quando si ha a che fare con distribuzioni dai valori così elevati, dunque, Envision aggrega automaticamente le distribuzioni intorno a segmenti più ampi. Gli algoritmi sono infatti predisposti in modo da mantenere gestibile la dimensione delle tabelle.

Per impostazione predefinita, extend.distrib() isola sempre il segmento zero. Di conseguenza, il segmento [0;0] ottiene sempre una riga corrispondente nella tabella generata. Questo comportamento è utile in molte situazioni di business in cui la domanda zero rappresenta un caso limite, come una copertura di scorte infinite, che richiedono una logica particolare.

Per un maggiore controllo sulla granularità specifica della tabella appena generata, poi, sono forniti tre sovraccarichi per extend.distrib().

Gap

Il primo sovraccarico contribuisce a creare una lista di priorità degli acquisti che tenga conto dei livelli di scorte attuali. La sintassi è la seguente:
table T = extend.distrib(D, S)
Il primo argomento D è lo stesso definito sopra. Il secondo argomento S deve essere un numero intero. Quando è presente questo secondo argomento, la tabella generata comprende sempre due righe dedicate ai segmenti [0;0] e [1;S]. Gli altri segmenti sono generati automaticamente a partire da S+1, come abbiamo spiegato prima in dettaglio. Il valore predefinito per questo argomento, se non specificato, è zero.

Nella pratica, l'argomento S è spesso definito come la somma delle scorte disponibili più quelle ordinate. In realtà, durante la procedura di riordino andrebbero considerate solo le probabilità della domanda che eccedono il livello di scorte attuali.

Moltiplicatore

Il secondo sovraccarico è pensato per le situazioni in cui sono presenti moltiplicatori di partite. In questi casi, la tabella deve ripetere segmenti di dimensioni specifiche. La sintassi è questa:
table T = extend.distrib(D, S, M)
Gli argomenti D e S sono gli stessi definiti in precedenza. Il terzo argomento M dev'essere un numero intero e rappresenta la lunghezza desiderata del segmento. La tabella includerà quindi i segmenti [0;0], [1;S], [S+1;S+M] [S+M+1;S+2M] … Se M è uguale a zero, allora la funzione rientra nella regolazione automatica della lunghezza dei segmenti.

In pratica, forzare i segmenti di lunghezza 1 può portare a problemi di performance, poiché le dimensioni della tabella possono "lievitare" in modo arbitrario. Envision consente quindi di ripiegare invece su un multiplo di M. Usare un multiplo fa sì che la logica del moltiplicatore di partite continui a funzionare, pur mantenendo il numero di righe da generare entro limiti ragionevoli.

In linea di massima, suggeriamo di non usare questo secondo sovraccarico a meno che non siano presenti moltiplicatori di partite e, anche in questo caso, facendo attenzione ad assegnare a M il valore zero per tutti gli articoli a cui non è associato uno specifico moltiplicatore di partite.

Reach

Il terzo sovraccarico è pensato per i casi in cui sono presenti restrizioni sui quantitativi minimi di ordine, o MOQ. In queste situazioni, la tabella dovrebbe ripetersi abbastanza a lungo da raggiungere determinati valori desiderati. La sintassi corrispondente è:
table T = extend.distrib(D, S, M, R)
Gli argomenti D, S e M sono quelli definiti in precedenza. Il quarto argomento, R, deve essere un numero intero non negativo e rappresenta il valore massimo desiderato che la tabella dovrebbe raggiungere: in pratica, indica che ci sarà una riga della tabella in cui T.Max sarà uguale o maggiore di R. Il valore predefinito per questo argomento, se non specificato, è zero.

Per riassumere, questo argomento è utilizzato per gestire particolari requisiti nei quantitativi minimi di ordine (MOQ), che possono essere soddisfatti soltanto se la tabella generata si ripete fino a coprire il valore dei MOQ.

In linea di massima, suggeriamo di non ricorrere a questo sovraccarico a meno che non siano presenti vincoli di tipo MOQ e, anche in questo caso, di mantenere il valore di R il più basso possibile. Un valore basso di R non evita che la tabella T raggiunga valori più alti, ma serve ad assicurare che vengano raggiunti valori più elevati.

extend.billOfMaterials()

La lista dei materiali (bill of materials) entra in gioco quando oggetto della nostra analisi sono non gli articoli venduti o serviti, ma le loro componenti. In questi casi, è utile trasformare la domanda storica a livello di “articoli” in una domanda storica a livello di “pezzi”. Questa trasformazione può essere gestita attraverso la lista dei materiali, che specifica la composizione di ogni articolo.

A questo proposito, possiamo utilizzare la funzione di chiamata extend.billOfMaterials():
table T = extend.billOfMaterials(
  Item: J.Id
  Part: B.PartId
  Quantity: B.Quantity
  DemandId: O.OrderId
  DemandValue: O.Quantity)

T.DemandDate by T.DemandId = same(O.Date) by O.OrderId // illustra come ottenere la data

show table "Details" with Id, T.DemandDate, T.Quantity
Il risultato saranno le tabelle J, B e O. La tabella J è solitamente (anche se non sempre) la tabella degli articoli. La tabella B è la tabella della lista dei materiali e rappresenta un'estensione della tabella J, del tipo (Id, *) se J è la tabella degli articoli. La tabella O rappresenta la domanda storica e corrisponde solitamente alla tabella degli ordini; anche la tabella O è un'estensione della tabella J.

La tabella che ne risulta è una tabella J, con tutte le affinità del caso al proprio posto. La tabella T contiene due campi già popolati:
  • T.DemandId, che offre un modo per identificare nella tabella T le righe originali della tabella O, e
  • T.Quantity, ottenuto dalla lista dei materiali.

La funzione extend.billOfMaterials() supporta prodotti assemblati di tipo ricorsivo: ogni articolo, cioè, può comparire all'interno della tabella B sia come componente che come pacchetto. Ovviamente, la funzione dà come risultato un errore se nella tabella della lista dei materiali sono presenti dipendenze cicliche.

Spesso è utile inserire nella tabella T una data, attraverso il costrutto left-by, come illustrato dalla riga sotto il blocco billOfMaterials() qui sopra.

L'argomento Quantity rappresenta il numero di unità B.PartId coinvolte nella vendita o nella fornitura di un prodotto assemblato definito da J.Id.