我一直在寻找各种来源,但这个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();
}
?>
答案 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假定以下架构:
此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。
您的工作参数如下所示:
注意:UDF转换仅支持JavaScript ECMAScript 5.1。所以只有基本的javascript,没有精美的箭头功能/ promise ...等等。
答案 1 :(得分:0)
抱歉,我并没有更具体,但是我是python标准env GAE用户,相当不熟悉PHP环境。
通常,您当前的方法是序列化和同步的-您一次要处理一行(或者,如果事务中的所有upsert
调用实际上都进入了数据存储区,则最多以20为批处理)一次),则每次数据存储区互动都将被阻止,并在互动完成后才前进到下一行。
我不确定PHP环境是否支持异步数据存储操作和/或真正的批处理操作(python ndb
库最多可以将500个写操作批处理到一个数据存储调用中)-这些可以帮助加快处理速度。< / p>
如果行是完全独立的,则还需要考虑 -您实际上是否需要事务来编写它们?如果PHP支持纯文本格式,则可以这样做(完成交易需要更长的时间)。
即使没有上述支持,您仍然可以通过将行读取与等待数据存储操作完成的操作分离开来,从而大大加快工作速度:
在当前请求处理程序中,您仅保留读取行的内容并以某种方式创建一批20行的行,以便在其他线程(任务队列,发布/订阅,单独的线程-在PHP中可以得到的任何东西)上进行处理
会收到这些批处理并进行实际的数据存储调用。这样,您可以并行处理多个批处理,从整体处理时间的角度来看,等待数据存储库答复的阻塞时间变得无关紧要。
使用这种方法,您的性能将仅受读取行并排队这些批处理的速度限制。如果您想提高速度-您还可以将单个CSV文件拆分为多个较小的文件,从而拥有多个可以并行工作的行读取器,从而为这些批处理工作人员提供帮助。
旁注:也许您想重试失败/回滚的事务或保存这些实体以供以后重试,目前看来您正在丢失它们。
答案 2 :(得分:0)
这个问题类似于Import CSV into google cloud datastore和Google Cloud Datastore: Bulk Importing w Node.js。
快速的答案是您可以使用Apache Beam或Cloud Dataflow将CSV数据导入Cloud Datastore。