Cloud Storage를 사용하여 FHIR 리소스 가져오기 및 내보내기

이 페이지에서는 projects.locations.datasets.fhirStores.importprojects.locations.datasets.fhirStores.export 메서드를 사용하여 FHIR 리소스를 Cloud Storage로 내보내고 가져오는 방법을 설명합니다.

FHIR 데이터의 형식에 따라 FHIR 저장소에 데이터를 로드하려면 projects.locations.datasets.fhirStores.import 메서드 또는 projects.locations.datasets.fhirStores.fhir.executeBundle 메서드를 사용할 수 있습니다. 메서드 선택에 대한 안내는 FHIR 가져오기를 참조하세요.

Cloud Storage 권한 설정

FHIR 리소스를 Cloud Storage로 내보내고 가져오려면 먼저 Cloud Healthcare 서비스 에이전트 서비스 계정에 추가 권한을 부여해야 합니다. 자세한 내용은 FHIR 저장소 Cloud Storage 권한을 참조하세요.

시뮬레이션된 환자 데이터 생성

Synthea™은 환자 모집단 데이터를 생성하기 위한 시뮬레이터입니다. Synthea™를 사용하여 환자 모집단 데이터를 생성하지 않는 경우 FHIR 리소스 가져오기 또는 FHIR 리소스 내보내기로 건너뛰세요.

FHIR 저장소에 허용되도록 구성된 버전의 데이터만 가져올 수 있습니다.

Synthea™를 다운로드 및 설치하려면 다음 단계를 완료합니다.

  1. GitHub에서 Synthea™ 도구 저장소를 복제합니다.

    git clone https://github.com/synthetichealth/synthea.git
    
  2. 설치 단계를 완료합니다.

다음 섹션 중 하나로 계속 진행하여 특정 FHIR 버전의 데이터를 생성합니다.

R4의 시뮬레이션된 환자 데이터 생성

