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 권한을 참조하세요.

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

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

기본적으로 생성된 Synthea™ 데이터는 리소스에 FHIR R4 JSON 표현을 사용합니다.

FHIR 저장소에 허용되도록 구성된 버전의 데이터만 가져올 수 있습니다. FHIR STU3 또는 DSTU2 저장소로 가져올 수 있도록 Synthea™ FHIR STU3 또는 FHIR DSTU2 데이터를 생성하려면 다음 단계를 완료합니다.

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

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

  3. synthea 디렉터리에서 텍스트 편집기를 사용하여 src/main/resources/synthea.properties 파일을 열고 다음 항목을 변경합니다.

    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
    
  4. 안내에 따라 합성 환자 데이터를 생성합니다. 생성된 데이터는 FHIR STU3의 synthea/output/fhir_stu3 또는 FHIR DSTU2의 synthea/output/fhir_dstu2 디렉터리로 출력됩니다.

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

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

FHIR 리소스 가져오기

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

  • CONTENT_STRUCTURE_UNSPECIFIED
  • BUNDLE: 소스 파일에는 줄바꿈으로 구분된 하나 이상의 JSON(ndjson) 줄이 포함됩니다. 각 줄은 하나 이상의 리소스를 포함하는 번들입니다. 리소스 버전을 가져오려면 번들 유형을 history로 설정합니다. 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 리소스를 가져오는 방법을 보여줍니다.

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 \
  [--content-structure=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'
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/viewer/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/viewer/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: %v", 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: %v", 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
			}
		}
	}
}

자바

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.jackson2.JacksonFactory;
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 JacksonFactory();
  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');
const healthcare = google.healthcare('v1');
const sleep = require('../sleep');

const importFhirResources = async () => {
  const auth = await google.auth.getClient({
    scopes: ['https://www.googleapis.com/auth/cloud-platform'],
  });
  google.options({auth});

  // 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, cloud_region, dataset_id, fhir_store_id, gcs_uri):
    """Import resources into the FHIR store by copying them from the
    specified source.
    """
    client = get_client()
    fhir_store_parent = "projects/{}/locations/{}/datasets/{}".format(
        project_id, cloud_region, dataset_id
    )
    fhir_store_name = "{}/fhirStores/{}".format(fhir_store_parent, fhir_store_id)

    body = {
        "contentStructure": "CONTENT_STRUCTURE_UNSPECIFIED",
        "gcsSource": {"uri": "gs://{}".format(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("Imported FHIR resources: {}".format(gcs_uri))

    return response

FHIR 리소스 내보내기

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

내보내기 중에는 Cloud Healthcare API가 각 리소스 유형에 대해 하나의 객체를 만듭니다. 각 객체는 각 줄이 FHIR 리소스인 줄바꿈으로 구분된 JSON 파일로 구성됩니다. 파일 이름에는 리소스 유형이 포함됩니다(예: 1264567891234567_Patient.ndjson).

gcloud

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

  • 상위 데이터세트의 이름
  • FHIR 저장소의 이름
  • 대상 Cloud Storage 버킷 또는 디렉터리입니다. Cloud Healthcare API는 각 리소스 유형에 대해 하나의 객체를 생성하므로 객체가 아닌 Cloud Storage 버킷 또는 디렉터리에 기록합니다. 각 객체는 줄바꿈으로 구분된 JSON으로 구성되며 각 줄은 FHIR 리소스입니다. 존재하지 않는 디렉터리를 지정하면 생성됩니다.

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

gcloud healthcare fhir-stores export gcs FHIR_STORE_ID \
  --dataset=DATASET_ID \
  --location=LOCATION \
  --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 버킷입니다.
  • 액세스 토큰

다음 샘플은 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/viewer/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 버킷 또는 디렉터리에 기록합니다. 각 객체는 newline-delimited JSON으로 구성되며 각 줄은 FHIR 리소스입니다.
  • 액세스 토큰

다음 샘플은 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/viewer/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: %v", 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: %v", 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
			}
		}
	}
}

자바

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.jackson2.JacksonFactory;
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 JacksonFactory();
  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');
const healthcare = google.healthcare('v1');
const sleep = require('../sleep');

const exportFhirResourcesGcs = async () => {
  const auth = await google.auth.getClient({
    scopes: ['https://www.googleapis.com/auth/cloud-platform'],
  });
  google.options({auth});

  // 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, cloud_region, dataset_id, fhir_store_id, gcs_uri):
    """Export resources to a Google Cloud Storage bucket by copying
    them from the FHIR store."""
    client = get_client()
    fhir_store_parent = "projects/{}/locations/{}/datasets/{}".format(
        project_id, cloud_region, dataset_id
    )
    fhir_store_name = "{}/fhirStores/{}".format(fhir_store_parent, fhir_store_id)

    body = {"gcsDestination": {"uriPrefix": "gs://{}/fhir_export".format(gcs_uri)}}

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

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

    return response

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

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