

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# 非同期操作によるドキュメントの処理
<a name="async"></a>

Amazon Textract は、PDF または TIFF 形式の複数ページのドキュメント内のテキストを検出して分析できます。これには、請求書と領収書が含まれます。複数ページのドキュメント処理は、非同期オペレーションです。ドキュメントの非同期処理は、大規模な複数ページのドキュメントを処理する場合に便利です。たとえば、1,000 ページを超える PDF ファイルの処理には時間がかかります。PDF ファイルを非同期的に処理すると、アプリケーションはプロセスの完了を待っている間に他のタスクを完了できます。

このセクションでは、Amazon Textract を使用して、複数ページまたは単一ページのドキュメントのテキストを非同期的に検出して分析する方法について説明します。複数ページのドキュメントは PDF 形式または TIFF 形式である必要があります。非同期操作で処理される単一ページのドキュメントは、JPEG、PNG、TIFF、または PDF 形式にすることができます。

Amazon Textract 非同期オペレーションは、次の目的に使用できます。
+ テキスト検出-複数ページの文書の行と単語を検出できます。非同期操作は次のとおりです。[StartDocumentTextDetection](API_StartDocumentTextDetection.md)そして[GetDocumentTextDetection](API_GetDocumentTextDetection.md)。詳細については、「[テキストの検出](how-it-works-detecting.md)」を参照してください。
+ テキスト分析-複数ページのドキュメントで検出されたテキスト間の関係を特定できます。非同期操作は次のとおりです。[StartDocumentAnalysis](API_StartDocumentAnalysis.md)そして[GetDocumentAnalysis](API_GetDocumentAnalysis.md)。詳細については、「[ドキュメントを分析する](how-it-works-analyzing.md)」を参照してください。
+ 経費分析 — 複数ページの請求書と領収書のデータ関係を特定できます。Amazon Textract は、複数ページのドキュメントの各請求書または領収書ページを個別の領収書または請求書として扱います。複数ページドキュメントの 1 つのページから別のページへのコンテキストは保持されません。非同期操作は次のとおりです。[StartExpenseAnalysis](API_StartExpenseAnalysis.md)そして[GetExpenseAnalysis](API_GetExpenseAnalysis.md)。詳細については、「[請求書と領収書の分析](invoices-receipts.md)」を参照してください。

**Topics**
+ [Amazon Textract 非同期オペレーションを呼び出す](api-async.md)
+ [非同期オペレーション用の Amazon Textract の設定](api-async-roles.md)
+ [複数ページドキュメント内のテキストの検出または分析](async-analyzing-with-sqs.md)
+ [Amazon Textract 結果通知](async-notification-payload.md)

# Amazon Textract 非同期オペレーションを呼び出す
<a name="api-async"></a>

Amazon Textract は、PDF または TIFF 形式で複数ページのドキュメントを処理するために使用できる非同期 API を提供します。非同期操作を使用して、JPEG、PNG、TIFF、または PDF 形式の単一ページのドキュメントを処理することもできます。

このトピックの情報は、テキスト検出操作を使用して Amazon Textract の非同期オペレーションの使用方法を示しています。同じアプローチが、のテキスト解析操作でも機能します。[StartDocumentAnalysis](API_StartDocumentAnalysis.md)そして[GetDocumentAnalysis](API_GetDocumentAnalysis.md)。また、で動作します。[StartExpenseAnalysis](API_StartExpenseAnalysis.md)そして[GetExpenseAnalysis](API_GetExpenseAnalysis.md)。

例については、[複数ページドキュメント内のテキストの検出または分析](async-analyzing-with-sqs.md) を参照してください。

Amazon Textract は、Amazon S3 バケットに保存されたドキュメントを非同期的に処理します。処理を開始するには、`Start`などの操作[StartDocumentTextDetection](API_StartDocumentTextDetection.md)。リクエストの完了ステータスが、Amazon Simple Notification Service (Amazon SNS) トピックに発行されます。Amazon SNS トピックから完了ステータスを取得するには、Amazon Simple Queue Service (Amazon SQS) キューまたはAWS Lambdafunction. 完了ステータスを取得したら、[GetDocumentTextDetection](API_GetDocumentTextDetection.md) などの `Get` オペレーションを呼び出してリクエストの結果を取得します。

非同期呼び出しの結果は、オペレーションを使用して Amazon S3 バケットを指定しない限り、デフォルトで暗号化され、Amazon Textract が所有するバケットに 7 日間保存されます。`OutputConfig`引数。

次の表に、Amazon Textract でサポートされているさまざまなタイプの非同期処理に対応する開始オペレーションと Get オペレーションを示します。


**Amazon Textract 非同期オペレーションの API オペレーションの開始/取得**  

| 処理タイプ | API を起動する | API の取得 | 
| --- | --- | --- | 
| テキストの検出 | StartDocumentTextDetection | GetDocumentTextDetection | 
| テキスト分析 | StartDocumentAnalysis | GetDocumentAnalysis | 
| 経費分析 | 経費分析の開始 | 経費分析を取得 | 

