0 Abonnés · 18 Publications

Java Database Connectivity (JDBC) est une interface de programmation d'applications (API) pour le langage de programmation Java, qui définit comment un client peut accéder à une base de données.

Il est actuellement possible de le télécharger à partir d'ici.

Article Sylvain Guilbaud · Juil 8, 2025 3m read

Si vous migrez d'Oracle vers InterSystems IRIS, comme beaucoup de mes clients, vous risquez de rencontrer des modèles SQL spécifiques à Oracle nécessitant une conversion.

Prenons l'exemple suivant:

SELECT (TO_DATE('2023-05-12','YYYY-MM-DD') - LEVEL + 1) AS gap_date
FROM dual
CONNECT BY LEVEL <= (TO_DATE('2023-05-12','YYYY-MM-DD') - TO_DATE('2023-05-02','YYYY-MM-DD') + 1);

Dans Oracle:

  • LEVEL est une pseudo-colonne utilisée dans les requêtes hiérarchiques (CONNECT BY). Elle commence à 1 et s'incrémente de 1.
  • CONNECT BY LEVEL <= (...) détermine le nombre de lignes à générer.
  • La différence entre les deux dates plus un donne 11, donc la requête génère 11 lignes, en comptant à rebours à partir du 12 mai 2023 jusqu'au 2 mai 2023.

Répartition du résultat:

LEVEL = 1  → 2023-05-12
LEVEL = 2  → 2023-05-11
...
LEVEL = 11 → 2023-05-02

La question est maintenant de savoir comment obtenir ce résultat dans InterSystems IRIS, qui ne prend pas en charge CONNECT BY?

Une solution consiste à implémenter une requête de type SQL à l'aide d'ObjectScript qui imite ce comportement. Vous trouverez ci-dessous un exemple de définition CREATE QUERY qui accepte une date de début STARTDATE et un nombre de jours DAYS, et renvoie la liste des dates par ordre descendant.


✅ InterSystems IRIS: mise en œuvre d'une requête de l'intervalle de date

CREATE QUERY GET_GAP_DATE(IN STARTDATE DATE, IN DAYS INT)
  RESULTS (GAP_DATE DATE)
  PROCEDURE
  LANGUAGE OBJECTSCRIPT

Execute(INOUT QHandle BINARY(255), IN STARTDATE DATE, IN DAYS INT) { SET QHandle("start") = STARTDATE SET QHandle("days") = DAYS SET QHandle("level") = 1 RETURN $$$OK }

Fetch(INOUT QHandle BINARY(255), INOUT Row %List, INOUT AtEnd INT) { IF (QHandle("level") > QHandle("days")) { SET Row = "" SET AtEnd = 1 } ELSE { SET Row = $ListBuild(QHandle("start") - QHandle("level") + 1) SET QHandle("level") = QHandle("level") + 1 } RETURN $$$OK }

Close(INOUT QHandle BINARY(255)) { KILL QHandle QUIT $$$OK }

Vous pouvez exécuter la commande CREATE QUERY Vous pouvez exécuter la commande CREATE QUERY ci-dessus dans le portail IRIS System Management, ou via un outil tel que DBeaver ou un éditeur Python/Jupyter Notebook utilisant JDBC/ODBC.


🧪 Exemple d'utilisation:

Pour générer le même résultat que la requête Oracle ci-dessus, utilisez:

SELECT * FROM GET_GAP_DATE(
  TO_DATE('2023-05-12', 'YYYY-MM-DD'),
  TO_DATE('2023-05-12', 'YYYY-MM-DD') - TO_DATE('2023-05-02', 'YYYY-MM-DD') + 1
);

Cela donnera le résultat suivant:

GAP_DATE
----------
2023-05-12
2023-05-11
...
2023-05-02
(11 rows)

🔁 Utilisation avancée: Jointure avec d'autres tables

Vous pouvez également utiliser cette requête comme sous-requête ou dans des jointures:

SELECT * 
FROM GET_GAP_DATE(TO_DATE('2023-05-12', 'YYYY-MM-DD'), 11) 
CROSS JOIN dual;

Cela vous permet d'intégrer des plages de dates dans des flux SQL plus importants.


J'espère que cela sera utile à tous ceux qui sont confrontés à des scénarios de migration d'Oracle vers IRIS ! Si vous avez mis au point des solutions alternatives ou si vous proposez des améliorations, n'hésitez pas à me faire part de vos commentaires.

0
0 31
Article Iryna Mykhailova · Fév 3, 2025 2m read

Bonjour ! J'ai étendu mon référentiel de démonstration, andreas5588/demo-dbs-iris, pour faciliter le test des fonctionnalités FOREIGN SERVER et FOREIGN TABLE dans IRIS.

Pour y parvenir, j'ai créé un espace de noms appelé FEDERATION. L'idée est la suivante :

  1. Configurez des connexions JDBC pour chaque espace de noms.
  2. Créez un FOREIGN SERVER dans l'espace de noms FEDERATION pour chaque connexion.
  3. Définissez une FOREIGN TABLE au moins pour une table basée sur chaque serveur étranger.

Le script :  demo-dbs-iris/src/sql/02_create_foreign_server.sql

0
0 30
Article Iryna Mykhailova · Oct 15, 2024 8m read

Problèmes de chaînes

J'utilise Python pour accéder aux bases de données IRIS avec JDBC (ou ODBC). Je veux récupérer les données dans pandas dataframe pour manipuler les données et créer des graphiques à partir de celles-ci. Lors de l'utilisation de JDBC, j'ai rencontré un problème avec la gestion des chaînes. Cet article est destiné à aider les personnes qui ont les mêmes problèmes. S'il existe un moyen plus simple de résoudre ce problème, faites-le moi savoir dans les commentaires !

J'utilise OSX, donc je ne sais pas à quel point mon problème est unique. J'utilise Jupyter Notebooks, mais le code serait généralement le même si vous utilisiez n'importe quel autre programme ou cadre en Python.

Le problème JDBC

Lorsque je récupère des données de la base de données, les descriptions de colonnes et toutes les données de type chaîne sont renvoyées en tant que données de type java.lang.String. Si vous imprimez une chaîne de données, elle se présentera sous la forme suivante : "(p,a,i,n,i,n,t,h,e,r,e,a,r)" au lieu de l'attendu "painintherear".

Ceci est probablement dû au fait que les chaînes de caractères de type java.lang.String se présentent sous la forme d'un itérable ou d'un tableau lorsqu'elles sont récupérées à l'aide de JDBC. Cela peut arriver si le pont Python-Java que vous utilisez (par exemple, JayDeBeApi, JDBC) ne convertit pas automatiquement java.lang.String en une chaîne Python en une seule étape.

La représentation de la chaîne str de Python, en revanche, dispose de la chaîne entière en tant qu'unité unique. Lorsque Python récupère une chaîne normale (par exemple via ODBC), elle n'est pas divisée en caractères individuels.

La solution JDBC

Pour résoudre ce problème, vous devez vous assurer que le type java.lang.String est correctement converti en type str de Python. Vous pouvez explicitement gérer cette conversion lors du traitement des données récupérées afin qu'elles ne soient pas interprétées comme un itérable ou une liste de caractères.

Il existe de nombreuses façons de manipuler les chaînes de caractères ; c'est ce que j'ai fait.

import pandas as pd

import pyodbc

import jaydebeapi
import jpype

def my_function(jdbc_used)

    # Un autre code pour créer la connexion se trouve ici

    cursor.execute(query_string)

    if jdbc_used:
        # Récupération des résultats, conversion des données java.lang.String en str Python
        # (java.lang.String est retourné comme suit : "(p,a,i,n,i,n,t,h,e,r,e,a,r)" Conversion en type str "painintherear"
        results = []
        for row in cursor.fetchall():

            converted_row = [str(item) if isinstance(item, jpype.java.lang.String) else item for item in row]

            results.append(converted_row)


        # Obtention des noms des colonnes et vérification qu'il s'agit bien de chaînes Python

        column_names = [str(col[0]) for col in cursor.description]


        # Création du cadre de données

        df = pd.DataFrame.from_records(results, columns=column_names)


        # Vérification des résultats

        print(df.head().to_string())


    else:

        # Je testais aussi ODBC
        # Dans le cas d'ensembles de résultats très volumineux, obtenez les résultats par blocs en utilisant cursor.fetchmany() ou fetchall()
        results = cursor.fetchall()
        # Obtention des noms des colonnes
        column_names = [column[0] for column in cursor.description]
        # Création du cadre de données
        df = pd.DataFrame.from_records(results, columns=column_names)

    # Faites des choses avec votre cadre de données

Le problème ODBC

Lors d'une connexion ODBC, les chaînes de caractères ne sont pas renvoyées ou sont S.O.

Si vous vous connectez à une base de données qui contient des données Unicode (par exemple, des noms dans des langues différentes) ou si votre application doit stocker ou récupérer des caractères qui ne sont pas ASCII, vous devez vous assurer que les données restent correctement encodées lorsqu'elles sont transmises entre la base de données et votre application Python.

La solution ODBC

Ce code garantit que les données de type chaîne sont encodées et décodées en utilisant UTF-8 lors de l'envoi et de la récupération de données dans la base de données. C'est particulièrement important lorsqu'il s'agit de caractères non ASCII ou d'assurer la compatibilité avec les données Unicode.

def create_connection(connection_string, password):
    connection = None

