#InterSystems IRIS for Health

0 Seguidores · 498 Publicaciones

InterSystems IRIS for Health™ es la primera y única plataforma de datos global diseñada específicamente para desarrollar aplicaciones que permitan a los servicios médicos administrar los datos más importantes del mundo. Incluye poderosas funciones listas para utilizarse: procesamiento y análisis de transacciones, un modelo flexible para la información de los servicios médicos, implementación de soluciones basadas en FHIR, soporte para las normas de compatibilidad operativa entre los servicios médicos, y mucho más. Todas estas funciones permiten que los desarrolladores realicen aplicaciones valiosas y novedosas rápidamente. Obtener más información.

InterSystems Official Mario Sanchez Macias · feb 11, 2022

9 de Febrero de 2022

InterSystems ha corregido un defecto donde  una consulta SQL podría obtener resultados incorrectos.

Este defecto solo se produce en la versión 2021.2 (Continuous Delivery):

            InterSystems IRIS Data Platform

            InterSystems IRIS for Health

            HealthShare Health Connect

0
0 121
Artículo Laura Blázquez García · feb 11, 2022 4m read

Hasta hace no mucho, todos los entornos con los que trabajábamos eran Ensemble 2017.2. Pero recientemente hemos migrado todos los entornos a la versión 2021.1 de IRIS for Health. Ha sido un camino complicado, pero tras analizarlo detenidamente, encontramos la forma de conseguirlo.

Contamos con un servidor de desarrollo y dos servidores en producción en mirroring, en modo Failover. Tenemos más de 40 Namespaces dando servicio, unos con integraciones HL7, otros con servicios Soap, servicios Rest, procesado de archivos... un poco de todo. Necesitábamos estar seguros de que la migración a IRIS no iba a suponer un problema y sobre todo, evitar a toda costa un corte de servicio. Así que lo primero que teníamos que hacer era establecer un plan.

0
0 225
InterSystems Official David Reche · feb 9, 2022

Desde 2018, InterSystems ha estado utilizando una cadencia de lanzamiento doble con InterSystems IRIS (aquí puedes ver el anuncio original desde cuando empezamos). Ofrecemos:

  • Versiones de Entrega Continua (Continuous delivery, CD) — estas versiones ofrecen acceso a nuevas funcionalidades de forma rápida. Son perfectas para el desarrollo e implementación de aplicaciones que son actualizadas continuamente y pueden aprovechar las nuevas funcionalidades de forma inmediata.
  • Versiones de Mantenimiento Extendido (Extended maintenance, EM) — estas versiones son menos frecuentes que las de Entrega Continua, pero ofrecen la estabilidad mejorada de las versiones de mantenimiento. Son perfectas para grandes aplicaciones empresariales en las que la facilidad de obtener parches en las versiones de mantenimiento es más importante que tener un acceso rápido a nuevas funcionalidades.
0
0 100
Artículo Ricardo Paiva · feb 8, 2022 7m read

Este artículo es una continuación de esta publicación.

En ese artículo, expliqué cómo funciona el menú de Interoperabilidad para su integración en el sistema.

En este artículo, me gustaría explicar cómo desarrollar una integración de sistemas utilizando el menú de interoperabilidad.

En primer lugar, ¿qué tipo de proceso quieres crear? Mientras piensas en ello, prepara el siguiente contenido.

  • Producción
  • Mensaje
  • Componentes
    • Business Services
    • Business Processes
    • Business Operations

Producción es una definición que se utiliza para especificar los componentes necesarios para la integración de sistemas y para almacenar la configuración de los componentes, que se configuran mediante el Portal de Administración (almacenado de forma interna como una definición de clase para la Producción).

Por ejemplo, supón que quieres crear un businessservice que procese los archivos colocados en un directorio específico a intervalos regulares. En ese caso, es necesario configurar exactamente qué directorios monitorizar y qué archivos procesar. Hay una Producción disponible para almacenar dicha configuración.

La configuración depende del adaptador usado por el componente que envía y recibe los datos.

Los adaptadores son clases para simplificar la conexión a los sistemas externos. Algunos son específicos de protocolos, como Mail/File/SOAP/FTP/HTTP/SQL/TCP, y otros son de específicos de estándares, como HL7.

Consulta la documentación (adaptadores específicos de protocolos y adaptadores relacionados con la documentación EDI) para más información sobre los adaptadores.

Como definiremos los componentes necesarios para la Producción, "Start Production" iniciará la integración del sistema, y "Stop Production" detendrá la integración del sistema.

El desarrollo necesario para completar la Producción es la creación de los componentes necesarios para la integración del sistema, concretamente los siguientes contenidos:

  • Mensaje
  • Componentes (Business Services, Business Processes, Business Operations)
  • Conversión de datos, etc.

El contenido anterior se explicará con más detalle en próximos artículos.

Primero vamos a iniciar la Producción utilizando la muestra Producción y comprobaremos el proceso de los mensajes al procesar los datos mientras se verifica la configuración.

La muestra puede descargarse en https://github.com/Intersystems-jp/selflearning-interoperability.

Para utilizar un contenedor, descarga el código de muestra por medio del clon en Git, ve al directorio del clon y ejecuta docker-compose up -d ¡Es así de fácil!

Consulta aquí el procedimiento (lleva un poco de tiempo crear un contenedor).

Si no utilizas contenedores, crea un nuevo namespace después de descargar la muestra, e importa todos los archivos de definición de clases (extensión .cls) a la carpeta src en el namespace creado.

Para más información sobre el proceso para crear un namespace, consulta el video desde el minuto 07:03 que aparece en este artículo.

Consulta el archivo README para más información sobre el código de muestra.

Cuando estés listo, ve al Portal de Administración (cambia el número de puerto del servidor web para que coincida con tu entorno).

http://localhost:52773/csp/sys/UtilHome.csp

Ve a Management Portal > Interoperability > Configuration > Production.

Si utilizas un método distinto al de los contenedores, conéctate al namespace donde importaste el código fuente, accede a [Configuration] > [Production], haz clic en el botón [Open], selecciona [Start] > [Production], y después haz clic en el botón [Start].

※ Si utilizas algo que no sea un contenedor, tendrás que hacer unos ajustes iniciales. Configura los contenidos descritos más abajo antes de probar los siguientes contenidos.

imagen

La página de producción se mostrará como [Component Name] para cada uno de los componentes "Service", "Process" y "Operation".

Haz clic sobre el nombre del componente para cambiar el contenido de la pestaña "Settings" en la parte derecha de la pantalla.

Por ejemplo, cuando haces clic sobre Start.GetKionOperation (un solo clic), se mostrará lo siguiente.

imagen

Este componente tiene la configuración de [HTTP Server] y de la [URL] para conectarse a la API Web. Hay un campo [appid] en la parte inferior de la configuración, donde se puede introducir la clave de la API que recibes. Hay un campo [lang] cerca de [appid] y se configura "ja" ("ja" = japonés). [lang] establece el idioma de la respuesta de OpenWeather. En el caso del inglés, selecciona "en". Cuando termines de definir esta configuración, haz clic en el botón "Apply".

imagen

Si utilizas un contenedor, la configuración está completa. Para más información, haz clic aquí.


Si estás probando con algo distinto a los contenedores

Realiza estos dos ajustes por adelantado:

  1. Configurar el cliente SSL.

Debido a que la API Web a la que se conectará estará comunicada mediante HTTPS, configura previamente el cliente SSL en el lado de IRIS.

Para que coincida con la configuración de la producción de muestra, utilizaremos el nombre [openweather]. La configuración de la Producción es la siguiente:

imagen

Haz clic en Management Portal > [System Administration] > [Security] > [SSL/TLS Configuration] > [Create New Configuration], escribe "openweather" en el campo "Configuration Name", y haz clic en el botón "Save" para terminar.

imagen

  1. Crear una URL base para REST

En la producción de muestra, lo configuramos para que la información se pueda introducir mediante REST, y la URL base para REST debe configurarse en el lado de IRIS.

En la muestra, definimos /start como la URL base. Dado que la clase Start.REST se encuentra en el namespace donde se importó la muestra, especificaremos esta clase como clase dispatch y añadiremos %All como el rol de aplicación para omitir la autenticación en el momento del acceso.

Management Portal > System Administration > Security > Applications > Web Application Path > Haz clic en el botón "Create new web application".

En el campo Name, especifica /start; en el campo Namespace, especifica el namespace desde el que se importó la muestra; en el campo Dispatch Class, especifica Start.REST; en el campo Allowed Authentication Method, selecciona "Unauthenticated", y guarda el archivo.

Después de guardar, añade %All al rol de aplicación en la pestaña "Application Roles".

imagen

imagen


Tratar de enviar datos

En cuanto tengas todo configurado, intenta utilizar un business service para enviar información a través de REST y hazlo funcionar.

http://localhost:52773/start/weather/Takoyaki/Osaka

El ejemplo anterior es una URL donde se supone que alguien compró "Takoyaki" en la ciudad de Osaka.

Después de la ejecución, en la pantalla aparece esto:

imagen

Comprueba los mensajes que se han enviado a la Producción.

En Management Portal > Interoperability > Configuration > Production, haz clic en el servicio que aparece a continuación:

Seleccione la pestaña "Messages " que aparece en la parte derecha de la pantalla y haz clic en cualquier número que se encuentre debajo de la columna "Header". Si no lo encuentras, vuelve a cargar tu navegador.

imagen

A través de la página de Visual Trace, se puede ver la información de messages enviados y recibidos entre los componentes. Puedes ver que la información meteorológica se recupera de la API web y se envía de nuevo en el marco azul claro.

De esta manera, se puede utilizar el seguimiento para ver qué datos se enviaron y recibieron en ese momento y en qué orden.

En este artículo, confirmamos que en la Producción se definieron los componentes necesarios y sus configuraciones para la integración del sistema, basándose en las configuraciones del código de muestra.

Además, confirmamos que podemos consultar los mensajes que circulan dentro de la Producción en orden cronológico, utilizando la página Visual Trace.

En los siguientes artículos, analizaremos el concepto que hay detrás de la creación del "mensaje" que se muestra en este recorrido y cómo se define realmente.

0
1 422
Artículo Nigel Salm · feb 4, 2022 3m read

Me permito adjuntar un documento que describe un producto que he desarrollado llamado NiPaRobotica Pharmacy. Se trata de una interfaz que desarrollé, que acepta solicitudes para dispensar a farmacias y convierte las líneas de pedido en diálogos de dispensación que se envían a los robots de las farmacias. Implementé la interfaz en 3 farmacias de hospitales, dos de las cuales tenían 6 robots que se organizaron de tal manera que las rampas de dispensación canalizaban los medicamentos hasta los mostradores de los farmacéuticos que atendían en las ventanillas a 1 200 pacientes al día. Los robots disminuyeron el tiempo promedio de espera de 2 a 1 hora.

Después, implementé la interfaz en 6 sitios construidos específicamente en lugares cercanos a las viviendas de los pacientes con enfermedades crónicas como tuberculosis, VIH, diabetes, epilepsia, hipertensión y asma. El propósito de este proyecto fue "Llevar los medicamentos al paciente". Estos sitios cuentan con 6 Unidades de Dispensación Farmacéutica (PDU) similares a los cajeros automáticos, que disponen de una interfaz que permite al paciente comunicarse con un centro de asistencia telefónica farmacéutica. En el interior de cada PDU hay un gran robot que contiene varios miles de medicamentos. Mi aplicación envía una instrucción de dispensación al robot, que dispensa el artículo en una banda transportadora que lleva el medicamento hasta situarlo debajo de una impresora. A la impresora llega el contenido de una etiqueta farmacéutica con el nombre del paciente, las instrucciones de administración y otras notas. La impresora coloca y pega la etiqueta al envase del medicamento. El artículo se desplaza un poco más y una esponja presiona la etiqueta para fijarla con mayor firmeza al envase. La banda transportadora pasa el artículo a un contenedor de la PDU y, una vez que se suministran todos los artículos, el paciente puede abrir una ventanilla de la PDU y recoger los artículos. Lo más importante de este proyecto es que eliminó la necesidad de que los pacientes tengan que faltar al trabajo, recorrer largas distancias hasta la clínica donde se hace el seguimiento de su estado de salud, recoger sus medicamentos y volver a casa. Ubicar estos sitios en los vecindarios donde viven los pacientes permite que puedan acudir a cualquiera de estos sitios y recoger sus medicamentos en el camino hacia o de vuelta del trabajo. 

Desde el final de la época victoriana se han producido muy pocos cambios en el mundo de las farmacias. Los ingredientes ahora son más especializados y, en muchos casos, permiten salvar vidas. La penicilina, las vacunas, los analgésicos, las terapias contra el cáncer y las inmunoterapias han modificado nuestra capacidad de tratar enfermedades que históricamente habrían sido letales para los pacientes. Sin embargo, el proceso de dispensación de esos medicamentos ha permanecido estancado en las profundidades de las farmacias de los hospitales o de las farmacias de barrio que venden más cachivaches que medicamentos. La aplicación puede hacer mucho más que transferir las solicitudes de dispensación desde la aplicación farmacéutica a los robots, y estas funciones se detallan en el documento. La aplicación ha sido modificada para admitir los mensajes FHIR relacionados con el inventario, las solicitudes y respuestas sobre medicamentos y los certificados de los mismos. El documento viene en formato PDF.

0
0 154
Artículo Nigel Salm · feb 4, 2022 3m read

Acabo de exponer este tema en Global Masters: "IRIS Cheatsheets". IRIS ha introducido muchas funciones nuevas, especialmente en los lenguajes de programación, la compatibilidad con FHIR R4, las herramientas de interoperabilidad mejoradas e IRIS Analytics. Después trabajar 35 años en PC's y portátiles con Windows, sorprendentemente tengo poco conocimiento sobre Linux, Docker y Git. Es más, he escrito casi todas las aplicaciones e interfaces en ObjectScript con pizcas de SQL, .Net y Java Gateways y los conocimientos más básicos de WinSCP, Putty y SSH.

Todo cambió cuando recibí mi primera Raspberry Pi. Primero, tuve que elegir un sistema operativo para escribir en la tarjeta de memoria Micro SD. Las Raspberry Pi tienen su propio sistema operativo, pero a menos que quiera limitarme a ejecutar mis instancias de IRIS, IRIS for Health, Report Server y Ensemble en contenedores Docker, necesitaba escoger un sistema operativo que sea una plataforma compatible con IRIS. Después de investigar mis opciones mediante búsquedas en Google, fue evidente que no era una buena opción tener Windows en la Raspberry Pi, así que rápidamente lo borré de mi lista. Casualmente el primero de mis Raspberry Pi será el controlador de mi primer kit de robot Adeept (PiCar Pro). Me incorporé a STEM. STEM es un modelo educativo para introducir a gente desde 5 años en el mundo de la ingeniería y la programación. STEM son las siglas en inglés de Ciencia, Tecnología, Ingeniería y Matemáticas, y es el modelo predominante que utilizan los fabricantes de Arduino, Adeept, Lego y otros kits de robots. El lenguaje de programación que se utiliza en todas estas implementaciones de STEM es Python. Qué alegría. Python me fascinó desde el momento que me enteré que se implementaría como Lenguaje de programación nativo en IRIS. Desde muy joven, mi asignatura favorita eran las matemáticas, por lo que la introducción de Python, R y Julia en el mundo de IRIS me llenó de emoción.

Descubrí que todos estos lenguajes tienen una gran afinidad con Ubuntu de Linux, una plataforma muy popular para las implementaciones de IRIS. Mejor dicho, es la única plataforma compatible con ARM64, la tecnología que se utiliza en la Raspberry Pi. Así que Ubuntu era claramente la ruta que debía seguir. La siguiente decisión que debía tomar era qué implementación de Ubuntu quería utilizar. Hay tres opciones: Desktop, Server y Core. Se recomienda Ubuntu Server, ya que incluye una garantía de soporte por 5 años. Se interactua con Ubuntu Server proporcionando instrucciones y comandos desde un terminal. Ubuntu Core es una versión inferior de Server y es ideal como base para un contenedor Docker. Siendo novato en Ubuntu, me decidí por Ubuntu Desktop, y encendí mi Pi por primera vez, me encontré con una Interfaz gráfica en el escritorio muy familiar. Además, enseguida descubrí que todas las aplicaciones que utilizo cada día en Windows tienen equivalentes en Ubuntu. En poco tiempo ya tenía instalados Docker, Putty, Git y muchas otras aplicaciones y, lo más satisfactorio de todo, Visual Studio Code.

Dado que de pronto me encontré con tantas tecnologías nuevas con las que trabajar, empecé a buscar documentación sobre todos estos temas y, por supuesto, hay una enorme cantidad de material. La dificultad está en saber qué libro, preguntas frecuentes, video o aplicación de aprendizaje elegir. Mientras recorría página tras página de búsquedas en Google, los documentos que más atrajeron mi atención fueron los Cheatsheets o Guías Rápidas. Consulta mi reto en Global Masters para obtener más información sobre los Cheatsheets. Hay una Guía Rápida sobre la que quería llamar vuestra atención, una que particularmente me impresionó. Es un PDF llamado "Python-cheat-sheet-April-2021".

También descubrí que varios miembros de la Comunidad de Desarrolladores me ayudaron con las preguntas que tenía sobre Raspberry Pi, Ubuntu y Docker. Estoy deseando pasar más tiempo con ellos para acelerar mi formación en estos temas.

0
0 145
InterSystems Official David Reche · ene 26, 2022

El equipo de Plataformas de Datos está encantado de anunciar el lanzamiento de la versión 2021.2 de InterSystems IRIS, InterSystems IRIS for Health y HealthShare Health Connect, ya disponible (GA) para clientes y partners.

Novedades de la versión