기본적으로 생성된 Synthea™ 데이터는 리소스에 FHIR R4 JSON 표현을 사용합니다. Synthea™ FHIR R4 데이터를 생성하여 Cloud Healthcare API FHIR 저장소로 가져오려면 다음 단계를 따르세요.

  1. 안내에 따라 합성 환자 데이터를 생성합니다. 생성된 데이터는 FHIR R4의 synthea/output/fhir_r4로 출력됩니다.

  2. 생성된 데이터를 Cloud Healthcare API FHIR 저장소로 가져올 수 있도록 Cloud Storage 버킷에 복사합니다. 예를 들어 기존 Cloud Storage 버킷의 synthea-data 디렉터리에 데이터를 복사하려면 synthea 디렉터리에서 다음 gcloud storage cp 명령어를 실행하세요.

    gcloud storage cp output/fhir_r4/* gs://BUCKET/synthea-data
    
  3. FHIR 리소스 가져오기 안내를 따릅니다.

DSTU2 또는 STU3의 시뮬레이션된 환자 데이터 생성

Synthea™ FHIR DSTU2 또는 STU3 데이터를 생성하여 Cloud Healthcare API FHIR 저장소로 가져오려면 다음 단계를 따르세요.

  1. synthea 디렉터리에서 텍스트 편집기를 사용하여 src/main/resources/synthea.properties 파일을 연 다음, DSTU2 또는 STU3 데이터를 생성하는지 여부에 따라 다음과 같이 변경합니다.

    FHIR STU3 데이터를 생성하려면 다음 안내를 따르세요.

    • 모든 *.fhir.export*.fhir_dstu2.export 값을 false로 설정합니다.
    • 모든 *.fhir_stu3.export 값을 true로 설정합니다.

    FHIR DSTU2 데이터를 생성하려면 다음 안내를 따르세요.

    • 모든 *.fhir.export*.fhir_stu3.export 값을 false로 설정합니다.
    • 모든 *.fhir_dstu2.export 값을 true로 설정합니다.

    예를 들어 FHIR STU3 데이터를 생성하려면 다음 안내를 따르세요.

    exporter.fhir.export = false
    exporter.fhir_stu3.export = true
    exporter.fhir_dstu2.export = false
    
    exporter.hospital.fhir.export = false
    exporter.hospital.fhir_stu3.export = true
    exporter.hospital.fhir_dstu2.export = false
    
    exporter.practitioner.fhir.export = false
    exporter.practitioner.fhir_stu3.export = true
    exporter.practitioner.fhir_dstu2.export = false
    
  2. 안내에 따라 합성 환자 데이터를 생성합니다. 생성된 데이터는 FHIR STU3의 synthea/output/fhir_stu3 또는 FHIR DSTU2의 synthea/output/fhir_dstu2 디렉터리로 출력됩니다.

  3. 생성된 데이터를 Cloud Healthcare API FHIR 저장소로 가져올 수 있도록 Cloud Storage 버킷에 복사합니다. 예를 들어 기존 Cloud Storage 버킷의 synthea-data 디렉터리에 데이터를 복사하려면 synthea 디렉터리에서 다음 gcloud storage cp 명령어를 실행하세요.

    gcloud storage cp output/fhir_stu3/* gs://BUCKET/synthea-data
    
  4. FHIR 리소스 가져오기 안내를 따릅니다.

FHIR 리소스 가져오기

가져오기 요청 본문을 구성할 때 ContentStructure를 다음 값 중 하나로 설정합니다.

  • CONTENT_STRUCTURE_UNSPECIFIED
  • BUNDLE: 소스 파일에는 줄바꿈으로 구분된 하나 이상의 JSON(ndjson) 줄이 포함됩니다. 각 줄은 하나 이상의 리소스를 포함하는 번들입니다. ContentStructure를 지정하지 않으면 기본적으로 BUNDLE로 지정됩니다.
  • RESOURCE: 소스 파일에는 줄바꿈으로 구분된 하나 이상의 JSON(ndjson) 줄이 포함됩니다. 각 줄은 단일 리소스입니다.
  • BUNDLE_PRETTY: 전체 소스 파일은 하나의 JSON 번들입니다. JSON은 여러 줄을 포함할 수 있습니다.
  • RESOURCE_PRETTY: 전체 소스 파일은 하나의 JSON 리소스입니다. JSON은 여러 줄을 포함할 수 있습니다.

예를 들어 다음 콘텐츠가 포함된 resources.ndjson 파일을 가져오는 경우,

{"class":{"code":"IMP","display":"inpatient encounter","system":"http://hl7.org/fhir/v3/ActCode"},"id":"6090e773-3e91-40a7-8fce-1e22f6774c29","reason":[{"text":"The patient had an abnormal heart rate. She was concerned about this."}],"resourceType":"Encounter","status":"finished","subject":{"reference":"Patient/2938bb9e-1f16-429e-8d44-9508ab0e4151"}}
{"class":{"code":"IMP","display":"inpatient encounter","system":"http://hl7.org/fhir/v3/ActCode"},"id":"7101f884-4f02-51b8-9gdf-2f33g7885d30","reason":[{"text":"The patient was experiencing recurrent fevers."}],"resourceType":"Encounter","status":"finished","subject":{"reference":"Patient/3049cc0f-2g27-530f-9e55-0619bc1f5262"}}
{"birthDate":"1970-01-01","gender":"female","id":"2938bb9e-1f16-429e-8d44-9508ab0e4151","name":[{"family":"Smith","given":["Darcy"],"use":"official"}],"resourceType":"Patient"}

파일에는 2개의 Encounter 리소스와 1개의 환자 리소스가 포함됩니다. 각 리소스는 별도의 줄에 있으므로 ContentStructureRESOURCE로 설정합니다.

ContentStructure가 데이터 형식과 일치하지 않으면 데이터를 잘못 가져오거나 전혀 가져올 수 없습니다. 예를 들어 위의 샘플 파일은 가져오기 요청에서 ContentStructureRESOURCE로 설정되지 않으면 올바르게 가져오지 않습니다.

다음 샘플은 Cloud Storage 버킷에서 FHIR 리소스를 가져오는 방법을 보여줍니다.

Console

Cloud Storage 버킷에서 FHIR 리소스를 가져오려면 다음 단계를 완료하세요.

  1. Google Cloud 콘솔에서 데이터 세트 페이지로 이동합니다.
    데이터 세트로 이동
  2. FHIR 리소스를 가져올 FHIR 저장소가 포함된 데이터 세트를 클릭합니다.
  3. 데이터 저장소 목록에서 FHIR 저장소의 작업 목록에서 가져오기를 선택합니다.

    FHIR 저장소로 가져오기 페이지가 나타납니다.
  4. 프로젝트 목록에서 Cloud Storage 프로젝트를 선택합니다.
  5. 위치 목록에서 Cloud Storage 버킷을 선택합니다.
  6. FHIR 가져오기 설정에서 관련 콘텐츠 구조를 선택합니다.
  7. 가져오기를 클릭하여 FHIR 리소스를 가져옵니다.
  8. 작업 상태를 추적하려면 작업 탭을 클릭합니다. 작업이 완료되면 다음과 같은 표시가 나타납니다.
    • 장기 실행 작업 상태 섹션의 확인 제목 아래에 녹색 체크표시가 있습니다.
    • 개요 섹션에 작업 ID와 같은 행에 녹색 체크표시와 확인 표시기가 있습니다.
    오류가 발생하면 작업을 클릭한 다음 Cloud Logging에서 세부정보 보기를 클릭합니다.

gcloud

FHIR 리소스를 FHIR 저장소로 가져오려면 gcloud healthcare fhir-stores import gcs 명령어를 사용합니다. 다음 정보를 지정합니다.

  • 상위 데이터 세트의 이름
  • FHIR 저장소의 이름
  • Cloud Storage 버킷에 있는 객체의 위치입니다. 버킷 내의 파일 위치는 임의적이며 다음 샘플에 지정된 형식을 정확하게 준수할 필요가 없습니다. Cloud Storage에서 FHIR 리소스를 지정할 때는 와일드 카드를 사용해서 하나 이상의 디렉터리에 있는 여러 파일을 가져올 수 있습니다. 다음 와일드 카드가 지원됩니다.
    • 구분 기호가 아닌 0자 이상의 일치하는 문자를 찾으려면 *를 사용합니다. 예를 들어 gs://BUCKET/DIRECTORY/Example*.ndjsonDIRECTORY의 Example.ndjson과 Example22 항목과 일치합니다.
    • 0자 이상의 일치하는 문자(구분 기호 포함)를 찾으려면 **를 사용합니다. 경로의 끝에 사용해야 하며 경로에 다른 와일드 카드가 없어야 합니다. 또한 지정된 디렉터리 및 하위 디렉터리에서 파일 이름 확장자가 있는 모든 파일을 가져오는 파일 이름 확장자 (예 : .ndjson)와 함께 사용할 수 있습니다. 예를 들어 gs://BUCKET/DIRECTORY/**.ndjsonDIRECTORY 및 하위 디렉터리에 파일명 확장자가 .ndjson인 파일을 모두 가져옵니다.
    • 일치하는 1개 문자를 찾으려면 ?를 사용합니다. 예를 들어 gs://BUCKET/DIRECTORY/Example?.ndjson는 Example1.ndjson과 일치하지만 Example.ndjson 또는 Example01.ndjson과 일치하지 않습니다.

다음 샘플은 gcloud healthcare fhir-stores import gcs 명령어를 보여줍니다.

gcloud healthcare fhir-stores import gcs FHIR_STORE_ID \
  --dataset=DATASET_ID \
  --location=LOCATION \
  --gcs-uri=gs://BUCKET/DIRECTORY/FHIR_RESOURCE_NAME.ndjson

FHIR 소스 파일 구조를 지정하려면 --content-structure 플래그를 사용합니다.

명령줄에 작업 ID가 표시되고 작업이 완료되면 done가 표시됩니다.

Request issued for: [FHIR_STORE_ID]
Waiting for operation [OPERATION_ID] to complete...done.
name: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID

작업의 세부정보를 보려면 gcloud healthcare operations describe 명령어를 실행하여 응답에서 OPERATION_ID를 제공합니다.

gcloud healthcare operations describe OPERATION_ID \
  --dataset=DATASET_ID

응답에 done: true가 포함됩니다.

done: true
metadata:
'@type': type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata
apiMethodName: google.cloud.healthcare.v1.fhir.FhirService.ImportResources
createTime: 'CREATE_TIME'
endTime: 'END_TIME'
logsUrl: https://console.cloud.google.com/logs/query/CLOUD_LOGGING_URL,
counter:
  success: 'SUCCESS_COUNT' 
name: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID
response:
'@type': type.googleapis.com/google.cloud.healthcare.v1.fhir.rest.ImportResourcesResponse
fhirStore: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID

API

FHIR 리소스를 FHIR 저장소로 가져오려면 projects.locations.datasets.fhirStores.import 메서드를 사용합니다.

  • 버킷 내의 파일 위치는 임의적이며 다음 샘플에 지정된 형식을 정확히 준수할 필요가 없습니다.
  • Cloud Storage에서 FHIR 리소스를 지정할 때는 와일드 카드를 사용해서 하나 이상의 디렉터리에 있는 여러 파일을 가져올 수 있습니다. 다음 와일드 카드가 지원됩니다.
    • 구분 기호가 아닌 0자 이상의 일치하는 문자를 찾으려면 *를 사용합니다. 예를 들어 gs://BUCKET/DIRECTORY/Example*.ndjsonDIRECTORY의 Example.ndjson과 Example22 항목과 일치합니다.
    • 0자 이상의 일치하는 문자(구분 기호 포함)를 찾으려면 **를 사용합니다. 경로의 끝에 사용해야 하며 경로에 다른 와일드 카드가 없어야 합니다. 또한 지정된 디렉터리 및 하위 디렉터리에서 파일 이름 확장자가 있는 모든 파일을 가져오는 파일 이름 확장자 (예 : .ndjson)와 함께 사용할 수 있습니다. 예를 들어 gs://BUCKET/DIRECTORY/**.ndjsonDIRECTORY 및 하위 디렉터리에 파일명 확장자가 .ndjson인 파일을 모두 가져옵니다.
    • 일치하는 1개 문자를 찾으려면 ?를 사용합니다. 예를 들어 gs://BUCKET/DIRECTORY/Example?.ndjson는 Example1.ndjson과 일치하지만 Example.ndjson 또는 Example01.ndjson과 일치하지 않습니다.

curl

FHIR 리소스를 FHIR 저장소로 가져오려면 POST 요청을 수행하고 다음 정보를 지정합니다.

  • 상위 데이터 세트의 이름
  • FHIR 저장소의 이름
  • Cloud Storage 버킷에 있는 객체의 위치
  • 액세스 토큰

다음 샘플은 curl를 사용하여 POST 요청을 사용하여 단일 파일을 가져오는 방법을 보여줍니다.

curl -X POST \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    -H "Content-Type: application/json; charset=utf-8" \
    --data "{
      'contentStructure': 'CONTENT_STRUCTURE',
      'gcsSource': {
        'uri': 'gs://BUCKET/DIRECTORY/FHIR_RESOURCE_FILE'
      }
    }" "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID:import"

요청이 성공하면 서버가 JSON 형식으로 응답을 반환합니다.

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"
}

응답에 작업 이름이 포함됩니다. 작업 상태를 추적하려면 작업 get 메서드를 사용합니다.

curl -X GET \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"

요청이 성공하면 서버는 JSON 형식의 작업 상태가 포함된 응답을 반환합니다.

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata",
    "apiMethodName": "google.cloud.healthcare.v1.fhir.FhirService.ImportResources",
    "createTime": "CREATE_TIME",
    "endTime": "END_TIME",
    "logsUrl": "https://console.cloud.google.com/logs/query/CLOUD_LOGGING_URL",
    "counter": {
      "success": "SUCCESS_COUNT"
    }
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.fhir.rest.ImportResourcesResponse",
  }
}

PowerShell

FHIR 리소스를 FHIR 저장소로 가져오려면 POST 요청을 수행하고 다음 정보를 지정합니다.

  • 상위 데이터 세트의 이름
  • FHIR 저장소의 이름
  • Cloud Storage 버킷에 있는 객체의 위치
  • 액세스 토큰

다음 샘플은 Windows PowerShell을 사용한 POST 요청을 보여줍니다.

$cred = gcloud auth application-default print-access-token
$headers = @{ Authorization = "Bearer $cred" }

Invoke-WebRequest `
  -Method Post `
  -Headers $headers `
  -ContentType: "application/json; charset=utf-8" `
  -Body "{
    'contentStructure': 'CONTENT_STRUCTURE',
    'gcsSource': {
      'uri': 'gs://BUCKET/DIRECTORY/FHIR_RESOURCE_FILE'
    }
  }" `
  -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID:import" | Select-Object -Expand Content

요청이 성공하면 서버가 JSON 형식으로 응답을 반환합니다.

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"
}

응답에 작업 이름이 포함됩니다. 작업 상태를 추적하려면 작업 get 메서드를 사용합니다.

$cred = gcloud auth application-default print-access-token
$headers = @{ Authorization = "Bearer $cred" }

Invoke-WebRequest `
  -Method Get `
  -Headers $headers `
  -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID" | Select-Object -Expand Content

요청이 성공하면 서버는 JSON 형식의 작업 상태가 포함된 응답을 반환합니다.

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata",
    "apiMethodName": "google.cloud.healthcare.v1.fhir.FhirService.ImportResources",
    "createTime": "CREATE_TIME",
    "endTime": "END_TIME",
    "logsUrl": "https://console.cloud.google.com/logs/query/CLOUD_LOGGING_URL",
    "counter": {
      "success": "SUCCESS_COUNT"
    }
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.fhir.rest.ImportResourcesResponse",
  }
}

Go

import (
	"context"
	"fmt"
	"io"
	"time"

	healthcare "google.golang.org/api/healthcare/v1"
)

// importsFHIRResource imports an FHIR resource.
func importFHIRResource(w io.Writer, projectID, location, datasetID, fhirStoreID, gcsURI string) error {
	ctx := context.Background()

	healthcareService, err := healthcare.NewService(ctx)
	if err != nil {
		return fmt.Errorf("healthcare.NewService: %w", err)
	}

	storesService := healthcareService.Projects.Locations.Datasets.FhirStores

	name := fmt.Sprintf("projects/%s/locations/%s/datasets/%s/fhirStores/%s", projectID, location, datasetID, fhirStoreID)
	req := &healthcare.ImportResourcesRequest{
		ContentStructure: "RESOURCE",
		GcsSource: &healthcare.GoogleCloudHealthcareV1FhirGcsSource{
			Uri: gcsURI,
		},
	}

	op, err := storesService.Import(name, req).Do()
	if err != nil {
		return fmt.Errorf("Import: %w", err)
	}

	operationsService := healthcareService.Projects.Locations.Datasets.Operations
	ticker := time.NewTicker(1 * time.Second)
	defer ticker.Stop()
	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-ticker.C:
			newOp, err := operationsService.Get(op.Name).Do()
			if err != nil {
				return fmt.Errorf("operationsService.Get(%q): %v", op.Name, err)
			}
			if newOp.Done {
				if newOp.Error != nil {
					return fmt.Errorf("import operation %q completed with error: %s", op.Name, newOp.Error.Details)
				}
				return nil
			}
		}
	}
}

Java

import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.healthcare.v1.CloudHealthcare;
import com.google.api.services.healthcare.v1.CloudHealthcare.Projects.Locations.Datasets.FhirStores;
import com.google.api.services.healthcare.v1.CloudHealthcareScopes;
import com.google.api.services.healthcare.v1.model.GoogleCloudHealthcareV1FhirGcsSource;
import com.google.api.services.healthcare.v1.model.ImportResourcesRequest;
import com.google.api.services.healthcare.v1.model.Operation;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.IOException;
import java.util.Collections;

public class FhirStoreImport {
  private static final String FHIR_NAME = "projects/%s/locations/%s/datasets/%s/fhirStores/%s";
  private static final JsonFactory JSON_FACTORY = new GsonFactory();
  private static final NetHttpTransport HTTP_TRANSPORT = new NetHttpTransport();

  public static void fhirStoreImport(String fhirStoreName, String gcsUri) throws IOException {
    // String fhirStoreName =
    //    String.format(
    //        FHIR_NAME, "your-project-id", "your-region-id", "your-dataset-id", "your-fhir-id");
    // String gcsUri = "gs://your-bucket-id/path/to/destination/dir"

    // Initialize the client, which will be used to interact with the service.
    CloudHealthcare client = createClient();

    // Configure where the store should be imported from.
    GoogleCloudHealthcareV1FhirGcsSource gcsSource =
        new GoogleCloudHealthcareV1FhirGcsSource().setUri(gcsUri);
    ImportResourcesRequest importRequest = new ImportResourcesRequest().setGcsSource(gcsSource);

    // Create request and configure any parameters.
    FhirStores.CloudHealthcareImport request =
        client
            .projects()
            .locations()
            .datasets()
            .fhirStores()
            .healthcareImport(fhirStoreName, importRequest);

    // Execute the request, wait for the operation to complete, and process the results.
    try {
      Operation operation = request.execute();
      while (operation.getDone() == null || !operation.getDone()) {
        // Update the status of the operation with another request.
        Thread.sleep(500); // Pause for 500ms between requests.
        operation =
            client
                .projects()
                .locations()
                .datasets()
                .operations()
                .get(operation.getName())
                .execute();
      }
      System.out.println("FHIR store import complete: " + operation.getResponse());
    } catch (Exception ex) {
      System.out.printf("Error during request execution: %s", ex.toString());
      ex.printStackTrace(System.out);
    }
  }

  private static CloudHealthcare createClient() throws IOException {
    // Use Application Default Credentials (ADC) to authenticate the requests
    // For more information see https://cloud.google.com/docs/authentication/production
    GoogleCredentials credential =
        GoogleCredentials.getApplicationDefault()
            .createScoped(Collections.singleton(CloudHealthcareScopes.CLOUD_PLATFORM));

    // Create a HttpRequestInitializer, which will provide a baseline configuration to all requests.
    HttpRequestInitializer requestInitializer =
        request -> {
          new HttpCredentialsAdapter(credential).initialize(request);
          request.setConnectTimeout(60000); // 1 minute connect timeout
          request.setReadTimeout(60000); // 1 minute read timeout
        };

    // Build the client for interacting with the service.
    return new CloudHealthcare.Builder(HTTP_TRANSPORT, JSON_FACTORY, requestInitializer)
        .setApplicationName("your-application-name")
        .build();
  }
}

Node.js

const google = require('@googleapis/healthcare');
const healthcare = google.healthcare({
  version: 'v1',
  auth: new google.auth.GoogleAuth({
    scopes: ['https://www.googleapis.com/auth/cloud-platform'],
  }),
});
const sleep = ms => {
  return new Promise(resolve => setTimeout(resolve, ms));
};

const importFhirResources = async () => {
  // TODO(developer): uncomment these lines before running the sample
  // const cloudRegion = 'us-central1';
  // const projectId = 'adjective-noun-123';
  // const datasetId = 'my-dataset';
  // const fhirStoreId = 'my-fhir-store';
  // const gcsUri = 'my-bucket/my-directory/*.json'
  const name = `projects/${projectId}/locations/${cloudRegion}/datasets/${datasetId}/fhirStores/${fhirStoreId}`;
  const request = {
    name,
    resource: {
      contentStructure: 'RESOURCE',
      gcsSource: {
        uri: `gs://${gcsUri}`,
      },
    },
  };

  const operation =
    await healthcare.projects.locations.datasets.fhirStores.import(request);
  const operationName = operation.data.name;

  const operationRequest = {name: operationName};

  // Wait twenty seconds for the LRO to finish.
  await sleep(20000);

  // Check the LRO's status
  const operationStatus =
    await healthcare.projects.locations.datasets.operations.get(
      operationRequest
    );

  const success = operationStatus.data.metadata.counter.success;

  if (typeof success !== 'undefined') {
    console.log(
      `Import FHIR resources succeeded. ${success} resources imported.`
    );
  } else {
    console.log(
      'Imported FHIR resources failed. Details available in Cloud Logging at the following URL:\n',
      operationStatus.data.metadata.logsUrl
    );
  }
};

importFhirResources();

Python

def import_fhir_resources(project_id, location, dataset_id, fhir_store_id, gcs_uri):
    """Import resources into the FHIR store by copying them from the
    specified source.

    See https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/healthcare/api-client/v1/fhir
    before running the sample."""
    # Imports the Google API Discovery Service.
    from googleapiclient import discovery

    api_version = "v1"
    service_name = "healthcare"
    # Instantiates an authorized API client by discovering the Healthcare API
    # and using GOOGLE_APPLICATION_CREDENTIALS environment variable.
    client = discovery.build(service_name, api_version)

    # TODO(developer): Uncomment these lines and replace with your values.
    # project_id = 'my-project'  # replace with your GCP project ID
    # location = 'us-central1'  # replace with the parent dataset's location
    # dataset_id = 'my-dataset'  # replace with the parent dataset's ID
    # fhir_store_id = 'my-fhir-store'  # replace with the FHIR store ID
    # gcs_uri = 'my-bucket'  # replace with a Cloud Storage bucket
    fhir_store_parent = "projects/{}/locations/{}/datasets/{}".format(
        project_id, location, dataset_id
    )
    fhir_store_name = f"{fhir_store_parent}/fhirStores/{fhir_store_id}"

    body = {
        "contentStructure": "CONTENT_STRUCTURE_UNSPECIFIED",
        "gcsSource": {"uri": f"gs://{gcs_uri}"},
    }

    # Escape "import()" method keyword because "import"
    # is a reserved keyword in Python
    request = (
        client.projects()
        .locations()
        .datasets()
        .fhirStores()
        .import_(name=fhir_store_name, body=body)
    )

    response = request.execute()
    print(f"Imported FHIR resources: {gcs_uri}")

    return response

FHIR 리소스 내보내기

다음 샘플은 Cloud Storage 버킷으로 FHIR 리소스를 내보내는 방법을 보여줍니다. FHIR 저장소에서 FHIR 리소스를 내보낼 때는 FHIR 저장소에 있는 모든 리소스에 대해 내보내기가 수행됩니다.

내보내는 동안 Cloud Healthcare API가 FHIR 저장소에서 각 리소스 유형마다 파일을 하나씩 만듭니다. 파일 이름은 작업 ID와 리소스 유형으로 구성되며 밑줄로 구분됩니다. 각 파일은 줄바꿈으로 구분된 JSON으로 구성됩니다. 여기서 각 줄은 파일 이름의 리소스 유형에 해당하는 FHIR 리소스입니다. 예를 들어 여러 환자 레코드를 내보내는 경우 출력 파일은 1264567891234567_Patient와 비슷한 이름으로 호출되고 FHIR 저장소의 각 환자 리소스 행을 포함합니다.

Console

FHIR 리소스를 Cloud Storage로 내보내려면 다음 단계를 완료합니다.

  1. Google Cloud 콘솔에서 데이터 세트 페이지로 이동합니다.
    데이터 세트로 이동
  2. FHIR 리소스를 내보내려는 FHIR 저장소가 포함된 데이터 세트를 클릭합니다.
  3. 데이터 저장소 목록에서 FHIR 저장소의 작업 목록에서 내보내기를 선택합니다.

    FHIR 리소스 내보내기 페이지가 표시됩니다.
  4. Google Cloud Storage 버킷을 선택합니다.
  5. 프로젝트 목록에서 Cloud Storage 프로젝트를 선택합니다.
  6. 위치 목록에서 Cloud Storage 버킷을 선택합니다.
  7. 내보내기를 클릭하여 FHIR 리소스를 Cloud Storage의 정의된 위치로 내보냅니다.
  8. 작업 상태를 추적하려면 작업 탭을 클릭합니다. 작업이 완료되면 다음과 같은 표시가 나타납니다.
    • 장기 실행 작업 상태 섹션의 확인 제목 아래에 녹색 체크표시가 있습니다.
    • 개요 섹션에 작업 ID와 같은 행에 녹색 체크표시와 확인 표시기가 있습니다.
    오류가 발생하면 작업을 클릭한 다음 Cloud Logging에서 세부정보 보기를 클릭합니다.

gcloud

FHIR 리소스를 Cloud Storage 버킷으로 내보내려면 gcloud healthcare fhir-stores export gcs 명령어를 사용합니다. 다음 정보를 지정합니다.

  • 상위 데이터 세트의 이름
  • FHIR 저장소의 이름
  • 상위 프로젝트 이름
  • 대상 Cloud Storage 버킷 또는 디렉터리입니다. Cloud Healthcare API는 각 리소스 유형에 대해 하나의 객체를 생성하므로 객체가 아닌 Cloud Storage 버킷 또는 디렉터리에 기록합니다. 각 객체는 줄바꿈으로 구분된 JSON으로 구성되며 각 줄은 FHIR 리소스입니다. 존재하지 않는 디렉터리를 지정하면 생성됩니다.
  • 쉼표로 구분된 하나 이상의 FHIR 리소스 유형으로 정의된 특정 리소스 유형만 내보내는 선택적 플래그인 --resource-type
  • YYYY-MM-DDThh:mm:ss.sss+zz:zz로 정의된 특정 시간 이후에 업데이트된 리소스만 내보내는 선택적 플래그인 --since

다음 샘플은 gcloud healthcare fhir-stores export gcs 명령어를 보여줍니다.

gcloud healthcare fhir-stores export gcs FHIR_STORE_ID \
  --dataset=DATASET_ID \
  --location=LOCATION \
  --project=PROJECT_ID
  --gcs-uri=gs://BUCKET/DIRECTORY

명령줄에 작업 ID가 표시됩니다.

Waiting for operation [OPERATION_ID] to complete...done.
name: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID

작업 상태를 보려면 gcloud healthcare operations describe 명령어를 사용하고 응답의 OPERATION_ID를 제공합니다.

gcloud healthcare operations describe OPERATION_ID \
  --dataset=DATASET_ID

명령어가 완료되면 응답에 done가 포함됩니다.

metadata:
'@type': type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata
apiMethodName: google.cloud.healthcare.v1.fhir.FhirService.ExportFhirData
createTime: "CREATE_TIME"
endTime: "END_TIME"
name: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID
response:
'@type': type.googleapis.com/google.cloud.healthcare.v1.fhir.rest.ExportResourcesResponse
fhirStore: projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID
resourceCount: 'RESOURCE_COUNT'

API

FHIR 리소스를 내보내려면 projects.locations.datasets.fhirStores.export 메서드를 사용합니다.

  • Cloud Healthcare API는 각 리소스 유형에 대해 하나의 줄바꿈으로 구분된 JSON 파일을 생성하므로 객체가 아닌 Cloud Storage 버킷 또는 디렉터리에 기록합니다. 각 JSON 파일에서 각 줄은 FHIR 리소스입니다.
  • 명령어가 존재하지 않는 디렉터리를 지정하면 디렉터리가 생성됩니다.

curl

FHIR 리소스를 내보내려면 POST 요청을 수행하고 다음 정보를 지정합니다.

  • 상위 데이터 세트의 이름
  • FHIR 저장소의 이름
  • 대상 Cloud Storage 버킷입니다.
  • 액세스 토큰
  • 쉼표로 구분된 하나 이상의 FHIR 리소스 유형으로 정의된 특정 리소스 유형만 내보내는 선택적 필드인 _type
  • YYYY-MM-DDThh:mm:ss.sss+zz:zz로 정의된 특정 시간 이후에 업데이트된 리소스만 내보내는 선택적 필드인 _since

다음 샘플은 curl을 사용하는 POST 요청을 보여줍니다.

curl -X POST \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    -H "Content-Type: application/json; charset=utf-8" \
    --data "{
      'gcsDestination': {
        'uriPrefix': 'gs://BUCKET/DIRECTORY'
      },
    }" "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID:export"

요청이 성공하면 서버가 JSON 형식으로 응답을 반환합니다.

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"
}

응답에 작업 이름이 포함됩니다. 작업 상태를 추적하려면 작업 get 메서드를 사용합니다.

curl -X GET \
    -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
    "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"

요청이 성공하면 서버는 JSON 형식의 작업 상태가 포함된 응답을 반환합니다.

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata",
    "apiMethodName": "google.cloud.healthcare.v1.fhir.FhirService.ExportResources",
    "createTime": "CREATE_TIME",
    "endTime": "END_TIME",
    "logsUrl": "https://console.cloud.google.com/logs/query/CLOUD_LOGGING_URL",
    "counter": {
      "success": "SUCCESS_COUNT"
    }
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.fhir.rest.ExportResourcesResponse",
  }
}

PowerShell

FHIR 리소스를 내보내려면 POST 요청을 수행하고 다음 정보를 지정합니다.

  • 상위 데이터 세트의 이름
  • FHIR 저장소의 이름
  • 대상 Cloud Storage 버킷 또는 디렉터리입니다. Cloud Healthcare API는 각 리소스 유형에 대해 하나의 객체를 생성하므로 객체가 아닌 Cloud Storage 버킷 또는 디렉터리에 기록합니다. 각 객체는 줄바꿈으로 구분된 JSON으로 구성되며 각 줄은 FHIR 리소스입니다.
  • 액세스 토큰
  • 쉼표로 구분된 하나 이상의 FHIR 리소스 유형으로 정의된 특정 리소스 유형만 내보내는 선택적 필드인 _type
  • YYYY-MM-DDThh:mm:ss.sss+zz:zz로 정의된 특정 시간 이후에 업데이트된 리소스만 내보내는 선택적 필드인 _since

다음 샘플은 Windows PowerShell을 사용한 POST 요청을 보여줍니다.

$cred = gcloud auth application-default print-access-token
$headers = @{ Authorization = "Bearer $cred" }

Invoke-WebRequest `
  -Method Post `
  -Headers $headers `
  -ContentType: "application/json; charset=utf-8" `
  -Body "{
    'gcsDestination': {
      'uriPrefix': 'gs://BUCKET/DIRECTORY'
    },
  }" `
  -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/fhirStores/FHIR_STORE_ID:export" | Select-Object -Expand Content

요청이 성공하면 서버가 JSON 형식으로 응답을 반환합니다.

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID"
}

응답에 작업 이름이 포함됩니다. 작업 상태를 추적하려면 작업 get 메서드를 사용합니다.

$cred = gcloud auth application-default print-access-token
$headers = @{ Authorization = "Bearer $cred" }

Invoke-WebRequest `
  -Method Get `
  -Headers $headers `
  -Uri "https://healthcare.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID" | Select-Object -Expand Content

요청이 성공하면 서버는 JSON 형식의 작업 상태가 포함된 응답을 반환합니다.

{
  "name": "projects/PROJECT_ID/locations/LOCATION/datasets/DATASET_ID/operations/OPERATION_ID",
  "metadata": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.OperationMetadata",
    "apiMethodName": "google.cloud.healthcare.v1.fhir.FhirService.ExportResources",
    "createTime": "CREATE_TIME",
    "endTime": "END_TIME",
    "logsUrl": "https://console.cloud.google.com/logs/query/CLOUD_LOGGING_URL",
    "counter": {
      "success": "SUCCESS_COUNT"
    }
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.cloud.healthcare.v1.fhir.rest.ExportResourcesResponse",
  }
}

Go

import (
	"context"
	"fmt"
	"io"
	"time"

	healthcare "google.golang.org/api/healthcare/v1"
)

// exportFHIRResource exports the resources in the FHIR store.
func exportFHIRResource(w io.Writer, projectID, location, datasetID, fhirStoreID, gcsURIPrefix string) error {
	ctx := context.Background()

	healthcareService, err := healthcare.NewService(ctx)
	if err != nil {
		return fmt.Errorf("healthcare.NewService: %w", err)
	}

	storesService := healthcareService.Projects.Locations.Datasets.FhirStores

	name := fmt.Sprintf("projects/%s/locations/%s/datasets/%s/fhirStores/%s", projectID, location, datasetID, fhirStoreID)
	req := &healthcare.ExportResourcesRequest{
		GcsDestination: &healthcare.GoogleCloudHealthcareV1FhirGcsDestination{
			UriPrefix: gcsURIPrefix,
		},
	}

	op, err := storesService.Export(name, req).Do()
	if err != nil {
		return fmt.Errorf("Export: %w", err)
	}

	operationsService := healthcareService.Projects.Locations.Datasets.Operations
	ticker := time.NewTicker(1 * time.Second)
	defer ticker.Stop()
	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-ticker.C:
			newOp, err := operationsService.Get(op.Name).Do()
			if err != nil {
				return fmt.Errorf("operationsService.Get(%q): %v", op.Name, err)
			}
			if newOp.Done {
				if newOp.Error != nil {
					return fmt.Errorf("export operation %q completed with error: %v", op.Name, newOp.Error)
				}
				return nil
			}
		}
	}
}

Java

import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.healthcare.v1.CloudHealthcare;
import com.google.api.services.healthcare.v1.CloudHealthcare.Projects.Locations.Datasets.FhirStores;
import com.google.api.services.healthcare.v1.CloudHealthcareScopes;
import com.google.api.services.healthcare.v1.model.ExportResourcesRequest;
import com.google.api.services.healthcare.v1.model.GoogleCloudHealthcareV1FhirGcsDestination;
import com.google.api.services.healthcare.v1.model.Operation;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.IOException;
import java.util.Collections;

public class FhirStoreExport {
  private static final String FHIR_NAME = "projects/%s/locations/%s/datasets/%s/fhirStores/%s";
  private static final JsonFactory JSON_FACTORY = new GsonFactory();
  private static final NetHttpTransport HTTP_TRANSPORT = new NetHttpTransport();

  public static void fhirStoreExport(String fhirStoreName, String gcsUri) throws IOException {
    // String fhirStoreName =
    //    String.format(
    //        FHIR_NAME, "your-project-id", "your-region-id", "your-dataset-id", "your-fhir-id");
    // String gcsUri = "gs://your-bucket-id/path/to/destination/dir"

    // Initialize the client, which will be used to interact with the service.
    CloudHealthcare client = createClient();

    // Configure where the store will be exported too.
    GoogleCloudHealthcareV1FhirGcsDestination gcsDestination =
        new GoogleCloudHealthcareV1FhirGcsDestination().setUriPrefix(gcsUri);
    ExportResourcesRequest exportRequest =
        new ExportResourcesRequest().setGcsDestination(gcsDestination);

    // Create request and configure any parameters.
    FhirStores.Export request =
        client.projects().locations().datasets().fhirStores().export(fhirStoreName, exportRequest);

    // Execute the request, wait for the operation to complete, and process the results.
    try {
      Operation operation = request.execute();
      while (operation.getDone() == null || !operation.getDone()) {
        // Update the status of the operation with another request.
        Thread.sleep(500); // Pause for 500ms between requests.
        operation =
            client
                .projects()
                .locations()
                .datasets()
                .operations()
                .get(operation.getName())
                .execute();
      }
      System.out.println("Fhir store export complete." + operation.getResponse());
    } catch (Exception ex) {
      System.out.printf("Error during request execution: %s", ex.toString());
      ex.printStackTrace(System.out);
    }
  }

  private static CloudHealthcare createClient() throws IOException {
    // Use Application Default Credentials (ADC) to authenticate the requests
    // For more information see https://cloud.google.com/docs/authentication/production
    GoogleCredentials credential =
        GoogleCredentials.getApplicationDefault()
            .createScoped(Collections.singleton(CloudHealthcareScopes.CLOUD_PLATFORM));

    // Create a HttpRequestInitializer, which will provide a baseline configuration to all requests.
    HttpRequestInitializer requestInitializer =
        request -> {
          new HttpCredentialsAdapter(credential).initialize(request);
          request.setConnectTimeout(60000); // 1 minute connect timeout
          request.setReadTimeout(60000); // 1 minute read timeout
        };

    // Build the client for interacting with the service.
    return new CloudHealthcare.Builder(HTTP_TRANSPORT, JSON_FACTORY, requestInitializer)
        .setApplicationName("your-application-name")
        .build();
  }
}

Node.js

const google = require('@googleapis/healthcare');
const healthcare = google.healthcare({
  version: 'v1',
  auth: new google.auth.GoogleAuth({
    scopes: ['https://www.googleapis.com/auth/cloud-platform'],
  }),
});
const sleep = ms => {
  return new Promise(resolve => setTimeout(resolve, ms));
};

const exportFhirResourcesGcs = async () => {
  // TODO(developer): uncomment these lines before running the sample
  // const cloudRegion = 'us-central1';
  // const projectId = 'adjective-noun-123';
  // const datasetId = 'my-dataset';
  // const fhirStoreId = 'my-fhir-store';
  // const gcsUri = 'my-bucket/my-directory'
  const name = `projects/${projectId}/locations/${cloudRegion}/datasets/${datasetId}/fhirStores/${fhirStoreId}`;
  const request = {
    name,
    resource: {
      gcsDestination: {
        // The destination location in Cloud Storage for the FHIR resources
        uriPrefix: `gs://${gcsUri}`,
      },
    },
  };

  const operation =
    await healthcare.projects.locations.datasets.fhirStores.export(request);
  const operationName = operation.data.name;

  // Wait ten seconds for the LRO to finish
  await sleep(10000);

  // Check the LRO's status
  const operationStatus =
    await healthcare.projects.locations.datasets.operations.get({
      name: operationName,
    });

  if (typeof operationStatus.data.metadata.counter !== 'undefined') {
    console.log('Exported FHIR resources successfully');
  } else {
    console.log('Export failed');
  }
};

exportFhirResourcesGcs();

Python

def export_fhir_store_gcs(project_id, location, dataset_id, fhir_store_id, gcs_uri):
    """Export resources to a Google Cloud Storage bucket by copying
    them from the FHIR store.

    See https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/healthcare/api-client/v1/fhir
    before running the sample."""
    # Imports the Google API Discovery Service.
    from googleapiclient import discovery

    api_version = "v1"
    service_name = "healthcare"
    # Instantiates an authorized API client by discovering the Healthcare API
    # and using GOOGLE_APPLICATION_CREDENTIALS environment variable.
    client = discovery.build(service_name, api_version)

    # TODO(developer): Uncomment these lines and replace with your values.
    # project_id = 'my-project'  # replace with your GCP project ID
    # location = 'us-central1'  # replace with the parent dataset's location
    # dataset_id = 'my-dataset'  # replace with the parent dataset's ID
    # fhir_store_id = 'my-fhir-store' # replace with the FHIR store ID
    # gcs_uri = 'my-bucket' # replace with a Cloud Storage bucket
    fhir_store_parent = "projects/{}/locations/{}/datasets/{}".format(
        project_id, location, dataset_id
    )
    fhir_store_name = f"{fhir_store_parent}/fhirStores/{fhir_store_id}"

    body = {"gcsDestination": {"uriPrefix": f"gs://{gcs_uri}/fhir_export"}}

    request = (
        client.projects()
        .locations()
        .datasets()
        .fhirStores()
        .export(name=fhir_store_name, body=body)
    )

    response = request.execute()
    print(f"Exported FHIR resources to bucket: gs://{gcs_uri}")

    return response

FHIR 가져오기 및 내보내기 요청 문제 해결

FHIR 가져오기 또는 내보내기 요청 중에 오류가 발생하면 오류가 Cloud Logging에 기록됩니다. 자세한 내용은 Cloud Logging에서 오류 로그 보기를 참조하세요.

전체 작업이 오류를 반환하는 경우 장기 실행 작업 문제 해결을 참조하세요.

다음 단계