try:
        # print(f"Connecting to {connection_string}")
        connection = pyodbc.connect(connection_string + ";PWD=" + password)

        # Veiller à ce que les chaînes de caractères soient lues correctement
        connection.setdecoding(pyodbc.SQL_CHAR, encoding="utf8")
        connection.setdecoding(pyodbc.SQL_WCHAR, encoding="utf8")
        connection.setencoding(encoding="utf8")

    except pyodbc.Error as e:
        print(f"The error '{e}' occurred")

    return connection

connection.setdecoding(pyodbc.SQL_CHAR, encoding="utf8")

Désigné ci-dessus indique à pyodbc comment décoder les données de caractères de la base de données lors de la récupération des types SQL_CHAR (typiquement, les champs de caractères de longueur fixe).

connection.setdecoding(pyodbc.SQL_WCHAR, encoding="utf8")

Désigné ci-dessus définit le décodage pour SQL_WCHAR, les types de caractères larges (c'est-à-dire les chaînes Unicode, telles que NVARCHAR ou NCHAR dans SQL Server).

connection.setencoding(encoding="utf8")

Désigné ci-dessus garantit que toutes les chaînes ou données de caractères envoyées de Python à la base de données seront encodées en UTF-8, cela signifie que Python traduira son type str interne (qui est Unicode) en octets UTF-8 lors de la communication avec la base de données.


La mise en place de l'ensemble

Installation de JDBC

Installation de JAVA-utiliser dmg

https://www.oracle.com/middleeast/java/technologies/downloads/#jdk23-mac

Mise à jour du shell pour définir la version par défaut

$ /usr/libexec/java_home -V
Matching Java Virtual Machines (2):
    23 (arm64) "Oracle Corporation" - "Java SE 23" /Library/Java/JavaVirtualMachines/jdk-23.jdk/Contents/Home
    1.8.421.09 (arm64) "Oracle Corporation" - "Java" /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home
/Library/Java/JavaVirtualMachines/jdk-23.jdk/Contents/Home
$ echo $SHELL
/opt/homebrew/bin/bash
$ vi ~/.bash_profile

Ajoutez JAVA_HOME à votre chemin

export JAVA_HOME=$(/usr/libexec/java_home -v 23)
export PATH=$JAVA_HOME/bin:$PATH

Obtention du pilote JDBC

https://intersystems-community.github.io/iris-driver-distribution/

Placement du fichier jar quelque part... Je l'ai placé dans $HOME

$ ls $HOME/*.jar
/Users/myname/intersystems-jdbc-3.8.4.jar

Exemple de code

Cela suppose que vous avez configuré ODBC (un exemple à suivre un autre jour, le chien a mangé mes notes...).

Remarque : il s'agit d'un piratage de mon propre code réel. Notez les noms des variables.

import os

import datetime
from datetime import date, time, datetime, timedelta

import pandas as pd
import pyodbc

import jaydebeapi
import jpype

def jdbc_create_connection(jdbc_url, jdbc_username, jdbc_password):

    # Chemin d'accès au pilote JDBC
    jdbc_driver_path = '/Users/yourname/intersystems-jdbc-3.8.4.jar'

    # Il faut s'assurer que JAVA_HOME est défini 
    os.environ['JAVA_HOME']='/Library/Java/JavaVirtualMachines/jdk-23.jdk/Contents/Home'
    os.environ['CLASSPATH'] = jdbc_driver_path

    # Démarrage de la JVM (si elle n'est pas déjà en cours d'exécution)
    if not jpype.isJVMStarted():
        jpype.startJVM(jpype.getDefaultJVMPath(), classpath=[jdbc_driver_path])

    # Connexion aux bases de données:
    connection = None

    try:
        connection = jaydebeapi.connect("com.intersystems.jdbc.IRISDriver",
                                  jdbc_url,
                                  [jdbc_username, jdbc_password],
                                  jdbc_driver_path)
        print("Connection successful")
    except Exception as e:
        print(f"An error occurred: {e}")

    return connection


def odbc_create_connection(connection_string):
    connection = None

    try:
        # print(f"Connecting to {connection_string}")
        connection = pyodbc.connect(connection_string)

        # Veiller à ce que les chaînes de caractères soient lues correctement
        connection.setdecoding(pyodbc.SQL_CHAR, encoding="utf8")
        connection.setdecoding(pyodbc.SQL_WCHAR, encoding="utf8")
        connection.setencoding(encoding="utf8")

    except pyodbc.Error as e:
        print(f"The error '{e}' occurred")

    return connection

# Paramètres

odbc_driver = "InterSystems ODBC"
odbc_host = "your_host"
odbc_port = "51773"
odbc_namespace = "your_namespace"
odbc_username = "username"
odbc_password = "password"

jdbc_host = "your_host"
jdbc_port = "51773"
jdbc_namespace = "your_namespace"
jdbc_username = "username"
jdbc_password = "password"

# Création d'une connexion et des graphiques

jdbc_used = True

if jdbc_used:
    print("Using JDBC")
    jdbc_url = f"jdbc:IRIS://{jdbc_host}:{jdbc_port}/{jdbc_namespace}?useUnicode=true&characterEncoding=UTF-8"
    connection = jdbc_create_connection(jdbc_url, jdbc_username, jdbc_password)
else:
    print("Using ODBC")
    connection_string = f"Driver={odbc_driver};Host={odbc_host};Port={odbc_port};Database={odbc_namespace};UID={odbc_username};PWD={odbc_password}"
    connection = odbc_create_connection(connection_string)


if connection is None:
    print("Unable to connect to IRIS")
    exit()

cursor = connection.cursor()

site = "SAMPLE"
table_name = "your.TableNAME"

desired_columns = [
    "RunDate",
    "ActiveUsersCount",
    "EpisodeCountEmergency",
    "EpisodeCountInpatient",
    "EpisodeCountOutpatient",
    "EpisodeCountTotal",
    "AppointmentCount",
    "PrintCountTotal",
    "site",
]

# Construction de la partie de la requête relative à la sélection des colonnes
column_selection = ", ".join(desired_columns)

query_string = f"SELECT {column_selection} FROM {table_name} WHERE Site = '{site}'"

print(query_string)
cursor.execute(query_string)

if jdbc_used:
    # Récupération des résultats
    results = []
    for row in cursor.fetchall():
        converted_row = [str(item) if isinstance(item, jpype.java.lang.String) else item for item in row]
        results.append(converted_row)

    #  Il faut récupérer les noms des colonnes et s'assurer qu'il s'agit bien de chaînes Python (java.lang.String is returned "(p,a,i,n,i,n,t,h,e,a,r,s,e)" 
    column_names = [str(col[0]) for col in cursor.description]

    # Création du cadre de données
    df = pd.DataFrame.from_records(results, columns=column_names)
    print(df.head().to_string())
else:
    # Dans le cas d'ensembles de résultats très volumineux, obtenez les résultats par blocs en utilisant cursor.fetchmany() ou fetchall()
    results = cursor.fetchall()
    # Obtention des noms des colonnes
    column_names = [column[0] for column in cursor.description]
    # Création du cadre de données
    df = pd.DataFrame.from_records(results, columns=column_names)

    print(df.head().to_string())

# # Construction des graphiques pour un site
# cf.build_7_day_rolling_average_chart(site, cursor, jdbc_used)

cursor.close()
connection.close()

# Arrêt de la JVM (si vous l'avez démarrée)
# jpype.shutdownJVM()
0
0 74
Article Lorenzo Scalese · Août 27, 2024 5m read

 

Démarrage rapide des données SQL d'InterSystems Cloud dans Databricks

La mise en œuvre de Databricks en SQL d'InterSystems Cloud se compose de quatre parties.

  • Obtention du certificat et du pilote JDBC Driver pour InterSystems IRIS
  • Ajout d'un script d'initialisation et d'une bibliothèque externe à votre Cluster de calcul Databricks
  • Obtention de données
  • Placement des données

Téléchargement du certificat X.509/du pilote JDBC de Cloud SQL

Naviguez vers la page d'aperçu de votre déploiement, si vous n'avez pas activé de connexions externes, faites-le et téléchargez votre certificat et le pilote jdbc depuis la page d'aperçu.

 

J'ai utilisé intersystems-jdbc-3.8.4.jar et intersystems-jdbc-3.7.1.jar avec succès dans Databricks à partir de la distribution de pilotes Driver Distribution.

Script d'initialisation pour votre cluster Databricks

La façon la plus simple d'importer un ou plusieurs certificats CA personnalisés dans votre cluster Databricks est de créer un script d'initialisation qui ajoute la chaîne complète de certificats CA aux magasins de certificats par défaut SSL et Java de Linux, et définit la propriété REQUESTS_CA_BUNDLE. Collez le contenu du certificat X.509 que vous avez téléchargé dans le bloc supérieur du script suivant:

import_cloudsql_certficiate.sh
#!/bin/bash

cat << 'EOF' > /usr/local/share/ca-certificates/cloudsql.crt
-----BEGIN CERTIFICATE-----
<PASTE>
-----END CERTIFICATE-----
EOF

update-ca-certificates

PEM_FILE="/etc/ssl/certs/cloudsql.pem" PASSWORD="changeit" JAVA_HOME=$(readlink -f /usr/bin/java | sed "s:bin/java::") KEYSTORE="$JAVA_HOME/lib/security/cacerts" CERTS=$(grep 'END CERTIFICATE'$PEM_FILE| wc -l)

# Pour traiter plusieurs certificats avec keytool, vous devez extraire# chacun d'eux du fichier PEM et l'importer dans le KeyStore Java.for N in $(seq 0 $(($CERTS - 1))); do ALIAS="$(basename $PEM_FILE)-$N"echo"Adding to keystore with alias:$ALIAS" cat $PEM_FILE | awk "n==$N { print }; /END CERTIFICATE/ { n++ }" | keytool -noprompt -import -trustcacerts
-alias$ALIAS -keystore $KEYSTORE -storepass $PASSWORDdoneecho"export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt" >> /databricks/spark/conf/spark-env.sh echo"export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt" >> /databricks/spark/conf/spark-env.sh

Maintenant vous avez le script initial, téléchargez-le dans le catalogue Unity sur un Volume.

Une fois que le script est sur un volume, vous pouvez ajouter le script initial au cluster à partir du volume dans les propriétés avancées de votre cluster.


Ensuite, ajoutez le pilote/la bibliothèque intersystems jdbc au cluster...

...et démarrez ou redémarrez votre calcul.

Station Databricks - Entrée vers le Cloud SQL d'InterSystems IRIS

 

Créez un Notebook Python dans votre espace de travail, attachez-le à votre cluster et testez le glissement de données vers Databricks.  Sous le capot, Databricks va utiliser pySpark, si cela n'est pas immédiatement évident.

La construction du Dataframe Spark suivant est tout ce qu'il vous faut, vous pouvez récupérer vos informations de connexion à partir de la page d'aperçu comme auparavant.

df = (spark.read
  .format("jdbc")
  .option("url", "jdbc:IRIS://k8s-05868f04-a4909631-ac5e3e28ef-6d9f5cd5b3f7f100.elb.us-east-1.amazonaws.com:443/USER")
  .option("driver", "com.intersystems.jdbc.IRISDriver")
  .option("dbtable", "(SELECT name,category,review_point FROM SQLUser.scotch_reviews) AS temp_table;") 
  .option("user", "SQLAdmin")
  .option("password", "REDACTED")
  .option("driver", "com.intersystems.jdbc.IRISDriver")\
  .option("connection security level","10")\
  .option("sslConnection","true")\
  .load())

df.show()

Illustration de la production d'un dataframe à partir de données dans Cloud SQL... boom!

Station Databricks - Sortie du Cloud SQL d'InterSystems IRIS

 

Prenons maintenant ce que nous avons lu dans IRIS et écrivons-le avec Databricks. Si vous vous souvenez bien, nous n'avons lu que 3 champs dans notre cadre de données, nous allons donc les réécrire immédiatement et spécifier un mode "écraser".

df = (spark.read
  .format("jdbc")
  .option("url", "jdbc:IRIS://k8s-05868f04-a4909631-ac5e3e28ef-6d9f5cd5b3f7f100.elb.us-east-1.amazonaws.com:443/USER")
  .option("driver", "com.intersystems.jdbc.IRISDriver")
  .option("dbtable", "(SELECT TOP 3 name,category,review_point FROM SQLUser.scotch_reviews) AS temp_table;") 
  .option("user", "SQLAdmin")
  .option("password", "REDACTED")
  .option("driver", "com.intersystems.jdbc.IRISDriver")\
  .option("connection security level","10")\
  .option("sslConnection","true")\
  .load())

df.show()

mode = "overwrite" properties = { "user": "SQLAdmin", "password": "REDACTED", "driver": "com.intersystems.jdbc.IRISDriver", "sslConnection": "true", "connection security level": "10", }

df.write.jdbc(url="jdbc:IRIS://k8s-05868f04-a4909631-ac5e3e28ef-6d9f5cd5b3f7f100.elb.us-east-1.amazonaws.com:443/USER", table="databricks_scotch_reviews", mode=mode, properties=properties)

Exécution du Notebook

 
Illustration des données dans le Cloud SQL d'InterSystems!

Les points à prendre en considération

  • Par défaut, PySpark écrit les données en utilisant plusieurs tâches concurrentes, ce qui peut entraîner des écritures partielles si l'une des tâches échoue.
  • Pour garantir que l'opération d'écriture est atomique et cohérente, vous pouvez configurer PySpark de manière à ce que les données soient écrites à l'aide d'une seule tâche (c'est-à-dire en définissant le nombre de partitions à 1) ou utiliser une fonctionnalité spécifique à IRIS, telle que les transactions.
  • En outre, vous pouvez utiliser l'API DataFrame de PySpark pour effectuer des opérations de filtrage et d'agrégation avant de lire les données de la base de données, ce qui peut réduire la quantité de données à transférer sur le réseau.
0
0 44
Article Guillaume Rongier · Mai 20, 2024 11m read

En tant qu'ancien développeur de JAVA, j'ai toujours eu du mal à décider quelle base de données était la plus appropriée pour le projet à développer. L'un des principaux critères que j'utilisais était la performance, ainsi que les capacités de configuration de HA (haute disponibilité). Eh bien, il est maintenant temps de mettre IRIS à l'épreuve en ce qui concerne certaines bases de données les plus couramment utilisées, j'ai donc décidé de créer un petit projet Java basé sur SpringBoot qui se connecte via JDBC avec une base de données MySQL, avec une autre base de données PostgreSQL et enfin avec une base de données IRIS.

Nous allons profiter du fait de disposer d'images Docker de ces bases de données pour les utiliser dans notre projet et vous permettre de l'essayer vous-même sans avoir à procéder à une quelconque installation. Nous pouvons vérifier la configuration du docker dans notre fichier docker-compose.yml

version:"2.2"services:# mysql  mysql:    build:      context:mysql    container_name:mysql    restart:always    command:--default-authentication-plugin=mysql_native_password    environment:      MYSQL_ROOT_PASSWORD:SYS      MYSQL_USER:testuser      MYSQL_PASSWORD:testpassword      MYSQL_DATABASE:test    volumes:    -./mysql/sql/dump.sql:/docker-entrypoint-initdb.d/dump.sql    ports:      -3306:3306# postgres  postgres:    build:      context:postgres    container_name:postgres    restart:always    environment:      POSTGRES_USER:testuser      POSTGRES_PASSWORD:testpassword    volumes:    -./postgres/sql/dump.sql:/docker-entrypoint-initdb.d/dump.sql    ports:      -5432:5432  adminer:    container_name:adminer    image:adminer    restart:always    depends_on:      -mysql      -postgres    ports:      -8081:8080# iris  iris:    init:true    container_name:iris    build:      context:.      dockerfile:iris/Dockerfile    ports:      -52773:52773      -1972:1972    command:--check-capsfalse# tomcat  tomcat:    init:true    container_name:tomcat    build:      context:.      dockerfile:tomcat/Dockerfile    volumes:      -./tomcat/performance.war:/usr/local/tomcat/webapps/performance.war    ports:      -8080:8080

D'un coup d'œil rapide, nous constatons que nous utilisons les images suivantes :

  • IRIS: Instance de la Communauté IRIS à laquelle nous nous connecterons par JDBC.
  • Postgres: Image de base de données PostgreSQL sur le port 5432.
  • MySQL: Image de base de données MySQL sur le port 3306
  • Tomcat: Image Docker configurée avec un serveur d'application Apache Tomcat sur lequel nous allons déployer le fichier WAR de notre application.
  • Adminer: Administrateur de base de données qui nous permettra de consulter les bases de données Postgres et MySQL.

Comme vous pouvez le voir, nous avons configuré les ports de listening de manière à ce qu'ils soient également mappés sur notre ordinateur, et pas seulement au sein de Docker. Pour les bases de données, ce n'est pas nécessaire, car la connexion se fait dans les conteneurs Docker, donc si vous avez des problèmes avec les ports, vous pouvez supprimer la ligne de prots de votre fichier docker-compose.yml.

Chaque image de base de données exécute un pré-script qui créera les tables nécessaires aux tests de performance. Examinons l'un des fichiers dump.sql

CREATESCHEMAtest;

DROPTABLEIFEXISTS test.patient;

CREATETABLE test.country ( idINT PRIMARY KEY, nameVARCHAR(225) );

CREATETABLE test.city ( idINT PRIMARY KEY, nameVARCHAR(225), lastname VARCHAR(225), photo BYTEA, phone VARCHAR(14), address VARCHAR(225), country INT, CONSTRAINT fk_country FOREIGN KEY(country) REFERENCES test.country(id) );

CREATETABLE test.patient ( idINTGENERATEDBYDEFAULTASIDENTITY PRIMARY KEY, nameVARCHAR(225), lastname VARCHAR(225), photo BYTEA, phone VARCHAR(14), address VARCHAR(225), city INT, CONSTRAINT fk_city FOREIGN KEY(city) REFERENCES test.city(id) );

INSERTINTO test.country VALUES (1,'Spain'), (2,'France'), (3,'Portugal'), (4,'Germany');

INSERTINTO test.city VALUES (1,'Madrid',1), (2,'Valencia',1), (3,'Paris',2), (4,'Bordeaux',2), (5,'Lisbon',3), (6,'Porto',3), (7,'Berlin',4), (8,'Frankfurt',4);

Nous allons créer 3 tables pour nos tests: patient, ville et pqys, ces deux dernières vont avoir des données préchargées de villes et de pays.

Parfait, maintenant nous allons étudier comment établir les connexions avec la base de données.

Pour ce faire, nous avons créé notre projet Java à partir d'un projet Spring Boot préconfiguré disponible dans Visual Studio Code qui nous fournit la structure de base.

Ne vous inquiétez pas si vous ne comprenez pas immédiatement la structure du projet, le but n'est pas d'apprendre Java, mais nous allons tout de même expliquer un peu plus en détail les documents principaux.

MyDataSourceFactory.java

Cette classe Java permet d'ouvrir les connexions aux différentes bases de données.

PerformancerController.java

Contrôleur chargé de publier les endpoints que nous appellerons depuis Postman.

application.properties

Fichier de configuration avec les différentes connexions aux bases de données déployées dans notre Docker.

Comme vous pouvez le constater, les URL de connexion utilisent le nom du conteneur puisque, lorsqu'elles sont déployées dans un conteneur Tomcat, les bases de données ne seront accessibles par notre application Java qu'avec le nom du conteneur correspondant. Nous pouvons également vérifier la manière dont l'URL établit une connexion via JDBC à nos bases de données. Les bibliothèques Java utilisées dans le projet sont définies dans le fichier pom.xml.

Si vous modifiez le code source, il vous suffit d'exécuter la commande suivante :

mvn package

Cela va générer un fichier performance-0.0.1-SNAPSHOT.war, renommez-le en performance.war et déplacez-le dans le répertoire /tomcat, en remplaçant le fichier existant.

Puisque le projet est sur GitHub, il suffit de le cloner sur notre ordinateur depuis Visual Studio et d'exécuter les commandes suivantes dans le terminal:

docker-compose build
docker-compose up -d

Vérifions le portail Docker:

Génial! Les conteneurs Docker fonctionnent. Vérifions maintenant depuis notre Adminer et le portail de gestion IRIS que nos tables sont correctement créées.

 Accédons d'abord à la base de données MySQL. Si vous consultez le fichier docker-compose.yml vous verrez que le nom d'utilisateur et le mot de passe définis pour MySQL et PostgreSQL sont les mêmes: testuser/testpassword

Les trois tables se trouvent dans notre base de données Test, regardons notre base de données PostgreSQL:

Sélectionnons la base de données testuser et le schéma test:

Nous avons ici nos tables parfaitement créées dans PostgreSQL. Vérifions enfin si tout est bien configuré dans IRIS:

Tout est correct, nous avons créé nos tables dans l'espace de noms USER Namespace sous le schéma Test.

Très bien, une fois les vérifications effectuées, c'est parti ! Pour ce faire, nous utiliserons Postman, dans lequel nous chargerons le fichier attaché au projet: performance.postman_collection.json

Voici les différents tests que nous allons lancer, nous commencerons par des insertions et nous continuerons par des requêtes sur la base de données. Je n'ai inclus aucun type d'index autre que ceux qui sont créés automatiquement avec la définition des clés primaires dans les différentes bases de données.

Insertion

Appel REST: GET http://localhost:8080/performance/tests/insert/{database}?total=1000

La variable {database} peut avoir les valeurs suivantes:

  • postgres
  • mysql
  • iris

Et l'attribut total sera celui que nous modifierons pour indiquer le nombre total d'insertions que nous voulons faire.

La méthode qui sera invoquée s'appelle insertRecords et se trouve dans le fichier PerformanceController.java situé dans /src/main/java/com/performance/controller/, vous pouvez voir qu'il s'agit d'une insertion extrêmement simple:

INSERTINTO test.patient VALUES (null, ?, ?, null, ?, ?, ?)

La première valeur est nulle car il s'agit de la clé primaire autogénérée et la deuxième valeur nulle correspond à un champ de type BLOB/BYTEA/LONGVARBINARY dans lequel nous enregistrerons une photo ultérieurement.

Nous allons lancer les lots de commandes type push suivants : 100, 1000, 10000, 20000 et nous allons vérifier les temps de réponse que nous recevons dans Postman. Pour chaque mesure, nous effectuerons 3 tests et nous calculerons la moyenne des 3 valeurs obtenues.

 10010001000020000
MySQL0.7548.91 s88 s192 s
PostgreSQL0.23 s2.24 s20.92 s40.35 s
IRIS0.07 s0.33 s2.6 s5 s

Représentons-le graphiquement.

Insertion avec un fichier binaire

Dans l'exemple précédent, nous avons fait des insertions simples, allons donc accélérer les choses en incluant dans notre insertion une image de 50 kB qui servira de photo pour nos patients.

Appel REST: GET http://localhost:8080/performance/tests/insertBlob/{database}?total=1000

La variable {database} peut avoir les valeurs suivantes:

  • postgres
  • mysql
  • iris

Et l'attribut total sera celui que nous modifierons pour indiquer le nombre total d'insertions que nous voulons faire.

La méthode qui sera invoquée s'appelle insertBlobRecords et se trouve dans le fichier PerformanceController.java situé dans /src/main/java/com/performance/controller/, vous pouvez vérifier qu'il s'agit d'une insertion similaire à la précédente à l'exception du fait d'introduire le fichier dans l'insertion:

INSERTINTO test.patient (Name, Lastname, Photo, Phone, Address, City) VALUES (?, ?, ?, ?, ?, ?)

Modifions un peu le nombre d'insertions ci-dessus pour éviter que le test ne prenne une éternité, puis nettoyons le Docker des images pour recommencer à zéro avec une égalité totale des chances.

 1001000500010000
MySQL1.87 s17 s149 s234 s
PostgreSQL0.6 s5.22 s23.93 s60.43 s
IRIS0.13 s0.88 s4.58 s12.57 s

Examinons le graphe:

 

Selection

Testons les performances avec une simple requête qui récupère tous les enregistrements de la table Patient.

Appel REST: GET http://localhost:8080/performance/tests/select/{database}

La variable {database} peut avoir les valeurs suivantes:

  • postgres
  • mysql
  • iris

La méthode qui sera invoquée s'appelle selectRecords et se trouve dans le fichier PerformanceController.java situé dans /src/main/java/com/performance/controller/, la requête est extrêmement simple:

SELECT * FROM test.patient

Nous allons tester la requête avec le même ensemble d'éléments que nous avons utilisé pour notre premier test d'insertion.

 10010001000020000
MySQL0.03 s0,02 s0.03 s0.04 s
PostgreSQL0.03 s0.02 s0.04 s0.03 s
IRIS0.02 s0.02 s0.04 s0.05 s

Et graphiquement:

Sélection d'un groupe par

Testons les performances avec une requête incluant une jointure gauche ainsi que des fonctions d'agrégation. 

Appel REST: GET http://localhost:8080/performance/tests/selectGroupBy/{database}

La variable {database} peut avoir les valeurs suivantes:

  • postgres
  • mysql
  • iris

La méthode qui sera invoquée s'appelle selectGroupBy et se trouve dans le fichier PerformanceController.java situé dans /src/main/java/com/performance/controller/, examinons donc la requête:

SELECTcount(p.Name), c.Name FROM test.patient p leftjoin test.city c on p.City = c.Id GROUPBY c.Name

Nous allons tester la requête encore une fois avec le même ensemble d'éléments que nous avons utilisé pour notre premier test d'insertion.

 10010001000020000
MySQL0.02 s0.02 s0.03 s0.03 s
PostgreSQL0.02 s0.02 s0.02 s0.02 s
IRIS0.02 s0.020.03 s0.04 s

Et graphiquement:

Mise à jour

Pour la mise à jour, nous allons lancer une requête associée à une sous-requête dans le cadre de ses conditions.

Appel REST: GET http://localhost:8080/performance/tests/update/{database}

La variable {database} peut avoir les valeurs suivantes:

  • postgres
  • mysql
  • iris

La méthode qui sera invoquée s'appelle UpdateRecords et se trouve dans le fichier PerformanceController.java situé dans /src/main/java/com/performance/controller/, examinons donc la requête:

UPDATE test.patient SET Phone = '+15553535301'WHERENamein (SELECTNameFROM test.patient whereNamelike'%12')

Lançons la requête et examinons les résultats.

 10010001000020000
MySQLXXXX
PostgreSQL0.02 s0.02 s0.02 s0.03 s
IRIS0.02 s0.02 s0.02 s0.04 s

Nous constatons que MySQL ne permet pas ce type de sous-requêtes dans la même table que celle que nous allons mettre à jour, de sorte que nous ne pouvons pas mesurer leurs durées dans des conditions égales. Ici, nous n'utiliserons pas le graphe, car il est très simple.

Suppression

Pour la suppression, nous allons lancer une requête associée à une sous-requête dans le cadre de ses conditions.

Appel REST: GET http://localhost:8080/performance/tests/delete/{database}

The variable {database} may have the following values:

  • postgres
  • mysql
  • iris

La méthode qui sera invoquée s'appelle DeleteRecords et se trouve dans le fichier PerformanceController.java situé dans /src/main/java/com/performance/controller/, examinons donc la requête:

DELETE test.patient WHERENamein (SELECTNameFROM test.patient whereNamelike'%12')

Lançons la requête et examinons les résultats.

 10010001000020000
MySQLXXXX
PostgreSQL0.01 s0.02 s0.02 s0.03 s
IRIS0.02 s0.02 s0.02 s0.04 s

Nous constatons encore une fois que MySQL ne permet pas ce type de sous-requêtes dans la même table que nous allons supprimer, de sorte que nous ne pouvons pas mesurer leurs durées dans des conditions égales.

Conclusions

Nous pouvons affirmer qu'ils sont tous très au point en ce qui concerne les requêtes de données, ainsi que la mise à jour et la suppression d'enregistrements (à l'exception de MySQL). La plus grande différence se trouve dans la gestion des insertions. IRIS est en effet le meilleur parmi les trois, étant 6 fois plus rapide que PostgreSQL et jusqu'à 20 fois plus rapide que MySQL lors de l'ingestion de données.

Pour travailler avec de grands ensembles de données, c'est IRIS qui est sans aucun doute la meilleure option dans les tests effectués.

Alors... nous avons déjà un champion! IRIS A GAGNÉ!

PS: Il ne s'agit que de quelques exemples de tests que vous pouvez effectuer, n'hésitez pas à modifier le code comme vous le souhaitez.

0
0 68
Article Sylvain Guilbaud · Avr 30, 2024 3m read

Gitter

Configuration de Production

Cette démo comporte une production d'interopérabilité contenant 16 composants. 

Configuration de Production HL7 + Kafka Producer

La première partie de cette démonstration consiste à envoyer un fichier HL7 SIU qui sera transmis aux 2 autres flux HL7 (HTTP et TCP), et transformé et transmis au serveur Kafka. Les flux HTTP et TCP transformeront les messages HL7 de la même manière avant de les envoyer également à Kafka.

0
0 189
Article Pierre LaFay · Avr 20, 2024 1m read

Bonjour,Je me débattais avec une procédure qui devait recevoir une chaîne de caractères et l'utiliser comme filtre, j'ai découvert que puisque je voulais que la procédure fasse une transformation de données et retourne un ensemble de données, j'avais besoin d'utiliser le langage objectScript.J'ai créé la procédure en utilisant l'interface graphique SQL dans le portail, et tout fonctionne correctement lorsque j'appelle la procédure à partir de l'interface graphique SQL, mais pas à travers une connexion JDBC - voici l'appel "call spPatientOS('2024-04-07T12:35:32Z')".Le résultat est que la

0
0 53
Article Pierre LaFay · Jan 21, 2024 4m read

Avec la sortie d'InterSystems IRIS Cloud SQL, nous recevons des questions plus fréquentes sur la manière d'établir des connexions sécurisées via JDBC et d'autres technologies de pilotes.

Bien que nous ayons une belle documentation générale et détaillée sur les technologies de pilote elles-mêmes, notre documentation ne va pas aussi loin pour décrire les outils clients individuels, tels que notre DBeaver préféré.

Dans cet article, nous décrirons les étapes pour créer une connexion sécurisée de DBeaver à votre déploiement Cloud SQL.

0
0 200
Question Sylvain Guilbaud · Août 23, 2023

Est-il prévu que LOAD DATA prenne en compte plusieurs formats de DATE/DATETIME avec, par exemple un paramètre de indiquant le format utilisé dans les données sources ?

exemple :

LOAD DATA .../...
USING
{
  "from": {
    "file": {
       "dateformat": "DD/MM/YYYY"
    }
  }
}
3
0 88
Article Pierre LaFay · Jan 7, 2024 8m read

Introduction

Cet article vise à explorer le fonctionnement du système FHIR-PEX et a été développé, en tirant parti des capacités d'InterSystems IRIS.

En rationalisant l'identification et le traitement des examens médicaux dans les centres de diagnostic clinique, notre système vise à améliorer l'efficacité et la précision des flux de travail de soins de santé. En intégrant les normes FHIR à la base de données InterSystems IRIS Java-PEX, le système aide les professionnels de santé avec des capacités de validation et de routage, contribuant ainsi à améliorer la prise de décision et les soins aux patients.

how it works

  • Interopérabilité IRIS : Reçoit les messages au standard FHIR, garantissant l'intégration et la compatibilité avec les données de santé.

  • Traitement de l'information avec 'PEX Java' : Traite les messages au format FHIR et les dirige vers des sujets Kafka en fonction de règles configurées globalement dans la base de données, facilitant ainsi le traitement et le routage efficaces des données, en particulier pour les examens dirigés vers la quarantaine.

  • Gestion des retours Kafka via un backend Java externe : Interprète uniquement les examens dirigés vers la quarantaine, permettant au système de gérer les retours de Kafka via un backend Java externe. Il facilite la génération d'informations pronostiques pour les professionnels de la santé grâce à l'IA générative, en s'appuyant sur les consultations des résultats d'examens précédents pour les patients respectifs.

Development

Grâce au PEX (Production EXtension) d'InterSystems, un outil d'extensibilité permettant d'améliorer et de personnaliser le comportement du système, nous avons élaboré une Opération Métier. Ce composant est chargé de traiter les messages entrants au format FHIR au sein du système. Comme exemple suivant :

import com.intersystems.enslib.pex.*;
import com.intersystems.jdbc.IRISObject;
import com.intersystems.jdbc.IRIS;
import com.intersystems.jdbc.IRISList;
import com.intersystems.gateway.GatewayContext;

import org.apache.kafka.clients.producer.*;
import org.apache.kafka.common.serialization.*;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class KafkaOperation extends BusinessOperation {
// Connection to InterSystems IRIS
private IRIS iris;

// Connection to Kafka
private Producer<Long, String> producer;

// Kafka server address (comma separated if several)
public String SERVERS;

// Name of our Producer
public String CLIENTID;

/// Path to Config File
public String CONFIG;

public void OnInit() throws Exception {
[...]
}

public void OnTearDown() throws Exception {
[...]
}

public Object OnMessage(Object request) throws Exception {
    IRISObject req = (IRISObject) request;
    LOGINFO("Received object: " + req.invokeString("%ClassName", 1));

    // Create record
    String value = req.getString("Text");
    String topic = getTopicPush(req);
    final ProducerRecord<Long, String> record = new ProducerRecord<>(topic, value);

    // Send new record
    RecordMetadata metadata = producer.send(record).get();

    // Return record info
    IRISObject response = (IRISObject)(iris.classMethodObject("Ens.StringContainer","%New",topic+"|"+metadata.offset()));
    return response;
}

private Producer<Long, String> createProducer() throws IOException {
[...]
}

private String getTopicPush(IRISObject req) {
[...]
}

[...]
}

`

Au sein de l'application, la méthode getTopicPush se charge d'identifier le sujet auquel le message sera envoyé.

La détermination du sujet auquel le message sera envoyé dépend de l'existence d'une règle dans la globale "quarantineRule", telle que lue dans IRIS.

String code = FHIRcoding.path("code").asText();
String system = FHIRcoding.path("system").asText();

IRISList quarantineRule = iris.getIRISList("quarantineRule",code,system);

 String reference = quarantineRule.getString(1);
 String value = quarantineRule.getString(2);

 String observationValue = fhir.path("valueQuantity").path("value").asText()

When the global ^quarantineRule exists, validation of the FHIR object can be validated.

private boolean quarantineValueQuantity(String reference, String value, String observationValue) {
    LOGINFO("quarantine rule reference/value: " + reference + "/" + value);
    double numericValue = Double.parseDouble(value);
    double numericObservationValue = Double.parseDouble(observationValue);

    if ("<".equals(reference)) {
        return numericObservationValue < numericValue;
    }
    else if (">".equals(reference)) {
        return numericObservationValue > numericValue;
    }
    else if ("<=".equals(reference)) {
        return numericObservationValue <= numericValue;
    }
    else if (">=".equals(reference)) {
        return numericObservationValue >= numericValue;
    }
    
    return false;
}

Exemple pratique :

Lors de la définition d'une globale, telle que :

Set ^quarantineRule("59462-2","http://loinc.org") = $LB(">","500") 

Ceci établit une règle pour le code "59462-2" et le système ""http://loinc.org"" dans la globale ^quarantineRule , spécifiant une condition dans laquelle la valeur supérieure à 500 est définie comme quarantaine. Dans l'application, la méthode getTopicPush peut ensuite utiliser cette règle pour déterminer le sujet approprié pour envoyer le message en fonction du résultat de la validation.

Compte tenu de l'affectation, le JSON ci-dessous serait envoyé en quarantaine car il correspond à la condition spécifiée en ayant :

 {
          "system": "http://loinc.org",
          "code": "59462-2",
          "display": "Testosterone"
}

"valueQuantity": { "value": 550, "unit": "ng/dL", "system": "http://unitsofmeasure.org", "code": "ng/dL" }

FHIR Observation:

{
    "resourceType": "Observation",
    "id": "3a8c7d54-1a2b-4c8f-b54a-3d2a7efc98c9",
    "status": "final",
    "category": [
      {
        "coding": [
          {
            "system": "http://terminology.hl7.org/CodeSystem/observation-category",
            "code": "laboratory",
            "display": "laboratory"
          }
        ]
      }
    ],
    "code": {
      "coding": [
        {
          "system": "http://loinc.org",
          "code": "59462-2",
          "display": "Testosterone"
        }
      ],
      "text": "Testosterone"
    },
    "subject": {
      "reference": "urn:uuid:274f5452-2a39-44c4-a7cb-f36de467762e"
    },
    "encounter": {
      "reference": "urn:uuid:100b4a8f-5c14-4192-a78f-7276abdc4bc3"
    },
    "effectiveDateTime": "2022-05-15T08:45:00+00:00",
    "issued": "2022-05-15T08:45:00.123+00:00",
    "valueQuantity": {
      "value": 550,
      "unit": "ng/dL",
      "system": "http://unitsofmeasure.org",
      "code": "ng/dL"
    }
}

L'application Java Quarkus

Après envoi sur le sujet souhaité, une application Quarkus Java a été construite pour recevoir les examens en quarantaine. @ApplicationScoped public class QuarentineObservationEventListener {

@Inject
PatientService patientService;

@Inject
EventBus eventBus;

@Transactional
@Incoming("observation_quarantine")
public CompletionStage<Void> onIncomingMessage(Message<QuarentineObservation> quarentineObservationMessage) {
	var quarentineObservation = quarentineObservationMessage.getPayload();
	var patientId = quarentineObservation.getSubject()
			.getReference();
	var patient = patientService.addObservation(patientId, quarentineObservation);
	publishSockJsEvent(patient.getId(), quarentineObservation.getCode()
			.getText());
	return quarentineObservationMessage.ack();
}

private void publishSockJsEvent(Long patientId, String text) {
	eventBus.publish("monitor", MonitorEventDto.builder()
			.id(patientId)
			.message(" is on quarentine list by observation ." + text)
			.build());
}
 }

Ce segment du système est chargé de conserver les informations reçues de Kafka, de les stocker dans les observations du patient dans la base de données et de notifier l'événement au moniteur.

The monitor

Enfin, le moniteur du système est chargé de fournir une visualisation frontale simple. Cela permet aux professionnels de la santé d’examiner les données des patients/examens et de prendre les mesures nécessaires.

Implementation of langchainPT

Grâce au moniteur, le système permet aux professionnels de la santé de demander des recommandations à l'IA générative.

@Unremovable
@Slf4j
@ApplicationScoped
public class PatientRepository {
	@Tool("Get anamnesis information for a given patient id")
	public Patient getAnamenisis(Long patientId) {
		log.info("getAnamenisis called with id " + patientId);
		Patient patient = Patient.findById(patientId);
		return patient;
	}

	@Tool("Get the last clinical results for a given patient id")
	public List<Observation> getObservations(Long patientId) {
		log.info("getObservations called with id " + patientId);
		Patient patient = Patient.findById(patientId);
		return patient.getObservationList();
	}

}

suivre la mise en œuvre de Langchain4j

@RegisterAiService(chatMemoryProviderSupplier = RegisterAiService.BeanChatMemoryProviderSupplier.class, tools = {PatientRepository.class})
public interface PatientAI {

	@SystemMessage("""
			You are a health care assistant AI. You have to recommend exams for patients based on history information.
			""")
	@UserMessage("""
			 Your task is to recommend clinical exams for the patient id {patientId}.

			 To complete this task, perform the following actions:
			 1 - Retrieve anamnesis information for patient id {patientId}.
			 2 - Retrieve the last clinical results for patient id {patientId}, using the property 'name' as the name of exam and 'value' as the value.
			 3 - Analyse results against well known conditions of health care.

			 Answer with a **single** JSON document containing:
			 - the patient id in the 'patientId' key
			 - the patient weight in the 'weight' key
			 - the exam recommendation list in the 'recommendations' key, with properties exam, reason and condition.
			 - the 'explanation' key containing an explanation of your answer, especially about well known diseases.

			Your response must be just the raw JSON document, without ```json, ``` or anything else.
			 """)
	String recommendExams(Long patientId);
}

Le système peut ainsi aider les professionnels de santé à prendre des décisions et à mener des actions.

Video demo

VIDEO

Authors

NOTE:

L'application https://openexchange.intersystems.com/package/fhir-pex participe actuellement au concours InterSystems Java 2023. N'hésitez pas à explorer davantage la solution et n'hésitez pas à nous contacter si vous avez des questions ou avez besoin d'informations supplémentaires. Nous vous recommandons d'exécuter l'application dans votre environnement local pour une expérience pratique. Merci pour l'opportunité 😀!

0
0 124
Article Anna Diak · Nov 30, 2023 3m read

Introduction

À l’ère du numérique en évolution rapide, une communication efficace est cruciale. Cet article présente un projet de chat basé sur Java, combinant la force de la base de données IRIS et l'intelligence artificielle de ChatGPT. Construit sur Java, il va au-delà de la messagerie en temps réel, en tirant parti d'IRIS et de ChatGPT pour une expérience de chat améliorée. De plus, le nom du projet fait référence au classique culturel – Star Wars.

Si vous appréciez mon application, n'oubliez pas de la soutenir lors du concours.

0
0 148
Article Andrii Mishchenko · Nov 28, 2023 2m read

GmOwl est une solution qui offre une plateforme d'apprentissage organisée et engageante. Il a été développé pour répondre au besoin croissant d'outils d'apprentissage offrant un environnement de quiz polyvalent qui répond aux exigences des utilisateurs.

L'objectif principal de GmOwl est d'offrir une expérience utilisateur aux personnes participant à des quiz tout en donnant aux administrateurs un contrôle complet sur le contenu et l'engagement des utilisateurs.

Si vous appréciez mon application, n'oubliez pas de la soutenir lors du concours.

0
0 65
Question Sylvain Guilbaud · Août 28, 2023

Je recherche dans DBeaver un moyen efficace permettant de filtrer les tables systèmes (ex: appartenant à un schéma commençant par "%").

En utilisant un utilisateur possédant le rôle %All, DBeaver nous affiche une longue liste de schémas systèmes, qui nous oblige à descendre la liste avant d'accéder aux tables utilisateurs.

En créant un utilisateur dans IRIS avec des droits restreints permet de réduire cette liste, mais on perd l'intérêt du rôle %All.

3
0 446
Article Sylvain Guilbaud · Août 24, 2023 9m read

À titre d'exemple d'application en Java fonctionnant avec le dialecte Hibernate pour IRIS, je souhaitais utiliser l'application RealWorld et j'ai trouvé une réalisation pour Quarkus. L'application RealWorld est un exemple d'application proche d'une application réelle, avec des tests déjà préparés pour le backend. La plupart des exemples de réalisations sont à retrouver ici

RealWorld Example App

L'exemple d'application RealWorld est souvent appelé « Wikipédia pour la création d'applications full-stack ». Il sert de prototype standardisé que les développeurs peuvent utiliser pour créer des applications à l'aide de divers langages et frameworks de programmation. L'application fournit un cas d'utilisation réel en imitant une plate-forme de blogs, avec des fonctionnalités telles que l'authentification des utilisateurs, la gestion des profils, la publication d'articles et les commentaires. Avec un ensemble complet de spécifications, y compris une documentation d'API backend prête à l'emploi et des conceptions frontend, il permet aux développeurs de voir comment les mêmes exigences fonctionnelles sont mises en œuvre dans différentes piles technologiques. L'exemple RealWorld est largement utilisé comme outil d'apprentissage et comme référence pour comparer diverses technologies.

Quarkus

Quarkus est un framework Java open source natif de Kubernetes, conçu pour GraalVM et HotSpot. Créé dans le but d'améliorer l'environnement cloud natif moderne, il réduit considérablement l'empreinte et le temps de démarrage des applications Java. Quarkus est connu pour sa philosophie « privilégiant le conteneur », permettant aux développeurs de créer des applications légères et performantes en mettant l'accent sur l'architecture des microservices. Cette flexibilité en a fait un choix populaire pour les organisations cherchant à passer à des plates-formes sans serveur ou basées sur le cloud, combinant des modèles de programmation impératifs et réactifs. Qu'il s'agisse d'une application Web traditionnelle ou d'un système complexe de microservices, Quarkus fournit une plate-forme robuste pour créer des logiciels évolutifs et maintenables.

0
0 70
Annonce Irène Mykhailova · Jan 10, 2023

Découvrez les étapes simples et rapides de configuration des connexions ODBC/JDBC à la plate-forme de données InterSystems IRIS® et InterSystems IRIS for Health™ :

Maintenant dans un format de liste de contrôle facile à utiliser pour vous aider à suivre le processus sur votre propre système.

0
0 45
Article Guillaume Rongier · Mai 21, 2022 16m read

Comme nous le savons tous, Caché est une excellente base de données qui accomplit de nombreuses tâches en son sein. Cependant, que faites-vous lorsque vous avez besoin d'accéder à une base de données externe ? Une façon de le faire est d'utiliser la passerelle Caché SQL Gateway via JDBC. Dans cet article, mon objectif est de répondre aux questions suivantes pour vous aider à vous familiariser avec cette technologie et à déboguer certains problèmes courants.

Plan de travail

Avant de se plonger dans ces questions, discutons rapidement de l'architecture de la passerelle JDBC SQL Gateway. Pour simplifier, vous pouvez considérer que l'architecture est la suivante : Cache établit une connexion TCP avec un processus Java, appelé processus de passerelle. Le processus de passerelle se connecte ensuite à une base de données distante, telle que Caché, Oracle ou SQL Server, en utilisant le pilote spécifié pour cette base de données. Pour plus d'informations sur l'architecture de la passerelle SQL Gateway, veuillez consulter la documentation sur Utilisation de la passerelle Caché SQL Gateway.

Paramètres de connexion

Lorsque vous vous connectez à une base de données distante, vous devez fournir les paramètres suivants :

  • nom d'utilisateur
  • mot de passe
  • nom du pilote
  • URL
  • chemin de classe

Connexion à la base de données Caché

Par exemple, si vous avez besoin de vous connecter à une instance de Caché en utilisant la passerelle SQL Gateway via JDBC, vous devez naviguer vers [System Administration] -> [Configuration] -> [Connectivity] -> [SQL Gateway Connections] dans le portail de gestion du système (SMP). Cliquez ensuite sur "Créer une nouvelle connexion" et spécifiez "JDBC" comme type de connexion.

Lors de la connexion à un système Caché, le nom du pilote doit toujours être com.intersys.jdbc.CacheDriver, comme indiqué dans la capture d'écran. Si vous vous connectez à une base de données tierce, vous devrez utiliser un nom de pilote différent (voir Connexion à des bases de données tierces ci-dessous).

Lorsque vous vous connectez aux bases de données Caché, vous n'avez pas besoin de spécifier un chemin de classe car le fichier JAR est téléchargé automatiquement.

Le paramètre URL varie également en fonction de la base de données à laquelle vous vous connectez. Pour les bases de données Caché, vous devez utiliser une URL de la forme suivante

jdbc:Cache://[server_address]:[superserver_port]/[namespace]

Connexion à des bases de données tierces

Une base de données tierce courante est Oracle. Un exemple de configuration est présenté ci-dessous.

Comme vous pouvez le constater, le nom du pilote et l'URL ont des caractéristiques différentes de celles que nous avons utilisées pour la connexion précédente. En outre, j'ai spécifié un chemin de classe dans cet exemple, car je dois utiliser le pilote d'Oracle pour me connecter à leur base de données.

Comme vous pouvez l'imaginer, SQL Server utilise différents modèles d'URL et de noms de pilotes.

Vous pouvez tester si les valeurs sont valides en cliquant sur le bouton " Testez la connexion ". Pour créer la connexion, cliquez sur "Enregistrer".

JDBC Gateway vs le service Java Gateway Business Service

Tout d'abord, la passerelle JDBC et le service de passerelle Java sont complètement indépendants l'un de l'autre. La passerelle JDBC peut être utilisée sur tous les systèmes basés sur Caché, alors que le service de passerelle Java n'existe que dans le cadre d'Ensemble. En outre, le service de passerelle Java utilise un processus différent de celui utilisé par la passerelle JDBC. Pour plus de détails sur le service commercial de passerelle Java, veuillez consulter Le service commercial de passerelle Java.

Méthodes et outils

Vous trouverez ci-dessous 5 outils et méthodes couramment utilisés pour résoudre des problèmes avec la passerelle JDBC SQL Gateway. Je vais d'abord parler de ces outils et vous montrer quelques exemples de leur utilisation dans la section suivante.

1. Journaux

A. Journal du pilote et journal de la passerelle

Lorsque vous utilisez la passerelle JDBC, le journal correspondant est le journal de la passerelle JDBC SQL. Comme nous l'avons vu précédemment, la passerelle JDBC est utilisée lorsque Caché doit accéder à des bases de données externes, ce qui signifie que Caché est le client. Le journal du pilote, par contre, correspond à l'utilisation du pilote JDBC d'InterSystems pour accéder à une base de données Caché à partir d'une application externe, ce qui signifie que Caché est le serveur. Si vous avez une connexion d'une base de données Caché à une autre base de données Caché, les deux types de journaux peuvent être utiles.

Dans notre documentation la section relative à l'activation du journal du pilote est intitulée "Activation de la journalisation pour JDBC", et la section relative à l'activation du journal de la passerelle est intitulée "Activation de la journalisation pour la passerelle SQL JDBC".

Même si les deux journaux comportent le mot "JDBC", ils sont totalement indépendants. L'objet de cet article est la passerelle JDBC, c'est pourquoi j'aborderai plus en détail le journal de la passerelle. Pour plus d'informations sur le journal du pilote, veuillez vous reporter à la section Activation du journal du pilote.

B. Activation du journal du pilote

Si vous utilisez la passerelle Caché JDBC SQL Gateway, vous devez effectuer les opérations suivantes pour activer la journalisation : dans le portail de gestion, allez dans [System Administration] > [Configuration] > [Connectivity] > [JDBC Gateway Settings]. Indiquez une valeur pour le journal de la passerelle JDBC. Ce doit être le chemin complet et le nom d'un fichier journal (par exemple, /tmp/jdbcGateway.log). Le fichier sera automatiquement créé s'il n'existe pas, mais le répertoire ne le sera pas. Caché va démarrer la passerelle JDBC SQL Gateway avec journalisation pour vous.

Si vous utilisez le service commercial Java Gateway dans Ensemble, veuillez consulter Activation de la journalisation de la passerelle Java Gateway dans Ensemble pour savoir comment activer la journalisation.

C. Analyse du journal d'une passerelle

Maintenant que vous avez collecté un journal de passerelle, vous vous posez peut-être la question suivante : quelle est la structure du journal et comment le lire ? Bonne question ! Je vais vous fournir ici quelques informations de base pour vous aider à démarrer. Malheureusement, il n'est pas toujours possible d'interpréter complètement le journal sans avoir accès au code source. Pour les situations complexes, n'hésitez pas à contacter le WRC (Centre de réponse global d'InterSystems) !

Pour démystifier la structure du journal, rappelez-vous qu'il s'agit toujours d'un morceau de données suivi d'une description de ce qu'il fait. Par exemple, voyez cette image avec une coloration syntaxique de base :

Afin de comprendre ce que Received signifie ici, vous devez vous rappeler que le journal de la passerelle enregistre les interactions entre la passerelle et la base de données descendante. Ainsi, Received signifie que la passerelle a reçu l'information de Caché/Ensemble. Dans l'exemple ci-dessus, la passerelle a reçu le texte d'une requête SELECT. Les significations des différentes valeurs de msgId peuvent être trouvées dans le code interne. Le 33 que nous voyons ici signifie " Preparer l'instruction ".

Le journal lui-même fournit également des informations sur le pilote, ce qui est intéressant à vérifier lors du débogage des problèmes. Voici un exemple,

Comme nous pouvons le voir, le Driver Name est com.intersys.jdbc.CacheDriver, ce qui est le nom du pilote utilisé pour se connecter au processus de passerelle. Le Jar File Name est cachejdbc.jar, ce qui est le nom du fichier jar situé dans <cache_install_directory>\lib\.

2. Trouver le processus de passerelle

Pour trouver le processus de passerelle, vous pouvez exécuter la commande ps. Par exemple,

ps -ef | grep java

Cette commande ps affiche des informations sur le processus Java, notamment le numéro de port, le fichier jar, le fichier journal, l'ID du processus Java et la commande qui a lancé le processus Java.

Voici un exemple du résultat de la commande :

mlimbpr15:~ mli$ ps -ef | grep java
17182 45402 26852   0 12:12PM ??         0:00.00 sh -c java -Xrs -classpath /Applications/Cache20151/lib/cachegateway.jar:/Applications/Cache20151/lib/cachejdbc.jar com.intersys.gateway.JavaGateway 62972 /Applications/Cache20151/mgr/JDBC.log 2>&1
17182 45403 45402   0 12:12PM ??         0:00.22 /usr/bin/java -Xrs -classpath /Applications/Cache20151/lib/cachegateway.jar:/Applications/Cache20151/lib/cachejdbc.jar com.intersys.gateway.JavaGateway 62972 /Applications/Cache20151/mgr/JDBC.log
502 45412 45365   0 12:12PM ttys000    0:00.00 grep java

Dans Windows, vous pouvez consulter le gestionnaire des tâches pour trouver des informations sur le processus de passerelle.

3. Lancement et arrêt de la passerelle

Il y a deux façons de lancer et d'arrêter la passerelle :

  1. Par le biais du SMP
  2. Utilisation du terminal

A. Par le biais du SMP

Vous pouvez lancer et arrêter la passerelle dans le SMP en accédant à [System Administration] -> [Configuration] -> [Connectivity] -> [JDBC Gateway Server].

B. Utilisation du terminal

Sur les machines Unix, vous pouvez également démarrer la passerelle depuis le terminal. Comme nous l'avons vu dans la section précédente, le résultat de ps -ef | grep java contient la commande qui a démarré le processus Java, qui dans l'exemple ci-dessus est le suivant:

java -Xrs -classpath /Applications/Cache20151/lib/cachegateway.jar:/Applications/Cache20151/lib/cachejdbc.jar com.intersys.gateway.JavaGateway 62972 /Applications/Cache20151/mgr/JDBC.log

Pour arrêter la passerelle depuis le terminal, vous pouvez tuer le processus. L'ID du processus Java est le deuxième chiffre de la ligne qui contient la commande ci-dessus, dans l'exemple ci-dessus c'est 45402. Ainsi, pour arrêter la passerelle, vous pouvez exécuter :

kill 45402

4. Écrire un programme Java

Exécuter un programme Java pour se connecter à une base de données descendante est un excellent moyen de tester la connexion, de vérifier la requête et d'aider à isoler la cause d'un problème donné. Je joins un exemple de programme Java qui établit une connexion avec SQL Server et imprime une liste de tous les tableaux. J'expliquerai pourquoi cela peut être utile dans la section suivante.

import java.sql.*;
import java.sql.Date;
import java.util.*;
import java.lang.reflect.Method;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import javax.sql.*;

// Auteur : Vicky Li
// Ce programme établit une connexion avec le serveur SQL et récupère tous les tableaux. Le résultat est une liste de tableaux.

public class TestConnection {
    public static void main(String[] args) {
        try {
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
            //please replace url, username, and password with the correct parameters
            Connection conn = DriverManager.getConnection(url,username,password);

            System.out.println("connected");

            DatabaseMetaData meta = conn.getMetaData();
            ResultSet res = meta.getTables(null, null, null, new String[] {"TABLE"});
            System.out.println("List of tables: ");
            while (res.next()) {
                System.out.println(
                    "   " + res.getString("TABLE_CAT") +
                    ", " + res.getString("TABLE_SCHEM") +
                    ", " + res.getString("TABLE_NAME") +
                    ", " + res.getString("TABLE_TYPE")
                );
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Pour exécuter ce programme Java (ou tout autre programme Java), vous devez d'abord compiler le fichier .java, qui dans notre cas s'appelle TestConnection.java. Ensuite, un nouveau fichier sera généré au même endroit, que vous pourrez ensuite exécuter avec la commande suivante sur un système UNIX :

java -cp "<path to driver>/sqljdbc4.jar:lib/*:." TestConnection

Dans Windows, vous pouvez exécuter la commande suivante :

java -cp "<path to driver>/sqljdbc4.jar;lib/*;." TestConnection

5. Suivi d'une trace de jstack

Comme son nom l'indique, jstack imprime l'arborescence des appels de procédure Java. Cet outil peut devenir pratique lorsque vous avez besoin de mieux comprendre ce que fait le processus Java. Par exemple, si vous voyez le processus de la passerelle s'accrocher à un certain message dans le journal des passerelles, vous pourriez vouloir recueillir une trace jstack. Je tiens à souligner que jstack est un outil de bas niveau qui ne devrait être utilisé que lorsque d'autres méthodes, comme l'analyse du journal des passerelles, ne résolvent pas le problème.

Avant de collecter une trace jstack, vous devez vous assurer que le JDK est installé. Voici la commande pour collecter une trace jstack :

jstack -F <pid> > /<path to file>/jstack.txt

où le pid est l'ID du processus de la passerelle, qui peut être obtenu en exécutant la commande ps, telle que ps -ef | grep java. Pour plus d'informations sur la façon de trouver le pid, veuillez consulter Lancement et arrêt de la passerelle.

Maintenant, voici quelques considérations spéciales pour les machines Red Hat. Dans le passé, il y a eu des problèmes pour attacher jstack au processus de la passerelle JDBC (ainsi qu'au processus du service métier de la passerelle Java lancé par Ensemble) sur certaines versions de Red Hat, donc la meilleure façon de collecter une trace jstack sur Red Hat est de lancer le processus de la passerelle manuellement. Pour les instructions, veuillez consulter Collecter une trace jstack sur Red Hat.

Types courants de problèmes et approches pour les résoudre

1. Problème : Java n'est pas installé correctement

Dans cette situation, vérifiez la version de Java et les variables d'environnement.

Pour vérifier la version de Java, vous pouvez exécuter la commande suivante à partir d'un terminal :

java -version

Si vous obtenez l'erreur java : Command not found, cela signifie que le processus Cache ne peut pas trouver l'emplacement des exécutables Java. Cela peut généralement être résolu en plaçant les exécutables Java dans le PATH. Si vous rencontrez des problèmes, n'hésitez pas à contacter le WRC (Centre de réponse global).

2. Problème : échec de la connexion

Un bon diagnostic des échecs de connexion est la vérification du lancement du processus de la passerelle. Vous pouvez le faire en vérifiant le journal de la passerelle ou le processus de la passerelle. Sur les versions modernes, vous pouvez également aller sur le SMP et visiter [System Administration] -> [Configuration] -> [Connectivity] -> [JDBC Gateway Server], et vérifier si la page affiche "JDBC Gateway is running".

Si le processus de passerelle ne s'exécute pas, il est probable que Java n'est pas installé correctement ou que vous utilisez le mauvais port ; si le processus de passerelle s'exécute, il est probable que les paramètres de connexion sont incorrects.

Dans le premier cas, veuillez vous reporter à la section précédente et vérifiez le numéro de port. Je discuterai plus en détail de la deuxième situation ici.

Il est de la responsabilité du client d'utiliser les paramètres de connexion corrects :

  • nom d'utilisateur
  • mot de passe
  • nom du pilote
  • URL
  • chemin de classe

Vous pouvez vérifier si vous avez les bons paramètres de l'une des trois façons suivantes :

  • Utilisez le bouton "Test Connection" après avoir sélectionné un nom de connexion dans [System Administration] -> [Configuration] -> [Connectivity] -> [SQL Gateway Connections]. Note : pour les systèmes modernes, "Test Connection" donne des messages d'erreur utiles ; pour les systèmes plus anciens, le JDBC gateway log est nécessaire pour trouver plus d'informations sur l'échec.

  • Exécutez la ligne de commande suivante depuis un terminal Caché pour tester la connexion :

      d $SYSTEM.SQLGateway.TestConnection(<connection name>)
    
  • Exécutez un programme Java pour établir une connexion. Le programme que vous écrivez peut être similaire à l' example dont nous avons parlé précédemment.

3. Problème : décalage entre la façon dont Caché comprend JDBC et la façon dont la base de données distante comprend JDBC, par exemple :

  • problèmes de type de données
  • procédure stockée avec des paramètres de sortie
  • flux

Pour cette catégorie, il est souvent plus utile de travailler avec le WRC (Centre de réponse global). Voici ce que nous faisons souvent pour déterminer si le problème se situe dans notre code interne ou dans la base de données distante (ou dans le pilote) :

Remarque

Le service commercial de la passerelle Java

Le nom de la classe du Service Métier d' Ensemble est EnsLib.JavaGateway.Service, et la classe de l'adaptateur est EnsLib.JavaGateway.ServiceAdapter. La session Ensemble crée d'abord une connexion avec le serveur Java Gateway, qui est un processus Java. L'architecture est similaire à celle de la passerelle JDBC SQL, sauf que le processus Java est géré par l'opération commerciale. Pour plus de détails, veuillez consulter la documentation.

Activation du journal du pilote

Pour activer le journal du pilote, vous devez ajouter un nom de fichier journal à la fin de la chaîne de connexion JDBC. Par exemple, si la chaîne de connexion originale ressemble à czci :

jdbc:Cache://127.0.0.1:1972/USER

Pour activer la journalisation, ajoutez un fichier (jdbc.log) à la fin de la chaîne de connexion, de sorte qu'elle ressemble à ceci :

jdbc:Cache://127.0.0.1:1972/USER/jdbc.log

Le fichier journal sera enregistré dans le répertoire de travail de l'application Java.

Activation de la journalisation de la passerelle Java dans Ensemble

Si vous utilisez le service métier de la passerelle Java dans Ensemble pour accéder à une autre base de données, vous devez, pour activer la journalisation, spécifier le chemin et le nom d'un fichier journal (par exemple, /tmp/javaGateway.log) dans le champ "Log File" du service de la passerelle Java. Veuillez noter que le chemin d'accès doit exister.

N'oubliez pas que la connexion de la passerelle Java utilisée par la production Ensemble est distincte des connexions utilisées par les tableaux liés ou d'autres productions. Ainsi, si vous utilisez Ensemble, vous devez collecter le journal dans le service de passerelle Java. Le code qui démarre le service de passerelle Java utilise le paramètre "Log File" dans Ensemble, et n'utilise pas le paramètre dans la passerelle Caché SQL dans le SMP comme décrit précédemment.

Récupération d'une trace jstack sur Red Hat

La clé ici est de lancer le processus de la passerelle manuellement, et la commande pour lancer la passerelle peut être obtenue en exécutant ps -ef | grep java. Vous trouverez ci-dessous les étapes complètes à suivre pour collecter une trace jstack sur Red Hat lors de l'exécution de la passerelle JDBC ou du service métier de la passerelle Java.

  1. Assurez-vous que le JDK est installé.

  2. Dans un terminal, exécutez ps -ef | grep java. Obtenez les deux informations suivantes à partir du résultat :

    • a. Copiez la commande qui a lancé la passerelle. Cela devrait ressembler à quelque chose comme ça : java -Xrs -classpath /Applications/Cache20151/lib/cachegateway.jar:/Applications/Cache20151/lib/cachejdbc.jar com.intersys.gateway.JavaGateway 62972 /Applications/Cache20151/mgr/JDBC2.log

    • b. Obtenez l'ID du processus Java (pid), qui est le deuxième chiffre de la ligne qui contient la commande ci-dessus.

  3. Arrêtez le processus avec kill <pid>.

  4. Exécutez la commande que vous avez copiée à l'étape 2.a. pour lancer manuellement un processus de passerelle.

  5. Jetez un coup d'oeil au journal de la passerelle (dans notre exemple, il est situé dans /Applications/Cache20151/mgr/JDBC2.log) et assurez-vous que vous voyez des entrées comme >> LOAD_JAVA_CLASS: com.intersys.jdbc.CacheDriver. Cette étape est juste pour vérifier qu'un appel à la passerelle est effectué avec succès.

  6. Dans un nouveau terminal, exécutez ps -ef | grep java pour obtenir le pid du processus de la passerelle.

  7. Rassemblez une trace jstack : jstack -F <pid> > /tmp/jstack.txt

0
0 286