InterSystems IRIS Data Platform 2021.2 hace aún más sencillo desarrollar, desplegar y gestionar aplicaciones aumentadas y procesos de negocio que canalizan silos de datos y aplicaciones aisladas. Ofrece muchas funcionalidades nuevas, como:

0
0 98
Artículo Jose-Tomas Salvador · dic 29, 2021 1m read

Para aquellos a los que, en un momento dado, necesitan probar cómo va eso del ECP para escalabilidad horizontal (cómputo y/o concurrencia de usuarios y procesos), pero les da pereza o no tienen tiempo de montar el entorno, configurar los nodos, etc..., acabo de publicar en Open Exchange la aplicación/ejemplo OPNEx-ECP Deployment .

0
0 224
Artículo Eduardo Anglada · dic 29, 2021 2m read

Hablando con mi amigo @Renato Banzai, especialista en Machine Learning, me comentó uno de los mayores retos a los que se enfrentan las empresas hoy en día: implementar el Machine Learning (ML) o la Inteligencia Artificial (IA) en entornos reales.

InterSystems IRIS ofrece IntegratedML. IntegratedML es una excelente funcionalidad para formarse, probar e implementar modelos de ML/IA.

La parte más difícil al crear ML/IA es el tratamiento de los datos, su limpieza, hacerlos fiables.

¡Y ahí es donde podemos sacar ventaja del potente estándar FHIR!

La idea del proyecto muestra cómo podemos crear/entrenar/validar modelos de ML/IA con FHIR y utilizarlos con datos de diferentes fuentes.

0
0 184
Artículo Muhammad Waseem · dic 22, 2021 3m read

La interoperabilidad en la asistencia sanitaria es esencial para mejorar la atención a los pacientes, reducir los costes de los proveedores de atención médica y ofrecer una imagen más precisa a los proveedores. Pero con tantos sistemas diferentes, los datos se presentan en diferentes formatos. Se han creado muchos estándares para tratar de resolver este problema, incluyendo HL7v2, HL7v3 y CDA, pero cada una tiene sus limitaciones.

FHIR, o Fast Healthcare Interoperability Resources, es un estándar para el intercambio de datos de salud, que tiene como objetivo resolver estos problemas. Fue desarrollado por Health Level Seven International (HL7), una organización que también desarrolló HL7v2, HL7v3 y CDA.

En este artículo descubriremos cómo crear y validar recursos FHIR usando el esquema FHIR con la ayuda de IntelliSense y la función de autocompletado en VS Code.

Paso 1: Descargar el archivo JSON Schema para Validación de Recursos desde la web oficial de FHIR: https://www.hl7.org/fhir/

Paso 2: Crear una carpeta (en este ejemplo estoy usando la carpeta Patient y el recurso Patient) y copiar el archivo fhir.schema.json extraído, en la misma carpeta. A continuación, abrir la carpeta desde VS Code 

 

Paso 3: Configurar el código VS para reconocer el esquema FHIR modificando el archivo setting.json.
Presionar CTRL+SHIFT+P y escribir en el espacio de trabajo settings.json

 

Paso 4: Crear un nuevo archivo patient.fhir.json, en la misma carpeta.
Pulsar Ctrl+ESPACIO y se obtendrán todos los atributos de los recursos de FHIR a través de IntelliSense

Escribir "resourceType": "Patient" y todos los atributos relacionados con el recurso Patient comenzarán a aparecer en el IntelliSense.

VS Code validará automáticamente la estructura y la sintaxis del recurso.


 

Con la ayuda de IntelliSense y la función de autocompletado hemos creado y validado nuestro recurso para los pacientes.

Paso 5: Publicar el recurso creado en el servidor FHIR de InterSystems usando la API Rest de Postman

Recuperar el recurso de Patient Creado utilizando el método GET

¡Enhorabuena! Hemos creado y validado nuestro recurso Patient, y lo hemos publicado y recuperado correctamente en el Servidor FHIR de InterSystems usando Postman.

De esta manera podemos crear y validar fácilmente cualquier Recurso FHIR.

0
1 916
InterSystems Official Mario Sanchez Macias · dic 17, 2021

13 de diciembre de 2021

InterSystems está investigando el impacto de una vulnerabilidad de seguridad relacionada con Apache Log4j2.

La vulnerabilidad — impactando al menos a Apache Log4j2 (versiones 2.0 a 2.14.1) — fue anunciada recientemente por Apache y ha sido notificada en la Base de Datos de Vulnerabilidad Local de Estados Unidos (NVD) como CVE-2021-44228 con la calificación de gravedad más alta, 10.0.

Por favor, consultad esta página para conocer más detalles sobre la vulnerabilidad y actualizaciones sobre si los productos de InterSystems están afectados.

0
0 172
Artículo Ricardo Paiva · dic 10, 2021 4m read

Me gustaría compartir algunas funciones de almacenamiento que también existen en Caché y que son prácticamente desconocidas y en su mayoría no se utilizan. Por supuesto, están disponibles en IRIS y son más relevantes con arquitecturas de almacenamiento extensas y distribuidas.

0
0 183
Artículo Bernardo Linarez · nov 22, 2021 3m read

Mas de una vez nos ha sucedido que requerimos añadir algún comportamiento a algún Bussiness Service core (tal como viene "de caja").

En este caso puntual, tomaré de ejemplo el BS EnsLib.RecordMap.Service.FileService, el cual nos permite leer un archivo (normalmente un csv) desde una carpeta configurable. A veces sucede que el archivo que estamos leyendo es muy grande, y por tanto contiene muchas filas, y nuestra lógica requiera saber exactamente cuando se termino de procesar y además generar un evento que incluso sea procesado por algún Host personalizado.

0
0 225
Artículo Bernardo Linarez · nov 22, 2021 2m read

Tal como sucede con otros tipos de Host, en ciertos casos de uso nos conviene personalizar el comportamiento de algún Business Operation (BO) de caja. En este caso, tomaré de ejemplo el siguiente EnsLib.REST.GenericOperation

En principio, el caso de uso era un simple Pass Through de una petición HTTPRest, por lo que se decidió usar tanto el BS y el BO core de IRIS para reenviarlo. Sin embargo, el destino de esta petición, necesitaba algunos Header por defecto, que no proporcionaba el request original.

0
0 195
InterSystems Official Mario Sanchez Macias · nov 22, 2021

19 de Noviembre de 2021

Los kits de InterSystems incluyen un servidor web Apache que ofrece una práctica manera de interactuar con el Portal de Gestión de Caché/IRIS sin necesidad de instalar un servidor web externo. Sin embargo, este servidor web nunca debería usarse para instancias de producción y se debe instalar un servidor web externo que se ajuste a las necesidades específicas y a los requisitos de seguridad y riesgo de cada cliente.

Pruebas recientes han detectado problemas de seguridad con el servidor web Apache incluido en los kits actuales. Como es una tecnología de terceros que InterSystems no controla, InterSystems recomienda instalar la versión del servidor web obtenida directamente desde Apache y deshabilitar el servidor web Apache incluido. Nuestra documentación incluye instrucciones sobre cómo deshabilitar el servidor web proporcionado con nuestros kits. Apache también ofrece instrucciones de desinstalación, que se pueden encontrar en su página web.

0
0 152
Anuncio Jose-Tomas Salvador · nov 18, 2021

¡Hola a todos!

Estamos encantados de anunciar una nueva manera de descargar los kits de la "Community Edition" de InterSystems IRIS e IRIS for Health. La "Community Edition" es una versión gratuita para desarrolladores, que hace más sencillo empezar a desarrollar soluciones con IRIS. Ahora se pueden descargar los kits a través del Servicio de Evaluación: evaluation.intersystems.com.

0
0 132
Artículo Ricardo Paiva · nov 18, 2021 2m read

Hablando con mi amigo @Renato Banzai, especialista en Machine Learning, me expuso uno de los mayores retos a los que se enfrentan actualmente las empresas: la implementación del Machine Learning (ML) y la Inteligencia Artificial (IA) en entornos reales.

Intersystems IRIS ofrece IntegratedML. IntegratedML es una excelente herramienta para practicar, probar y realizar implementaciones de modelos de ML e IA.

La parte más complicada de crear ML/IA es procesar los datos, depurarlos y hacerlos fiables.

¡Ahí es donde podemos aprovechar el estándar FHIR!

La idea del proyecto muestra cómo podemos crear/practicar/validar modelos ML/IA con FHIR y utilizarlos con datos de distintas fuentes.

Creemos que este proyecto tiene un gran potencial y también hay algunas ideas que pueden analizarse:

  • Reutilizar/ampliar las transformaciones DTL en otras bases de datos FHIR para modelos de ML personalizados
  • Utilizar las transformaciones DTL para normalizar los mensajes FHIR y publicar los modelos ML como servicios
  • Crear un tipo de modelos + un repositorio con las reglas de las transformaciones para utilizarlos en cualquier conjunto de datos FHIR

Si exploramos nuevas posibilidades de este proyecto, imaginemos datos de distintas fuentes.

 

Como se muestra en la imagen anterior, el recurso FHIR, que consume la API REST, se puede utilizar con un FHIRaaS.

