Dans ce tutoriel, nous partons du principe que vous disposez de connaissances de base sur Linux. Des connaissances de base sur Google Cloud ainsi que sur la spécification FHIR et son utilisation dans les systèmes de dossiers médicaux électroniques (EHR) sont également utiles. Exécutez toutes les commandes de ce tutoriel dans Cloud Shell.
Objectifs
- Créer un dataset et un magasin FHIR pour l'API Cloud Healthcare
- Importer des données FHIR dans le magasin FHIR de l'API Cloud Healthcare
- Utiliser l'opération d'anonymisation FHIR de l'API Cloud Healthcare pour supprimer ou modifier les informations personnelles et les données de santé protégées dans les instances FHIR d'un magasin FHIR
- Utiliser l'outil de ligne de commande
curl
pour effectuer un appel d'anonymisation FHIR via l'API Cloud Healthcare
Coûts
Ce tutoriel utilise les composants facturables Google Cloud suivants :Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût.
Avant de commencer
Toute utilisation de l'API Cloud Healthcare s'effectue dans le cadre d'un projet Google Cloud. Les projets constituent une base pour la création, l'activation et l'utilisation de tous les services Google Cloud, comme la gestion des API, la facturation, l'ajout et la suppression de collaborateurs et la gestion des autorisations pour les ressources Google Cloud. Utilisez la procédure suivante pour créer un projet Google Cloud ou sélectionnez un projet que vous avez déjà créé.-
In the Google Cloud console, go to the project selector page.
-
Select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the Cloud Healthcare API.
-
In the Google Cloud console, activate Cloud Shell.
At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.
- Dans Cloud Shell, exécutez la commande
gcloud components update
pour vous assurer que vous disposez de la dernière version de l'outil incluant les fonctionnalités de l'API Cloud Healthcare.
Une fois que vous avez terminé les tâches décrites dans ce document, vous pouvez éviter de continuer à payer des frais en supprimant les ressources que vous avez créées. Pour en savoir plus, consultez la section Effectuer un nettoyage.
Créer un compte de service IAM
Les rôles Administrateur d'ensembles de données Healthcare, Administrateur FHIR et Éditeur de ressources FHIR sont requis pour ce tutoriel. Pour créer un compte de service et attribuer les rôles appropriés, procédez comme suit :
- Créez un compte de service.
Attribuez des rôles au compte de service :
- Administrateur d'ensembles de données Healthcare
- Administrateur Healthcare FHIR
- Éditeur de ressources FHIR Healthcare
Activez la clé de votre compte de service :
gcloud auth activate-service-account --key-file=path-to-key-file
Le résultat est le suivant :
Activated service account credentials for: [key-name@project-name.iam.gserviceaccount.com]
key-name
est le nom que vous avez attribué à la clé du compte de service.project-name
est le nom de votre projet Google Cloud.
Obtenir un jeton d'accès OAuth 2.0
Pour ingérer des données à l'aide de l'API Cloud Healthcare, vous devez disposer d'un jeton d'accès OAuth 2.0 que les commandes de ce tutoriel vous permettent d'obtenir. Dans ce tutoriel, certains exemples de requêtes API Cloud Healthcare utilisent l'outil de ligne de commande curl
. Ces exemples font appel à la commande gcloud auth print-access-token
pour obtenir un jeton de support OAuth 2.0 et pour inclure ce jeton dans l'en-tête d'autorisation de la requête. Pour en savoir plus sur cette commande, consultez la page sur gcloud auth application-default print-access-token
.
Configurer l'ensemble de données FHIR pour l'anonymisation
Chaque ressource FHIR est un objet de type JSON contenant des paires clé/valeur. Certains éléments sont standardisés, d'autres sont en texte libre. Vous pouvez utiliser l'opération d'anonymisation pour les opérations suivantes :
- Supprimer les valeurs de clés spécifiques dans la ressource FHIR
- Traiter le texte non structuré pour ne supprimer que les éléments d'informations personnelles, en laissant le reste du contenu tel quel
Lorsque vous anonymisez un ensemble de données, l'ensemble de données de destination ne doit pas exister avant le lancement de l'appel d'API d'anonymisation. Cette opération entraîne la création de l'ensemble de données de destination.
Lorsque vous anonymisez un seul magasin FHIR, l'ensemble de données de destination doit exister avant le lancement de l'appel d'API d'anonymisation.
L'ensemble de données source, le magasin FHIR et le magasin FHIR de l'ensemble de données de destination doivent résider dans le même projet Google Cloud. Lorsque vous exécutez l'opération d'anonymisation, l'ensemble de données de destination et son magasin FHIR sont créés dans le même projet Google Cloud que l'ensemble de données source et son magasin FHIR.
Si vous souhaitez générer des données FHIR synthétiques afin de les utiliser pour ce tutoriel, vous pouvez utiliser Synthea pour générer des données synthétiques au format FHIR STU3, copier les données générées dans un bucket Cloud Storage, puis les importer dans le magasin FHIR de l'API Cloud Healthcare. Synthea ne génère pas de données FHIR avec des composants textuels gratuits ou non structurés. Vous ne pouvez donc pas l'utiliser pour explorer ces aspects de l'anonymisation.
Pour ce tutoriel, vous allez importer des exemples de données FHIR dans le magasin FHIR, comme indiqué dans la procédure suivante.
Configurez des variables d'environnement pour le projet et l'emplacement où l'ensemble de données, le magasin FHIR et les données FHIR seront stockés. Les valeurs attribuées aux variables d'environnement sont des exemples de valeurs, comme suit :
export PROJECT_ID=MyProj export REGION=us-central1 export SOURCE_DATASET_ID=dataset1 export FHIR_STORE_ID=FHIRstore1 export DESTINATION_DATASET_ID=deid-dataset1
Les définitions des variables d'environnement déclarées dans l'exemple précédent sont les suivantes :
$PROJECT_ID
correspond à votre identifiant de projet Google Cloud.$REGION
correspond à la région Google Cloud dans laquelle l'ensemble de données de l'API Cloud Healthcare est créé.$SOURCE_DATASET_ID
correspond au nom de l'ensemble de données de l'API Cloud Healthcare dans lequel les données sources sont stockées.$FHIR_STORE_ID
correspond au nom du magasin FHIR source de l'API Cloud Healthcare.$DESTINATION_DATASET_ID
correspond au nom de l'ensemble de données de destination de l'API Cloud Healthcare dans lequel les données anonymisées sont écrites.
Vous utiliserez également ces variables d'environnement dans la suite de ce tutoriel.
Créez un ensemble de données pour l'API Cloud Healthcare :
gcloud healthcare datasets create $SOURCE_DATASET_ID --location=$REGION
Le résultat ressemble à ce qui suit, où
[OPERATION_NUMBER]
est l'identifiant de l'opération de création de l'ensemble de données permettant de suivre la requête :Create request issued for: $SOURCE_DATASET_ID Waiting for operation [OPERATION_NUMBER] to complete...done. Created dataset $SOURCE_DATASET_ID.
La commande ci-dessus crée l'ensemble de données source nommé
$SOURCE_DATASET_ID
dans la région$REGION
.Créez un magasin FHIR à l'aide de la commande suivante :
gcloud healthcare fhir-stores create $FHIR_STORE_ID \ --dataset=$SOURCE_DATASET_ID --location=$REGION
La commande ci-dessus crée un magasin FHIR nommé
$FHIR_STORE_ID
dans l'ensemble de données$SOURCE_DATASET_ID
.Ajoutez la ressource Patient FHIR au magasin FHIR à l'aide de la fonction FHIR
create
avec la commande suivante :curl -X POST \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "Content-Type: application/fhir+json; charset=utf-8" \ --data "{ \"address\": [ { \"city\": \"Anycity\", \"district\": \"Anydistrict\", \"line\": [ \"123 Main Street\" ], \"period\": { \"start\": \"1990-12-05\" }, \"postalCode\": \"12345\", \"state\": \"CA\", \"text\": \"123 Main Street Anycity, Anydistrict, CA 12345\", \"use\": \"home\" } ], \"name\": [ { \"family\": \"Smith\", \"given\": [ \"Darcy\" ], \"use\": \"official\" } ], \"gender\": \"female\", \"birthDate\": \"1980-12-05\", \"resourceType\": \"Patient\" }" \ "https://healthcare.googleapis.com/v1/projects/$PROJECT_ID/locations/$REGION/datasets/$SOURCE_DATASET_ID/fhirStores/$FHIR_STORE_ID/fhir/Patient"
L'argument de la commande correspond à l'exemple de ressource FHIR, une ressource Patient FHIR.
{ "address": [ { "city": "Anycity", "district": "Anydistrict", "line": [ "123 Main Street" ], "period": { "start": "1990-12-05" }, "postalCode": "12345", "state": "CA", "text": "123 Main Street Anycity, Anydistrict, CA 12345", "use": "home" } ], "name": [ { "family": "Smith", "given": [ "Darcy" ], "use": "official" } ], "gender": "female", "birthDate": "1980-12-05", "resourceType": "Patient" }
Si la requête aboutit, le serveur renvoie un résultat semblable à celui-ci :
{ "address": [ { "city": "Anycity", "district": "Anydistrict", "line": [ "123 Main Street" ], "period": { "start": "1990-12-05" }, "postalCode": "12345", "state": "CA", "text": "123 Main Street Anycity, Anydistrict, CA 12345", "use": "home" } ], "birthDate": "1980-12-05", "gender": "female", "id": "0359c226-5d63-4845-bd55-74063535e4ef", "meta": { "lastUpdated": "2020-02-08T00:03:21.745220+00:00", "versionId": "MTU4MTEyMDIwMTc0NTIyMDAwMA" }, "name": [ { "family": "Smith", "given": [ "Darcy" ], "use": "official" } ], "resourceType": "Patient" }
La commande
curl
précédente insère une nouvelle ressource Patient dans le magasin FHIR source. Un identifiant de patient (id
) est généré dans le résultat. L'identifiant de patient est une chaîne alphanumérique anonymisée utilisée dans la ressource FHIR Encounter pour associer la ressource Patient FHIR.Ajoutez la ressource Encounter FHIR au magasin FHIR à l'aide de la fonction FHIR
create
avec la commande suivante. Dans la commande, remplacez la valeursubject.reference
par la valeur de l'identifiant du patient issue du résultat de la commandecurl
précédente :curl -X POST \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "Content-Type: application/fhir+json; charset=utf-8" \ --data "{ \"status\": \"finished\", \"class\": { \"system\": \"http://hl7.org/fhir/v3/ActCode\", \"code\": \"IMP\", \"display\": \"inpatient encounter\" }, \"reason\": [ { \"text\": \"Mrs. Smith is a 39-year-old female who has a past medical history significant for a myocardial infarction. Catheterization showed a possible kink in one of her blood vessels.\" } ], \"subject\": { \"reference\": \"Patient/0359c226-5d63-4845-bd55-74063535e4ef\" }, \"resourceType\": \"Encounter\" }" \ "https://healthcare.googleapis.com/v1/projects/$PROJECT_ID/locations/$REGION/datasets/$SOURCE_DATASET_ID/fhirStores/$FHIR_STORE_ID/fhir/Encounter"
L'argument de la commande correspond à l'exemple de ressource FHIR, une ressource Encounter FHIR :
{ "status": "finished", "class": { "system": "http://hl7.org/fhir/v3/ActCode", "code": "IMP", "display": "inpatient encounter" }, "reason": [ { "text": "Mrs. Smith is a 39-year-old female who has a past medical history significant for a myocardial infarction. Catheterization showed a possible kink in one of her blood vessels." } ], "subject": { "reference": "Patient/0359c226-5d63-4845-bd55-74063535e4ef" }, "resourceType": "Encounter" }
Si la requête aboutit, le serveur renvoie un résultat semblable à celui-ci :
{ "class": { "code": "IMP", "display": "inpatient encounter", "system": "http://hl7.org/fhir/v3/ActCode" }, "id": "0038a95f-3c11-4163-8c2e-10842b6b1547", "meta": { "lastUpdated": "2020-02-12T00:39:16.822443+00:00", "versionId": "MTU4MTQ2Nzk1NjgyMjQ0MzAwMA" }, "reason": [ { "text": "Mrs. Smith is a 39-year-old female who has a past medical history significant for a myocardial infarction. Catheterization showed a possible kink in one of her blood vessels." } ], "resourceType": "Encounter", "status": "finished", "subject": { "reference": "Patient/0359c226-5d63-4845-bd55-74063535e4ef" }
La commande
curl
précédente insère une nouvelle ressource Encounter dans le magasin FHIR source.
Anonymiser des données FHIR
Ensuite, vous devez anonymiser les données FHIR que vous avez insérées dans le magasin FHIR source.
Vous masquez ou transformez tous les éléments d'informations personnelles dans des champs structurés, tels que les champs Patient.name
et Patient.address
. Vous pouvez également supprimer les éléments d'informations personnelles dans les données non structurées dans du texte, tels que Encounter.reason.text
.
Vous pouvez éventuellement exporter les données obtenues directement vers BigQuery à des fins d'analyse et de machine learning.
Cette configuration d'anonymisation peut être utilisée pour une analyse de l'état de santé de la population ou un cas d'utilisation similaire. Dans le contexte de ce tutoriel, vous pouvez déplacer des données structurées anonymisées vers BigQuery pour évaluer les tendances à grande échelle. Vous n'aurez peut-être pas besoin de champs non structurés, qui sont difficiles à normaliser et analyser à grande échelle. Toutefois, les champs non structurés sont inclus dans ce tutoriel comme référence.
L'anonymisation des données FHIR s'applique à de nombreux cas d'utilisation potentiels. Il existe également de nombreuses options de configuration compatibles avec l'API Cloud Healthcare. Pour obtenir plus d'informations, y compris des exemples de commandes curl
et des exemples Tools for PowerShell pour différents scénarios, consultez la page Anonymiser des données FHIR.
Les champs contenant une date sont transformés par changement de date, une technique qui modifie toutes les dates d'une ressource FHIR de manière aléatoire et cohérente. Le changement de date permet de maintenir la cohérence au sein d'une ressource FHIR afin que les informations pertinentes sur le plan médical, telles que l'âge du patient et le délai entre les rendez-vous, soient conservées sans révéler d'informations permettant d'identifier le patient. Tous les identifiants de champs non structurés sont également transformés.
L'exemple suivant inclut également une transformation de hachage sur les champs name
. Le hachage est une technique de chiffrement à sens unique qui garantit qu'un nom est toujours transformé vers la même valeur de sortie, ce qui génère des résultats cohérents pour le même nom de patient sur plusieurs enregistrements de l'ensemble de données.
Dans cette opération, vous masquez les informations personnelles tout en conservant les liens entre les ressources.
Dans cet exemple, la clé cryptographique fournie, U2FsdGVkX19bS2oZsdbK9X5zi2utBn22uY+I2Vo0zOU=
, est un exemple de clé 256 bits encodée en base64 et chiffrée par AES, générée à l'aide de la commande ci-dessous.
echo -n "test" | openssl enc -e -aes-256-ofb -a -salt
La commande vous invite à saisir un mot de passe. Saisissez le mot de passe de votre choix.
Utilisez la commande
curl
pour masquer ou transformer tous les éléments d'informations personnelles dans les champs structurés, tels que les champsname
etaddress
, et pour transformer tous les identifiants dans les champs non structurés.curl -X POST \ -H "Authorization: Bearer "$(gcloud auth print-access-token) \ -H "Content-Type: application/json; charset=utf-8" \ --data "{ 'destinationDataset': 'projects/$PROJECT_ID/locations/$REGION/datasets/$DESTINATION_DATASET_ID', 'config': { 'fhir': { 'fieldMetadataList': { 'paths': [ 'Patient.address.state', 'Patient.address.line', 'Patient.address.text', 'Patient.address.postalCode' ], 'action': 'TRANSFORM' }, 'fieldMetadataList': { 'paths': [ 'Encounter.reason.text' ], 'action': 'INSPECT_AND_TRANSFORM' }, 'text': { 'transformations': [ { 'infoTypes': [], 'replaceWithInfoTypeConfig': {} } ] }, 'fieldMetadataList': { 'paths': [ 'Patient.name.family', 'Patient.name.given' ], 'action': 'TRANSFORM' }, 'text': { 'transformations': { 'infoTypes': [ 'PERSON_NAME' ], 'cryptoHashConfig': { 'cryptoKey': 'U2FsdGVkX19bS2oZsdbK9X5zi2utBn22uY+I2Vo0zOU=' } } }, 'fieldMetadataList': { 'paths': [ 'Patient.birthDate', 'Patient.address.period.start' ], 'action': 'TRANSFORM' }, 'text': { 'transformations': { 'infoTypes': [ 'DATE' ], 'dateShiftConfig': { 'cryptoKey': 'U2FsdGVkX19bS2oZsdbK9X5zi2utBn22uY+I2Vo0zOU=' } } } } }" "https://healthcare.googleapis.com/v1/projects/$PROJECT_ID/locations/$REGION/datasets/$SOURCE_DATASET_ID:deidentify"
Si la requête aboutit, le serveur affiche une réponse au format JSON comme suit :
{ "name": "projects/$PROJECT_ID/locations/$REGION/datasets/$SOURCE_DATASET_ID/OPERATION_NAME" }
Dans l'exemple ci-dessus, la commande
curl
anonymise la ressource FHIR en transformant les valeurs de plusieurs manières :- Elle masque la valeur
Patient.address.line
, la valeurPatient.address.text
et la valeurPatient.address.postalCode
. - Elle remplace les valeurs
Patient.name.family
etPatient.name.given
par des valeurs de hachage. - Elle remplace les valeurs des champs
Patient.birthDate
etperiod.start
par les valeurs générées par le changement de date avec un différentiel de 100 jours. - Dans le champ
Encounter.reason.text
, elle remplace le nom de famille du patient par une valeur de hachage et remplace l'âge du patient par la valeur littérale[AGE]
.
- Elle masque la valeur
La réponse à l'opération précédente contient un nom d'opération. Utilisez la méthode
get
pour suivre l'état de l'opération :curl -X GET \ -H "Authorization: Bearer "$(gcloud auth print-access-token) \ -H "Content-Type: application/json; charset=utf-8" \ "https://healthcare.googleapis.com/v1/projects/$PROJECT_ID/locations/$REGION/datasets/$SOURCE_DATASET_ID/operations/OPERATION_NAME"
Si la requête aboutit, le serveur affiche une réponse au format JSON. Une fois le processus d'anonymisation terminé, la réponse inclut
"done": true
.{ "name": "projects/$PROJECT_ID/locations/$REGION/datasets/$SOURCE_DATASET_ID/operations/OPERATION_NAME", "metadata": { "@type": "type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata", "apiMethodName": "google.cloud.healthcare.v1.dataset.DatasetService.DeidentifyDataset", "createTime": "2018-01-01T00:00:00Z", "endTime": "2018-01-01T00:00:00Z" }, "done": true, "response": { "@type": "...", "successStoreCount": "SUCCESS_STORE_COUNT" } }
La commande précédente renvoie l'état de l'opération d'anonymisation.
Utilisez l'identifiant du patient pour obtenir les détails de la ressource Patient FHIR dans le nouvel ensemble de données de destination en exécutant la commande suivante :
curl -X GET \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ "https://healthcare.googleapis.com/v1/projects/$PROJECT_ID/locations/$REGION/datasets/$DESTINATION_DATASET_ID/fhirStores/$FHIR_STORE_ID/fhir/Patient/a952e409-2403-43e6-9815-cb78c5b5eca2/\$everything"
Si la requête aboutit, le serveur renvoie une réponse semblable à la suivante, qui est la version anonymisée des ressources FHIR d'origine :
"entry": [\ {\ "resource": {\ "class": {\ "code": "IMP",\ "display": "inpatient encounter",\ "system": "http://hl7.org/fhir/v3/ActCode"\ },\ "id": "0038a95f-3c11-4163-8c2e-10842b6b1547",\ "reason": [\ {\ "text": "Mr. NlVBV12Hhb5DD8WNqlTpXboFxzlUSlqAmYDet/jIViQ= is a [AGE] gentleman who has a past medical history significant for a myocardial infarction. Catheterization showed a possible kink in one of his vessels."\ }\ ],\ "resourceType": "Encounter",\ "status": "finished",\ "subject": {\ "reference": "Patient/0359c226-5d63-4845-bd55-74063535e4ef"\ }\ }\ },\ {\ "resource": {\ "address": [\ {\ "city": "Anycity",\ "district": "Anydistrict",\ "line": [\ ""\ ],\ "period": {\ "start": "1990-09-23"\ },\ "postalCode": "",\ "state": "",\ "text": "",\ "use": "home"\ }\ ],\ "birthDate": "1980-09-23",\ "gender": "female",\ "id": "0359c226-5d63-4845-bd55-74063535e4ef",\ "name": [\ {\ "family": "NlVBV12Hhb5DD8WNqlTpXboFxzlUSlqAmYDet/jIViQ=",\ "given": [\ "FSH4e the project.D/IGb80a1rS0L0kqfC3DCDt6//17VPhIkOzH2pk="\ ],\ "use": "official"\ }\ ],\ "resourceType": "Patient"\ }\ }\ ],\ "resourceType": "Bundle",\ "total": 2,\ "type": "searchset"\ }
La commande précédente vérifie que l'opération d'anonymisation a réussi à anonymiser les ressources FHIR.
Nettoyer
Pour éviter que les ressources utilisées lors de ce tutoriel soient facturées sur votre compte Google Cloud, supprimez le projet contenant les ressources, ou conservez le projet et supprimez les ressources individuelles.
Supprimer le projet
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
Supprimer les ressources individuelles
Supprimez les ensembles de données de destination :
gcloud healthcare datasets delete $DESTINATION_DATASET_ID
Étape suivante
- Découvrez les concepts FHIR de l'API Cloud Healthcare.
- Importez des données cliniques FHIR dans le cloud à l'aide de l'API Cloud Healthcare.
- Anonymisez des données FHIR.
- Exportez des ressources FHIR vers BigQuery.
- Consultez la documentation sur l'API Cloud Healthcare.
- Découvrez notre API Cloud Healthcare et les autres solutions conçues pour accompagner les organisations du secteur de la santé et des sciences de la vie durant la pandémie.
- Découvrez des architectures de référence, des schémas et des bonnes pratiques concernant Google Cloud. Consultez notre Centre d'architecture cloud.