使用 Cloud Storage 导入和导出 FHIR 资源

本页面介绍如何使用 projects.locations.datasets.fhirStores.importprojects.locations.datasets.fhirStores.export 方法将 FHIR 资源导出和导入 Cloud Storage。

根据 FHIR 数据的格式,您可以使用 projects.locations.datasets.fhirStores.import 方法或 projects.locations.datasets.fhirStores.fhir.executeBundle 方法将数据加载到 FHIR 存储区。有关选择方法的指导,请参阅 FHIR 导入

设置 Cloud Storage 权限

在将 FHIR 资源导出到 Cloud Storage 以及从 Cloud Storage 导入 FHIR 资源之前,您必须向 Cloud Healthcare Service Agent 服务帐号授予其他权限。如需了解详情,请参阅 FHIR 存储 Cloud Storage 权限

为 DSTU2 或 STU3 生成模拟患者数据

Synthea™ 是用于生成患者群体数据的模拟器。如果您未使用合成器,请跳至导入 FHIR 资源导出 FHIR 资源

默认情况下,生成的合成数据会使用 FHIR R4 JSON 表示法表示。

您只能导入 FHIR 存储空间配置为接受的版本中的数据。要生成 Synthea™FHIR STU3 或 FHIR DSTU2 数据,以便您可以将其导入 FHIR STU3 或 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 Storage 存储分区,以便您可以将其导入 Cloud Healthcare API FHIR 存储区。例如,要将数据复制到现有 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"}

该文件包含两个 Encounter 资源和一个患者资源。每个资源都在单独的行上,因此您将 ContentStructure 设置为 RESOURCE

如果 ContentStructure 与您的数据格式不匹配,您的数据可能会导入不正确或根本无法导入。例如,除非在导入请求中将 ContentStructure 设置为 RESOURCE,否则上述示例文件无法正确导入。

以下示例展示了如何从 Cloud Storage 存储分区导入 FHIR 资源。

gcloud

要将 FHIR 资源导入 FHIR 存储区,请使用 gcloud healthcare fhir-stores import gcs 命令。请指定以下信息:

  • 父数据集的名称
  • FHIR 存储区的名称
  • 对象在 Cloud Storage 存储分区中的位置。文件在存储分区中的位置是任意的,无需严格遵循以下示例中指定的格式。在 Cloud Storage 中指定 FHIR 资源的位置时,您可以使用通配符从一个或多个目录导入多个文件。支持以下通配符:
    • 使用 * 可以匹配零个或更多的非分隔符字符。例如,gs://BUCKET/DIRECTORY/Example*.ndjson 匹配 DIRECTORY 中的 example.ndjson 和 example22.ndjson。
    • 使用 ** 匹配 0 个或多个字符(包括分隔符)。必须在路径末尾使用,且路径中没有其他通配符。也可以与扩展名(如.ndjson)一起使用,该扩展名会导入指定目录及其子目录中扩展名中的所有文件。例如,gs://BUCKET/DIRECTORY/**.ndjson 会导入 DIRECTORY 及其子目录中扩展名为.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 资源的位置时,您可以使用通配符从一个或多个目录导入多个文件。支持以下通配符:
    • 使用 * 可以匹配零个或更多的非分隔符字符。例如,gs://BUCKET/DIRECTORY/Example*.ndjson 匹配 DIRECTORY 中的 example.ndjson 和 example22.ndjson。
    • 使用 ** 匹配 0 个或多个字符(包括分隔符)。必须在路径末尾使用,且路径中没有其他通配符。也可以与扩展名(如.ndjson)一起使用,该扩展名会导入指定目录及其子目录中扩展名中的所有文件。例如,gs://BUCKET/DIRECTORY/**.ndjson 会导入 DIRECTORY 及其子目录中扩展名为.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"
}

响应包含操作名称。要跟踪操作的状态,您可以使用 Operation 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"
}

响应包含操作名称。要跟踪操作的状态,您可以使用 Operation 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
			}
		}
	}
}

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.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 资源

以下示例展示了如何将 FHIR 资源导出到 Cloud Storage 存储分区。从 FHIR 存储区导出 FHIR 资源时,系统会导出 FHIR 存储区中的所有资源。

在导出期间,Cloud Healthcare API 会为每个资源类型创建一个对象。每个对象都包含一个换行符分隔的 JSON 文件,其中每行都是一个 FHIR 资源。文件名包含资源类型,例如 1264567891234567_Patient.ndjson

gcloud

要将 FHIR 实例导出到 Cloud Storage 存储分区,请使用 gcloud healthcare fhir-stores export gcs 命令。请指定以下信息:

  • 父数据集的名称
  • FHIR 存储区的名称
  • 目标 Cloud Storage 存储分区或目录。写入 Cloud Storage 存储分区或目录(而不是对象),因为 Cloud Healthcare API 会为每个资源类型创建一个对象。每个对象都包含换行符分隔的 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 Storage 存储分区或目录(而非对象),因为 Cloud Healthcare API 会为每个资源类型创建一个以换行符分隔的 JSON 文件。在每个 JSON 文件中,每行都是一个 FHIR 资源。
  • 如果该命令指定的目录不存在,则会创建该目录。

curl

要导出 FHIR 资源,请发出 POST 请求并指定以下信息:

  • 父数据集的名称
  • FHIR 存储区的名称
  • 目标 Cloud Storage 存储分区
  • 访问令牌

以下示例展示了使用 curlPOST 请求。

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"
}

响应包含操作名称。要跟踪操作的状态,您可以使用 Operation 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 Storage 存储分区或目录(而不是对象),因为 Cloud Healthcare API 会为每个资源类型创建一个对象。每个对象都包含换行符分隔的 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"
}

响应包含操作名称。要跟踪操作的状态,您可以使用 Operation 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
			}
		}
	}
}

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.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 中查看错误日志