Y no solo es posible utilizar FHIRaaS en AWS, sino que además podemos aprovechar el nuevo servicio de HealthShare Message Transformation Services, que automatiza la conversión de HL7v2 a FHIR® para ingresar datos en Amazon HealthLake, donde podrás extraer más valor para tus datos.

Con estas sencillas demostraciones, creo que estos recursos pueden utilizarse muy bien en escenarios más grandes, permitiendo implementaciones más sencillas en entornos de producción verdaderamente novedosos, como el de AWS Healthlake. ¿Por qué no? 😃 

0
0 108
Anuncio Esther Sanchez · nov 11, 2021

¡Hola desarrolladores!

Os invitamos a participar en el Hackathon Europeo de Salud 2021 que tendrá lugar del 19 al 21 de noviembre de 2021. La participación es gratuita y la fecha límite para aplicaciones que compitan en el modo ON-LINE es el 15 de noviembre.

Tendremos un reto de InterSystems allí: "Innova con FHIR". Los premios del reto serán:

🥇1er puesto: 1500 EUR
🥈2º puesto: 1000 EUR
🥉3er puesto: 500 EUR

¡Y todos los participantes de nuestro reto tendrán un premio!
Más abajo puedes consultar todos los detalles sobre nuestro reto. ¿Participarás? ¡Cuéntanoslo respondiendo a la encuesta!

 

0
0 79
Artículo Ariel Arias · nov 8, 2021 8m read

MODELO RESUMIDO {#1}

Siguiendo el ejemplo disponible en GitHub FHIR IntegratedML vamos usar el modelo resumido para entrenar el modelo de predicción de "No Asistirá" (NotShow).

Haremos un match entre los campos de la tabla PackageSample.NoShowMLRow y los campos de TrakCare. El punto de partida en TrakCare será la tabla SQLUser.RB_Appointment.

CAMPOTRAKCAREOBSERVACIONES
GenderAPPT_PAPMI_DR->PAPMI_Sex_DR->CTSEX_GenderSe espera valores "F" y "M"
ScheduledWeekDay{fn DAYOFWEEK(APPT_DateComp) }Días de la semana Domingo (1) a Sábado (7)
ScheduledWeek{fn WEEK(APPT_DateComp)}El número de la semana (1 a 52)
WaitingDaysDATEDIFF('dd',APPT_BookedDate, APPT_DateComp)Días entre el agendamiento y la fecha del compromiso)
AgeDATEDIFF('YY',APPT_PAPMI_DR->PAPMI_PAPER_DR->PAPER_DOB,APPT_DateComp)Edad del paciente (en años) al día de la cita.
HypertensionCIE10: (I10-I15) Enfermedades hipertensivas
DiabetesCIE10: (E10-E14) Diabetes mellitus
AlcoholismCIE10: (F10) Trastornos mentales y de comportamiento debidos al consumo de alcohol
HandicapCIE10: (Z73.6) Problemas relacionados con la limitación de las actividades debido a discapacidad
SMSreceivedAPPT_ConfirmationSi no tenemos sistema de envío de mensajes, usaremos el campo "Confirmado"
NoshowAPPT_StatusUsaremos el estado de cita para saber si el paciente fue atendido o se presentó al menos al compromiso

