Oggetti CacheThing
Un oggetto CacheThing fornisce un'interfaccia rapida in memoria per la memorizzazione e il recupero dei dati chiave-valore. È ideale per memorizzare nella cache i risultati di operazioni costose o dispendiose in termini di tempo, come le interrogazioni lente.
Poiché l'oggetto CacheThing opera in memoria, al riavvio di ThingWorx il relativo contenuto viene cancellato. Negli ambienti a disponibilità elevata, ogni nodo ThingWorx gestisce la propria cache indipendente. Di conseguenza, le voci della cache create o aggiornate in un nodo non vengono condivise automaticamente con gli altri. Sono incluse le chiamate di invalidazione della cache, ad esempio PurgeCache, DeleteEntry e DeleteEntryByKey.
È possibile utilizzare un oggetto CacheThing per memorizzare nella cache vari tipi di dati, come i seguenti:
Risultati di interrogazioni costose o frequenti a oggetti Database
Risultati di interrogazioni costose o frequenti a oggetti ValueStream o DataTable
Risultati di chiamate di rete lente, ad esempio chiamate effettuate con funzioni ContentLoader
Valori calcolati costosi
Contenuti di file di uso frequente e dimensioni ridotte da oggetti FileRepository
L'utilizzo di un oggetto CacheThing consente di migliorare significativamente le prestazioni e ridurre l'utilizzo delle risorse rispetto all'accesso a sistemi esterni come database o risorse di rete.
Linee guida per l'utilizzo
Un oggetto CacheThing non è concepito per essere utilizzato come archivio dati permanente. Tutti i dati memorizzati nella cache di un oggetto CacheThing devono essere riproducibili dall'origine.
I dati in un oggetto CacheThing possono essere scaduti o rimossi. I servizi che utilizzano un oggetto CacheThing devono essere progettati per recuperare i dati dall'origine, se la cache non restituisce alcun risultato. Vedere alcuni esempi per maggiori dettagli.
Configurazione
Ogni oggetto CacheThing deve essere configurato con una data shape che includa una chiave principale. La chiave principale viene utilizzata per recuperare voci dalla cache.
Le chiavi principali composite sono supportate, ma impediscono l'utilizzo dei servizi ByKey, della regola di scadenza e della dimensione massima globale elencati di seguito.
Regola di scadenza
La regola di scadenza definisce il periodo TTL (Time To Live) di ogni voce della cache. È possibile configurare la scadenza utilizzando l'impostazione Tempo di scadenza voce cache (secondi). Dopo la scadenza di una voce, il recupero del valore restituisce un risultato vuoto, come in caso di eliminazione dalla cache.
Regole di scadenza supportate:
Regola scadenza voce cache
Descrizione
Mai
La voce nella cache non viene mai rimossa in base alla quantità di tempo trascorso al suo interno. Tuttavia, può comunque essere rimossa se la cache raggiunge la configurazione della dimensione massima o utilizzando il servizio DeleteEntry. L'impostazione Tempo di scadenza voce cache (secondi) viene ignorata quando è configurata la regola di scadenza Never.
Tempo di scadenza dall'ultimo accesso
La voce viene rimossa se non è stata letta entro il tempo di scadenza specificato.
Tempo di scadenza dalla creazione
La voce viene rimossa dopo che è trascorso il tempo specificato dalla sua creazione.
Tempo di scadenza dall'ultima modifica
La voce viene rimossa se non è stata modificata entro il tempo di scadenza specificato.
Tempo di scadenza dall'ultimo contatto
La voce viene rimossa se non vi è stato alcun accesso o modifica entro il tempo di scadenza specificato.
Per ulteriori informazioni sulle regole di scadenza dell'interfaccia, vedere Interface ExpiryPolicy.
Dimensione massima della cache (rimozione)
Le voci della cache vengono rimosse (eliminate) automaticamente quando la cache raggiunge la dimensione specificata nell'impostazione Dimensione massima cache (MB). Il processo rimuove le voci utilizzate memo frequentemente per liberare spazio per nuove voci. Quando una voce viene rimossa, il recupero restituisce un risultato vuoto, in modo analogo a quando viene eliminata.
Se viene aggiunta una voce di grandi dimensioni, potrebbero essere rimosse più voci di dimensioni ridotte per liberare spazio. Per evitare questo problema, utilizzare il servizio EstimateEntrySize per controllare le dimensioni di una voce prima di aggiungerla alla cache.
La rimozione e la scadenza della cache funzionano in modo indipendente:
La rimozione si basa sulla dimensione della cache e sulla frequenza di utilizzo.
La scadenza si basa sul tempo, come definito dalla regola di scadenza configurata.
Dimensione massima globale
Il sottosistema Piattaforma include un'impostazione denominata Dimensione massima condivisa tra tutti gli oggetti CacheThing per nodo ThingWorx (MB). Questa impostazione limita la dimensione combinata di tutti gli oggetti CacheThing in un singolo nodo per evitare un utilizzo eccessivo della memoria. Gli oggetti CacheThing disattivati non sono inclusi in questo limite.
Questa configurazione impedisce le seguenti azioni:
Creazione di un nuovo oggetto CacheThing che supera la dimensione massima
Aggiornamento del valore di Dimensione massima cache (MB) di un oggetto CacheThing che supera la dimensione massima
Importazione di oggetti CacheThing (come importazioni di entità o come parte di un'estensione) che superano la dimensione massima, determinando l'esito negativo dell'intera importazione
Riduzione della dimensione massima al di sotto del valore combinato corrente di Dimensione massima cache (MB) per tutti gli oggetti CacheThing
Attivazione di un oggetto CacheThing che supera il limite globale
Modifica della configurazione della cache
Eventuali modifiche alla configurazione di una cache eliminano automaticamente il contenuto della cache per mantenere uniformità interna. La modifica di uno dei seguenti elementi determina l'eliminazione del contenuto della cache:
Data shape - Include la modifica della data shape configurata, ad esempio l'aggiunta o la rimozione di campi.
Regola scadenza voce cache
Tempo di scadenza voce cache (secondi)
Dimensione massima cache (MB)
Cache Performs Loading of Missing Entries
Servizi
In un oggetto CacheThing sono disponibili i servizi riportati di seguito. Negli ambienti a disponibilità elevata, questi servizi influiscono sulla cache nel nodo ThingWorx in cui viene eseguito il rispettivo servizio.
I servizi *ByKey elencati di seguito sono disponibili solo quando la data shape della cache dispone di una sola chiave principale. Se la data shape della cache include più chiavi principali, utilizzare la versione di input della infotable completa del servizio.
Nome servizio
Descrizione
PutEntry
Aggiunge una voce alla cache.
Valore di input - Infotable di una riga che utilizza la data shape configurata dell'oggetto CacheThing.
GetEntry
Restituisce il risultato di una infotable di una riga dalla cache.
Se la voce non viene trovata (mancato riscontro nella cache) e la cache non è configurata con Cache Performs Loading of Missing Entries, viene restituita una infotable vuota. Se la cache è configurata con tale opzione, viene chiamato automaticamente il servizio LoadEntry e viene restituito il risultato.
Possono verificarsi mancati riscontri nella cache se la voce non è mai stata aggiunta alla cache, è stata rimossa o è scaduta.
Valore di input - Infotable di una riga che utilizza la data shape configurata dell'oggetto CacheThing. È necessario completare solo i valori di Primary Key.
GetEntryByKey
Restituisce il risultato di una infotable di una riga dalla cache.
Se la voce non viene trovata, viene restituita una infotable vuota. Possono verificarsi mancati riscontri nella cache se la voce non è mai stata aggiunta alla cache, è stata rimossa o è scaduta.
Valore di input - Stringa che rappresenta la chiave principale della voce da recuperare. Questo servizio è disponibile solo se la data shape configurata dispone di una sola chiave principale. È ideale per l'utilizzo con le chiavi principali di tipo stringa, ma supporta anche la maggior parte dei tipi con una conversione di stringa ben definita.
LoadEntry
Consente di recuperare automaticamente i dati della cache dall'origine dati quando si verifica un mancato riscontro nella cache.
Questo servizio deve essere sostituito se l'opzione Cache Performs Loading of Missing Entries è attivata.
DeleteEntry
Elimina una voce dalla cache.
In un ambiente ad alta disponibilità, influisce solo sul nodo in cui viene chiamato il servizio DeleteEntry.
Valore di input - Infotable di una riga che utilizza la data shape configurata dell'oggetto CacheThing. È necessario completare solo i valori di Primary Key.
DeleteEntryByKey
Elimina una voce dalla cache.
In un ambiente ad alta disponibilità, influisce solo sul nodo in cui viene chiamato il servizio DeleteEntryByKey.
Valore di input - Stringa che rappresenta la chiave principale della voce da recuperare. Questo servizio è disponibile solo se la data shape configurata dispone di una sola chiave principale.
PurgeCache
Rimuove tutte le voci della cache.
In un ambiente ad alta disponibilità, influisce solo sul nodo in cui viene chiamato il servizio PurgeCache.
GetDataShape
Restituisce la data shape configurata della cache.
SetDataShape
Imposta il campo della data shape nella tabella di configurazione della cache. La modifica di questo valore comporta l'eliminazione automatica del contenuto della cache.
GetEstimatedEntryCount
Restituisce il numero stimato di voci nella cache. Le operazioni PUT e DELETE in corso, così come i processi di scadenza o di rimozione, possono influire sulla precisione.
EstimateEntrySize
Restituisce la dimensione stimata di una voce se fosse stata aggiunta alla cache. In questo modo, la voce non viene inserita nella cache e non sono necessarie altre voci già presenti al suo interno. Questo servizio può essere utile per stimare un valore appropriato di Dimensione massima cache (MB) o per impedire l'aggiunta di voci di grandi dimensioni alla cache.
Valore di input - Infotable di una riga che utilizza la data shape configurata dell'oggetto CacheThing.
Sostituzione del servizio LoadEntry
Per attivare Cache Performs Loading of Missing Entries (memorizzazione nella cache read-through), è necessario sostituire il servizio LoadEntry sull'oggetto CacheThing. Questo servizio viene chiamato internamente quando si verifica un mancato riscontro nella cache, consentendo alla cache di recuperare e memorizzare i dati dall'origine.
Se si chiama direttamente il servizio LoadEntry, non vengono aggiunte voci alla cache. Le voci vengono aggiunte solo quando il servizio LoadEntry viene richiamato internamente da GetEntry in caso di un mancato riscontro nella cache.
Input
L'input è una infotable di una riga che corrisponde ai parametri della chiamata GetEntry corrispondente. In genere, vengono completati solo i campi delle chiavi principali.
Implementazione del servizio
Il servizio LoadEntry deve recuperare o generare il valore da memorizzare nella cache dall'origine dati. Può includere interrogazioni di database, chiamate a servizi Web o valori generati. Evitare di aggiornare lo stato di un'applicazione, ad esempio le proprietà o i file, all'interno del servizio.
Non chiamare altri servizi di memorizzazione nella cache, ad esempio GetEntry o PutEntry, da LoadEntry. La cache gestisce automaticamente la memorizzazione del valore restituito dopo un mancato riscontro nella cache.
Output
L'output deve essere una infotable con la stessa data shape dell'input. Completare i campi di chiavi non principali con i dati recuperati. Eventuali eccezioni vengono propagate alla chiamata GetEntry chiamante.
È consigliabile creare una nuova infotable per l'infotable dei risultati dell'output. Sebbene sia possibile riutilizzare e completare la infotable dei valori di input, questa operazione può causare comportamenti imprevisti dovuti a limitazioni nella gestione di determinati tipi di base in JavaScript da parte delle infotable. Vedere alcuni esempi per maggiori dettagli sull'utilizzo di LoadEntry.
Memorizzazione nella cache read-through
La selezione della casella di controllo Cache Performs Loading of Missing Entries abilita la memorizzazione nella cache read-through. In questa modalità, la cache carica automaticamente i valori delle voci mancanti mediante il servizio LoadEntry sull'oggetto CacheThing quando si verifica un mancato riscontro nella cache.
Per supportare questo comportamento, è necessario sostituire il servizio LoadEntry sull'oggetto CacheThing per interrogare i dati di origine e restituire il valore appropriato. Quando il servizio GetEntry non trova un valore nella cache, quest'ultima chiama il servizio LoadEntry per recuperarlo.
La memorizzazione nella cache read-through può contribuire a ridurre gli effetti degli scenari di "thundering herd". Se per la stessa chiave vengono effettuate più richieste GetEntry parallele prima che venga completata, il servizio LoadEntry di backup viene chiamato una sola volta. Al termine della chiamata LoadEntry, tutte le richieste GetEntry in sospeso restituiscono il valore recuperato.
Per maggiori dettagli su come fornire un'implementazione del servizio LoadEntry, vedere la sezione Sostituzione del servizio LoadEntry.
Metriche
Sono disponibili diverse metriche relative alla cache. Negli ambienti a disponibilità elevata, le cache sono indipendenti per ciascun nodo. Le metriche devono essere elaborate per nodo utilizzando le etichette platform e cache_name.
Sono disponibili le seguenti metriche della cache:
Metriche della cache
Descrizione
thingworx_cache_hit_rate
Rapporto tra le richieste di cache che hanno restituito una voce nella cache
thingworx_cache_hits
Numero di volte in cui i metodi di ricerca nella cache hanno restituito un valore memorizzato nella cache
thingworx_cache_request_count
Numero di volte in cui i metodi di ricerca nella cache hanno restituito un valore memorizzato o non memorizzato nella cache
thingworx_cache_miss_rate
Rapporto tra i metodi di ricerca nella cache che hanno restituito un valore non memorizzato nella cache (caricato di recente) o null
thingworx_cache_misses
Numero di volte in cui i metodi di ricerca nella cache hanno restituito un valore non memorizzato nella cache (caricato di recente) o null
thingworx_cache_eviction_count
Numero di volte in cui una voce è stata rimossa
thingworx_cache_average_load_penalty
Tempo medio impiegato per il caricamento di nuovi valori
thingworx_cache_weighted_size
Dimensione approssimativa corrente della cache in byte
thingworx_cache_max_weight
Dimensione massima della cache in byte prima della rimozione
thingworx_cache_estimated_entry_count
Numero stimato di voci nella cache
thingworx_cache_global_max_size
Dimensione massima globale configurata per tutte le cache in byte
Avvisi (disponibili negli ambienti ospitati in PTC Cloud)
Gli avvisi seguenti sono disponibili negli ambienti ospitati in PTC Cloud:
thingworxEntityCacheMissRate - Avvisa quando il tasso di cache miss supera l'80% per 1 ora.
thingworxEntityCacheEvictions - Avvisa quando il tasso di rimozione di una cache supera l'80% per 30 minuti.
Esempi e best practice
L'implementazione di servizi che utilizzano in modo efficace l'oggetto CacheThing richiede una certa attenzione ai dettagli. Considerare le best practice riportate di seguito.
La cache viene cancellata al riavvio del nodo ThingWorx.
Le voci possono essere rimosse o scadere dalla cache senza l'intervento dell'utente. Non presupporre che le entità rimangano nella cache a tempo indeterminato.
Utilizzare le metriche della cache per verificare che sia opportuno eseguire un dimensionamento.
Evitare di memorizzare tutti i dati in un'unica voce o di creare voci di dimensioni molto elevate nella cache.
Negli ambienti a disponibilità elevata, ogni nodo dispone di una cache indipendente. L'aggiunta o l'eliminazione di una cache oppure la rimozione del suo contenuto in un nodo non influisce su tutti i nodi ThingWorx.
Quando l'opzione Cache Performs Loading of Missing Entries è disattivata (cache non read-through), attenersi alla procedura descritta di seguito.
1. Recuperare una voce dalla cache utilizzando la chiave principale.
2. Controllare se il risultato è completato (la infotable restituita è di una riga).
3. Se il risultato viene trovato, utilizzarlo.
4. Se il risultato non viene trovato, procedere come segue:
Recuperare o generare la voce richiesta dai dati di origine (ad esempio, oggetto di database, DataTable o ContentLoader).
Aggiungere la voce alla cache utilizzando PutEntry.
Restituire la nuova voce memorizzata nella cache.
Quando l'opzione Cache Performs Loading of Missing Entries è attivata (cache read-through), attenersi alla procedura descritta di seguito.
1. Sostituire il servizio LoadEntry sull'oggetto CacheThing.
2. Recuperare una voce dalla cache utilizzando la chiave principale.
Se la voce non viene trovata, LoadEntry viene chiamato automaticamente per completare il valore.
Esempio di utilizzo del servizio TimesTwo 
Il servizio TimesTwo acquisisce un numero, lo moltiplica per 2 e memorizza il risultato in una cache. Per impostarlo, attenersi alla procedura descritta di seguito.
1. Creare una data shape (TimesTwoDataShape) con i campi seguenti: operand: (LONG, primaryKey) e timesTwoValue: (LONG).
2. Creare un oggetto CacheThing (MyTimesTwoCache) con il valore di TimesTwoDataShape configurato.
3. Aggiungere il servizio TimesTwo a MyTimesTwoCache:
Input - x (un numero LONG)
Output - result (un numero LONG)
// Input is x as a LONG
// Output is result as LONG
// MyTimesTwoCache CacheThing is configured with a DataShape with two fields:
// operand: (LONG, primaryKey)
// timesTwoValue: (LONG)
result = -1;
// Check the cache first, to see if we have already calculated x*2
// GetEntryByKey is a convenience method that takes the String value the configured DataShape's Primary Key ("key" in this example)
// cacheResult is an InfoTable with the DataShape of the cache
let cacheResult = Things["MyTimesTwoCache"].GetEntryByKey({ operand: x.toString() });
if (cacheResult.getRowCount() === 0) {
// Cache didn't have a result, so calculate it
let timesTwo = x*2;

// Put the result in the cache for the next time we need this multiple
// operand and value are from the Cache's configured DataShape
let cacheInput = getInfoTableForPut(x, timesTwo);
Things["MyTimesTwoCache"].PutEntry({
values: cacheInput
});

// Turn ScriptLogger to debug mode to see the logger messages
logger.debug("PutEntry the following entry into the MyTimesTwoCache: {operand: " + x + ", timesTwoValue: " + timesTwo + "}");

// Set the global result Output variable
result = timesTwo;
} else {
// If results are found, they are always in the first row of the InfoTable
let row = cacheResult.getRow(0);
logger.debug("Found the following entry already in MyTimesTwoCache: {operand: " + row.operand + ", timesTwoValue: " + row.timesTwoValue + "}");
result = row.timesTwoValue;
}
function getInfoTableForPut(operand, timesTwoValue) {
let infoTable = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: Things["MyTimesTwoCache"].GetDataShape()
});
infoTable.AddRow({"operand": operand, "timesTwoValue ": timesTwoValue });
return infoTable;
}
Esempio di wrapper del servizio di memorizzazione nella cache 
Questo esempio illustra come memorizzare manualmente nella cache i risultati del servizio QueryImplementingThingsV2.
1. Creare una data shape denominata Cached_QueryImplementingThingsV2_DataShape con i campi seguenti:
maxItems: (NUMBER, primaryKey)
nameMask: (STRING, primaryKey)
query: (QUERY, primaryKey)
isSortFirst: (BOOLEAN, primaryKey)
result: (INFOTABLE, DataShape RootEntityListV2)
2. Creare un oggetto CacheThing denominato Cached_QueryImplementingThingsV2 e assegnare Cached_QueryImplementingThingsV2_DataShape come data shape correlata.
3. Per osservare il comportamento di scadenza della cache, configurare un valore breve per ExpirationTime e impostare un valore di ExpirationPolicy diverso da Never nell'oggetto Cached_ReadThrough_QueryImplementingThingsV2.
4. Creare un servizio denominato CachingQueryImplementingThingsV2 con i parametri seguenti:
Input
maxItems: (NUMBER, required)
nameMask: (STRING, required)
query: (QUERY, required)
isSortFirst: (BOOLEAN, required)
Output result: (INFOTABLE, DataShape RootEntityListV2)
/* 
This Service queries QueryImplementingThingsV2 and caches the results as needed
Service Name: CachingQueryImplementingThingsV2 (Overridden on CacheThing)
Input: values InfoTable with Cached_QueryImplementingThingsV2_DataShape
Cached_QueryImplementingThingsV2_DataShape:
maxItems: NUMBER, Primary Key
nameMask: STRING, Primary Key
query: QUERY, Primary Key
isSortFirst: BOOLEAN, Primary Key
result: INFOTABLE, DataShape RootEntityListV2 (NOT a Primary Key!)
*/
let cacheEntryInfoTable = getCacheEntryInfoTable();
cacheEntryInfoTable.AddRow({
maxItems: maxItems /* NUMBER */,
nameMask: nameMask /* STRING */,
query: query /* QUERY */,
isSortFirst: isSortFirst /* BOOLEAN */
});
let getEntryResult = me.GetEntry({values: cacheEntryInfoTable});
if (getEntryResult.getRowCount() === 0) {
// Cache didn't have results, so call QueryImplementingThingsV2
let queryResult = ThingTemplates["GenericThing"].QueryImplementingThingsV2({
maxItems: maxItems /* NUMBER */,
nameMask: nameMask /* STRING */,
query: query /* QUERY */,
isSortFirst: isSortFirst /* BOOLEAN */
});

// Add the result to the cache, with the primaryKey parameters used to uniquely identify the query.
let newCacheEntryInfoTable = getCacheEntryInfoTable();
newCacheEntryInfoTable.AddRow({
maxItems: maxItems /* NUMBER */,
nameMask: nameMask /* STRING */,
query: query /* QUERY */,
isSortFirst: isSortFirst /* BOOLEAN */,
result: queryResult /* INFOTABLE */
});
me.PutEntry({
values: newCacheEntryInfoTable
});
logger.debug("Entry not found in Cache, retrieved from QueryImplementingThingsV2:" + queryResult.ToJSON());
result = queryResult;
} else {
logger.debug("Found entry from Cache:" + getEntryResult.ToJSON());
let row = getEntryResult.getRow(0);
result = row.result;
}

