

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 使用 Amazon Rekognition 和 Lambda 标记 Amazon S3 存储桶中的资产
<a name="images-lambda-s3-tutorial"></a>

在本教程中，您将创建一个自动标记位于 Amazon S3 存储桶中的数字资产的AWS Lambda函数。Lambda 函数会读取给定 Amazon S3 存储桶中的所有对象。对于存储桶中的每个对象，它都会将图像传递给 Amazon Rekognition 服务以生成一系列标签。每个标签都用于创建应用于图像的标签。在您执行 Lambda 函数后，它会根据给定 Amazon S3 存储桶中的所有图像自动创建标签并将其应用于图像。

例如，假设您运行了 Lambda 函数，并且在 Amazon S3 存储桶中存储了这张图片。

![火山喷发，熔岩汩汩而下，火山灰遮天蔽日。](http://docs.aws.amazon.com/zh_cn/rekognition/latest/dg/images/v2-image-tutorial-picture.png)


然后，应用程序会自动创建标签并将其应用于图像。

![表中显示用于跟踪存储成本的标签，包括“自然”、“火山”、“喷发”、“熔岩”、“山脉”和“户外”，并带有数值。](http://docs.aws.amazon.com/zh_cn/rekognition/latest/dg/images/v2-image-tutorial-results.png)


**注意**  
您在本教程中使用的服务是AWS免费套餐的一部分。完成本教程后，我们建议终止您在教程中创建的所有资源，这样您无需为此付费。

本教程使用适用于 Java 的 AWS SDK 版本 2。有关其他 Java V2 教程，请参阅[AWS文档 SDK 示例 GitHub 存储库](https://github.com/awsdocs/aws-doc-sdk-examples/tree/master/javav2/usecases)。

**Topics**
+ [先决条件](#lambda-s3-tutorial-prerequisites)
+ [配置 IAM Lambda 角色](#lambda-s3-tutorial-lambda-role)
+ [创建项目](#lambda-s3-tutorial-pom)
+ [编写代码](#lambda-s3-tutorial-code)
+ [打包项目](#lambda-s3-tutorial-package)
+ [部署 Lambda 函数](#lambda-s3-tutorial-deploy)
+ [测试 Lambda 方法](#lambda-s3-tutorial-test)

## 先决条件
<a name="lambda-s3-tutorial-prerequisites"></a>

在开始之前，您需要完成[设置 AWS SDK for Java](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/setup.html) 中的步骤。然后确保执行以下操作：
+ Java 1.8 JDK。
+ Maven 3.6 或更高版本。
+ 一个含有 5-7 张自然图像的 [Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html) 存储桶。这些图像由 Lambda 函数读取。

## 配置 IAM Lambda 角色
<a name="lambda-s3-tutorial-lambda-role"></a>

本教程使用 Amazon Rekognition 和 Amazon S3 服务。将 **lambda 支持**角色配置为具有允许其从 Lambda 函数调用这些服务的策略。

**配置角色**

1. 登录AWS 管理控制台并打开 IAM 控制台，网址为[https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)。

1. 在导航窗格中，选择**角色**，然后选择**创建角色**。

1. 选择 **AWS 服务**，然后选择 **Lambda**。

1. 选择**权限**选项卡。

1. 搜索 **AWSLambdaBasicExecutionRole**。

1. 请选择**下一个标签**。

1. 选择**审核**。

1. 为角色命名 **lambda 支持**。

1. 选择**创建角色**。

1. 选择 **lambda 支持**以查看概述页面。

1. 选择**附加策略**。

1. *AmazonRekognitionFullAccess*从策略列表中选择。

1. 选择**附加策略**。

1. 搜索 A **mazonS3 FullAccess**，然后选择**附加政策**。

## 创建项目
<a name="lambda-s3-tutorial-pom"></a>

创建一个新的 Java 项目，然后使用所需的设置和依赖项配置 Maven pom.xml。确保您的 pom.xml 文件如下所示：

```
<?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>WorkflowTagAssets</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>java-basic-function</name>
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>bom</artifactId>
            <version>2.10.54</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
   <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>aws-lambda-java-core</artifactId>
        <version>1.2.1</version>
    </dependency>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.6</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.10.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.13.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j18-impl</artifactId>
        <version>2.13.3</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.6.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.6.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.googlecode.json-simple</groupId>
        <artifactId>json-simple</artifactId>
        <version>1.1.1</version>
    </dependency>
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>s3</artifactId>
    </dependency>
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>rekognition</artifactId>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.22.2</version>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.2.2</version>
            <configuration>
                <createDependencyReducedPom>false</createDependencyReducedPom>
            </configuration>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
  </build>
 </project>
```

## 编写代码
<a name="lambda-s3-tutorial-code"></a>

使用AWS Lambda运行时 Java API 创建定义 Lambda 函数的 Java 类。在此示例中，Lambda 函数有一个名为 **Handler** 的 Java 类以及此用例所需的其他类。下图显示了项目中的 Java 类。请注意，所有 Java 类都位于名为 **com.example.tags** 的包中。

![项目结构显示了用于标记工作流资产的 Java 类 AnalyzePhotos，例如、、Handler BucketItem、S3Service 和。 WorkItem](http://docs.aws.amazon.com/zh_cn/rekognition/latest/dg/images/v2-image-tutorial-files.png)


为代码创建以下 Java 类：
+ Handl@@ **er** 使用 Lambda Java 运行时 API 并执行本教程中描述的用例。AWS执行的应用程序逻辑位于 handleRequest 方法中。
+ **S3Service** 使用 Amazon S3 API 来执行 S3 操作。
+ **AnalyzePhotos**使用 Amazon Rekognition API 来分析图片。
+ **BucketItem**定义了存储 Amazon S3 存储桶信息的模型。
+ **WorkItem**定义存储亚马逊 Rekognition 数据的模型。

### 处理程序类
<a name="w2aac52b9c25c11"></a>

此 Java 代码代表**处理程序**类。该类会读取传递到 Lambda 函数的标志。**s3Service。 ListBucketObjects**方法返回一个 **Lis** t 对象，其中每个元素都是一个表示对象键的字符串值。如果标志值为真，则通过对列表进行迭代操作应用标签，并通过调用 **s3Service.tagAssets** 方法将标签应用于每个对象。如果标志值为假，则为 s **3Service。 deleteTagFrom调用删除标签的对象**方法。另外，请注意，您可以使用**LambdaLogger**对象将消息记录到 Amazon CloudWatch 日志中。

**注意**  
确保将存储桶名称分配给 **bucketName** 变量。

```
package com.example.tags;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class Handler implements RequestHandler<Map<String,String>, String> {

@Override
public String handleRequest(Map<String, String> event, Context context) {
    LambdaLogger logger = context.getLogger();
    String delFlag = event.get("flag");
    logger.log("FLAG IS: " + delFlag);
    S3Service s3Service = new S3Service();
    AnalyzePhotos photos = new AnalyzePhotos();

    String bucketName = "<Enter your bucket name>";
    List<String> myKeys = s3Service.listBucketObjects(bucketName);
    if (delFlag.compareTo("true") == 0) {

        // Create a List to store the data.
        List<ArrayList<WorkItem>> myList = new ArrayList<>();

        // loop through each element in the List and tag the assets.
        for (String key : myKeys) {

            byte[] keyData = s3Service.getObjectBytes(bucketName, key);

            // Analyze the photo and return a list where each element is a WorkItem.
            ArrayList<WorkItem> item = photos.detectLabels(keyData, key);
            myList.add(item);
        }

        s3Service.tagAssets(myList, bucketName);
        logger.log("All Assets in the bucket are tagged!");

    } else {

        // Delete all object tags.
        for (String key : myKeys) {
            s3Service.deleteTagFromObject(bucketName, key);
            logger.log("All Assets in the bucket are deleted!");
        }
     }
    return delFlag;
  }
 }
```

### S3Service 类
<a name="w2aac52b9c25c13"></a>

以下类使用 Amazon S3 API 执行 S3 操作。例如，该**getObjectBytes**方法返回一个表示图像的字节数组。同样，该**listBucketObjects**方法返回一个 **Lis** t 对象，其中每个元素都是指定键名的字符串值。

```
 package com.example.tags;

 import software.amazon.awssdk.core.ResponseBytes;
 import software.amazon.awssdk.regions.Region;
 import software.amazon.awssdk.services.s3.S3Client;
 import software.amazon.awssdk.services.s3.model.GetObjectRequest;
 import software.amazon.awssdk.services.s3.model.PutObjectTaggingRequest;
 import software.amazon.awssdk.services.s3.model.GetObjectResponse;
 import software.amazon.awssdk.services.s3.model.S3Exception;
 import software.amazon.awssdk.services.s3.model.ListObjectsResponse;
 import software.amazon.awssdk.services.s3.model.S3Object;
 import software.amazon.awssdk.services.s3.model.GetObjectTaggingResponse;
 import software.amazon.awssdk.services.s3.model.ListObjectsRequest;
 import java.util.ArrayList;
 import java.util.List;
 import software.amazon.awssdk.services.s3.model.Tagging;
 import software.amazon.awssdk.services.s3.model.Tag;
 import software.amazon.awssdk.services.s3.model.GetObjectTaggingRequest;
 import software.amazon.awssdk.services.s3.model.DeleteObjectTaggingRequest;

 public class S3Service {

 private S3Client getClient() {

    Region region = Region.US_WEST_2;
    return S3Client.builder()
            .region(region)
            .build();
 }

 public byte[] getObjectBytes(String bucketName, String keyName) {

    S3Client s3 = getClient();

    try {

        GetObjectRequest objectRequest = GetObjectRequest
                .builder()
                .key(keyName)
                .bucket(bucketName)
                .build();

        // Return the byte[] from this object.
        ResponseBytes<GetObjectResponse> objectBytes = s3.getObjectAsBytes(objectRequest);
        return objectBytes.asByteArray();

    } catch (S3Exception e) {
        System.err.println(e.awsErrorDetails().errorMessage());
        System.exit(1);
    }
    return null;
 }

 // Returns the names of all images in the given bucket.
 public List<String> listBucketObjects(String bucketName) {

    S3Client s3 = getClient();
    String keyName;

    List<String> keys = new ArrayList<>();

    try {
        ListObjectsRequest listObjects = ListObjectsRequest
                .builder()
                .bucket(bucketName)
                .build();

        ListObjectsResponse res = s3.listObjects(listObjects);
        List<S3Object> objects = res.contents();

        for (S3Object myValue: objects) {
            keyName = myValue.key();
            keys.add(keyName);
        }
        return keys;

    } catch (S3Exception e) {
        System.err.println(e.awsErrorDetails().errorMessage());
        System.exit(1);
    }
    return null;
 }

 // Tag assets with labels in the given list.
 public void tagAssets(List myList, String bucketName) {

    try {

        S3Client s3 = getClient();
        int len = myList.size();

        String assetName = "";
        String labelName = "";
        String labelValue = "";

        // Tag all the assets in the list.
        for (Object o : myList) {

            // Need to get the WorkItem from each list.
            List innerList = (List) o;
            for (Object value : innerList) {

                WorkItem workItem = (WorkItem) value;
                assetName = workItem.getKey();
                labelName = workItem.getName();
                labelValue = workItem.getConfidence();
                tagExistingObject(s3, bucketName, assetName, labelName, labelValue);
            }
        }

    } catch (S3Exception e) {
        System.err.println(e.awsErrorDetails().errorMessage());
        System.exit(1);
    }
 }

 // This method tags an existing object.
 private void tagExistingObject(S3Client s3, String bucketName, String key, String label, String LabelValue) {

    try {

        // First need to get existing tag set; otherwise the existing tags are overwritten.
        GetObjectTaggingRequest getObjectTaggingRequest = GetObjectTaggingRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build();

        GetObjectTaggingResponse response = s3.getObjectTagging(getObjectTaggingRequest);

        // Get the existing immutable list - cannot modify this list.
        List<Tag> existingList = response.tagSet();
        ArrayList<Tag> newTagList = new ArrayList(new ArrayList<>(existingList));

        // Create a new tag.
        Tag myTag = Tag.builder()
                .key(label)
                .value(LabelValue)
                .build();

        // push new tag to list.
        newTagList.add(myTag);
        Tagging tagging = Tagging.builder()
                .tagSet(newTagList)
                .build();

        PutObjectTaggingRequest taggingRequest = PutObjectTaggingRequest.builder()
                .key(key)
                .bucket(bucketName)
                .tagging(tagging)
                .build();

        s3.putObjectTagging(taggingRequest);
        System.out.println(key + " was tagged with " + label);

    } catch (S3Exception e) {
        System.err.println(e.awsErrorDetails().errorMessage());
        System.exit(1);
    }
  }

 // Delete tags from the given object.
 public void deleteTagFromObject(String bucketName, String key) {

    try {

        DeleteObjectTaggingRequest deleteObjectTaggingRequest = DeleteObjectTaggingRequest.builder()
                .key(key)
                .bucket(bucketName)
                .build();

        S3Client s3 = getClient();
        s3.deleteObjectTagging(deleteObjectTaggingRequest);

    } catch (S3Exception e) {
        System.err.println(e.awsErrorDetails().errorMessage());
        System.exit(1);
    }
  }
}
```

### AnalyzePhotos 班级
<a name="w2aac52b9c25c15"></a>

以下 Java 代码代表该**AnalyzePhotos**类。该类使用 Amazon Rekognition API 来分析图像。

```
package com.example.tags;

import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
import software.amazon.awssdk.core.SdkBytes;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.rekognition.RekognitionClient;
import software.amazon.awssdk.services.rekognition.model.Image;
import software.amazon.awssdk.services.rekognition.model.DetectLabelsRequest;
import software.amazon.awssdk.services.rekognition.model.DetectLabelsResponse;
import software.amazon.awssdk.services.rekognition.model.Label;
import software.amazon.awssdk.services.rekognition.model.RekognitionException;
import java.util.ArrayList;
import java.util.List;

public class AnalyzePhotos {

 // Returns a list of WorkItem objects that contains labels.
 public ArrayList<WorkItem> detectLabels(byte[] bytes, String key) {

    Region region = Region.US_EAST_2;
    RekognitionClient rekClient = RekognitionClient.builder()
            .credentialsProvider(EnvironmentVariableCredentialsProvider.create())
            .region(region)
            .build();

    try {

        SdkBytes sourceBytes = SdkBytes.fromByteArray(bytes);

        // Create an Image object for the source image.
        Image souImage = Image.builder()
                .bytes(sourceBytes)
                .build();

        DetectLabelsRequest detectLabelsRequest = DetectLabelsRequest.builder()
                .image(souImage)
                .maxLabels(10)
                .build();

        DetectLabelsResponse labelsResponse = rekClient.detectLabels(detectLabelsRequest);

        // Write the results to a WorkItem instance.
        List<Label> labels = labelsResponse.labels();
        ArrayList<WorkItem> list = new ArrayList<>();
        WorkItem item ;
        for (Label label: labels) {
            item = new WorkItem();
            item.setKey(key); // identifies the photo.
            item.setConfidence(label.confidence().toString());
            item.setName(label.name());
            list.add(item);
        }
        return list;

    } catch (RekognitionException e) {
        System.out.println(e.getMessage());
        System.exit(1);
    }
    return null ;
  }
}
```

### BucketItem 班级
<a name="w2aac52b9c25c17"></a>

以下 Java 代码表示存储 Amazon S3 对象数据的**BucketItem**类。

```
package com.example.tags;

public class BucketItem {

 private String key;
 private String owner;
 private String date ;
 private String size ;


 public void setSize(String size) {
    this.size = size ;
 }

 public String getSize() {
    return this.size ;
 }

 public void setDate(String date) {
    this.date = date ;
 }

 public String getDate() {
    return this.date ;
 }

 public void setOwner(String owner) {
    this.owner = owner ;
 }

 public String getOwner() {
    return this.owner ;
 }

 public void setKey(String key) {
    this.key = key ;
 }

 public String getKey() {
    return this.key ;
 }
}
```

### WorkItem 班级
<a name="w2aac52b9c25c19"></a>

以下 Java 代码代表该**WorkItem**类。

```
 package com.example.tags;

 public class WorkItem {

 private String key;
 private String name;
 private String confidence ;

public void setKey (String key) {
    this.key = key;
}

public String getKey() {
    return this.key;
}

public void setName (String name) {
    this.name = name;
}

public String getName() {
    return this.name;
}

public void setConfidence (String confidence) {
    this.confidence = confidence;
}

public String getConfidence() {
    return this.confidence;
}

}
```

## 打包项目
<a name="lambda-s3-tutorial-package"></a>

使用以下 Maven 命令将项目打包成 .jar (JAR) 文件。

```
mvn package
```

JAR 文件位于**目标**文件夹（这是项目文件夹的子文件夹）。

![文件资源管理器窗口显示目标文件夹，其中包含 WorkflowTagAssets -1.0-Snapshot.jar 等 JAR 文件以及其他项目文件和文件夹。](http://docs.aws.amazon.com/zh_cn/rekognition/latest/dg/images/v2-image-tutorial-folder.png)


**注意**  
请注意项目的 POM 文件**maven-shade-plugin**中使用了。此插件负责创建包含所需依赖项的 JAR。如果您尝试在没有此插件的情况下打包项目，则所需的依赖项不包含在 JAR 文件中，您将遇到. **ClassNotFoundException** 

## 部署 Lambda 函数
<a name="lambda-s3-tutorial-deploy"></a>

1. 打开 [Lambda 控制台](https://console.aws.amazon.com/lambda/home)。

1. 选择**创建函数**。

1. 选择**从头开始创作**。

1. 在**基本信息**部分，输入 **cron** 作为名称。

1. 在**运行时系统**中，选择 **Java 8**。

1. 选择**使用现有角色**，然后选择 **lambda 支持**（您创建的 IAM 角色）。

1. 选择**创建函数**。

1. 对于**代码输入种类**，选择**上传 .zip 文件或 .jar 文件**。

1. 选择**上传**，然后浏览到您创建的 JAR 文件。

1. 对于**处理程序**，输入函数的完全限定名称，例如 **com.example.tags.Handler:handleRequest**（**com.example.tags** 指定程序包，**处理程序**是后跟 :: 和方法名称的类）。

1. 选择**保存**。

## 测试 Lambda 方法
<a name="lambda-s3-tutorial-test"></a>

在教程的这一部分，您可以测试 Lambda 函数。

1. 在 Lambda 控制台中，单击**测试**选项卡，然后输入以下 JSON。

   ```
                    {
   "flag": "true"
    }
   ```  
![使用标志键值对、“删除”和“格式化”按钮以及“调用”按钮测试事件 JSON 编辑器。](http://docs.aws.amazon.com/zh_cn/rekognition/latest/dg/images/v2-image-tutorial-test.png)
**注意**  
传递 **true** 会标记数字资产，传递 **false** 会删除标签。

1. 选择**调用**按钮。调用 Lambda 函数后，您会看到一条成功消息。  
![执行结果消息带有“详细信息”按钮，表示操作成功。](http://docs.aws.amazon.com/zh_cn/rekognition/latest/dg/images/v2-image-tutorial-success.png)

恭喜，您创建了一个自动将标签应用于 Amazon S3 存储桶中的数字资产的AWS Lambda函数。如本教程开头所述，请务必在学习本教程时终止您创建的所有资源，以确保系统不会向您收费。

有关更多AWS多服务示例，请参阅[AWS文档 SDK 示例 GitHub 存储库](https://github.com/awsdocs/aws-doc-sdk-examples/tree/master/javav2/usecases)。