Preparamos la consulta para traer los datos de las citas {#2}

Para traer los datos desde TrakCare, vamos a preparar la consulta, y teniendo en cuenta los campos que se requieren, la query quedaría así:

Select
APPT_PAPMI_DR->PAPMI_PAPER_DR PatientID,
APPT_RowId ApptID,
APPT_DateComp ApptDate,
APPT_PAPMI_DR->PAPMI_Sex_DR->CTSEX_Gender Gender,
{fn DAYOFWEEK(APPT_DateComp)} ScheduledWeekDay,
{fn WEEK(APPT_DateComp)} ScheduledWeek,
DATEDIFF('dd',APPT_BookedDate, APPT_DateComp) WaitingDays,
DATEDIFF('YY',APPT_PAPMI_DR->PAPMI_PAPER_DR->PAPER_DOB,APPT_DateComp) Age,
CASE APPT_Confirmation
WHEN 'Y' THEN 1
ELSE 0
END SMSreceived,
CASE APPT_Status
WHEN 'P' THEN 1
WHEN 'A' THEN 0
WHEN 'X' THEN 0
WHEN 'I' THEN 0
WHEN 'N' THEN 1
WHEN 'T' THEN 0
WHEN 'H' THEN 0
WHEN 'C' THEN 0
WHEN 'S' THEN 0
WHEN 'D' THEN 0
ELSE APPT_Status
END Noshow
from RB_Appointment

Se puede modificar para traer todos los registros o filtrar por ejemplo el año en curso (dejar al menos fuera las citas futuras, pues estas servirán posteriormente, una vez entrenado el modelo para predecir el comportamiento de citas futuras. Se puede igualmente filtrar por establecimiento (APPT_AS_ParRef->AS_RES_ParRef->RES_CTLOC_DR->CTLOC_HOSPITAL_DR) pues es posible que el comportamiento sea diferente dependiendo esta variable (por cercanía al centro de atención por ejemplo).

Nota: Considerar si excluir del análsis citas canceladas (X) u otros estados como Transferido (T) pues son citas que se mostrarán como "NoShow" pero no se puede atribuir eso a un comportamiento del paciente necesariamente. Para este ejemplo se han considerado, pero a valor "0", es decir NoShow = False.

import pandas as pd
import jaydebeapi as jdbc
import time
import pyodbc as odbc
import irisnative

Función Diagnósticos {#3}

Tendremos funciones para determinar si el paciente está diagnosticado con Huipertensión, Diabetes, Alcoholismo o alguna restricción física (invalidez).

La función recibirá un arreglo con los diagnósticos del paciente al momento de la cita (filtrados por fecha) para retornar un 0 (False) o un 1 (True). Basta con que uno de los diagnósticos sea HTA para saber que el paciente en ese momento es hipertenso.

def is_hta (dxlist):
    ishta = 0
    htalist = ('I10', 'I11','I12', 'I13', 'I14', 'I15')
    for i in dxlist:
        if i in htalist:
            ishta = 1
    return ishta

def is_dbt (dxlist):
    isdbt = 0
    dbtlist = ('E10', 'E11','E12', 'E13', 'I14')
    for i in dxlist:
        if i in dbtlist:
            isdbt = 1
    return isdbt

def is_disabilited (dxlist):
    isdisabilited = 0
    disabilitedlist = ('Z73.6','1')
    for i in dxlist:
        if i in disabilitedlist:
            isdisabilited = 1
    return isdisabilited

def is_alcoholism (dxlist):
    isalcoholism = 0
    alcoholismlist = ('F10','1')
    for i in dxlist:
        if i in alcoholismlist:
            isalcoholism = 1
    return isalcoholism

def listdxbypatid (patid):
listadxsql = ()
if patid:
    idpaciente = patid
    sqlpatdx = """
    select %nolock
    MR_DIAGNOS.MRDIA_ICDCode_DR->MRCID_Code,
    MR_DIAGNOS.MRDIA_DATE
    from    SQLUser.MR_ADM, SQLUser.MR_DIAGNOS
    where   MR_ADM.MRADM_RowId IN (SELECT PAADM_MainMRADM_DR
    FROM  PA_Adm
    WHERE PAADM_PAPMI_DR = """ + str(idpaciente) + """ )
    and MR_ADM.MRADM_RowId = MR_DIAGNOS.MRDIA_MRADM_ParRef
    """
    listadxsql = pd.read_sql(sqlpatdx, conn)
return listadxsql

Preparar la Conexión {#4}

Preparamos la conexión utilizando la librería jaydebeapi y el conector que corresponde al ambiente a utilizar. En este caso, se trata de un ambiente sobre HealthShare, por lo que usaremos el JDBC de Cache.

# Establecemos nuestras variables de conexión (host, port, namespace)
envhost = "localhost"
envport = 1983
envns = "TRAK"

dbuser = "superuser"
dbaccess = "SYS"

url = "jdbc:Cache://" + envhost + ":" + str(envport) + "/" + envns
driver = 'com.intersys.jdbc.CacheDriver'
irisdriver = 'com.intersystems.jdbc.IRISDriver'

user = dbuser
password = dbaccess
# Para este ejemplo, el jar para Cache se encuentra bajo la carpeta "resources"
# ruta relativa a la ubicación de este notebook
#jarfile = "resources/cachejdbc.jar"
jarfile = "/Users/ArielArias/cachejdbc.jar"
conn = jdbc.connect(driver, url, [user, password], jarfile)
curs = conn.cursor()

Asignamos la consulta en una variable, para poder modificar posteriormente si es necesario. De esta forma además podemos utilizar asignación en múltiples líneas para tener una mejor vosión de lo que estamos extrayendo desde TrakCare.

sql_str = """Select TOP 3500
APPT_PAPMI_DR->PAPMI_PAPER_DR PatientID,
APPT_RowId ApptID,
APPT_DateComp ApptDate,
APPT_PAPMI_DR->PAPMI_Sex_DR->CTSEX_Gender Gender,
{fn DAYOFWEEK(APPT_DateComp)} ScheduledWeekDay,
{fn WEEK(APPT_DateComp)} ScheduledWeek,
DATEDIFF('dd',APPT_BookedDate, APPT_DateComp) WaitingDays,
DATEDIFF('YY',APPT_PAPMI_DR->PAPMI_PAPER_DR->PAPER_DOB,APPT_DateComp) Age,
CASE APPT_Confirmation
WHEN 'Y' THEN 1
ELSE 0
END SMSreceived,
CASE APPT_Status
WHEN 'P' THEN 1
WHEN 'A' THEN 0
WHEN 'X' THEN 0
WHEN 'I' THEN 0
WHEN 'N' THEN 1
WHEN 'T' THEN 0
WHEN 'H' THEN 0
WHEN 'C' THEN 0
WHEN 'S' THEN 0
WHEN 'D' THEN 0
ELSE APPT_Status
END Noshow
from RB_Appointment
Where 
APPT_DateComp BETWEEN to_date('01/01/2021','dd/mm/yyyy') AND NOW()
AND APPT_AS_ParRef->AS_RES_ParRef->RES_CTLOC_DR->CTLOC_HOSPITAL_DR IN (12129)"""

Ejecutar la consulta (DataFrame) {#5}

Utilizando la librerías pandas ejecutamos la consulta SQL y la dejamos en un DataFrame para posterior manipulación. Nos falta aún las columnas relacionadas a diagnósticos del paciente a la fecha de la cita (por ahora no consideraremos TODOS los diagnósticos del paciente, sólo los confirmados y que fueron ingresados previo a la fecha del compromiso.

start = time.time()
data = pd.read_sql(sql_str, conn)
end = time.time()
elapsedtime = end - start

# Sólo para tener una referencia veremos el tiempo de ejecución de la consulta
# Esto ayudará a evaluar cuántos registros se puede procesar
# O planificar una ejecución por períodos de tiempo más reducidos
print("Tiempo de Ejecución SQL: ",int(elapsedtime), " Segundos")

# Agregamos las columnas de Dx;  con valores negativos por ahora
data["Hypertension"] = 0
data["Diabetes"] = 0
data["Alcoholism"] = 0
data["Handicap"] = 0

# Verificamos nuestro dataframe
data.head()
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
</style>
PatientIDApptIDApptDateGenderScheduledWeekDayScheduledWeekWaitingDaysAgeSMSreceivedNoshowHypertensionDiabetesAlcoholismHandicap
059820511683||11250||12021-01-21F54027000000
159820511683||11804||12021-01-28F55127010000
259820511683||13466||12021-02-18F58027000000
359820511683||15128||12021-03-11F511027000000
459820511683||15682||12021-03-18F512027000000

Recorremos el Arreglo y traemos la lista de diagnósticos para cada paciente. Para optimizar el tiempo, verificamos si ya tenemos los diagnósticos del paciente teniendo una lista con los PatientID

start = time.time()
patient = []
## is_hta
## is_dbt
## is_disabilited
## is_alcoholism
for index, row in data.iterrows():
    if row['PatientID'] not in patient:
        patient.append(row['PatientID'])
        patappt = (row['ApptID'], row['PatientID'], row['ApptDate'])
        listpatdx = listdxbypatid(row['PatientID'])
    # Ya tenemos los diagnósticos del Paciente; 
    # ahora filtramos sólo los previos a la cita y los dejamos en una lista:
    if len(listpatdx):
        low_apptdate = listpatdx[listpatdx["MRDIA_Date"] <= patappt[2]]
        if len(low_apptdate):
            # Ahora necesitamos saber si el paciente "ES" o "ERA" Hipertenso para la fecha de la cita:
            diaghta = is_hta(low_apptdate.MRCID_Code)
            diagdbt = is_dbt(low_apptdate.MRCID_Code)
            diagdis = is_disabilited(low_apptdate.MRCID_Code)
            diagalcohol = is_alcoholism(low_apptdate.MRCID_Code)
        else:
            diaghta = 0
            diagdbt = 0
            diagdis = 0
    else:
        diaghta = 0
        diagdbt = 0
        diagdis = 0
    # Modificamos la información en la fila correspondiente
    # Sabemos que por ApptID habrá sólo un registro:
    data.loc[data.ApptID == row['ApptID'],'Hypertension'] = diaghta
    data.loc[data.ApptID == row['ApptID'],'Diabetes'] = diagdbt
    data.loc[data.ApptID == row['ApptID'],'Handicap'] = diagdis
    data.loc[data.ApptID == row['ApptID'],'Alcoholism'] = diagalcohol
    
end = time.time()

print(end - start)

Cerramos la conexión, de momento no la usaremos.

conn.close()

LLEVAR LOS REGISTROS A UNA INSTANCIA CON ML INTEGRADO {#6}

En este ejemplo, no podemos usar el mismo servidor pues en su versión no incluye la función de ML; así es que usaremos una instancia con IRIS for Health que incorpora ML.

Dado que la librería de python jaydebeapi soporta sólo un dirver conexión por ejecución, no podemos usar el mismo método pues habrá un error al intentar usarla para conectar IRIS (posterior a conectar Caché).

Para seguir con el ejemplo y no perder el DataFrame obtenido, vamos a crear una conexión a IRIS utilizando ODBC

Usaremos la misma instancia del ejemplo que hemos usado hasta ahora, es decir el NameSpace FHIRSERVER

dsn = 'IRIS FHIRML'
server = 'localhost' #IRIS server container or the docker machine's IP
port = '32782' # or 8091 if docker machine IP is used
database = 'FHIRSERVER'
username = 'SUPERUSER'
password = 'SYS'

irisconn = odbc.connect('DSN='+dsn+';')
irisconn.setencoding(encoding='utf-8')
iriscurs = irisconn.cursor()

modelName = "TrakNoShow"

fhirsql = """Select
Age, Alcoholism, Diabetes, 
Gender, Handicap, Hypertension, 
Noshow, SMSreceived, ScheduledWeek, 
ScheduledWeekDay, WaitingDays
FROM PackageSample.""" + modelName + "MLRow"

# Copiamos la tabla NoShowMLRow a nuestra TrakNoShowMLRow:
sqlcreate = "CREATE TABLE PackageSample." + modelName + "MLRow ("
sqlcreate = sqlcreate + "Gender CHAR(30)," 
sqlcreate = sqlcreate + "ScheduledWeekDay INT," 
sqlcreate = sqlcreate + "ScheduledWeek INT," 
sqlcreate = sqlcreate + "WaitingDays INT," 
sqlcreate = sqlcreate + "Age INT," 
sqlcreate = sqlcreate + "Hypertension BIT," 
sqlcreate = sqlcreate + "Diabetes BIT," 
sqlcreate = sqlcreate + "Alcoholism BIT," 
sqlcreate = sqlcreate + "Handicap BIT," 
sqlcreate = sqlcreate + "SMSreceived BIT," 
sqlcreate = sqlcreate + "Noshow BIT)" 

Ejecutamos la creción de la tabla:

iriscurs.execute(sqlcreate)
iriscurs.commit()

Inserción del DataFrame TrakCare {#7}

Para hacer una inserción directa de los datos, haremos una copia del DataFrame para eliminar luego algunas columnas que no usaremos de momento; esto sólo para hacer un INSERT más directo al momento de recorrer el DataFrame.

sqltest = "INSERT INTO PackageSample." + modelName + "MLRow"
sqltest = sqltest + " (Gender,ScheduledWeekDay,ScheduledWeek,WaitingDays,"
sqltest = sqltest + "Age,SMSreceived,Noshow,Hypertension,Diabetes,Alcoholism,Handicap) "
sqltest = sqltest + "values(?,?,?,?,?,?,?,?,?,?,?)"

for index, row in data.iterrows():
    params = [[row.Gender,row.ScheduledWeekDay,row.ScheduledWeek,row.WaitingDays,row.Age,row.SMSreceived,row.Noshow,row.Hypertension,row.Diabetes,row.Alcoholism,row.Handicap]]
    iriscurs.executemany(sqltest,params)

iriscurs.commit()

Preparación del Modelo {#8}

Para efecto de visualización, vamos a trabajar con variables para nombrar nuestro modelo, y definir con cuántos datos vamos a entrenar y cuántos vamos a utilizar para validar.

datasize = len(irisdata)
modelName = "TrakNoShow"
predictingCol = "Noshow"
# si requiere reiniciar el modelo, se elimina las tablas creadas:
sqldropcross = "DROP TABLE PackageSample." + modelName + "MLRowCrossValidation"
sqldroptest = "DROP TABLE PackageSample." + modelName + "MLRowTest"
sqldroptrain = "DROP TABLE PackageSample." + modelName + "MLRowTraining"
sqldropval = "DROP TABLE PackageSample." + modelName + "MLRowValidation"
sqldropmodel = "DROP MODEL " + modelName + "Model"

# definimos con qué porcentaje de los datos realizaremos el crossvalidation:
cvLen = int(datasize * 0.9)
# Y el resto para testing:
testLen = datasize - cvLen
# tamaño de los datos para entrenamiento:
trainLen = int(cvLen * 0.75)
validationLen = cvLen - trainLen
# Crearemos modelo con CrossValidation:
sqlcrossval = "CREATE TABLE PackageSample." + modelName + "MLRowCrossValidation AS "
sqlcrossval = sqlcrossval + "SELECT * FROM PackageSample." + modelName + "MLRow WHERE Id IN ("
sqlcrossval = sqlcrossval + "SELECT TOP " + str(cvLen) + " idx "
sqlcrossval = sqlcrossval + "FROM community.randrange(1, " + str(datasize+1)  + ") "
sqlcrossval = sqlcrossval + "ORDER BY randValue)"

# Creamos la tabla para pruebas del modelo
sqltest = "CREATE TABLE PackageSample." + modelName + "MLRowTest AS "
sqltest = sqltest + "SELECT TOP " + str(testLen) + " * FROM PackageSample." + modelName + "MLRow WHERE Id NOT IN ("
sqltest = sqltest + "SELECT Id FROM PackageSample." + modelName + "MLRowCrossValidation)"

# Creamos tabla para entrenamiento:
sqltrain = "CREATE TABLE PackageSample." + modelName + "MLRowTraining AS "
sqltrain = sqltrain + "SELECT * FROM PackageSample." + modelName + "MLRowCrossValidation WHERE Id IN ("
sqltrain = sqltrain + "SELECT TOP " + str(trainLen) + " idx "
sqltrain = sqltrain + "FROM community.randrange(1, " + str(datasize+1) + ") "
sqltrain = sqltrain + "ORDER BY randValue)"

# Tabla para validación:
sqlval = "CREATE TABLE PackageSample." + modelName + "MLRowValidation AS "
sqlval = sqlval + "SELECT TOP " + str(validationLen) + " * "
sqlval = sqlval + "FROM PackageSample." + modelName + "MLRowCrossValidation "
sqlval = sqlval + "WHERE Id NOT IN ("
sqlval = sqlval + "SELECT Id FROM PackageSample." + modelName + "MLRowTraining)"

# Para creación del modelo:
sqlcreatemodel = "CREATE MODEL "+ modelName + "Model PREDICTING (" + predictingCol + ") "
sqlcreatemodel = sqlcreatemodel + "FROM PackageSample." + modelName + "MLRowTraining"

# Para entrenar modelo:
sqltrainmodel = 'TRAIN MODEL ' + modelName + 'Model USING {"seed": 1}'

# Para validar modelo:
sqlvalmodel = "VALIDATE MODEL " + modelName + "Model FROM PackageSample." + modelName + "MLRowValidation"

Podemos ejecutar una a una las sentencias desde nuestro notebook para crear el modelo, y luego entrenarlo.

# Creamos tabla CrossValidation:
iriscurs.execute(sqlcrossval)
iriscurs.commit()

# Creamos tabla Test:
iriscurs.execute(sqltest)
iriscurs.commit()

# Creamos tabla para entrenamiento:
iriscurs.execute(sqltrain)
iriscurs.commit()

# Creamos tabla para validacion:
iriscurs.execute(sqlval)
iriscurs.commit()

# Creamos el modelo:
iriscurs.execute(sqlcreatemodel)
iriscurs.commit()

# Entrenamos el modelo:
iriscurs.execute(sqltrainmodel)
iriscurs.commit()

# Validamos el modelo:
iriscurs.execute(sqlvalmodel)
iriscurs.commit()

Entrenado el modelo, podemos utilizarlo para conocer la predicción, ya sea que enviamos datos desde otro origen o podemos utilizar consultas directamente sobre el modelo. Un ejemplo:

# TrakNoShowModel
# Probar consultas hacia el modelo:

sqlpredict = "SELECT top 10 PREDICT(TrakNoShowModel) AS PredictedNoshow, Noshow AS ActualNoshow FROM PackageSample.TrakNoShowMLRowTest"

predictdata = pd.read_sql(sqlpredict, irisconn)
predictdata
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
</style>
PredictedNoshowActualNoshow
0FalseFalse
1TrueTrue
2FalseFalse
3FalseFalse
4FalseFalse
5FalseFalse
6FalseFalse
7FalseFalse
8FalseFalse
9TrueFalse

ALGUNOS PROBLEMAS ENCONTRADOS {#9}

Durante la preparación de este documento se debió ajustar algunos parámetros y consultas para poder terminarlo. Se detalla a continuación para posible solución al replicar los pasos en otro ambiente:

  • Se ajustó la conexión a IRIS para forzar utilización de encoding UTF8; al no hacerlo, se detectó que el campo "Gender" quedaba vacío.
  • Problema de Performance al consultar los diagnósticos del paciente de forma iterativa; por eso se ajustó la consulta para traer todos los diagnósticos del paciente con fecha de ingreso, y luego con Python filtrar según fecha de la cita.
  • jaydebeapi soporta una conexión por ejecución; por esto se trabajó la conexión a TrakCare (sobre Caché) con esta librería y se utilizó pyodbc para conectar IRIS. Se puede hacer lo contrario, ODBC para Caché y JDBC para IRIS.

TO DO {#10}

Algunas mejoras a la aplicación de este ejemplo, y que pueden estar disponible en nuevos post:

  1. Se puede trabajar estos mismos pasos, direcamente desde IRIS, aprovechando aún más sus propiedades y facilidad para acceder a los datos. Se hizo como notebook sólo para ejemplificar que se puede traer varios origenes de datos a IRIS para crear un modelo de Machine Learning, entrenarlo, y validarlo.

  2. Tener estos pasos en una clase de IRIS, permitirá además operativizar el modelo, por medio de webservice como el ejemplo disponible en readmision demo

  3. Contar con una carga programada desde el origen que permita incluso actualizar datos, por ejemplo, del estado de cita. Esto permitirá por ejemplo, construir un cubo y posterior cuadro de mando que permita identificar a los pacientes con alta posibilidad de no asistir para reforzar el contacto.

0
2 149
Artículo Ricardo Paiva · nov 4, 2021 5m read

En este artículo describiré los procesos para ejecutar pruebas unitarias mediante ObjectScript Package Manager (consulta https://openexchange.intersystems.com/package/ObjectScript-Package-Manager-2), incluyendo el cálculo de la Cobertura de pruebas (mediante https://openexchange.intersystems.com/package/Test-Coverage-Tool).

Pruebas unitarias en ObjectScript

Ya hay mucha documentación sobre cómo escribir pruebas unitarias en ObjectScript, por lo que no repetiré nada de eso. Puedes consultar el Tutorial de Pruebas Unitarias aquí: https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=TUNT_preface

La práctica recomendada es incluir las pruebas Unitarias en algún lugar/carpeta separada en la estructura de fuentes, ya sea simplemente "/pruebas" o algo más sofisticado. Dentro de InterSystems, terminamos usando /internal/testing/unit_tests/ como nuestro estándar de facto, lo que tiene sentido porque las pruebas son internas/no distribuibles y hay otros tipos de pruebas además de las unitarias, pero esto podría ser un poco complejo para proyectos sencillos de código abierto. Puedes ver esta estructura en algunos de nuestros repositorios de GitHub.

Desde el punto de vista del flujo de trabajo, esto es súper fácil en VSCode: solo hay que crear el directorio y colocar las clases allí. Con enfoques más antiguos centrados en el servidor para el control de la fuente (los utilizados en Studio), tendrás que mapear este paquete de manera apropiada, y el enfoque para eso varía según la extensión del control de la fuente.

Desde la perspectiva de los nombres de clases para las pruebas unitarias, mi preferencia personal (y la práctica recomendada de mi grupo) es:

UnitTest.<package/class being tested>[.<method/feature being tested>]

Por ejemplo, si las pruebas unitarias son para el Método Foo en la clase MyApplication.SomeClass, la clase de la prueba unitaria se llamaría UnitTest.MyApplication.SomeClass.Foo; si las pruebas fueran para la clase en su totalidad, simplemente sería UnitTest.MyApplication.SomeClass.

Pruebas unitarias en ObjectScript Package Manager

¡Hacer que ObjectScript Package Manager esté informado de tus pruebas unitarias es sencillo! Basta con añadir una línea como la siguiente a module.xml (tomada de https://github.com/timleavitt/ObjectScript-Math/blob/master/module.xml, una bifurcación del excelente paquete matemático de @Peter Steiwer de Open Exchange, el cual utilizo como un simple ejemplo inspirador):

&lt;Module>&lt;br>  ...&lt;br>  &lt;UnitTest Name="tests" Package="UnitTest.Math" Phase="test"/>&lt;br>&lt;/Module>

Lo que todo esto significa es:

  • Las pruebas unitarias están en el directorio "tests" debajo de la raíz del módulo.
  • Las pruebas unitarias están en el paquete "UnitTest.Math". Esto tiene sentido, porque las clases que se están probando están en el paquete "Math".
  • Las pruebas unitarias se ejecutan en la fase "test" en el ciclo de vida del paquete. (También hay una fase de "verificación" en la que podrían ejecutarse, pero esa es una historia para otro día).

Cómo ejecutar pruebas unitarias

Con las pruebas unitarias definidas como se explicó anteriormente, el administrador de paquetes ofrece algunas herramientas realmente útiles para ejecutarlas. Todavía puedes configurar ^UnitTestRoot, como lo harías normalmente con %UnitTest.Manager, pero probablemente encontrarás las siguientes opciones mucho más fáciles, especialmente si estás trabajando en varios proyectos en el mismo entorno.

Puedes probar todos estas opciones clonando el repositorio objectscript-math enumerado anteriormente y luego cargarlo con zpm "load /path/to/cloned/repo/", o en tu propio paquete reemplazando "objectscript-math" con los nombres de tus paquetes (y nombres de prueba).

Para recargar el módulo y luego ejecutar todas las pruebas unitarias:

zpm "objectscript-math test"

Para simplemente ejecutar las pruebas unitarias (sin recargar):

zpm "objectscript-math test -only"

Para simplemente ejecutar las pruebas unitarias (sin recargar) y proporcionar una salida detallada:

zpm "objectscript-math test -only -verbose"

Para ejecutar un conjunto de pruebas en particular (es decir, un directorio de pruebas, en este caso, todas las pruebas en UnitTest/Math/Utils) sin recargar, y proporcionar una salida detallada:

zpm "objectscript-math test -only -verbose -DUnitTest.Suite=UnitTest.Math.Utils"

Para ejecutar un caso particular de prueba (en este caso, UnitTest.Math.Utils.TestValidateRange) sin recargar y proporcionar una salida detallada:

zpm "objectscript-math test -only -verbose -DUnitTest.Case=UnitTest.Math.Utils.TestValidateRange"

O, si solo estás resolviendo los problemas de un único método de prueba:

zpm "objectscript-math test -only -verbose -DUnitTest.Case=UnitTest.Math.Utils.TestValidateRange -DUnitTest.Method=TestpValueNull"

Cálculo de la Cobertura de pruebas mediante ObjectScript Package Manager

Así que tienes algunas pruebas unitarias, pero ¿son buenas? Calcular la cobertura de pruebas no responderá completamente a esa pregunta, pero al menos ayuda. Presenté esto en la Convención anual (Global Summit) de InterSystems, allá por el año 2018 - aquí puedes ver el vídeo: https://youtu.be/nUSeGHwN5pc .

Lo primero que tendrás que hacer es instalar el paquete de cobertura de pruebas:

zpm "install testcoverage"

Ten en cuenta que esto no requiere la instalación/ejecución de ObjectScript Package Manager; puedes encontrar más información en Open Exchange: https://openexchange.intersystems.com/package/Test-Coverage-Tool

Dicho esto, puedes aprovechar al máximo la herramienta de cobertura de pruebas si también utilizas ObjectScript Package Manager.

Antes de ejecutar pruebas, debes especificar qué clases/rutinas esperas que cubran tus pruebas. Esto es importante porque, en las bases de código muy grandes (por ejemplo, HealthShare), calcular y recopilar la Cobertura de pruebas para todos los archivos del proyecto puede requerir más memoria de la que tiene tu sistema. (Específicamente, gmheap para un análisis por linea de código, si tienes curiosidad).

La lista de archivos se incluye en un archivo llamado cover.list, que está dentro de la raíz de la prueba unitaria. Diferentes subdirectorios (conjuntos) de pruebas unitarias pueden tener su propia copia de esto para anular las clases/rutinas que se rastrearán mientras se ejecuta el conjunto de pruebas.

Para ver un ejemplo sencillo con objectscript-math, consulta: https://github.com/timleavitt/ObjectScript-Math/blob/master/tests/UnitTest/coverage.list. La guía de usuario para la Herramienta de cobertura de pruebas incluye más detalles.

Para ejecutar las pruebas unitarias con el cálculo de la Cobertura de pruebas habilitado, solo hay que añadir un argumento más al comando, especificando que se debe utilizar TestCoverage.Manager en vez de %UnitTest.Manager para ejecutar las pruebas:

zpm "objectscript-math test -only -DUnitTest.ManagerClass=TestCoverage.Manager"
 
La salida (incluso en el modo resumido) incluirá una URL donde podrás ver qué líneas de tus clases/rutinas estaban cubiertas por las pruebas unitarias, así como algunas estadísticas agregadas.

Siguientes pasos

¿Qué sucede con la automatización de todo esto en CI? ¿Qué sucede con los reportes de resultados de las pruebas unitarias y las puntuaciones/diffs de cobertura? ¡También puedes hacer eso! Para ver un ejemplo sencillo usando Docker, Travis CI y codecov.io, consulta https://github.com/timleavitt/ObjectScript-Math. Estoy planeando escribir esto en un artículo futuro que analice algunos enfoques diferentes.

0
0 133
Artículo Alberto Fuentes · nov 4, 2021 2m read

Algunos de vosotros no conoceréis esta limitación o problema conocido que se produce en los Procesos de Negocio (Business Processes) basados en BPL.

Aquellos que no estabais al tanto quizá os habéis encontrado esto:

ERROR <Ens>ErrBPTerminated: Terminating BP <my_process_name> # due to error:

ERROR #7201: Datatype value 'xxS6xxS6...xxS6' length longer than MAXLEN allowed of 5

Y / o:

ERROR #5802: Datatype validation failed on property '<my_process_class>.Thread1:%HandlerStack', with value equal to "xxS6xxS6...xxS6"

Esta es la información que encontramos en la documentación al respecto:

Restricción de la actividad «Scope» dentro de un bucle en BPL

Bajo ciertas condiciones, los bucles que contienen actividades «Scope» (Ámbito) y tienen un gran número de repeticiones, pueden provocar un error. Si es posible, define la actividad «Scope» para que incluya el bucle en vez de que se defina dentro del bucle.

Así que si tienes un bucle dentro de un BPL, e introduces un «Scope» (Ámbito) en él (y probablemente una actividad «Continue»), y tienes, por ejemplo, unas 15 o más iteraciones, se producirá el error anterior.

Este es un ejemplo de este tipo de bucles:

Así es como se vería el error:

La solución, como se menciona en la documentación, es colocar el bucle dentro de la actividad «Scope», en vez de que el «Scope» esté dentro del bucle.

Espero que esto ayude a cualquiera que se encuentre con este error.

0
0 106
Anuncio Jose-Tomas Salvador · oct 27, 2021

Nos han comentado que la licencia incluida en las versiones Community Edition de InterSystems IRIS e IRIS for Health 2021.1 se ha establecido incorrectamente con fecha de expiracíón: Octubre 30, 2021.  

Por favor, estad atentos a este espacio porque en breve vamos a desplegar un nuevo build para corregir este tema. Actualizaremos este post en cuanto esté disponible.

No hay impacto en ninguna  versión de producción (la Community Edition es sólo para desarrollo), pero quería alertar a los desarrolladores lo antes posible.

Disculpas de antemano por cualquier molestia que esto pueda causar. 

2
0 161
Pregunta Mathew Lambert · oct 22, 2021

Tenemos un escenario bastante complejo pero creo que es sencillo de explicar y que quede claro.

Estamos desarrollando un ejecutador de tareas que corre en un servidor con una timezone indiferente.

Las tareas se tienen que ejecutar cada dia pero a una hora definida para una cierta timezone

Guardamos en base de datos la hora a la que queremos ejecutar la tarea y de que timezone es (no vayas al pozo de guardar en UTC, ya que cuando tengas DST será a horas distintas)

Lo que queremos es que cuando obtengamos nuestra tarea de la DB, convertir el 02:00 Europe/Madrid ya sea a UTC o a local (servidor)

2
0 104
InterSystems Official Mario Sanchez Macias · oct 29, 2021

InterSystems ha corregido un defecto que puede vulnerar la garantía de bloqueo de aplicación en un cluster distribuido de cache (configuración ECP), lo que puede provocar problemas de integridad de aplicación. Este defecto afecta a:

  • Todas las versiones principales y versiones de mantenimiento de InterSystems IRIS e InterSystems IRIS for Health, desde 2020.1.0
0
0 117
Artículo Ricardo Paiva · oct 22, 2021 3m read

Hola Comunidad,

Quiero compartir mi experiencia creando el portal iris-fhir con FHIR.  

Decidí dar un paso adelante y participar en el concurso IRIS for Health FHIR, pero nunca antes había trabajado con FHIR.

Después del webinar para el lanzamiento del concurso sobre FHIR , en el que nos explicaron de forma general cómo funciona IRIS for Health con FHIR, comencé a buscar en la documentación de FHIR para crear mi proyecto de Registro de pacientes.

En la página web de HL7 FHIR (versión 4), encontré un "mapa de recursos":

El principal recurso de FHIR para mi Registro de pacientes es el "Recurso para Pacientes".

Tomada como ejemplo la documentación de Recurso para Pacientes, ofrece al usuario toda la información que proporciona el Paquete de Recursos para Pacientes, y eso fue genial para descubrir cada pieza de información que tenía en mis manos: 

https://www.hl7.org/fhir/patient.html

La información proporcionada por mi Registro de Pacientes es la siguiente: 

  • Lista de pacientes
  • Detalles del paciente 
  • Alergia
  • Signos vitales
  • Laboratorio 
  • Vacunas

Para obtener la información que necesitaba, utilicé 4 recursos de FHIR: 

Como se informa en la documentación, el Recurso para Pacientes está en el nivel 3 y se describe como "Linking to real-world concepts in the healthcare system" - "Vinculación con conceptos del mundo real en el sistema de salud".

Los otros tres los encontré en el siguiente nivel 4. La descripción de este nivel es "Record-keeping and Data Exchange for the healthcare process" - "Mantenimiento de registros e intercambio de datos para el proceso sanitario": 

Para Paciente, Alergia y Vacuna, contamos con recursos específicos para cada uno de ellos. Pero para Signos Vitales y Laboratorio, todos están dentro de Observación. ¿Cómo podemos gestionar eso?

Usando fhir.js, como se muestra en la plantilla creada por @Guillaume Rongier, es bastante sencillo.

Para ilustrar esta búsqueda en un Recurso FHIR, pongo este fragmento de código para mostrar cómo obtuve la información de los signos vitales dentro del Recurso de Observación.

&lt;tt>client.search({
    type: 'Observation',
    query: {
        patient: patientId,
        category: 'vital-signs',
        _sort: 'date'
    }
})&lt;/tt>

Lo conseguí utilizando el parámetro de categoría.

Todas las categorías dentro del Recurso de Observación se describen en  https://www.hl7.org/fhir/observation.html

  • Signos vitales como el peso corporal, la presión arterial y la temperatura
  • Datos de laboratorio como la glucosa en sangre o una estimación del Índice de filtración glomerular (GFR)
  • Resultados de imágenes como la densidad ósea o las dimensiones fetales
  • Hallazgos clínicos * como el dolor abdominal
  • Medidas obtenidas de dispositivos como datos de electrocardiograma (ECG o EKG) u oximetría de pulso
  • Herramientas de evaluación clínica como APGAR o la puntuación en la escala de coma de Glasgow
  • Características personales: como el color de los ojos
  • Antecedentes sociales como el consumo de tabaco, el respaldo familiar o el estado cognitivo
  • Características esenciales como el estado de embarazo, o una declaración de fallecimiento

Como hemos visto en este artículo, obtener información de los recursos de FHIR es bastante sencillo, y en gran parte gracias a la documentación tan detallada.

Espero que esto ayude a todos los desarrolladores que tienen los mismos problemas que yo cuando comencé a utilizar los recursos de FHIR.

¡Nos vemos en el próximo artículo!

0
0 376
Artículo Ricardo Paiva · sep 23, 2021 4m read

InterSystems SAM es una gran herramienta para monitorizar tus clústeres de InterSystems IRIS e InterSystems IRIS For Health en instalaciones físicas o en un entorno de nube. En este artículo se describe cómo puedes implementar un administrador de alertas personalizado. Actualmente esta es una función no documentada y muy probablemente desconocida de InterSystems SAM. Con futuras versiones probablemente será más fácil aprovechar este útil concepto.

Para ser breve, en este artículo solo mencionaré InterSystems IRIS, pero todo aplica a InterSystems IRIS e InterSystems IRIS For Health. 

InterSystems SAM es un clúster de cinco contenedores y cada uno de ellos desempeña una función específica. Estos son:

  • Grafana para crear paneles de control con los que visualizar las métricas del sistema que selecciones. Es decir, tanto las métricas que InterSystems IRIS proporciona con la configuración predeterminada, como tus propias métricas (de la aplicación).
  • Prometheus, una herramienta de monitorización nativa de la nube, que recopila datos de series temporales de las instancias de destino
  • Nginx como el servidor web
  • Alertmanager, que recopila las alertas de InterSystems IRIS y de Prometheus
  • SAM Manager, que es el núcleo del SAM. Es una instancia de InterSystems IRIS en la que se almacenan todos los datos métricos

InterSystems SAM activa dos diferentes clases de alertas.

Las alertas que se activan se muestran en el portal del SAM, pero ¿qué sucedería si quieres notificar a alguien responsable del clúster InterSystems IRIS monitorizado y quieres hacerlo a través de diferentes canales de comunicación como el correo electrónico o el SMS, para que pueda hacerse cargo del clúster y solucionar el problema? Ahí es donde entra en acción un administrador de alertas personalizado.  

En este artículo se describen los pasos necesarios para implementar tu propio administrador de alertas para tu instancia del SAM Manager. En este ejemplo, el administrador de alertas enviará un correo electrónico a una dirección de correo electrónico preconfigurada, junto con la información de la alerta. 

La clave aquí es que hay una clase abstracta "oculta" %SAM.AbstractAlertsHandler en la instancia del SAM Manager. Mira la referencia de la clase:

  Primero, tienes que extraer tu propio administrador de alertas de esta clase abstracta y después implementar el método de clase HandleAlerts. El método recibe una matriz JSON con los detalles de la alerta.

Así que en mi sencillo ejemplo, el administrador de alertas es una clase SAM.AlertHandler con subclases %SAM.AbstractAlertsHandler. La implementación del método HandleAlerts() es sencilla. Mira el código completo:

Delega el trabajo al método SendAlert. Asume que tienes una cuenta de correo electrónico de usuario, que puedes utilizar para las alertas. La contraseña del correo electrónico se almacena en la base de datos, pero la contraseña se encripta utilizando la función de InterSystems IRIS para el encriptado de "elementos de datos". Por lo tanto, tienes que crear una clave de encriptación en el SAM Manager y esta clave se debe cargar. De lo contrario, el administrador de alertas no podrá enviar el correo electrónico. Mi proveedor de correo electrónico requiere SSL/TLS para enviar el correo electrónico. He definido una configuración SSL ForMail en la instancia de SAM Manager. El resto del código es sencillo. Mira el código:

   

En el cuerpo del correo electrónico copia la matriz JSON que recibió con los detalles de la alerta y la envía a los destinatarios. 

Queda un problema pendiente. No puedes crear y editar directamente la clase de administrador de alertas en tu instancia del SAM Manager. La configuración predeterminada no permite conexiones desde tu IDE (IRIS Studio o VSCode) a la instancia del SAM Manager.

Para resolver esto he creado y editado la clase del administrador de alertas en mi instancia de InterSystems IRIS, y la he importado al namespace del SAM proveniente de mi instancia del SAM Manager. Otra opción sería modificar el archivo docker-compose para iniciar InterSystems SAM, pero no quería tocar este tema. 

Una vez que hayas cargado correctamente tu clase del administrador de alertas en tu instancia del InterSystems SAM Manager, el método HandleAlerts se ejecutará para cada alerta que se active en tu clúster de InterSystems IRIS monitorizado.

¡Espero que os resulte útil!

1
0 207
Artículo Muhammad Waseem · oct 20, 2021 2m read

En este artículo demostraré lo siguiente:

  • Cómo actualizar ReferencesRange (OBX: 7) contra ObservationIdentifier (OBX: 3.1) [TestCode] de la base de datos mediante la función de utilidad personalizada
  • Cómo actualizar Abnormal Flag (OBX: 8) contra ObservationIdentifier (OBX: 3.1) [TestCode] y ObservationValue (OBX: 5) [Resultado] desde la función de utilidad de base de datos
  • Mensaje de ruta basado en un Abnormal Flag (OBX: 8)
0
0 142
Anuncio Esther Sanchez · oct 19, 2021

¡Hola desarrolladores!

Os traemos un nuevo vídeo, ya disponible en el Canal de YouTube de la Comunidad de Desarrolladores en inglés.

Es la grabación de una de las ponencias realizadas en la Convención Anual de InterSystems del año pasado, así que el idioma del vídeo es el inglés. Pero recordad que podéis activar los subtítulos en inglés, por si os resulta más fácil entender el vídeo leyendo el texto.

En el vídeo, @Patrick Jamieson nos enseña cómo buscar recursos FHIR con una variedad de opciones de consulta:

⏯ Búsqueda de recursos FHIR (Virtual Summit 2020)

0
0 143
Artículo Muhammad Waseem · oct 5, 2021 2m read

Oí hablar del Banco de Mensajes (Message Bank) cuando comenzamos a rediseñar una producción de Health Connect para que se ejecutara en contenedores en la nube. Como habría varios contenedores de IRIS, se nos indicó que utilizáramos el Banco de Mensajes como un sitio único para ver los mensajes y registros de todos los contenedores.

¿Cómo funciona Message Bank?

Añadí la operación del Banco de Mensajes a nuestra Producción de Interoperabilidad. Envía automáticamente mensajes y registros de eventos al Banco de Mensajes.

0
0 118