如何从AppEngine PHP应用程序将数据从云存储加载到云数据存储?

时间:2018-06-17 14:43:28

标签: google-app-engine google-cloud-datastore datastore

我一直在寻找各种来源,但这个neewbie还不清楚。如何从AppEngine PHP应用程序将数据(CSV文件)从云存储加载到云数据存储?我有一个现有的方法,下载文件,然后将每一行作为一个事务加载。几百万行需要几个小时,所以这似乎不是最好的方法,并且一直在寻找更有效的方法。我很感激任何指导。

编辑此内容,因为我已切换到尝试使用远程URL从中将GASON数据从GAE加载到数据存储区。代码不起作用虽然我不知道为什么(还):

<?php

require 'vendor/autoload.php';
use Google\Auth\ApplicationDefaultCredentials;
use Google\Cloud\Datastore\DatastoreClient;

/**
 * Create a new product with a given SKU.
 *
 * @param DatastoreClient $datastore
 * @param $sku
 * @param $product
 * @return Google\Cloud\Datastore\Entity
 */
function add_product(DatastoreClient $datastore, $sku, $product)
{
    $productKey = $datastore->key('SKU', $sku);
    $product = $datastore->entity(
        $productKey,
        [
            'created' => new DateTime(),
            'name' => strtolower($product)
        ]);
    $datastore->upsert($product);
    return $product;
}

/*
  Load Cloud DataStore Kind from remote URL

  @param $projectId
  @param $url
*/
function load_datastore($projectId, $url) {
  // Create Datastore client
  $datastore = new DatastoreClient(['projectId' => $projectId]);

  // Enable `allow_url_fopen` to allow reading file from URL
  ini_set("allow_url_fopen", 1);

  // Read the products listing and load to Cloud Datastore.
  // Use batches of 20 for a transaction
  $json = json_decode(file_get_contents($url), true);
  $count = 1;
  foreach($json as $sku_key => $product_val) {
    if ($count == 1) {
          $transaction = $datastore->transaction();
    }
    add_product($datastore, $sku_key, $product_val);
        if ($count == 20) {
          $transaction->commit();
          $count = 0;
        } catch (Exception $err) {
        echo 'Caught exception: ',  $err->getMessage(), "\n";
      $transaction->rollback();
    }
    $count++;
  }
}

try
{
    $projectId = 'development';
    $url = 'https://raw.githubusercontent.com/BestBuyAPIs/open-data-set/master/products.json';
    load_datastore($projectId, $url);
} catch (Exception $err) {
    echo 'Caught exception: ',  $err->getMessage(), "\n";
  $transaction->rollback();
}
?>

3 个答案:

答案 0 :(得分:1)

Google提供了预先编写的数据流模板。您可以使用GCS到数据存储区数据流模板读取CSV,将CSV转换为数据存储区实体JSON,然后将结果写入数据存储区。

假设您的CSV如下:

username, first, last, age, location.zip, location.city, location.state
samsmith, Sam, Smith, 33, 94040, Mountain View, California
johndoe, John, Doe, 50, 30075, Roswell, Georgia
dannyboy, Danny, Mac, 94040, Mountain View, California

您可以使用以下UDF将此CSV转换为亲朋好友的数据存储实体。此UDF假定以下架构:

  • 用户名=键和字符串属性
  • first =字符串属性
  • 最后一个=字符串属性
  • 年龄=整数属性
  • 位置=记录
  • Location.Zip =整数属性
  • Location.City =字符串属性
  • Location.State =字符串属性

此UDF输出JSON编码的Entity。这与Cloud Datastore REST API使用的JSON有效负载相同。值可以为以下types

function myTransform(csvString) {
 var row = csvString.split(",");
 if (row.length != 4) { return; }

 return JSON.stringify({
   "key": {
     "partition_id": {
       // default namespace is an empty string
       "namespace_id": ""
     },
     "path": {
       "kind": "People",
       "name": row[0]
     }
   },
   "properties": {
     "username": { "stringValue": row[0] },
     "first": { "stringValue": row[1] },
     "last": { "stringValue": row[2] },
     "age": { "integerValue": row[3] },
     "location": { 
       "entityValue": {
         "properties": {
           "zip": { "integerValue": row[4] },
           "city": { "stringValue": row[5] },
           "state": { "stringValue": row[6] }
         }
       }
     } 
   }
 });
}

运行数据流模板。首先使用gsutil将UDF保存到GCS存储桶中。

gsutil cp my_csv_udf.js gs://mybucket/my_csv_udf.js

现在进入Google Cloud Platform Console。转到数据流页面。单击从模板创建作业,然后选择“ GCS文本到数据存储”。您也可以参考此doc

您的工作参数如下所示:

  • textReadPattern = gs://path/to/data/*.csv
  • javascriptTextTransformGcsPath = gs://mybucket/my_csv_udf.js
  • javascriptTextTransformFunctionName = myTransform
  • datastoreWriteProjectId = my-project-id
  • errorWritePath = gs:// path / to / data / errors

注意:UDF转换仅支持JavaScript ECMAScript 5.1。所以只有基本的javascript,没有精美的箭头功能/ promise ...等等。

答案 1 :(得分:0)

抱歉,我并没有更具体,但是我是python标准env GAE用户,相当不熟悉PHP环境。

通常,您当前的方法是序列化和同步的-您一次要处理一行(或者,如果事务中的所有upsert调用实际上都进入了数据存储区,则最多以20为批处理)一次),则每次数据存储区互动都将被阻止,并在互动完成后才前进到下一行。

我不确定PHP环境是否支持异步数据存储操作和/或真正的批处理操作(python ndb库最多可以将500个写操作批处理到一个数据存储调用中)-这些可以帮助加快处理速度。< / p>

如果行是完全独立的,则还需要考虑 -您实际上是否需要事务来编写它们?如果PHP支持纯文本格式,则可以这样做(完成交易需要更长的时间)。

即使没有上述支持,您仍然可以通过将行读取与等待数据存储操作完成的操作分离开来,从而大大加快工作速度:

  • 在当前请求处理程序中,您仅保留读取行的内容并以某种方式创建一批20行的行,以便在其他线程(任务队列,发布/订阅,单独的线程-在PHP中可以得到的任何东西)上进行处理

  • 在单独的请求处理程序(或任务队列或pub / sub处理程序,取决于您选择如何传递批处理数据)上的
  • 会收到这些批处理并进行实际的数据存储调用。这样,您可以并行处理多个批处理,从整体处理时间的角度来看,等待数据存储库答复的阻塞时间变得无关紧要。

使用这种方法,您的性能将仅受读取行并排队这些批处理的速度限制。如果您想提高速度-您还可以将单个CSV文件拆分为多个较小的文件,从而拥有多个可以并行工作的行读取器,从而为这些批处理工作人员提供帮助。

旁注:也许您想重试失败/回滚的事务或保存这些实体以供以后重试,目前看来您正在丢失它们。

答案 2 :(得分:0)

这个问题类似于Import CSV into google cloud datastoreGoogle Cloud Datastore: Bulk Importing w Node.js

快速的答案是您可以使用Apache Beam或Cloud Dataflow将CSV数据导入Cloud Datastore。