本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
使用 Amazon Rekognition 和 Lambda 在 Amazon S3 儲存貯體中標記資產
在本教學中,您會建立自動標記位於 Amazon S3 儲存貯體中的數位資產的 AWS Lambda 函數。Lambda 函數可讀取指定 Amazon S3 儲存貯體中的所有物件。對於儲存貯體中的每個物件,它會將映像傳遞至 Amazon Rekognition 服務,以建立一系列標籤。每個標籤都用來建立套用至影像的標籤。執行 Lambda 函數後,其會根據指定 Amazon S3 儲存貯體中的所有映像自動建立標籤,並將其套用至映像檔。
例如,假設您執行 Lambda 函數,而 Amazon S3 儲存貯體中有這個映像。
然後,應用程式會自動建立標籤並將其套用至影像。
注意
您在本教學課程中使用的服務屬於 AWS 免費方案的一部分。完成教學課程後,我們建議您終止在教學課程中建立的任何資源,這樣就不會被收取任何費用。
本教學課程使用適用於 Java 版本 2 的 AWS SDK。如需其他 Java V2 教學課程,請參閱AWS 文件 SDK 範例 GitHub 儲存庫
必要條件
在開始之前,您需要完成設定 Java AWS SDK 中的步驟。請確定執行下列操作:
Java 1.8 JDK.
Maven 3.6 或更高版本。
一個 Amazon S3 儲存貯體,其中包含 5 至 7 個自然映像。這些映像由 Lambda 函數讀取。
設定 IAM Lambda 角色
本教學使用 Amazon Rekognition 和 Amazon S3 服務。將 Lambda 支援 角色設定為具有可讓其從 Lambda 函數調用這些服務的政策。
設定角色
登入 AWS Management Console 並開啟身分與存取權管理主控台,網址為 https://console.aws.amazon.com/iam/
。 -
在導覽窗格中,選擇角色,然後選擇建立角色。
-
選擇AWS 服務,接著選擇Lambda。
-
選擇許可標籤。
-
搜尋 AWSLambdaBasicExecutionRole。
-
選擇下一個標籤。
-
選擇檢閱。
-
對角色 Lambda 支援命名。
-
選擇建立角色。
-
選擇 Lambda 支援來檢視概觀頁面。
-
選擇連接政策。
-
AmazonRekognitionFullAccess從策略清單中選擇。
-
選擇連接政策。
-
搜尋亞馬遜 S3 FullAccess,然後選擇 [附加原則]。
建立專案
建立一個新的 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>
撰寫程式碼
使用 AWS Lambda 執行階段 Java API 來建立定義 Lambda 函數的 Java 類別。在此範例中,有一個名為處理常式的 Lambda 函數的 Java 類別,以及此使用案例所需的其他類別。下圖顯示專案中的 Java 類別。請注意,所有的 Java 類別都位於一個名為com.example.tags的套件中。
為程式碼建立下列 Java 類別:
處理常式會使用 Lambda Java 執行階段 API,並執行 AWS 本教學課程中所述的使用案例。執行的應用程式邏輯位於 handleRequest 方法中。
S3Service 使用 Amazon S3 API 來執行 S3 操作。
AnalyzePhotos使用 Amazon Rekognition API 來分析圖像。
BucketItem定義存放 Amazon S3 儲存貯體資訊的模型。
WorkItem定義存放亞馬遜重新認知資料的模型。
處理常式類別:
這個 Java 程式碼代表處理常式類別。此類別會讀取傳遞至 Lambda 函數的旗標。該 S3 服務。 ListBucketObjects方法返回一個 List 對象,其中每個元素都是代表對象鍵的字符串值。如果旗標值為真,則會透過反覆執行清單並呼叫 s3Service.tagAssets 方法,將標籤套用至每個物件,以套用標籤。如果標誌值為假,則 S3 服務。 deleteTagFrom對象方法被調用刪除的標籤。此外,請注意,您可以使用LambdaLogger物件將訊息 CloudWatch 記錄到 Amazon 日誌。
注意
請務必將儲存貯體名稱指派給 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 類
下列類別使用 Amazon S3 API 來執行 S3 操作。例如,此方getObjectBytes法會傳回代表影像的位元組陣列。同樣地,此方listBucketObjects法會傳回 List 物件,其中每個項目都是指定索引鍵名稱的字串值。
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 類
下面的 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 類
下列 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 類
下面的 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; } }
Package 專案
透過使用下面的 Maven 命令將該專案打包到一個 .jar (JAR) 檔案。
mvn package
JAR 檔案位於目標資料夾 (專案資料夾的子資料夾) 中。
注意
請注意專案maven-shade-plugin的 POM 檔案中的使用。此外掛程式負責建立包含所需相依性的 JAR。如果您嘗試在沒有此外掛程式的情況下封裝專案,所需的相依性不會包含在 JAR 檔案中,您將會遇到. ClassNotFoundException
部署 Lambda 函數。
開啟 Lambda 主控台
。 選擇 Create Function (建立函數)。
選擇從頭開始撰寫。
在基本資訊區段中,輸入 Cron 做為名稱。
在執行期中,選擇 Java 8。
選擇使用現有角色,然後選擇 Lambda支援 (建立的 IAM 角色)。
選擇建立函數。
針對程式碼專案類型,選擇上傳 .zip 檔案。
選擇上傳,然後瀏覽至您建立的 JAR 檔案。
針對處理程式,請輸入該函數的完整名稱,例如:com.example.tags.Handler:handleRequest (com.example.tags會指定套件,處理程式是後面接著::和方法名稱的類別)。
選擇儲存。
測試 Lambda 方法
在教學課程中,您可以測試 Lambda 函數。
在 Lambda 主控台中,點擊測試索引標籤,然後輸入下列 JSON。
{ "flag": "true" }
注意
傳遞真索引標籤的數字資產和傳遞假刪除標籤。
選擇叫用按鈕。調用 Lambda 函數之後,您會看到成功的訊息。
恭喜您,您已建立一個 AWS Lambda 函數,可自動將標籤套用至位於 Amazon S3 儲存貯體中的獨立資產。如同本教學課程開頭所述,請務必終止您在進行本教學課程時所建立的資源,以確保不會產生費用。
如需更 AWS 多多服務範例,請參閱AWS 文件 SDK 範例 GitHub 儲存庫