という例を挙げてAWS Lambda関数、「」を参照してください。[Amazon Textract による大規模なドキュメント処理](https://github.com/aws-samples/amazon-textract-serverless-large-scale-document-processing)。

以下の図は、Amazon S3 バケットに保存されているドキュメントイメージ内のドキュメントテキストを検出するプロセスを示しています。この図では、Amazon SQS キューによって Amazon SNS トピックから完了ステータスが表示されます。

![\[alt text not found\]](http://docs.aws.amazon.com/ja_jp/textract/latest/dg/images/asynchronous.png)


前の図に表示されるプロセスは、テキストおよび請求書/領収書の分析と同じです。テキスト分析を開始するには、を呼び出します。[StartDocumentAnalysis](API_StartDocumentAnalysis.md)そして、電話をかけて請求書/領収書の分析を開始する[StartExpenseAnalysis](API_StartExpenseAnalysis.md)あなたは呼び出すことによって結果を得ます[GetDocumentAnalysis](API_GetDocumentAnalysis.md)または[GetExpenseAnalysis](API_GetExpenseAnalysis.md)それぞれ。

## テキストの検出の開始
<a name="api-async-start"></a>

Amazon Textract テキストリクエストを開始するには、を呼び出します。[StartDocumentTextDetection](API_StartDocumentTextDetection.md)。以下は、`StartDocumentTextDetection` により渡される JSON リクエストの例を示しています。

```
{
    "DocumentLocation": {
        "S3Object": {
            "Bucket": "bucket",
            "Name": "image.pdf"
        }
    },
    "ClientRequestToken": "DocumentDetectionToken",
    "NotificationChannel": {
        "SNSTopicArn": "arn:aws:sns:us-east-1:nnnnnnnnnn:topic",
        "RoleArn": "arn:aws:iam::nnnnnnnnnn:role/roleTopic"
    },
    "JobTag": "Receipt"
}
```

入力パラメータ`DocumentLocation`は、ドキュメントファイル名と、取得先の Amazon S3 バケットを提供します。`NotificationChannel`には、Amazon SNS トピックの Amazon リソースネーム (ARN) と、テキスト検出リクエストの完了時に Amazon Textract が通知します。Amazon SNS トピックは、呼び出し先の Amazon Textract エンドポイントと同じ AWS リージョン内に存在する必要があります。`NotificationChannel`には、Amazon Textract を Amazon SNS トピックに発行できるようにするためのロールの ARN も含まれています。Amazon SNS トピックへの Amazon Textract 発行アクセス許可を付与するには、IAM サービスロールを作成します。詳細については、「[非同期オペレーション用の Amazon Textract の設定](api-async-roles.md)」を参照してください。

オプションの入力パラメータを指定することもできます。`JobTag`を選択すると、Amazon SNS トピックに発行された完了ステータスのジョブまたはジョブのグループを特定できます。たとえば、を使用すると、`JobTag`税金フォームや領収書など、処理中の文書のタイプを識別します。

`ClientRequestToken` というべき等トークンをオプションで設定すると、分析ジョブが誤って重複するのを防ぐことができます。の値を指定した場合`ClientRequestToken`とすると、`Start`オペレーションが同じを返す`JobId`への複数の同一のコールに対して`Start`などの操作`StartDocumentTextDetection`。`ClientRequestToken` トークンの有効期間は 7 日です。7 日後に再利用することができます。トークンの有効期間中にトークンを再利用すると、以下のことが発生します。
+ 同じ `Start` オペレーション、同じ入力パラメータでトークンを再利用すると、同じ `JobId` が返されます。ジョブは再度実行されず、Amazon Textract は、登録されている Amazon SNS トピックに完了ステータスを送信しません。
+ 同じ `Start` オペレーションで、入力パラメータを少し変更してトークンを再利用すると、`idempotentparametermismatchexception` (HTTP ステータスコード: 400) 例外を受け取ります。
+ 別の `Start` オペレーションでトークンを再利用すると、オペレーションは正常に実行されます。

使用可能なもう 1 つのオプションパラメータは次のとおりです。`OutputConfig`で、出力の配置場所を調整できます。デフォルトでは、Amazon Textract は結果を内部的に保存し、Get API オペレーションによってのみアクセスできます。と`OutputConfig`有効にすると、出力が送信されるバケットの名前と、結果をダウンロードできる結果のファイルプレフィックスを設定できます。さらに、`KMSKeyID`パラメータを使用して、出力を暗号化するためにカスタマー管理キーを指定します。このパラメータを設定しないと、Amazon Textract は、AWS マネージドキーAmazon S3 におけるもの

**注記**  
このパラメータを使用する前に、出力バケットの PutObject 権限があることを確認してください。さらに、の [復号化]、[ReEncrypt]、[generateDataKey]、および [describeKey] 権限があることを確認します。AWS KMS使用することに決めた場合はキーを指定します。

`StartDocumentTextDetection` オペレーションに対する応答は、ジョブ識別子 (`JobId`) です。を使用する`JobId`Amazon Textract が完了ステータスを Amazon SNS トピックに発行したら、リクエストを追跡し、分析結果を取得します。次に例を示します。

```
{"JobId":"270c1cc5e1d0ea2fbc59d97cb69a72a5495da75851976b14a1784ca90fc180e3"}
```

同時に開始するジョブが多すぎると、`StartDocumentTextDetection`を育てる`LimitExceededException`同時に実行されるジョブの数が Amazon Textract のサービスの制限を下回るまで、の例外 (HTTP ステータスコード:400)。

アクティビティのバーストにより LimitExceedededException 例外が発生した場合は、Amazon SQS キューを使用して受信リクエストを管理することを検討してください。連絡先AWS同時リクエストの平均数を Amazon SQS キューで管理できないと、引き続き受信されている場合のSupport`LimitExceededException`例外。

## Amazon Textract 分析リクエストの完了ステータスの取得
<a name="api-async-get-status"></a>

Amazon Textract は、登録されている Amazon SNS トピックに分析完了の通知を送信します。通知には、ジョブ識別子およびオペレーション完了ステータスが JSON 文字列で含まれています。成功したテキスト検出リクエストには、`SUCCEEDED`status。たとえば、次の結果は、テキスト検出ジョブが正常に処理されたことを示しています。

```
{
    "JobId": "642492aea78a86a40665555dc375ee97bc963f342b29cd05030f19bd8fd1bc5f",
    "Status": "SUCCEEDED",
    "API": "StartDocumentTextDetection",
    "JobTag": "Receipt",
    "Timestamp": 1543599965969,
    "DocumentLocation": {
        "S3ObjectName": "document",
        "S3Bucket": "bucket"
    }
}
```

詳細については、「[Amazon Textract 結果通知](async-notification-payload.md)」を参照してください。

Amazon Textract によって Amazon SNS トピックに発行されたステータス情報を取得するには、次のいずれかのオプションを使用します。
+ **AWS Lambda**— をサブスクライブできますAWS LambdaAmazon SNS トピックに書き込む関数。この関数は、Amazon Textract が Amazon SNS トピックにリクエスト完了を通知したときに呼び出されます。Lambda 関数を使用すると、サーバー側のコードでテキスト検出リクエストの結果を処理できます。たとえば、クライアントアプリケーションに情報を返す前に、イメージに注釈を付けたり、検出されたテキストに関するレポートを作成したりする場合があります。
+ **Amazon SQS**— Amazon SNS トピックに Amazon SQS キューをサブスクライブできます。Amazon SQS キューをポーリングすることで、リクエストの完了時に Amazon Textract が発行する完了ステータスを取得できます。詳細については、「[複数ページドキュメント内のテキストの検出または分析](async-analyzing-with-sqs.md)」を参照してください。Amazon Textract オペレーションをクライアントアプリケーションからのみ呼び出す場合は、Amazon SQS キューを使用します。

**重要**  
Amazon Textract を繰り返し呼び出すことでリクエスト完了ステータスを取得することは推奨されません。`Get`オペレーション. これは、Amazon Textract が`Get`実行されるリクエストが多すぎると、操作が実行されます。複数のドキュメントを同時に処理する場合は、Amazon Textract をポーリングして各ジョブのステータスを個別に取得するよりも、1 つの SQS キューの完了通知を監視するほうがシンプルかつ効率的です。

## Amazon Textract テキスト検出結果の取得
<a name="api-async-get"></a>

テキスト検出リクエストの結果を取得するには、Amazon SNS トピックから取得された完了ステータスがであることを最初に確認します。`SUCCEEDED`。次に `GetDocumentTextDetection` を呼び出し、`StartDocumentTextDetection` から返された `JobId` の値を渡します。リクエストの JSON は次の例のようになります。

```
{
    "JobId": "270c1cc5e1d0ea2fbc59d97cb69a72a5495da75851976b14a1784ca90fc180e3",
    "MaxResults": 10,
    "SortBy": "TIMESTAMP"
}
```

`JobId`テキスト検出操作の識別子です。テキスト検出によって大量のデータが生成されるため、`MaxResults`は、1 件で返す結果の最大数を指定します。`Get`オペレーション. のデフォルト値`MaxResults`は1,000です。1,000 より大きい値を指定した場合、1,000 件の結果だけが返されます。オペレーションによってすべての結果が返されない場合、次のページのページ分割トークンが返されます。次の結果ページを取得するには、`NextToken`パラメータ。

**注記**  
Amazon Textract は非同期オペレーションの結果を 7 日間保持します。この時間を過ぎると結果を取得することはできません。

-`GetDocumentTextDetection`オペレーションの応答の JSON は次のようになります。検出されたページの総数が`DocumentMetadata`。検出されたテキストは`Blocks`配列。の詳細については、`Block`オブジェクト、「」を参照してください。[テキスト検出および文書分析応答オブジェクト](how-it-works-document-layout.md)。

```
{
    "DocumentMetadata": {
        "Pages": 1
    },
    "JobStatus": "SUCCEEDED",
    "Blocks": [
        {
            "BlockType": "PAGE",
            "Geometry": {
                "BoundingBox": {
                    "Width": 1.0,
                    "Height": 1.0,
                    "Left": 0.0,
                    "Top": 0.0
                },
                "Polygon": [
                    {
                        "X": 0.0,
                        "Y": 0.0
                    },
                    {
                        "X": 1.0,
                        "Y": 0.0
                    },
                    {
                        "X": 1.0,
                        "Y": 1.0
                    },
                    {
                        "X": 0.0,
                        "Y": 1.0
                    }
                ]
            },
            "Id": "64533157-c47e-401a-930e-7ca1bb3ac3fa",
            "Relationships": [
                {
                    "Type": "CHILD",
                    "Ids": [
                        "4297834d-dcb1-413b-8908-3b96866ebbb5",
                        "1d85ba24-2877-4d09-b8b2-393833d769e9",
                        "193e9c47-fd87-475a-ba09-3fda210d8784",
                        "bd8aeb62-961b-4b47-b78a-e4ed9eeecd0f"
                    ]
                }
            ],
            "Page": 1
        },
        {
            "BlockType": "LINE",
            "Confidence": 53.301639556884766,
            "Text": "ellooworio",
            "Geometry": {
                "BoundingBox": {
                    "Width": 0.9999999403953552,
                    "Height": 0.5365243554115295,
                    "Left": 0.0,
                    "Top": 0.46347561478614807
                },
                "Polygon": [
                    {
                        "X": 0.0,
                        "Y": 0.46347561478614807
                    },
                    {
                        "X": 0.9999999403953552,
                        "Y": 0.46347561478614807
                    },
                    {
                        "X": 0.9999999403953552,
                        "Y": 1.0
                    },
                    {
                        "X": 0.0,
                        "Y": 1.0
                    }
                ]
            },
            "Id": "4297834d-dcb1-413b-8908-3b96866ebbb5",
            "Relationships": [
                {
                    "Type": "CHILD",
                    "Ids": [
                        "170c3eb9-5155-4bec-8c44-173bba537e70"
                    ]
                }
            ],
            "Page": 1
        },
        {
            "BlockType": "LINE",
            "Confidence": 89.15632629394531,
            "Text": "He llo,",
            "Geometry": {
                "BoundingBox": {
                    "Width": 0.33642634749412537,
                    "Height": 0.49159330129623413,
                    "Left": 0.13885067403316498,
                    "Top": 0.17169663310050964
                },
                "Polygon": [
                    {
                        "X": 0.13885067403316498,
                        "Y": 0.17169663310050964
                    },
                    {
                        "X": 0.47527703642845154,
                        "Y": 0.17169663310050964
                    },
                    {
                        "X": 0.47527703642845154,
                        "Y": 0.6632899641990662
                    },
                    {
                        "X": 0.13885067403316498,
                        "Y": 0.6632899641990662
                    }
                ]
            },
            "Id": "1d85ba24-2877-4d09-b8b2-393833d769e9",
            "Relationships": [
                {
                    "Type": "CHILD",
                    "Ids": [
                        "516ae823-3bab-4f9a-9d74-ad7150d128ab",
                        "6bcf4ea8-bbe8-4686-91be-b98dd63bc6a6"
                    ]
                }
            ],
            "Page": 1
        },
        {
            "BlockType": "LINE",
            "Confidence": 82.44834899902344,
            "Text": "worlo",
            "Geometry": {
                "BoundingBox": {
                    "Width": 0.33182239532470703,
                    "Height": 0.3766750991344452,
                    "Left": 0.5091826915740967,
                    "Top": 0.23131252825260162
                },
                "Polygon": [
                    {
                        "X": 0.5091826915740967,
                        "Y": 0.23131252825260162
                    },
                    {
                        "X": 0.8410050868988037,
                        "Y": 0.23131252825260162
                    },
                    {
                        "X": 0.8410050868988037,
                        "Y": 0.607987642288208
                    },
                    {
                        "X": 0.5091826915740967,
                        "Y": 0.607987642288208
                    }
                ]
            },
            "Id": "193e9c47-fd87-475a-ba09-3fda210d8784",
            "Relationships": [
                {
                    "Type": "CHILD",
                    "Ids": [
                        "ed135c3b-35dd-4085-8f00-26aedab0125f"
                    ]
                }
            ],
            "Page": 1
        },
        {
            "BlockType": "LINE",
            "Confidence": 88.50325775146484,
            "Text": "world",
            "Geometry": {
                "BoundingBox": {
                    "Width": 0.35004907846450806,
                    "Height": 0.19635874032974243,
                    "Left": 0.527581512928009,
                    "Top": 0.30100569128990173
                },
                "Polygon": [
                    {
                        "X": 0.527581512928009,
                        "Y": 0.30100569128990173
                    },
                    {
                        "X": 0.8776305913925171,
                        "Y": 0.30100569128990173
                    },
                    {
                        "X": 0.8776305913925171,
                        "Y": 0.49736443161964417
                    },
                    {
                        "X": 0.527581512928009,
                        "Y": 0.49736443161964417
                    }
                ]
            },
            "Id": "bd8aeb62-961b-4b47-b78a-e4ed9eeecd0f",
            "Relationships": [
                {
                    "Type": "CHILD",
                    "Ids": [
                        "9e28834d-798e-4a62-8862-a837dfd895a6"
                    ]
                }
            ],
            "Page": 1
        },
        {
            "BlockType": "WORD",
            "Confidence": 53.301639556884766,
            "Text": "ellooworio",
            "Geometry": {
                "BoundingBox": {
                    "Width": 1.0,
                    "Height": 0.5365243554115295,
                    "Left": 0.0,
                    "Top": 0.46347561478614807
                },
                "Polygon": [
                    {
                        "X": 0.0,
                        "Y": 0.46347561478614807
                    },
                    {
                        "X": 1.0,
                        "Y": 0.46347561478614807
                    },
                    {
                        "X": 1.0,
                        "Y": 1.0
                    },
                    {
                        "X": 0.0,
                        "Y": 1.0
                    }
                ]
            },
            "Id": "170c3eb9-5155-4bec-8c44-173bba537e70",
            "Page": 1
        },
        {
            "BlockType": "WORD",
            "Confidence": 88.46246337890625,
            "Text": "He",
            "Geometry": {
                "BoundingBox": {
                    "Width": 0.15350718796253204,
                    "Height": 0.29955607652664185,
                    "Left": 0.13885067403316498,
                    "Top": 0.21856294572353363
                },
                "Polygon": [
                    {
                        "X": 0.13885067403316498,
                        "Y": 0.21856294572353363
                    },
                    {
                        "X": 0.292357861995697,
                        "Y": 0.21856294572353363
                    },
                    {
                        "X": 0.292357861995697,
                        "Y": 0.5181190371513367
                    },
                    {
                        "X": 0.13885067403316498,
                        "Y": 0.5181190371513367
                    }
                ]
            },
            "Id": "516ae823-3bab-4f9a-9d74-ad7150d128ab",
            "Page": 1
        },
        {
            "BlockType": "WORD",
            "Confidence": 89.8501968383789,
            "Text": "llo,",
            "Geometry": {
                "BoundingBox": {
                    "Width": 0.17724157869815826,
                    "Height": 0.49159327149391174,
                    "Left": 0.2980354428291321,
                    "Top": 0.17169663310050964
                },
                "Polygon": [
                    {
                        "X": 0.2980354428291321,
                        "Y": 0.17169663310050964
                    },
                    {
                        "X": 0.47527703642845154,
                        "Y": 0.17169663310050964
                    },
                    {
                        "X": 0.47527703642845154,
                        "Y": 0.6632899045944214
                    },
                    {
                        "X": 0.2980354428291321,
                        "Y": 0.6632899045944214
                    }
                ]
            },
            "Id": "6bcf4ea8-bbe8-4686-91be-b98dd63bc6a6",
            "Page": 1
        },
        {
            "BlockType": "WORD",
            "Confidence": 82.44834899902344,
            "Text": "worlo",
            "Geometry": {
                "BoundingBox": {
                    "Width": 0.33182239532470703,
                    "Height": 0.3766750991344452,
                    "Left": 0.5091826915740967,
                    "Top": 0.23131252825260162
                },
                "Polygon": [
                    {
                        "X": 0.5091826915740967,
                        "Y": 0.23131252825260162
                    },
                    {
                        "X": 0.8410050868988037,
                        "Y": 0.23131252825260162
                    },
                    {
                        "X": 0.8410050868988037,
                        "Y": 0.607987642288208
                    },
                    {
                        "X": 0.5091826915740967,
                        "Y": 0.607987642288208
                    }
                ]
            },
            "Id": "ed135c3b-35dd-4085-8f00-26aedab0125f",
            "Page": 1
        },
        {
            "BlockType": "WORD",
            "Confidence": 88.50325775146484,
            "Text": "world",
            "Geometry": {
                "BoundingBox": {
                    "Width": 0.35004907846450806,
                    "Height": 0.19635874032974243,
                    "Left": 0.527581512928009,
                    "Top": 0.30100569128990173
                },
                "Polygon": [
                    {
                        "X": 0.527581512928009,
                        "Y": 0.30100569128990173
                    },
                    {
                        "X": 0.8776305913925171,
                        "Y": 0.30100569128990173
                    },
                    {
                        "X": 0.8776305913925171,
                        "Y": 0.49736443161964417
                    },
                    {
                        "X": 0.527581512928009,
                        "Y": 0.49736443161964417
                    }
                ]
            },
            "Id": "9e28834d-798e-4a62-8862-a837dfd895a6",
            "Page": 1
        }
    ]
}
```

# 非同期オペレーション用の Amazon Textract の設定
<a name="api-async-roles"></a>

以下の手順は、Amazon Simple Notification Service (Amazon SNS) トピックと Amazon Simple Queue Service (Amazon SQS) キューと一緒に使用する Amazon Textract を設定する方法を示しています。

**注記**  
これらの手順を使用してをセットアップする場合[複数ページドキュメント内のテキストの検出または分析](async-analyzing-with-sqs.md)たとえば、ステップ 3 ～ 6 を実行する必要はありません。この例には、Amazon SNS トピックと Amazon SQS キューを作成して設定するコードが含まれています。

**Amazon Textract を設定するには**

1. をセットアップするAWSAmazon Textract にアクセスするためのアカウント。詳細については、「[ステップ 1: AWS アカウントを設定して IAM ユーザーの作成](setting-up.md)」を参照してください。

   ユーザーに少なくとも以下のアクセス許可があることを確認します。
   + AmazonTextractFullAccess
   + AmazonS3ReadOnlyAccess
   + AmazonSNSFullAccess
   + AmazonSQSFullAccess

1. 必要な AWS SDK をインストールして設定します。詳細については、「[ステップ 2: のセットアップAWS CLIそしてAWSSDK](setup-awscli-sdk.md)」を参照してください。

1. [Amazon SNS トピックを作成する](https://docs.aws.amazon.com/sns/latest/dg/sns-tutorial-create-topic.html)。トピック名の先頭に「」を追加します。*AmazonExtract*。その Amazon リソースネーム (ARN) をメモします。トピックが、と同じリージョンにあることを確認します。AWSAWS アカウントで使用しているエンドポイント。

1. [Amazon SQS 標準キューを作成する](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-create-queue.html)を使用して[Amazon SQS コンソール](https://console.aws.amazon.com/sqs/)。キューの ARN をメモします。

1. ステップ 3 で作成した[トピックにキューをサブスクライブ](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-subscribe-queue-sns-topic.html)します。

1. [Amazon SQS キューにメッセージを送信するアクセス許可を Amazon SNS トピックに付与する](https://docs.aws.amazon.com/sns/latest/dg/subscribe-sqs-queue-to-sns-topic.html)。

1. IAM サービスロールを作成して、Amazon Textract に Amazon SNS トピックへのアクセス権を付与します。このサービスロールの Amazon リソースネーム (ARN) をメモします。詳細については、「[Amazon SNS トピックへの Amazon Textract アクセスを付与する](#api-async-roles-all-topics)」を参照してください。

1. [以下のインラインポリシーを追加します。](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html#embed-inline-policy-console)をステップ 1 で作成した IAM ユーザーに指定します。

   ```
   {
       "Version": "2012-10-17",
       "Statement": [
           {
               "Sid": "MySid",
               "Effect": "Allow",
               "Action": "iam:PassRole",
               "Resource": "Service role ARN from step 7"
           }
       ]
   }
   ```

   インラインポリシーに名前を付けます。

1. これで、の例を実行できます。[複数ページドキュメント内のテキストの検出または分析](async-analyzing-with-sqs.md)。

## Amazon SNS トピックへの Amazon Textract アクセスを付与する
<a name="api-async-roles-all-topics"></a>

Amazon Textract では、非同期操作が完了したときに Amazon SNS トピックにメッセージを送信するためのアクセス許可が必要です。IAM サービスロールを使用して、Amazon Textract に Amazon SNS トピックへのアクセス権を付与します。

 Amazon SNS トピックを作成するときは、トピック名の先頭に「」を付ける必要があります。**AmazonTextract**— たとえば、**AmazonTextractMyTopicName**。

1. IAM コンソール ([https://console.aws.amazon.com/iam](https://console.aws.amazon.com/iam)) にサインインします。

1. ナビゲーションペインで [**Roles (ロール) **] を選択します。

1. [**ロールの作成**] を選択します。

1. [**Select type of trusted entity (信頼されたエンティティのタイプの選択)**] で、[**AWS サービス**] を選択します。

1. を使用する場合**このロールを使用するサービスを選択**で、**Textract**。

1. [**Next: (次へ:)**] を選択します **アクセス許可**.

1. になっていることを確認します。**AmazonTextractServiceRole**ポリシーがアタッチされたポリシーのリストに含まれている。リストにポリシーを表示するには、にポリシー名の一部を入力します。**フィルタポリシー**。

1. [**Next: (次へ:)**] を選択します **タグ**

1. タグの作成は必要ないため、**次へ: 確認**.

1. [**確認**] セクションの [**ロール名**] に、ロールの名前を入力します (例: `TextractRole`)。Eclipse**ロールの説明**で、ロールの説明を更新して、**ロールの作成**。

1. 新しいロールを選択して、ロールの詳細ページを開きます。

1. [**概要**] で、[**ロール ARN**] の値をコピーして保存します。

1. [**Trust relationships (信頼関係)**] を選択します。

1. 選択**信頼関係を編集する**を選択し、信頼ポリシーが次のようになっていることを確認します。

   ```
   {
     "Version": "2012-10-17",
     "Statement": [
       {
         "Effect": "Allow",
         "Principal": {
           "Service": "textract.amazonaws.com"
         },
         "Action": "sts:AssumeRole"
       }
     ]
   }
   ```

1. **[Update Trust Policy]** (信頼ポリシーの更新) をクリックします。

# 複数ページドキュメント内のテキストの検出または分析
<a name="async-analyzing-with-sqs"></a>

この手順では、Amazon Textract 検出オペレーション、Amazon S3 バケットに格納されたドキュメント、Amazon SNS トピック、および Amazon SQS キューを使用して、複数ページのドキュメント内のテキストを検出または分析する方法について説明します。複数ページのドキュメント処理は、非同期オペレーションです。詳細については、「[Amazon Textract 非同期オペレーションを呼び出す](api-async.md)」を参照してください。

コードで実行する処理のタイプ (テキスト検出、テキスト分析、または経費分析) を選択できます。

処理結果は、次の配列で返されます。[Block](API_Block.md)オブジェクト。使用する処理の種類によって異なります。

 複数ページのドキュメント内のテキストを検出したり、分析したりするには、次の操作を行います。

1. Amazon SNS トピックと Amazon SQS キューを作成します。

1. トピックをキューにサブスクライブします。

1. キューにメッセージを送信するアクセス許可をトピックに付与します。

1. ドキュメントの処理を開始します。選択した解析タイプに適切な操作を使用します。
   + [StartDocumentTextDetection](API_StartDocumentTextDetection.md)テキスト検出タスク用。
   + [StartDocumentAnalysis](API_StartDocumentAnalysis.md)テキスト分析タスク用。
   + [StartExpenseAnalysis](API_StartExpenseAnalysis.md)経費分析タスクの場合。

1. 完了ステータスを Amazon SQS キューから取得します。サンプルコードは、ジョブ識別子 () を追跡します。`JobId`) によって返される`Start`オペレーション. 完了ステータスから読み取られた、一致するジョブ識別子の結果だけを取得します。これは、他のアプリケーションが同じキューとトピックを使用している場合、重要です。わかりやすいように、この例では一致しないジョブが削除されます。削除したジョブを Amazon SQS デッドレターキューに追加して詳しく調査することを検討してください。

1. 選択した解析タイプの適切なオペレーションを呼び出して、処理結果を取得して表示します。
   + [GetDocumentTextDetection](API_GetDocumentTextDetection.md)テキスト検出タスク用。
   + [GetDocumentAnalysis](API_GetDocumentAnalysis.md)テキスト分析タスク用。
   + [GetExpenseAnalysis](API_GetExpenseAnalysis.md)経費分析タスクの場合。

1. Amazon SNS トピックと Amazon SQS キューを削除します。

## 非同期操作の実行
<a name="async-prerequisites"></a>

この手順のコード例は Java、Python、AWS CLI。開始する前に、適切なをインストールします。AWSSDK。詳細については、「[ステップ 2: のセットアップAWS CLIそしてAWSSDK](setup-awscli-sdk.md)」を参照してください。

**複数ページのドキュメント内のテキストを検出または分析するには**

1. Amazon Textract へのユーザーアクセスを設定し、Amazon SNS への Amazon Textract アクセスを設定します。詳細については、「[非同期オペレーション用の Amazon Textract の設定](api-async-roles.md)」を参照してください。この手順を完了するには、PDF 形式の複数ページのドキュメントファイルが必要です。コード例によって Amazon SNS トピックと Amazon SQS キューが作成されて設定されるため、ステップ 3 ～ 6 をスキップします。もし複雑ならtCLI の例では、SQS キューを設定する必要はありません。

1. PDF または TIFF 形式の複数ページのドキュメントファイルを Amazon S3 バケットにアップロードします。（JPEG、PNG、TIFF、または PDF 形式の単一ページのドキュメントも処理できます）。

   手順については、以下を参照してください。[Amazon S3 へのオブジェクトのアップロード](https://docs.aws.amazon.com/AmazonS3/latest/user-guide/UploadingObjectsintoAmazonS3.html)の*Amazon Simple Storage Service ユーザーガイド*。

1. 以下を使用します。AWS SDK for Java、SDK for Python (Boto3)、またはAWS CLI複数ページの文書でテキストを検出したり、テキストを分析したりするためのコードです。左`main`関数:
   + の値を置換する`roleArn`で保存した IAM ロール ARN を持つ[Amazon SNS トピックへの Amazon Textract アクセスを付与する](api-async-roles.md#api-async-roles-all-topics)。
   + の値を置換する`bucket`そして`document`に、ステップ 2 で指定したバケット名とドキュメントファイル名を使用します。
   + の値を置換します。`type`の入力パラメータ`ProcessDocument`関数を使用して、実行する処理の種類を指定します。を使用する`ProcessType.DETECTION`テキストを検出します。を使用する`ProcessType.ANALYSIS`テキストを分析します。
   + Python の例では、の値を置き換えます。`region_name`クライアントが操作している地域で。

   向けのAWS CLIたとえば、以下を実行します。
   + 呼び出し時[StartDocumentTextDetection](API_StartDocumentTextDetection.md)で、の値を置き換えます。`bucket-name`を S3 バケットの名前に置き換えます。`file-name`に、ステップ 2 で指定したファイル名を使用します。置き換えてバケットのリージョンを指定します。`region-name`お住まいの地域の名前を付けて。CLI の例では SQS を使用しないことに注意してください。
   + 呼び出し時[GetDocumentTextDetection](API_GetDocumentTextDetection.md)置換`job-id-number`と`job-id`によって返される[StartDocumentTextDetection](API_StartDocumentTextDetection.md)。置き換えてバケットのリージョンを指定します。`region-name`お住まいの地域の名前を付けて。

------
#### [ Java ]

   ```
   package com.amazonaws.samples;
   
   import java.util.Arrays;
   import java.util.HashMap;
   import java.util.List;
   import java.util.Map;
   
   import com.amazonaws.auth.policy.Condition;
   import com.amazonaws.auth.policy.Policy;
   import com.amazonaws.auth.policy.Principal;
   import com.amazonaws.auth.policy.Resource;
   import com.amazonaws.auth.policy.Statement;
   import com.amazonaws.auth.policy.Statement.Effect;
   import com.amazonaws.auth.policy.actions.SQSActions;
   import com.amazonaws.services.sns.AmazonSNS;
   import com.amazonaws.services.sns.AmazonSNSClientBuilder;
   import com.amazonaws.services.sns.model.CreateTopicRequest;
   import com.amazonaws.services.sns.model.CreateTopicResult;
   import com.amazonaws.services.sqs.AmazonSQS;
   import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
   import com.amazonaws.services.sqs.model.CreateQueueRequest;
   import com.amazonaws.services.sqs.model.Message;
   import com.amazonaws.services.sqs.model.QueueAttributeName;
   import com.amazonaws.services.sqs.model.SetQueueAttributesRequest;
   import com.amazonaws.services.textract.AmazonTextract;
   import com.amazonaws.services.textract.AmazonTextractClientBuilder;
   import com.amazonaws.services.textract.model.Block;
   import com.amazonaws.services.textract.model.DocumentLocation;
   import com.amazonaws.services.textract.model.DocumentMetadata;
   import com.amazonaws.services.textract.model.GetDocumentAnalysisRequest;
   import com.amazonaws.services.textract.model.GetDocumentAnalysisResult;
   import com.amazonaws.services.textract.model.GetDocumentTextDetectionRequest;
   import com.amazonaws.services.textract.model.GetDocumentTextDetectionResult;
   import com.amazonaws.services.textract.model.NotificationChannel;
   import com.amazonaws.services.textract.model.Relationship;
   import com.amazonaws.services.textract.model.S3Object;
   import com.amazonaws.services.textract.model.StartDocumentAnalysisRequest;
   import com.amazonaws.services.textract.model.StartDocumentAnalysisResult;
   import com.amazonaws.services.textract.model.StartDocumentTextDetectionRequest;
   import com.amazonaws.services.textract.model.StartDocumentTextDetectionResult;
   import com.fasterxml.jackson.databind.JsonNode;
   import com.fasterxml.jackson.databind.ObjectMapper;;
   public class DocumentProcessor {
   
       private static String sqsQueueName=null;
       private static String snsTopicName=null;
       private static String snsTopicArn = null;
       private static String roleArn= null;
       private static String sqsQueueUrl = null;
       private static String sqsQueueArn = null;
       private static String startJobId = null;
       private static String bucket = null;
       private static String document = null; 
       private static AmazonSQS sqs=null;
       private static AmazonSNS sns=null;
       private static AmazonTextract textract = null;
   
       public enum ProcessType {
           DETECTION,ANALYSIS
       }
   
       public static void main(String[] args) throws Exception {
           
           String document = "document";
           String bucket = "bucket";
           String roleArn="role";
   
           sns = AmazonSNSClientBuilder.defaultClient();
           sqs= AmazonSQSClientBuilder.defaultClient();
           textract=AmazonTextractClientBuilder.defaultClient();
           
           CreateTopicandQueue();
           ProcessDocument(bucket,document,roleArn,ProcessType.DETECTION);
           DeleteTopicandQueue();
           System.out.println("Done!");
           
           
       }
       // Creates an SNS topic and SQS queue. The queue is subscribed to the topic. 
       static void CreateTopicandQueue()
       {
           //create a new SNS topic
           snsTopicName="AmazonTextractTopic" + Long.toString(System.currentTimeMillis());
           CreateTopicRequest createTopicRequest = new CreateTopicRequest(snsTopicName);
           CreateTopicResult createTopicResult = sns.createTopic(createTopicRequest);
           snsTopicArn=createTopicResult.getTopicArn();
           
           //Create a new SQS Queue
           sqsQueueName="AmazonTextractQueue" + Long.toString(System.currentTimeMillis());
           final CreateQueueRequest createQueueRequest = new CreateQueueRequest(sqsQueueName);
           sqsQueueUrl = sqs.createQueue(createQueueRequest).getQueueUrl();
           sqsQueueArn = sqs.getQueueAttributes(sqsQueueUrl, Arrays.asList("QueueArn")).getAttributes().get("QueueArn");
           
           //Subscribe SQS queue to SNS topic
           String sqsSubscriptionArn = sns.subscribe(snsTopicArn, "sqs", sqsQueueArn).getSubscriptionArn();
           
           // Authorize queue
             Policy policy = new Policy().withStatements(
                     new Statement(Effect.Allow)
                     .withPrincipals(Principal.AllUsers)
                     .withActions(SQSActions.SendMessage)
                     .withResources(new Resource(sqsQueueArn))
                     .withConditions(new Condition().withType("ArnEquals").withConditionKey("aws:SourceArn").withValues(snsTopicArn))
                     );
                     
   
             Map queueAttributes = new HashMap();
             queueAttributes.put(QueueAttributeName.Policy.toString(), policy.toJson());
             sqs.setQueueAttributes(new SetQueueAttributesRequest(sqsQueueUrl, queueAttributes)); 
             
   
            System.out.println("Topic arn: " + snsTopicArn);
            System.out.println("Queue arn: " + sqsQueueArn);
            System.out.println("Queue url: " + sqsQueueUrl);
            System.out.println("Queue sub arn: " + sqsSubscriptionArn );
        }
       static void DeleteTopicandQueue()
       {
           if (sqs !=null) {
               sqs.deleteQueue(sqsQueueUrl);
               System.out.println("SQS queue deleted");
           }
           
           if (sns!=null) {
               sns.deleteTopic(snsTopicArn);
               System.out.println("SNS topic deleted");
           }
       }
       
       //Starts the processing of the input document.
       static void ProcessDocument(String inBucket, String inDocument, String inRoleArn, ProcessType type) throws Exception
       {
           bucket=inBucket;
           document=inDocument;
           roleArn=inRoleArn;
   
           switch(type)
           {
               case DETECTION:
                   StartDocumentTextDetection(bucket, document);
                   System.out.println("Processing type: Detection");
                   break;
               case ANALYSIS:
                   StartDocumentAnalysis(bucket,document);
                   System.out.println("Processing type: Analysis");
                   break;
               default:
                   System.out.println("Invalid processing type. Choose Detection or Analysis");
                   throw new Exception("Invalid processing type");
              
           }
   
           System.out.println("Waiting for job: " + startJobId);
           //Poll queue for messages
           List<Message> messages=null;
           int dotLine=0;
           boolean jobFound=false;
   
           //loop until the job status is published. Ignore other messages in queue.
           do{
               messages = sqs.receiveMessage(sqsQueueUrl).getMessages();
               if (dotLine++<40){
                   System.out.print(".");
               }else{
                   System.out.println();
                   dotLine=0;
               }
   
               if (!messages.isEmpty()) {
                   //Loop through messages received.
                   for (Message message: messages) {
                       String notification = message.getBody();
   
                       // Get status and job id from notification.
                       ObjectMapper mapper = new ObjectMapper();
                       JsonNode jsonMessageTree = mapper.readTree(notification);
                       JsonNode messageBodyText = jsonMessageTree.get("Message");
                       ObjectMapper operationResultMapper = new ObjectMapper();
                       JsonNode jsonResultTree = operationResultMapper.readTree(messageBodyText.textValue());
                       JsonNode operationJobId = jsonResultTree.get("JobId");
                       JsonNode operationStatus = jsonResultTree.get("Status");
                       System.out.println("Job found was " + operationJobId);
                       // Found job. Get the results and display.
                       if(operationJobId.asText().equals(startJobId)){
                           jobFound=true;
                           System.out.println("Job id: " + operationJobId );
                           System.out.println("Status : " + operationStatus.toString());
                           if (operationStatus.asText().equals("SUCCEEDED")){
                               switch(type)
                               {
                                   case DETECTION:
                                       GetDocumentTextDetectionResults();
                                       break;
                                   case ANALYSIS:
                                       GetDocumentAnalysisResults();
                                       break;
                                   default:
                                       System.out.println("Invalid processing type. Choose Detection or Analysis");
                                       throw new Exception("Invalid processing type");
                                  
                               }
                           }
                           else{
                               System.out.println("Document analysis failed");
                           }
   
                           sqs.deleteMessage(sqsQueueUrl,message.getReceiptHandle());
                       }
   
                       else{
                           System.out.println("Job received was not job " +  startJobId);
                           //Delete unknown message. Consider moving message to dead letter queue
                           sqs.deleteMessage(sqsQueueUrl,message.getReceiptHandle());
                       }
                   }
               }
               else {
                   Thread.sleep(5000);
               }
           } while (!jobFound);
   
           System.out.println("Finished processing document");
       }
       
       private static void StartDocumentTextDetection(String bucket, String document) throws Exception{
   
           //Create notification channel 
           NotificationChannel channel= new NotificationChannel()
                   .withSNSTopicArn(snsTopicArn)
                   .withRoleArn(roleArn);
   
           StartDocumentTextDetectionRequest req = new StartDocumentTextDetectionRequest()
                   .withDocumentLocation(new DocumentLocation()
                       .withS3Object(new S3Object()
                           .withBucket(bucket)
                           .withName(document)))
                   .withJobTag("DetectingText")
                   .withNotificationChannel(channel);
   
           StartDocumentTextDetectionResult startDocumentTextDetectionResult = textract.startDocumentTextDetection(req);
           startJobId=startDocumentTextDetectionResult.getJobId();
       }
       
     //Gets the results of processing started by StartDocumentTextDetection
       private static void GetDocumentTextDetectionResults() throws Exception{
           int maxResults=1000;
           String paginationToken=null;
           GetDocumentTextDetectionResult response=null;
           Boolean finished=false;
           
           while (finished==false)
           {
               GetDocumentTextDetectionRequest documentTextDetectionRequest= new GetDocumentTextDetectionRequest()
                       .withJobId(startJobId)
                       .withMaxResults(maxResults)
                       .withNextToken(paginationToken);
               response = textract.getDocumentTextDetection(documentTextDetectionRequest);
               DocumentMetadata documentMetaData=response.getDocumentMetadata();
   
               System.out.println("Pages: " + documentMetaData.getPages().toString());
               
               //Show blocks information
               List<Block> blocks= response.getBlocks();
               for (Block block : blocks) {
                   DisplayBlockInfo(block);
               }
               paginationToken=response.getNextToken();
               if (paginationToken==null)
                   finished=true;
               
           }
           
       }
   
       private static void StartDocumentAnalysis(String bucket, String document) throws Exception{
           //Create notification channel 
           NotificationChannel channel= new NotificationChannel()
                   .withSNSTopicArn(snsTopicArn)
                   .withRoleArn(roleArn);
           
           StartDocumentAnalysisRequest req = new StartDocumentAnalysisRequest()
                   .withFeatureTypes("TABLES","FORMS")
                   .withDocumentLocation(new DocumentLocation()
                       .withS3Object(new S3Object()
                           .withBucket(bucket)
                           .withName(document)))
                   .withJobTag("AnalyzingText")
                   .withNotificationChannel(channel);
   
           StartDocumentAnalysisResult startDocumentAnalysisResult = textract.startDocumentAnalysis(req);
           startJobId=startDocumentAnalysisResult.getJobId();
       }
       //Gets the results of processing started by StartDocumentAnalysis
       private static void GetDocumentAnalysisResults() throws Exception{
   
           int maxResults=1000;
           String paginationToken=null;
           GetDocumentAnalysisResult response=null;
           Boolean finished=false;
           
           //loops until pagination token is null
           while (finished==false)
           {
               GetDocumentAnalysisRequest documentAnalysisRequest= new GetDocumentAnalysisRequest()
                       .withJobId(startJobId)
                       .withMaxResults(maxResults)
                       .withNextToken(paginationToken);
               
               response = textract.getDocumentAnalysis(documentAnalysisRequest);
   
               DocumentMetadata documentMetaData=response.getDocumentMetadata();
   
               System.out.println("Pages: " + documentMetaData.getPages().toString());
   
               //Show blocks, confidence and detection times
               List<Block> blocks= response.getBlocks();
   
               for (Block block : blocks) {
                   DisplayBlockInfo(block);
               }
               paginationToken=response.getNextToken();
               if (paginationToken==null)
                   finished=true;
           }
   
       }
       //Displays Block information for text detection and text analysis
       private static void DisplayBlockInfo(Block block) {
           System.out.println("Block Id : " + block.getId());
           if (block.getText()!=null)
               System.out.println("\tDetected text: " + block.getText());
           System.out.println("\tType: " + block.getBlockType());
           
           if (block.getBlockType().equals("PAGE") !=true) {
               System.out.println("\tConfidence: " + block.getConfidence().toString());
           }
           if(block.getBlockType().equals("CELL"))
           {
               System.out.println("\tCell information:");
               System.out.println("\t\tColumn: " + block.getColumnIndex());
               System.out.println("\t\tRow: " + block.getRowIndex());
               System.out.println("\t\tColumn span: " + block.getColumnSpan());
               System.out.println("\t\tRow span: " + block.getRowSpan());
   
           }
           
           System.out.println("\tRelationships");
           List<Relationship> relationships=block.getRelationships();
           if(relationships!=null) {
               for (Relationship relationship : relationships) {
                   System.out.println("\t\tType: " + relationship.getType());
                   System.out.println("\t\tIDs: " + relationship.getIds().toString());
               }
           } else {
               System.out.println("\t\tNo related Blocks");
           }
   
           System.out.println("\tGeometry");
           System.out.println("\t\tBounding Box: " + block.getGeometry().getBoundingBox().toString());
           System.out.println("\t\tPolygon: " + block.getGeometry().getPolygon().toString());
           
           List<String> entityTypes = block.getEntityTypes();
           
           System.out.println("\tEntity Types");
           if(entityTypes!=null) {
               for (String entityType : entityTypes) {
                   System.out.println("\t\tEntity Type: " + entityType);
               }
           } else {
               System.out.println("\t\tNo entity type");
           }
           
           if(block.getBlockType().equals("SELECTION_ELEMENT")) {
               System.out.print("    Selection element detected: ");
               if (block.getSelectionStatus().equals("SELECTED")){
                   System.out.println("Selected");
               }else {
                   System.out.println(" Not selected");
               }
           }
           if(block.getPage()!=null)
               System.out.println("\tPage: " + block.getPage());            
           System.out.println();
       }
   }
   ```

------
#### [ AWS CLI ]

   このAWS CLIコマンドは、指定したドキュメント内のテキストの非同期検出を開始します。このメソッドからは、`job-id`これにより、検出結果を取得できます。

   ```
   aws textract start-document-text-detection --document-location 
   "{\"S3Object\":{\"Bucket\":\"bucket-name\",\"Name\":\"file-name\"}}" --region region-name
   ```

   このAWS CLIコマンドを使用すると、Amazon Textract 非同期オペレーションの結果が返されます。`job-id`。

   ```
   aws textract get-document-text-detection --region region-name --job-id job-id-number
   ```

   Windows デバイスで CLI にアクセスする場合は、一重引用符ではなく二重引用符を使用し、内部の二重引用符をバックスラッシュ（つまり\$1）でエスケープして、発生する可能性のあるパーサーエラーに対処します。例については、以下を参照してください

   ```
   aws textract start-document-text-detection --document-location "{\"S3Object\":{\"Bucket\":\"bucket\",\"Name\":\"document\"}}" --region region-name
   ```

------
#### [ Python ]

   ```
   import boto3
   import json
   import sys
   import time
   
   
   class ProcessType:
       DETECTION = 1
       ANALYSIS = 2
   
   
   class DocumentProcessor:
       jobId = ''
       region_name = ''
   
       roleArn = ''
       bucket = ''
       document = ''
   
       sqsQueueUrl = ''
       snsTopicArn = ''
       processType = ''
   
       def __init__(self, role, bucket, document, region):
           self.roleArn = role
           self.bucket = bucket
           self.document = document
           self.region_name = region
   
           self.textract = boto3.client('textract', region_name=self.region_name)
           self.sqs = boto3.client('sqs')
           self.sns = boto3.client('sns')
   
       def ProcessDocument(self, type):
           jobFound = False
   
           self.processType = type
           validType = False
   
           # Determine which type of processing to perform
           if self.processType == ProcessType.DETECTION:
               response = self.textract.start_document_text_detection(
                   DocumentLocation={'S3Object': {'Bucket': self.bucket, 'Name': self.document}},
                   NotificationChannel={'RoleArn': self.roleArn, 'SNSTopicArn': self.snsTopicArn})
               print('Processing type: Detection')
               validType = True
   
           if self.processType == ProcessType.ANALYSIS:
               response = self.textract.start_document_analysis(
                   DocumentLocation={'S3Object': {'Bucket': self.bucket, 'Name': self.document}},
                   FeatureTypes=["TABLES", "FORMS"],
                   NotificationChannel={'RoleArn': self.roleArn, 'SNSTopicArn': self.snsTopicArn})
               print('Processing type: Analysis')
               validType = True
   
           if validType == False:
               print("Invalid processing type. Choose Detection or Analysis.")
               return
   
           print('Start Job Id: ' + response['JobId'])
           dotLine = 0
           while jobFound == False:
               sqsResponse = self.sqs.receive_message(QueueUrl=self.sqsQueueUrl, MessageAttributeNames=['ALL'],
                                                      MaxNumberOfMessages=10)
   
               if sqsResponse:
   
                   if 'Messages' not in sqsResponse:
                       if dotLine < 40:
                           print('.', end='')
                           dotLine = dotLine + 1
                       else:
                           print()
                           dotLine = 0
                       sys.stdout.flush()
                       time.sleep(5)
                       continue
   
                   for message in sqsResponse['Messages']:
                       notification = json.loads(message['Body'])
                       textMessage = json.loads(notification['Message'])
                       print(textMessage['JobId'])
                       print(textMessage['Status'])
                       if str(textMessage['JobId']) == response['JobId']:
                           print('Matching Job Found:' + textMessage['JobId'])
                           jobFound = True
                           self.GetResults(textMessage['JobId'])
                           self.sqs.delete_message(QueueUrl=self.sqsQueueUrl,
                                                   ReceiptHandle=message['ReceiptHandle'])
                       else:
                           print("Job didn't match:" +
                                 str(textMessage['JobId']) + ' : ' + str(response['JobId']))
                       # Delete the unknown message. Consider sending to dead letter queue
                       self.sqs.delete_message(QueueUrl=self.sqsQueueUrl,
                                               ReceiptHandle=message['ReceiptHandle'])
   
           print('Done!')
   
       def CreateTopicandQueue(self):
   
           millis = str(int(round(time.time() * 1000)))
   
           # Create SNS topic
           snsTopicName = "AmazonTextractTopic" + millis
   
           topicResponse = self.sns.create_topic(Name=snsTopicName)
           self.snsTopicArn = topicResponse['TopicArn']
   
           # create SQS queue
           sqsQueueName = "AmazonTextractQueue" + millis
           self.sqs.create_queue(QueueName=sqsQueueName)
           self.sqsQueueUrl = self.sqs.get_queue_url(QueueName=sqsQueueName)['QueueUrl']
   
           attribs = self.sqs.get_queue_attributes(QueueUrl=self.sqsQueueUrl,
                                                   AttributeNames=['QueueArn'])['Attributes']
   
           sqsQueueArn = attribs['QueueArn']
   
           # Subscribe SQS queue to SNS topic
           self.sns.subscribe(
               TopicArn=self.snsTopicArn,
               Protocol='sqs',
               Endpoint=sqsQueueArn)
   
           # Authorize SNS to write SQS queue
           policy = """{{
     "Version":"2012-10-17",
     "Statement":[
       {{
         "Sid":"MyPolicy",
         "Effect":"Allow",
         "Principal" : {{"AWS" : "*"}},
         "Action":"SQS:SendMessage",
         "Resource": "{}",
         "Condition":{{
           "ArnEquals":{{
             "aws:SourceArn": "{}"
           }}
         }}
       }}
     ]
   }}""".format(sqsQueueArn, self.snsTopicArn)
   
           response = self.sqs.set_queue_attributes(
               QueueUrl=self.sqsQueueUrl,
               Attributes={
                   'Policy': policy
               })
   
       def DeleteTopicandQueue(self):
           self.sqs.delete_queue(QueueUrl=self.sqsQueueUrl)
           self.sns.delete_topic(TopicArn=self.snsTopicArn)
   
       # Display information about a block
       def DisplayBlockInfo(self, block):
   
           print("Block Id: " + block['Id'])
           print("Type: " + block['BlockType'])
           if 'EntityTypes' in block:
               print('EntityTypes: {}'.format(block['EntityTypes']))
   
           if 'Text' in block:
               print("Text: " + block['Text'])
   
           if block['BlockType'] != 'PAGE':
               print("Confidence: " + "{:.2f}".format(block['Confidence']) + "%")
   
           print('Page: {}'.format(block['Page']))
   
           if block['BlockType'] == 'CELL':
               print('Cell Information')
               print('\tColumn: {} '.format(block['ColumnIndex']))
               print('\tRow: {}'.format(block['RowIndex']))
               print('\tColumn span: {} '.format(block['ColumnSpan']))
               print('\tRow span: {}'.format(block['RowSpan']))
   
               if 'Relationships' in block:
                   print('\tRelationships: {}'.format(block['Relationships']))
   
           print('Geometry')
           print('\tBounding Box: {}'.format(block['Geometry']['BoundingBox']))
           print('\tPolygon: {}'.format(block['Geometry']['Polygon']))
   
           if block['BlockType'] == 'SELECTION_ELEMENT':
               print('    Selection element detected: ', end='')
               if block['SelectionStatus'] == 'SELECTED':
                   print('Selected')
               else:
                   print('Not selected')
   
       def GetResults(self, jobId):
           maxResults = 1000
           paginationToken = None
           finished = False
   
           while finished == False:
   
               response = None
   
               if self.processType == ProcessType.ANALYSIS:
                   if paginationToken == None:
                       response = self.textract.get_document_analysis(JobId=jobId,
                                                                      MaxResults=maxResults)
                   else:
                       response = self.textract.get_document_analysis(JobId=jobId,
                                                                      MaxResults=maxResults,
                                                                      NextToken=paginationToken)
   
               if self.processType == ProcessType.DETECTION:
                   if paginationToken == None:
                       response = self.textract.get_document_text_detection(JobId=jobId,
                                                                            MaxResults=maxResults)
                   else:
                       response = self.textract.get_document_text_detection(JobId=jobId,
                                                                            MaxResults=maxResults,
                                                                            NextToken=paginationToken)
   
               blocks = response['Blocks']
               print('Detected Document Text')
               print('Pages: {}'.format(response['DocumentMetadata']['Pages']))
   
               # Display block information
               for block in blocks:
                   self.DisplayBlockInfo(block)
                   print()
                   print()
   
               if 'NextToken' in response:
                   paginationToken = response['NextToken']
               else:
                   finished = True
   
       def GetResultsDocumentAnalysis(self, jobId):
           maxResults = 1000
           paginationToken = None
           finished = False
   
           while finished == False:
   
               response = None
               if paginationToken == None:
                   response = self.textract.get_document_analysis(JobId=jobId,
                                                                  MaxResults=maxResults)
               else:
                   response = self.textract.get_document_analysis(JobId=jobId,
                                                                  MaxResults=maxResults,
                                                                  NextToken=paginationToken)
   
                   # Get the text blocks
               blocks = response['Blocks']
               print('Analyzed Document Text')
               print('Pages: {}'.format(response['DocumentMetadata']['Pages']))
               # Display block information
               for block in blocks:
                   self.DisplayBlockInfo(block)
                   print()
                   print()
   
                   if 'NextToken' in response:
                       paginationToken = response['NextToken']
                   else:
                       finished = True
   
   
   def main():
       roleArn = ''
       bucket = ''
       document = ''
       region_name = ''
   
       analyzer = DocumentProcessor(roleArn, bucket, document, region_name)
       analyzer.CreateTopicandQueue()
       analyzer.ProcessDocument(ProcessType.DETECTION)
       analyzer.DeleteTopicandQueue()
   
   
   if __name__ == "__main__":
       main()
   ```

------
#### [ Node.JS ]

   この例では、の値を置き換えます。`roleArn`で保存した IAM ロール ARN を持つ[Amazon SNS トピックへの Amazon Textract アクセスを付与する](api-async-roles.md#api-async-roles-all-topics)。の値を置換する`bucket`そして`document`は、上記のステップ 2 で指定したバケット名とドキュメントファイル名を使用します。の値を置換する`processType`入力ドキュメントで使用する処理の種類を指定します。最後に、の値を置き換えます。`REGION`クライアントが操作している地域で。

   ```
    // snippet-start:[sqs.JavaScript.queues.createQueueV3]
   // Import required AWS SDK clients and commands for Node.js
   import { CreateQueueCommand, GetQueueAttributesCommand, GetQueueUrlCommand, 
       SetQueueAttributesCommand, DeleteQueueCommand, ReceiveMessageCommand, DeleteMessageCommand } from  "@aws-sdk/client-sqs";
     import {CreateTopicCommand, SubscribeCommand, DeleteTopicCommand } from "@aws-sdk/client-sns";
     import  { SQSClient } from "@aws-sdk/client-sqs";
     import  { SNSClient } from "@aws-sdk/client-sns";
     import  { TextractClient, StartDocumentTextDetectionCommand, StartDocumentAnalysisCommand, GetDocumentAnalysisCommand, GetDocumentTextDetectionCommand, DocumentMetadata } from "@aws-sdk/client-textract";
     import { stdout } from "process";
     
     // Set the AWS Region.
     const REGION = "us-east-1"; //e.g. "us-east-1"
     // Create SNS service object.
     const sqsClient = new SQSClient({ region: REGION });
     const snsClient = new SNSClient({ region: REGION });
     const textractClient = new TextractClient({ region: REGION });
     
     // Set bucket and video variables
     const bucket = "bucket-name";                                                                                                                  
     const documentName = "document-name";
     const roleArn = "role-arn"
     const processType = "DETECTION"
     var startJobId = ""
     
     var ts = Date.now();
     const snsTopicName = "AmazonTextractExample" + ts;
     const snsTopicParams = {Name: snsTopicName}
     const sqsQueueName = "AmazonTextractQueue-" + ts;
   
     // Set the parameters
     const sqsParams = {
       QueueName: sqsQueueName, //SQS_QUEUE_URL
       Attributes: {
         DelaySeconds: "60", // Number of seconds delay.
         MessageRetentionPeriod: "86400", // Number of seconds delay.
       },
     };
     
     // Process a document based on operation type
     const processDocumment = async (type, bucket, videoName, roleArn, sqsQueueUrl, snsTopicArn) =>
       {
       try
       {
           // Set job found and success status to false initially
         var jobFound = false
         var succeeded = false
         var dotLine = 0
         var processType = type
         var validType = false
   
         if (processType == "DETECTION"){
           var response = await textractClient.send(new StartDocumentTextDetectionCommand({DocumentLocation:{S3Object:{Bucket:bucket, Name:videoName}}, 
             NotificationChannel:{RoleArn: roleArn, SNSTopicArn: snsTopicArn}}))
           console.log("Processing type: Detection")
           validType = true
         }
   
         if (processType == "ANALYSIS"){
           var response = await textractClient.send(new StartDocumentAnalysisCommand({DocumentLocation:{S3Object:{Bucket:bucket, Name:videoName}}, 
             NotificationChannel:{RoleArn: roleArn, SNSTopicArn: snsTopicArn}}))
           console.log("Processing type: Analysis")
           validType = true
         }
   
         if (validType == false){
             console.log("Invalid processing type. Choose Detection or Analysis.")
             return
         }
       // while not found, continue to poll for response
       console.log(`Start Job ID: ${response.JobId}`)
       while (jobFound == false){
         var sqsReceivedResponse = await sqsClient.send(new ReceiveMessageCommand({QueueUrl:sqsQueueUrl, 
           MaxNumberOfMessages:'ALL', MaxNumberOfMessages:10}));
         if (sqsReceivedResponse){
           var responseString = JSON.stringify(sqsReceivedResponse)
           if (!responseString.includes('Body')){
             if (dotLine < 40) {
               console.log('.')
               dotLine = dotLine + 1
             }else {
               console.log('')
               dotLine = 0 
             };
             stdout.write('', () => {
               console.log('');
             });
             await new Promise(resolve => setTimeout(resolve, 5000));
             continue
           }
         }
   
           // Once job found, log Job ID and return true if status is succeeded
           for (var message of sqsReceivedResponse.Messages){
               console.log("Retrieved messages:")
               var notification = JSON.parse(message.Body)
               var rekMessage = JSON.parse(notification.Message)
               var messageJobId = rekMessage.JobId
               if (String(rekMessage.JobId).includes(String(startJobId))){
                   console.log('Matching job found:')
                   console.log(rekMessage.JobId)
                   jobFound = true
                   // GET RESUlTS FUNCTION HERE
                   var operationResults = await GetResults(processType, rekMessage.JobId)
                   //GET RESULTS FUMCTION HERE
                   console.log(rekMessage.Status)
               if (String(rekMessage.Status).includes(String("SUCCEEDED"))){
                   succeeded = true
                   console.log("Job processing succeeded.")
                   var sqsDeleteMessage = await sqsClient.send(new DeleteMessageCommand({QueueUrl:sqsQueueUrl, ReceiptHandle:message.ReceiptHandle}));
               }
               }else{
               console.log("Provided Job ID did not match returned ID.")
               var sqsDeleteMessage = await sqsClient.send(new DeleteMessageCommand({QueueUrl:sqsQueueUrl, ReceiptHandle:message.ReceiptHandle}));
               }
           }
   
       console.log("Done!")
       }
       }catch (err) {
           console.log("Error", err);
         }
     }
   
     // Create the SNS topic and SQS Queue
     const createTopicandQueue = async () => {
       try {
         // Create SNS topic
         const topicResponse = await snsClient.send(new CreateTopicCommand(snsTopicParams));
         const topicArn = topicResponse.TopicArn
         console.log("Success", topicResponse);
         // Create SQS Queue
         const sqsResponse = await sqsClient.send(new CreateQueueCommand(sqsParams));
         console.log("Success", sqsResponse);
         const sqsQueueCommand = await sqsClient.send(new GetQueueUrlCommand({QueueName: sqsQueueName}))
         const sqsQueueUrl = sqsQueueCommand.QueueUrl
         const attribsResponse = await sqsClient.send(new GetQueueAttributesCommand({QueueUrl: sqsQueueUrl, AttributeNames: ['QueueArn']}))
         const attribs = attribsResponse.Attributes
         console.log(attribs)
         const queueArn = attribs.QueueArn
         // subscribe SQS queue to SNS topic
         const subscribed = await snsClient.send(new SubscribeCommand({TopicArn: topicArn, Protocol:'sqs', Endpoint: queueArn}))
         const policy = {
           Version: "2012-10-17",
           Statement: [
             {
               Sid: "MyPolicy",
               Effect: "Allow",
               Principal: {AWS: "*"},
               Action: "SQS:SendMessage",
               Resource: queueArn,
               Condition: {
                 ArnEquals: {
                   'aws:SourceArn': topicArn
                 }
               }
             }
           ]
         };
     
         const response = sqsClient.send(new SetQueueAttributesCommand({QueueUrl: sqsQueueUrl, Attributes: {Policy: JSON.stringify(policy)}}))
         console.log(response)
         console.log(sqsQueueUrl, topicArn)
         return [sqsQueueUrl, topicArn]
     
       } catch (err) {
         console.log("Error", err);
   
       }
     }
   
     const deleteTopicAndQueue = async (sqsQueueUrlArg, snsTopicArnArg) => {
       const deleteQueue = await sqsClient.send(new DeleteQueueCommand({QueueUrl: sqsQueueUrlArg}));
       const deleteTopic = await snsClient.send(new DeleteTopicCommand({TopicArn: snsTopicArnArg}));
       console.log("Successfully deleted.")
     }
   
     const displayBlockInfo = async (block) => {
       console.log(`Block ID: ${block.Id}`)
       console.log(`Block Type: ${block.BlockType}`)
       if (String(block).includes(String("EntityTypes"))){
           console.log(`EntityTypes: ${block.EntityTypes}`)
       }
       if (String(block).includes(String("Text"))){
           console.log(`EntityTypes: ${block.Text}`)
       }
       if (!String(block.BlockType).includes('PAGE')){
           console.log(`Confidence: ${block.Confidence}`)
       }
       console.log(`Page: ${block.Page}`)
       if (String(block.BlockType).includes("CELL")){
           console.log("Cell Information")
           console.log(`Column: ${block.ColumnIndex}`)
           console.log(`Row: ${block.RowIndex}`)
           console.log(`Column Span: ${block.ColumnSpan}`)
           console.log(`Row Span: ${block.RowSpan}`)
           if (String(block).includes("Relationships")){
               console.log(`Relationships: ${block.Relationships}`)
           }
       }
   
       console.log("Geometry")
       console.log(`Bounding Box: ${JSON.stringify(block.Geometry.BoundingBox)}`)
       console.log(`Polygon: ${JSON.stringify(block.Geometry.Polygon)}`)
   
       if (String(block.BlockType).includes('SELECTION_ELEMENT')){
         console.log('Selection Element detected:')
         if (String(block.SelectionStatus).includes('SELECTED')){
           console.log('Selected')
         } else {
           console.log('Not Selected')
         }
   
       }
     }
   
     const GetResults = async (processType, JobID) => {
   
       var maxResults = 1000
       var paginationToken = null
       var finished = false
   
       while (finished == false){
         var response = null
         if (processType == 'ANALYSIS'){
           if (paginationToken == null){
             response = textractClient.send(new GetDocumentAnalysisCommand({JobId:JobID, MaxResults:maxResults}))
         
           }else{
             response = textractClient.send(new GetDocumentAnalysisCommand({JobId:JobID, MaxResults:maxResults, NextToken:paginationToken}))
           }
         }
           
         if(processType == 'DETECTION'){
           if (paginationToken == null){
             response = textractClient.send(new GetDocumentTextDetectionCommand({JobId:JobID, MaxResults:maxResults}))
         
           }else{
             response = textractClient.send(new GetDocumentTextDetectionCommand({JobId:JobID, MaxResults:maxResults, NextToken:paginationToken}))
           }
         }
   
         await new Promise(resolve => setTimeout(resolve, 5000));
         console.log("Detected Documented Text")
         console.log(response)
         //console.log(Object.keys(response))
         console.log(typeof(response))
         var blocks = (await response).Blocks
         console.log(blocks)
         console.log(typeof(blocks))
         var docMetadata = (await response).DocumentMetadata
         var blockString = JSON.stringify(blocks)
         var parsed = JSON.parse(JSON.stringify(blocks))
         console.log(Object.keys(blocks))
         console.log(`Pages: ${docMetadata.Pages}`)
         blocks.forEach((block)=> {
           displayBlockInfo(block)
           console.log()
           console.log()
         })
   
         //console.log(blocks[0].BlockType)
         //console.log(blocks[1].BlockType)
   
   
         if(String(response).includes("NextToken")){
           paginationToken = response.NextToken
         }else{
           finished = true
         }
       }
   
     }
   
   
     // DELETE TOPIC AND QUEUE
     const main = async () => {
       var sqsAndTopic = await createTopicandQueue();
       var process = await processDocumment(processType, bucket, documentName, roleArn, sqsAndTopic[0], sqsAndTopic[1])
       var deleteResults = await deleteTopicAndQueue(sqsAndTopic[0], sqsAndTopic[1])
     }
   
   main()
   ```

------

1. コードを実行します。オペレーションの完了までに時間がかかる場合があります。完了すると、検出または分析されたテキストのブロックのリストが表示されます。

# Amazon Textract 結果通知
<a name="async-notification-payload"></a>

Amazon Textract は、完了ステータスを含む Amazon Textract 分析リクエストの結果を、Amazon Simple Notification Service (Amazon SNS) トピックに発行します。Amazon SNS トピックから通知を取得するには、Amazon SQS キューまたはAWS Lambdafunction. 詳細については、「[Amazon Textract 非同期オペレーションを呼び出す](api-async.md)」を参照してください。例については、[複数ページドキュメント内のテキストの検出または分析](async-analyzing-with-sqs.md) を参照してください。

結果の JSON 形式は次のとおりです。

```
{
  "JobId": "String",
  "Status": "String",
  "API": "String",
  "JobTag": "String",
  "Timestamp": Number,
  "DocumentLocation": {
    "S3ObjectName": "String",
    "S3Bucket": "String"
  }
}
```

次の表に、Amazon Textract レスポンス内のさまざまなパラメータを示します。


| パラメータ | 説明 | 
| --- | --- | 
|  JobId  |  Amazon Textract がジョブに割り当てる一意の識別子。これは、から返されたジョブ識別子と一致します。`Start`などの操作[StartDocumentTextDetection](API_StartDocumentTextDetection.md)。  | 
|  [Status] (ステータス)  |  ジョブのステータス。有効な値は、[成功]、[失敗]、または [エラー] です。  | 
|  API  |  入力ドキュメントの分析に使用された Amazon Textract オペレーション。[StartDocumentTextDetection](API_StartDocumentTextDetection.md)または[StartDocumentAnalysis](API_StartDocumentAnalysis.md)。  | 
|  JobTag  |  ジョブのユーザー指定の識別子。指定する`JobTag`への呼び出しで`Start`などの操作[StartDocumentTextDetection](API_StartDocumentTextDetection.md)。  | 
|  タイムスタンプ  |  ジョブが終了したことを示す Unix タイムスタンプ。ミリ秒単位で返されます。  | 
|  ドキュメントロケーション  |  処理されたドキュメントに関する詳細。ファイル名やファイルが保存されている Amazon S3 バケットなどが含まれます。  | 