CacheThings
En CacheThing se proporciona una interfaz rápida en memoria para almacenar y recuperar datos de clave-valor. Es ideal para almacenar en caché los resultados de operaciones costosas o que requieren mucho tiempo, como consultas lentas.
Dado que CacheThing funciona en memoria, su contenido se despeja cuando se reinicia ThingWorx. En entornos de alta disponibilidad (HA), cada nodo de ThingWorx mantiene su propia caché independiente. Como resultado, las entradas de caché creadas o actualizadas en un nodo no se comparten automáticamente con otros nodos. Esto incluye las llamadas de invalidación de caché, como PurgeCache, DeleteEntry y DeleteEntryByKey.
CacheThing se puede utilizar para almacenar en caché distintos tipos de datos, entre los que se incluyen los siguientes:
Resultados de consultas costosas o frecuentes a cosas de base de datos
Resultados de consultas costosas o frecuentes a flujos de valor o tablas de datos
Resultados de llamadas de red lentas, por ejemplo, llamadas realizadas con ContentLoaderFunctions
Valores calculados costosos
Contenido de ficheros pequeños y de uso frecuente de FileRepositories
El uso de CacheThing puede mejorar significativamente el rendimiento y reducir el uso de recursos en comparación con el acceso a sistemas externos, como bases de datos o recursos de red.
Directrices de uso
CacheThing no está diseñado para utilizarse como almacén de datos permanente. Todos los datos almacenados en caché en CacheThing deben ser reproducibles desde el origen original.
Los datos de CacheThing pueden estar caducados o desalojados. Los servicios que utilizan CacheThing deben diseñarse para recuperar datos del origen original si la caché no devuelve ningún resultado. Consulte los ejemplos para obtener más detalles.
Configuración
Cada CacheThing se debe configurar con una definición de datos que tenga una clave primaria. La clave primaria se utiliza para recuperar entradas de la caché.
Se soportan las claves primarias compuestas, pero estas impiden el uso de la directiva de caducidad y tamaño máximo global de los servicios de conveniencia ByKey que se enumeran a continuación.
Directiva de caducidad
En la directiva de caducidad se define el período de vida (TTL) de cada entrada de caché. El tiempo de caducidad se puede configurar mediante la opción Hora de vencimiento de la entrada de caché (segundos). Después de que una entrada caduque, al recuperar el valor se devuelve un resultado vacío, similar a si se borrara de la caché.
Directivas de vencimiento soportadas:
Directiva de caducidad de entrada de caché
Descripción
Nunca
La entrada de la caché nunca se elimina en función de la cantidad de tiempo que ha pasado en la caché. Sin embargo, todavía se puede expulsar si la caché alcanza la configuración de tamaño máximo o mediante el servicio DeleteEntry. La opción de configuración Hora de vencimiento de la entrada de caché (segundos) se desestima cuando se configura la directiva de caducidad Never.
Hora de vencimiento desde el último acceso
La entrada se quita si no se ha leído dentro de la hora de vencimiento especificada.
Hora de vencimiento desde la creación
La entrada se quita una vez transcurrido el tiempo especificado desde su creación.
Hora de vencimiento desde la última modificación
La entrada se quita si no se ha modificado dentro de la hora de vencimiento especificada.
Hora de vencimiento desde la última vez que se tocó
La entrada se quita si no se ha accedido a ella o no se ha modificado dentro de la hora de vencimiento especificada.
Para obtener más información sobre la póliza de vencimiento de la interfaz, consulte Interface ExpiryPolicy.
Tamaño máximo de la caché (expulsión)
Las entradas de la caché se expulsan (borran) automáticamente cuando la caché alcanza el tamaño especificado en la opción de configuración Tamaño máximo de caché (MB). En el proceso de expulsión, se quitan las entradas de uso menos frecuente (LFU) para dejar espacio para nuevas entradas. Una vez expulsada una entrada, al recuperarla se devuelve un resultado vacío, similar a si se borrara.
Si se añade una entrada grande, se pueden expulsar múltiples entradas más pequeñas para acomodarla. Para evitar esto, utilice el servicio EstimateEntrySize para comprobar el tamaño de una entrada antes de añadirla a la caché.
La expulsión y la caducidad de la caché funcionan de forma independiente:
La expulsión se basa en el tamaño de la caché y la frecuencia de uso.
El vencimiento se basa en el tiempo, según se define en la directiva de caducidad configurada.
Tamaño máximo global
El subsistema de plataforma incluye una configuración denominada Tamaño máximo compartido entre todas las cosas de caché por nodo de ThingWorx (MB). Esta opción de configuración limita el tamaño combinado de todas las CacheThings en un solo nodo para evitar un uso excesivo de la memoria. Las CacheThings desactivadas no se incluyen en este límite.
Esta opción de configuración impide las siguientes acciones:
Creación de una nueva CacheThing que supere el tamaño máximo
Actualización del valor de Tamaño máximo de caché (MB) de una CacheThing que supera el tamaño máximo
Importación de CacheThings (ya sea como importaciones de entidades o como parte de una extensión) que superen el tamaño máximo, lo que hace que falle toda la importación
Reducción del tamaño máximo por debajo del valor de Tamaño máximo de caché (MB) combinado actual de todas las CacheThings
Activación de una CacheThing que supere el límite global
Cambio de la configuración de la caché
Cualquier cambio en la configuración de una caché depurará automáticamente la caché para conservar la coherencia interna. Si se edita cualquiera de los siguientes elementos, se depurará la caché:
Definición de datos: se incluye la modificación de la definición de datos configurada, como la adición o eliminación de campos.
Directiva de caducidad de entrada de caché
Hora de vencimiento de la entrada de caché (segundos)
Tamaño máximo de caché (MB)
Cache Performs Loading of Missing Entries
Servicios
Los siguientes servicios están disponibles en CacheThing. En entornos de alta disponibilidad (HA), estos servicios afectan a la caché del nodo de ThingWorx donde se ejecuta el servicio.
Los servicios de conveniencia *ByKey que se enumeran a continuación solo están disponibles cuando la definición de datos de la caché tiene una única clave primaria. Si en la definición de datos de la caché se incluye múltiples claves primarias, utilice la versión completa de entrada de infotable del servicio.
Nombre del servicio
Descripción
PutEntry
Permite añadir una entrada a la caché.
Valor de entrada: infotable de una fila que utiliza la definición de datos configurada de la CacheThing.
GetEntry
Se devuelve el resultado de una infotable de una fila de la caché.
Si no se encuentra la entrada (error de caché) y la caché no está configurada con Cache Performs Loading of Missing Entries, se devuelve una infotable vacía. Si la caché está configurada con esa opción, se llama automáticamente al servicio LoadEntry y se devuelve su resultado.
Se pueden producir errores de caché si la entrada nunca se ha añadido a la caché, se ha expulsado o ha caducado.
Valor de entrada: infotable de una fila que utiliza la definición de datos configurada de la CacheThing. Solo se deben rellenar los valores Primary Key.
GetEntryByKey
Se devuelve el resultado de una infotable de una fila de la caché.
Si no se encuentra la entrada, se devuelve una infotable vacía. Se pueden producir errores de caché si la entrada nunca se ha añadido a la caché, se ha expulsado o ha caducado.
Valor de entrada: cadena que representa la clave primaria de la entrada que se recupera. Este servicio solo está disponible si la definición de datos configurada tiene una única clave primaria. Esto funciona mejor con claves primarias de cadena, pero también soporta la mayoría de los tipos con una conversión de cadena clara.
LoadEntry
Se utiliza para obtener automáticamente datos de caché del origen de datos cuando se produce un error de caché.
Este servicio se debe sustituir si la opción Cache Performs Loading of Missing Entries está activada.
DeleteEntry
Permite borrar una entrada de la caché.
En un entorno de alta disponibilidad, esto solo afecta al nodo donde se llama al servicio DeleteEntry.
Valor de entrada: infotable de una fila que utiliza la definición de datos configurada de la CacheThing. Solo se deben rellenar los valores Primary Key.
DeleteEntryByKey
Permite borrar una entrada de la caché.
En un entorno de alta disponibilidad, esto solo afecta al nodo donde se llama al servicio DeleteEntryByKey.
Valor de entrada: cadena que representa la clave primaria de la entrada que se recupera. Este servicio solo está disponible si la definición de datos configurada tiene una única clave primaria.
PurgeCache
Permite quitar todas las entradas de la caché.
En un entorno de alta disponibilidad, esto solo afecta al nodo donde se llama al servicio PurgeCache.
GetDataShape
Se devuelve la definición de datos configurada de la caché.
SetDataShape
Permite definir el campo de la definición de cosa en la tabla de configuración de la caché. Si se cambia este valor, se depurará automáticamente la caché.
GetEstimatedEntryCount
Permite devolver el número estimado de entradas en la caché. Las operaciones PUT y DELETE en curso, así como los procesos de caducidad o expulsión, pueden afectar a la precisión.
EstimateEntrySize
Se devuelve el tamaño estimado de una entrada si se ha añadido a la caché. Esto no coloca la entrada en la caché y no requiere ninguna entrada que ya esté en la caché. Este servicio puede ser de utilidad para estimar un valor de Tamaño máximo de caché (MB) adecuado o para evitar que se añadan entradas de gran tamaño a la caché.
Valor de entrada: infotable de una fila que utiliza la definición de datos configurada de la CacheThing.
Sustitución del servicio LoadEntry
Para activar la opción Cache Performs Loading of Missing Entries (almacenamiento en caché de lectura), se debe sustituir el servicio LoadEntry en CacheThing. Este servicio se llama internamente cuando se produce un error de caché, lo que permite que la caché recupere y almacene datos del origen.
La llamada directa al servicio LoadEntry no añade entradas a la caché. Las entradas solo se añaden cuando LoadEntry se invoca internamente mediante GetEntry durante un error de caché.
Entrada
La entrada es una infotable de una fila que coincide con los parámetros de la llamada a GetEntry correspondiente. Normalmente, solo se rellenan los campos de clave primaria.
Implementación de servicios
El servicio LoadEntry debe recuperar o generar el valor que se almacenará en caché desde el origen de datos. Esto podría incluir consultas a la base de datos, llamadas a servicios Web o valores generados. Se debe evitar actualizar el estado de la aplicación, como propiedades o ficheros, dentro del servicio.
No se deben llamar a otros servicios de almacenamiento en caché, como GetEntry o PutEntry, desde LoadEntry. En la caché se gestiona automáticamente el almacenamiento del valor devuelto después de un error de caché.
Salida
La salida debe ser una infotable con la misma definición de datos que la entrada. Rellene los campos de clave no primaria con los datos recuperados. Cualquier excepción se propaga a la llamada a GetEntry que llama.
Se recomienda crear una nueva infotable para la infotable de resultados de salida. Aunque es posible reutilizar y rellenar los valores de entrada de la infotable, hacerlo puede provocar un comportamiento inesperado debido a las limitaciones en la forma en que las infotable gestionan determinados objetos BaseTypes en Javascript. Consulte los ejemplos para obtener más detalles. Uso de LoadEntry.
Almacenamiento en caché de lectura
Al seleccionar la casilla Cache Performs Loading of Missing Entries , se activa el almacenamiento en caché de lectura. En este modo, en la caché se cargan automáticamente los valores de entrada que faltan mediante el servicio LoadEntry en CacheThing cuando se produce un error de caché.
Para soportar este comportamiento, se debe sustituir el servicio LoadEntry en CacheThing para consultar los datos de origen y devolver el valor adecuado. Cuando el servicio GetEntry no encuentra un valor en la caché, la caché llama al servicio LoadEntry para recuperar el valor.
El almacenamiento en caché de lectura puede ayudar a mitigar los escenarios de colapso por activación simultánea de varios hilos de ejecución. Si se realizan múltiples solicitudes GetEntry paralelas para la misma clave antes de que se rellene, solo se llama una vez al servicio LoadEntry de respaldo. Una vez completada la llamada a LoadEntry, todas las solicitudes GetEntry pendientes devuelven el valor recuperado.
Consulte la sección Sustitución del servicio LoadEntry anterior para obtener información detallada sobre la implementación de un servicio LoadEntry.
Métricas
Hay disponibles varias métricas relacionadas con la caché. En entornos de alta disponibilidad (HA), las cachés son independientes para cada nodo. Las métricas se deben procesar por nodo mediante los rótulos platform y cache_name.
Están disponibles las siguientes métricas de caché:
Métricas de caché
Descripción
thingworx_cache_hit_rate
Proporción de solicitudes de caché que han dado lugar a la búsqueda de una entrada en la caché
thingworx_cache_hits
Número de veces que los métodos de búsqueda en caché han devuelto un valor almacenado en caché
thingworx_cache_request_count
Número de veces que los métodos de búsqueda en caché han devuelto un valor almacenado en caché o no almacenado en caché
thingworx_cache_miss_rate
Proporción de métodos de búsqueda en caché que han devuelto un valor no almacenado en caché (recién cargado) o nulo
thingworx_cache_misses
Número de veces que los métodos de búsqueda en caché han devuelto un valor no almacenado en caché (recién cargado) o nulo
thingworx_cache_eviction_count
Número de veces que se ha expulsado una entrada
thingworx_cache_average_load_penalty
Tiempo medio empleado en cargar nuevos valores
thingworx_cache_weighted_size
Tamaño actual aproximado de la caché en bytes
thingworx_cache_max_weight
Tamaño máximo de la caché en bytes antes de la expulsión
thingworx_cache_estimated_entry_count
Número estimado de entradas en la caché
thingworx_cache_global_max_size
Tamaño máximo global configurado para todas las cachés en bytes
Alertas (disponibles en entornos alojados en PTC Cloud)
Las siguientes alertas están disponibles en entornos alojados en PTC Cloud:
thingworxEntityCacheMissRate: se avisa cuando la tasa de fallos de una caché supera el 80 % durante 1 hora.
thingworxEntityCacheEvictions: se avisa cuando la tasa de expulsión de una caché supera el 80 % durante 30 minutos.
Ejemplos y prácticas recomendadas
La implementación de servicios que utilizan CacheThing de manera eficaz requiere atención a los detalles. Se deben tener en cuenta las siguientes prácticas recomendadas:
La caché se borra cuando se reinicia el nodo de ThingWorx.
Las entradas se pueden expulsar o caducar de la caché sin que el usuario lo haga. No se debe dar por sentado que los enteros permanecerán en la caché indefinidamente.
Se deben utilizar métricas de caché para validar que el tamaño de caché es adecuado.
Se debe evitar almacenar todos los datos en una sola entrada o crear entradas de caché muy grandes.
En entornos de alta disponibilidad (HA), cada nodo tiene una caché de independiente. La adición, el borrado o la depuración de una caché en un nodo no afectará a todos los nodos de ThingWorx.
Cuando la opción Cache Performs Loading of Missing Entries está desactivada (caché no de lectura):
1. Recuperar una entrada de la caché mediante la clave primaria.
2. Comprobar si el resultado se ha rellenado (la infotable devuelta tiene una fila).
3. Si se encuentra el resultado, utilícelo.
4. Si no se encuentra el resultado:
Extraer o generar la entrada necesaria a partir de los datos de origen (por ejemplo, cosa de base de datos, tabla de datos o cargador de contenido).
Añada la entrada a la caché mediante PutEntry.
Devuelva la nueva entrada almacenada en caché.
Cuando la opción Cache Performs Loading of Missing Entries está activada (caché de lectura):
1. Sustituya el servicio LoadEntry en CacheThing.
2. Recuperar una entrada de la caché mediante la clave primaria.
Si no se encuentra la entrada, LoadEntry se llama automáticamente para rellenar el valor.
Ejemplo de uso del servicio TimesTwo 
El servicio TimesTwo toma un número, lo multiplica por 2 y almacena el resultado en una caché. Para configurarlo, siga estos pasos:
1. Cree una definición de datos (TimesTwoDataShape) con los siguientes campos: operand: (LONG, primaryKey) y timesTwoValue: (LONG).
2. Cree una CacheThing (MyTimesTwoCache) con el valor de TimesTwoDataShape configurado.
3. Añada el servicio TimesTwo a MyTimesTwoCache:
Entrada: x (un número LONG)
Salida: result (un número 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;
}
Ejemplo: Empaquetador del servicio de almacenamiento en caché 
En este ejemplo se muestra cómo almacenar manualmente en caché los resultados del servicio QueryImplementingThingsV2.
1. Cree una definición de datos denominada Cached_QueryImplementingThingsV2_DataShape con los siguientes campos:
maxItems: (NUMBER, primaryKey)
nameMask: (STRING, primaryKey)
query: (QUERY, primaryKey)
isSortFirst: (BOOLEAN, primaryKey)
result: (INFOTABLE, DataShape RootEntityListV2)
2. Cree una CacheThing denominada Cached_QueryImplementingThingsV2 y asígnele Cached_QueryImplementingThingsV2_DataShape como su definición de datos.
3. Para observar el comportamiento de vencimiento de la caché, configure un valor de ExpirationTime corto y defina un valor de ExpirationPolicy distinto de Never en la cosa Cached_ReadThrough_QueryImplementingThingsV2.
4. Cree un servicio denominado CachingQueryImplementingThingsV2 con los siguientes parámetros:
Entradas
maxItems: (NUMBER, required)
nameMask: (STRING, required)
query: (QUERY, required)
isSortFirst: (BOOLEAN, required)
Salida 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"
});
}
Ejemplo: Contenedor del servicio de almacenamiento en caché como caché de lectura 
En este ejemplo se muestra cómo almacenar automáticamente en caché los resultados del servicio QueryImplementingThingsV2 mediante una caché de lectura. Después de sustituir el servicio LoadEntry, se puede utilizar el servicio GetEntry para cargar automáticamente los resultados de la consulta QueryImplementingThingsV2 en la caché.
1. Cree una definición de datos denominada Cached_QueryImplementingThingsV2_DataShape con los siguientes campos:
maxItems: (NUMBER, primaryKey)
nameMask: (STRING, primaryKey)
query: (QUERY, primaryKey)
isSortFirst: (BOOLEAN, primaryKey)
result: (INFOTABLE, DataShape RootEntityListV2)
2. Cree una CacheThing denominada Cached_ReadThrough_QueryImplementingThingsV2. Asigne Cached_QueryImplementingThingsV2_DataShape como su definición de datos y active la opción Cache Performs Loading of Missing Entries.
3. Para observar el comportamiento de vencimiento de la caché, configure un valor de ExpirationTime corto y defina un valor de ExpirationPolicy distinto de Never en la cosa Cached_ReadThrough_QueryImplementingThingsV2.
4. Vaya a la ficha Servicios y seleccione Sustituir junto al servicio LoadEntry, con el siguiente ejemplo:
/* 
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;
Ejemplo: Uso de DataTableQuery 
En este ejemplo se muestra cómo utilizar un servicio BetweenDatesDataTableQuery en funcionamiento para buscar el valor más grande en una tabla de datos entre dos fechas y almacenar los resultados en una caché. Las llamadas únicas a CachingBetweenDatesDataTableQuery consultan inicialmente la tabla de datos de respaldo, pero las llamadas idénticas posteriores utilizan la caché en su lugar.
Para configurarlo, siga estos pasos:
1. Cree una definición de datos (TimeValueDataShape), con los siguientes campos: longKey: (LONG, primaryKey) y dateKey: (DATETIME, primaryKey).
2. Cree una tabla de datos (DemoDataTable) con la definición de datos TimeValueDataShape.
3. Cree una definición de datos (TimeSpanValueCacheDataShape) con los siguientes campos: startDate: (DATETIME, primaryKey), endDate: (DATETIME, primaryKey) y longValue: (LONG).
4. Cree una CacheThing (CacheThingDemo) con la definición de datos TimeSpanValueCacheDataShape configurada.
5. Cree los siguientes servicios en CacheThingDemo:
CachingBetweenDatesDataTableQuery. Entradas: StartDate y EndDate como DATETIME. Salidas: result como LONG
BetweenDatesDataTableQuery. Entradas: StartDate y EndDate como DATETIME. Salidas: result como LONG
* 
Este servicio permite rellenar automáticamente los datos de demostración en la tabla de datos del rango de fechas consultado.
6. Opcional. Configure un valor de ExpirationTime corto con un valor de ExpirationPolicy distinto de Never en CacheThingDemo para observar las entradas que caducan de la caché.
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);
}
¿Fue esto útil?