4

对于大量项目中的每一个,我需要检查 S3 中是否存在一组键。(每组键都与大量项目中的一个相关)。

我正在使用 PHP SDK (v2)

目前我正在调用$client->doesObjectExist(BUCKET, $key)每个键,这是一个瓶颈(每次调用到 S3 的往返时间)。

我更愿意做类似$client->doesObjectExist(BUCKET, $batch)where的事情$batch = array($key1, $key2 ... $keyn),让客户检查所有这些键,然后返回一系列响应(或其他类似结构)。

我遇到了一些 对“批处理 api”的引用,这听起来很有希望,但没有什么具体的。我猜这可能只存在于 v1 SDK 中。

4

3 回答 3

6

您可以利用底层 Guzzle 库功能使用适用于 PHP 的 AWS 开发工具包执行并行请求。由于该doesObjectExist方法实际上HeadObject在该引擎盖下进行操作。您可以通过执行以下操作来创建 HeadObject 命令组:

use Aws\S3\S3Client;
use Guzzle\Service\Exception\CommandTransferException;

function doObjectsExist(S3Client $s3, $bucket, array $objectKeys)
{
    $headObjectCommands = array();
    foreach ($objectKeys as $key) {
        $headObjectCommands[] = $s3->getCommand('HeadObject', array(
            'Bucket' => $bucket,
            'Key'    => $key
        ));
    }

    try {
        $s3->execute($headObjectCommands); // Executes in parallel
        return true;
    } catch (CommandTransferException $e) {
        return false;
    }
}

$s3 = S3Client::factory(array(
    'key'    => 'your_aws_access_key_id',
    'bucket' => 'your_aws_secret_key',
));
$bucket = 'your_bucket_name';
$objectKeys = array('object_key_1', 'object_key_2','object_key_3');

// Returns true only if ALL of the objects exist
echo doObjectsExist($s3, $bucket, $objectKeys) ? 'YES' : 'NO';

如果您想从响应中获取数据,而不仅仅是键是否存在,您可以更改 try-catch 块以执行类似的操作。

try {
    $executedCommands = $s3->execute($headObjectCommands);
} catch (CommandTransferException $e) {
    $executedCommands = $e->getAllCommands();
}

// Do stuff with the command objects
foreach ($executedCommands as $command) {
    $exists = $command->getResponse()->isSuccessful() ? "YES" : "NO";
    echo "{$command['Bucket']}/{$command['Key']}: {$exists}\n";
}

AWS SDK for PHP 用户指南中提到了并行发送命令,但我也想看看Guzzle 批处理文档

于 2013-09-05T20:52:46.917 回答
0

进行批量检查以查看是否存在某些键的唯一方法是列出存储桶中的对象。

对于列表调用doesObjectExistAWS 最多返回 1000 个键/调用,因此它比为每个键进行调用要快得多。但是,如果您有大量键并且只想检查其中几个,列出存储桶中的所有对象将不切实际,因此在这种情况下,您唯一的选择仍然是单独检查每个对象。

问题不在于 PHP v2 SDK 缺少批量功能,而是 S3 API 没有实现这种批量处理。

于 2013-09-05T14:08:17.613 回答
0

我正在建立 Jeremy Lindblom 的回答。

只想OnComplete指出您可以在每个命令上设置的回调。

$bucket = 'my-bucket';
$keys = array('page1.txt', 'page2.txt');

$commands = array();
foreach ($keys as $key) {
    $commands[] = $s3Client->getCommand('HeadObject', array('Bucket' => $bucket, 'Key' => $key))
        ->setOnComplete(
            function($command) use ($bucket, $key)
            {
                echo "\nBucket: $bucket\n";
                echo "\nKey: $key\n";

                // see http://goo.gl/pIWoYr for more detail on command objects
                var_dump($command->getResult());
            }
        );
}

try {
    $ex_commands = $s3Client->execute($commands);
}
catch (\Guzzle\Service\Exception\CommandTransferException $e) {
    $ex_commands = $e->getAllCommands();
}

// this is necesary; without this, the OnComplete handlers wouldn't get called (strange?!?)
foreach ($ex_commands as $command)
{
    $command->getResult();
}

如果有人能阐明为什么我需要调用$command->getResult()来调用OnComplete处理程序,那就太好了。

于 2015-01-30T03:12:17.150 回答