function getCacheEntryInfoTable() {
return Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: "Cached_QueryImplementingThingsV2_DataShape"
});
}
Esempio di wrapper del servizio di memorizzazione nella cache come cache read-through 
Questo esempio illustra come memorizzare automaticamente nella cache i risultati del servizio QueryImplementingThingsV2 utilizzando una cache read-through. Dopo aver sostituito il servizio LoadEntry, è possibile utilizzare il servizio GetEntry per caricare automaticamente i risultati dell'interrogazione di QueryImplementingThingsV2 nella cache.
1. Creare una data shape denominata Cached_QueryImplementingThingsV2_DataShape con i campi seguenti:
maxItems: (NUMBER, primaryKey)
nameMask: (STRING, primaryKey)
query: (QUERY, primaryKey)
isSortFirst: (BOOLEAN, primaryKey)
result: (INFOTABLE, DataShape RootEntityListV2)
2. Creare un oggetto CacheThing denominato Cached_ReadThrough_QueryImplementingThingsV2. Assegnare Cached_QueryImplementingThingsV2_DataShape come data shape correlata e attivare l'opzione Cache Performs Loading of Missing Entries.
3. Per osservare il comportamento di scadenza della cache, configurare un valore breve per ExpirationTime e impostare un valore di ExpirationPolicy diverso da Never nell'oggetto Cached_ReadThrough_QueryImplementingThingsV2.
4. Passare alla scheda Servizi e selezionare Sostituisci accanto al servizio LoadEntry, con l'esempio seguente:
/* 
This Service simply proxies a query to QueryImplementingThingsV2 for Read Through caching
Service Name: LoadEntry (Overridden on CacheThing)
Input: values InfoTable with Cached_QueryImplementingThingsV2_DataShape
Cached_QueryImplementingThingsV2_DataShape:
maxItems: NUMBER, Primary Key
nameMask: STRING, Primary Key
query: QUERY, Primary Key
isSortFirst: BOOLEAN, Primary Key
result: INFOTABLE, DataShape RootEntityListV2 (NOT a Primary Key!)
*/
let queryResult = ThingTemplates["GenericThing"].QueryImplementingThingsV2({
maxItems: values.maxItems /* NUMBER */,
nameMask: values.nameMask /* STRING */,
query: values.query /* QUERY */,
isSortFirst: values.isSortFirst /* BOOLEAN */
});
// Copy the results into a new InfoTable.
// This prevents some internal ThingWorx casting issues with some InfoTables
let resultTable = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: me.GetDataShape() // Returns Cached_QueryImplementingThingsV2_DataShape
});
resultTable.AddRow({
maxItems: values.maxItems /* NUMBER {"defaultValue":500} */,
nameMask: values.nameMask /* STRING */,
query: values.query /* QUERY */,
isSortFirst: values.isSortFirst /* BOOLEAN */,
result: queryResult
});
let result = resultTable;
Esempio di utilizzo di DataTableQuery 
Questo esempio illustra come utilizzare un servizio BetweenDatesDataTableQuery funzionante per trovare il valore più grande in un oggetto DataTable tra due date e memorizzare i risultati in una cache. Chiamate univoche a CachingBetweenDatesDataTableQuery interrogano inizialmente l'oggetto DataTable di backup, mentre le chiamate identiche successive utilizzano la cache.
Per impostarlo, attenersi alla procedura descritta di seguito.
1. Creare una data shape (TimeValueDataShape) con i campi seguenti: longKey: (LONG, primaryKey) e dateKey: (DATETIME, primaryKey).
2. Creare un oggetto DataTable (DemoDataTable) con la data shape TimeValueDataShape.
3. Creare una data shape (TimeSpanValueCacheDataShape) con i campi seguenti: startDate: (DATETIME, primaryKey), endDate: (DATETIME, primaryKey) e longValue: (LONG).
4. Creare un oggetto CacheThing (CacheThingDemo) con la data shape TimeSpanValueCacheDataShape configurata.
5. Creare i seguenti servizi in CacheThingDemo:
CachingBetweenDatesDataTableQuery - Input: StartDate ed EndDate come DATETIME. Output: result come LONG
BetweenDatesDataTableQuery - Input: StartDate ed EndDate come DATETIME. Output: result come LONG
* 
Questo servizio completa automaticamente i dati demo nell'oggetto DataTable nell'intervallo di date interrogato.
6. Facoltativo. Configurare una durata breve per ExpirationTime con un valore di ExpirationPolicy diverso da Never in CacheThingDemo per osservare le voci scadute della cache.
CachingBetweenDatesDataTableQuery
/* Reads the Cached results of BetweenDatesDataTableQuery Service.
If Cache doesn't have the result, call BetweenDatesDataTableQuery and load results into Cache.

Service Name: CachingBetweenDatesDataTableQuery
Inputs: StartDate[DATETIME, required], EndDate[DATETIME, required]
Output: LONG
*/
// This example uses CacheThing.GetEntry, which requires a one-row infoTable populated with the CacheThing's DataShapes primaryKey getEntryByKey
let cacheEntryInfoTable = getCacheEntryInfoTable();
cacheEntryInfoTable.AddRow({"startDate": StartDate, "endDate": EndDate});
let getEntryResult = Things["CacheThingDemo"].GetEntry({
values: cacheEntryInfoTable
});
if (getEntryResult.getRowCount() === 0) {
// Cache didn't have results, so go to backing DataTable, by calling the BetweenDatesDataTableQuery Service
let queryResult = Things["CacheThingDemo"].BetweenDatesDataTableQuery({
StartDate: StartDate,
EndDate: EndDate
});

// Turn ScriptLogger to debug mode to see the logger messages
logger.debug("PutEntry called for BetweenDatesQueryCache: {StartDate: " + StartDate + ", EndDate: " + EndDate + " value: " + queryResult + "}");
if (!queryResult || queryResult < 0) {
// BetweenDatesDataTableQuery should always populate with demo data if no data is in the StartDate - EndDate range
throw new Error("BetweenDatesDataTableQuery did not return results");
}
let newCacheEntryInfoTable = getCacheEntryInfoTable();
newCacheEntryInfoTable.AddRow({"startDate": StartDate, "endDate": EndDate, "longValue": queryResult});
Things["CacheThingDemo"].PutEntry({
values: newCacheEntryInfoTable
});
result = queryResult;
} else {
let row = getEntryResult.getRow(0);
logger.debug("Found the following entry already in Cache : {StartDate: " + row.startDate + ", EndDate: " + row.endDate + ", LongValue: " + row.longValue + "}");
result = row.longValue;
}
function getCacheEntryInfoTable() {
return Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: "TimeSpanValueCacheDataShape"
});
}
BetweenDatesDataTableQuery
/*  This service queries a range of dates, based on the dateKey column, and returns the greatest longKey value found.
If there are no entries between StartDate and EndDate this Service dynamically populates demo data into demoDataTable, and returns that result.

Service Name: BetweenDatesDataTableQuery
Inputs: StartDate[DATETIME, required], EndDate[DATETIME, required]
Output: LONG
*/
if (StartDate >= EndDate) {
throw Error("StartDate must be before EndDate");
}
let dataTable = Things["DemoDataTable"];
let queryResult = queryGreatestLongKeyBetweenDates(dataTable, StartDate, EndDate);
if (queryResult.getRowCount() === 0) {
// If we don't get any results, first populate the date range with random values, then retry
// Turn ScriptLogger to debug mode to see the logger messages
logger.debug("No values found between [" + StartDate + "] and [" + EndDate + "], populating 100 demo values and re-querying");
populateDemoDataTable(dataTable, StartDate, EndDate);
// Re-query the now populated DateTable
queryResult = queryGreatestLongKeyBetweenDates(dataTable, StartDate, EndDate);
result = queryResult.getRow(0).get("longKey");
} else {
result = queryResult.getRow(0).get("longKey");
}
// Queries the DataTable for the largest longKey column value between the given dates
// Returns: One-row InfoTable with the found row.
function queryGreatestLongKeyBetweenDates(dateTable, startDate, endDate) {
let greatestBetweenDatesQuery = {
"filters": {
"type": "Between",
"fieldName": "dateKey",
"from": startDate,
"to": endDate
},
"sorts": [{
"fieldName": "longKey",
"isAscending": false
}]
};
// Run the Query to find the greatest Value Between Two Dates
let queryResult = dataTable.QueryDataTableEntries({
maxItems: 1,
query: greatestBetweenDatesQuery,
});

logger.debug("Queried between [" + StartDate + "] and [" + EndDate + "], found:" + queryResult.toJSON());
return queryResult;
}
function populateDemoDataTable(dataTable, startDate, endDate) {
// add 100 random entries between startDate and endDate
for (let entry = 0; entry < 100; entry++) {
let randomTimeBetween = randomDate(startDate, endDate);
let entry = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: "TimeValueDataShape"
});
entry.AddRow({
"longKey": Math.floor(Math.random() * 1000),
"dateKey": randomTimeBetween
});
Things["DemoDataTable"].AddDataTableEntry({
values: entry /* INFOTABLE */ ,
});
}
}
function randomDate(startDate, endDate) {
let randomTime = Math.random() * (endDate.getTime() - startDate.getTime()) + startDate.getTime();
return new Date(randomTime);
}
È stato utile?