

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

# 分析のためにテキストを抽出して AWS Comprehend に送信する
<a name="textract-to-comprehend"></a>

Amazon Textract では、ドキュメントテキストの検出と分析をアプリケーションに含めることができます。Amazon Textract では、同期ドキュメント処理と非同期ドキュメント処理の両方を使用して、さまざまなドキュメントタイプからテキストを抽出できます。抽出されたテキストは、ファイルまたはデータベースに保存することも、別の AWS サービスに送信してさらに処理することもできます。

このチュートリアルでは、一般的なend-to-endのワークフローを実行します。このワークフローには、以下が含まれます。
+ Amazon Textract を使用した多数の入力ドキュメントの処理
+ 抽出したテキストを分析のために Amazon Comprehend に提供する
+ 分析されたテキストと分析データの両方を Amazon Simple Storage Service (S3) バケットに保存

このチュートリアルでは [AWS SDK for Python ](https://aws.amazon.com/sdk-for-python/)を使用します。その他の Python チュートリアルについては、 AWS 「Documentation SDK examples [GitHub repo](https://github.com/awsdocs/aws-doc-sdk-examples)」も参照してください。

## 前提条件
<a name="tutorial-prerequisites"></a>

このチュートリアルを開始する前に、Python をインストールし、[Python AWS SDK のセットアップ](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html)に必要な手順を完了する必要があります。これ以外にも、次のことを確認してください:
+ [AWS アカウントと IAM ロールを作成しました](https://docs.aws.amazon.com/rekognition/latest/dg/setting-up.html)
+ [AWS アクセス認証情報を適切に設定する](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html)
+ [Amazon S3 バケットを作成しました](https://docs.aws.amazon.com/AmazonS3/latest/userguide/create-bucket-overview.html)
+ [ 非同期処理用に Amazon Textract を設定し](https://docs.aws.amazon.com/en_us/textract/latest/dg/api-async-roles.html)、Amazon Textract で使用するように設定した IAM ロールの Amazon リソースナンバー (ARN) をコピーダウンしました
+ [IAM ロールに Amazon Comprehend へのアクセスを許可](https://docs.aws.amazon.com/comprehend/latest/dg/security-iam.html#security_iam_access-manage) 
+ テキスト抽出/分析の目的でいくつかのドキュメントを選択し、そのドキュメントを Amazon S3 にアップロードしました。分析用に選択したファイルが Amazon Textract でサポートされている形式であることを確認します。

## 非同期ドキュメントテキスト検出の開始
<a name="tutorial-step-1"></a>

ドキュメントからテキストを抽出し、抽出したテキストを Amazon Comprehend などのサービスで分析できます。Textract は、大規模な複数ページのドキュメントを処理するための非同期オペレーションによる複数ページのドキュメントからのテキストの抽出をサポートしています。PDF ファイルを非同期的に処理すると、アプリケーションはプロセスが完了するまで待機しながら他のタスクを完了できます。このセクションでは、Amazon S3 バケットからドキュメントをインポートし、Textract の非同期テキスト検出オペレーションに提供する方法を示します。

このチュートリアルでは、Amazon S3 を使用してテキストを抽出するファイルを保存することを前提としています。まず、入力ドキュメント内のテキストを検出するクラスと関数を作成します。アプリケーションは、非同期ジョブの完了ステータスをモニタリングするために、Textract クライアント、Amazon SQS および Amazon SNS クライアントに接続する必要があります。

1. まず、Amazon SNS トピックと Amazon SQS キューを作成するコードを記述します。

   次のコードサンプルは、3 つの必要なサービスに接続する`DocumentProcessor`クラスを作成し、Amazon SQS キューと Amazon SNS トピックの両方を作成します。Amazon SNS トピックは、ジョブの完了ステータスに関する情報を Amazon SQS キューに提供するために使用されます。このキューは、ジョブの完了ステータスを取得するためにポーリングされます。ジョブが完了し、リソースが不要になったら、Amazon SQS キューと Amazon SNS トピックを削除する方法もあります。

   ```
   import boto3
   import json
   import sys
   import time
   
   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
   
           # Instantiates necessary AWS clients
           session = boto3.Session(profile_name='profile-name',
           region_name='self.region_name')
           self.textract = session.client('textract', region_name=self.region_name)
           self.sqs = session.client('sqs', region_name=self.region_name)
           self.sns = session.client('sns', region_name=self.region_name)
   
       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)
   ```

1. `StartDocumentTextDetection` オペレーションを呼び出すコードを記述し、オペレーションの結果を取得します。

   `DocumentProcessor` クラスには、以下の方法も必要です。
   + `StartDocumentTextDetection` オペレーションを呼び出す
   + ジョブ完了ステータスの Amazon SQS をポーリングする
   + 処理が完了したら、ジョブの結果を取得する

   次のコードは、 を呼び出す `ProcessDocument`メソッド`StartDocumentTextDetection`と `GetResults`メソッドを作成し、抽出されたテキストをそれぞれ取得します。

   ```
       def ProcessDocument(self):
       
               # Checks if job found
               jobFound = False
       
               # Starts the text detection operation on the documents in the provided bucket
               # Sends status to supplied SNS topic arn
               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')
       
               print('Start Job Id: ' + response['JobId'])
               dotLine = 0
               while jobFound == False:
                   sqsResponse = self.sqs.receive_message(QueueUrl=self.sqsQueueUrl, MessageAttributeNames=['ALL'],
                                                       MaxNumberOfMessages=10)
       
                   # Waits until messages are found in the SQS queue
                   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
       
                       # Checks for a completed job that matches the jobID in the response from
                       # StartDocumentTextDetection
                       for message in sqsResponse['Messages']:
                           notification = json.loads(message['Body'])
                           textMessage = json.loads(notification['Message'])
                           if str(textMessage['JobId']) == response['JobId']:
                               print('Matching Job Found:' + textMessage['JobId'])
                               jobFound = True
                               text_data = self.GetResults(textMessage['JobId'])
                               self.sqs.delete_message(QueueUrl=self.sqsQueueUrl,
                                                       ReceiptHandle=message['ReceiptHandle'])
                               return text_data
                           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!')
           
       # gets the results of the completed text detection job
       # checks for pagination tokens to determine if there are multiple pages in the input doc
       def GetResults(self, jobId):
           maxResults = 1000
           paginationToken = None
           finished = False
   
           while finished == False:
               response = None
               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']
   
               # List to hold detected text
               detected_text = []
   
               # Display block information and add detected text to list
               for block in blocks:
                   if 'Text' in block and block['BlockType'] == "LINE":
                       detected_text.append(block['Text'])
   
               # If response contains a next token, update pagination token
               if 'NextToken' in response:
                   paginationToken = response['NextToken']
               else:
                   finished = True
   
               return detected_text
   ```

1. 上記のコードを というファイルに保存します`detectFileAsync.py`。

   次のセクションでこのファイルを使用して、入力ドキュメント内のテキストの検出を処理します。

## ドキュメントの処理と理解するテキストの送信
<a name="tutorial-step-2"></a>

アプリケーションは、前のセクションで作成した クラスを使用して、次の操作を行います。
+ Amazon S3 バケットからドキュメントを読み取る
+ これらのドキュメント内のテキストを抽出する
+ テキストを Amazon Comprehend に送信して分析する

まず、Amazon Comprehend を使用して入力ドキュメントで検出されたテキストを分析する関数をいくつか作成します。テキスト分析の一般的なタイプは感情分析であり、ステートメントの影響 (肯定的、否定的、中立のいずれであるか) をキャプチャすることを目指しています。データに対してエンティティ検出とキーフレーズ検出を実行することもできます。

以下のコードは、検出されたテキストを受け取り、感情分析を実行するために Amazon Comprehend から `BatchDetectSentiment`オペレーションを呼び出します。

1. 検出されたテキストに対して感情分析を実行するコードを記述します。

   ```
   from detectFileAsync import DocumentProcessor
   import boto3
   import pandas as pd
   
   # Detect sentiment
   def sentiment_analysis(detected_text, lang):
   
       comprehend = boto3.client("comprehend")
   
       detect_sent_response = comprehend.batch_detect_sentiment(
               TextList=detected_text, LanguageCode=lang)
   
       # Lists to hold sentiment labels and sentiment scores
       sentiments = []
       pos_score = []
       neg_score = []
       neutral_score = []
       mixed_score = []
   
       # for all results add the Sentiment label and sentiment scores to lists
       for res in detect_sent_response['ResultList']:
           sentiments.append(res['Sentiment'])
           print(res['SentimentScore'])
           print(type(res['SentimentScore']))
           for key, val in res['SentimentScore'].items():
               if key == "Positive":
                   pos_score.append(val)
               if key == "Negative":
                   neg_score.append(val)
               if key == "Neutral":
                   neutral_score.append(val)
               if key == "Mixed":
                   mixed_score.append(val)
   
       return sentiments, pos_score, neg_score, neutral_score, mixed_score
   ```

   検出されたテキストに対して、エンティティ検出やキーフレーズ検出などの他の分析オペレーションを実行することもできます。関数を記述して、前述の感情分析オペレーションと同様に、テキストに対してこれらの分析オペレーションを実行できます。

1. 検出されたテキストでエンティティ検出を実行するコードを記述します。

   ```
   # detect entities
   def entity_detection(detected_text, lang):
   
       comprehend = boto3.client("comprehend")
   
       # convert and handle string here
       # do string handling
       detect_ent_response = comprehend.batch_detect_entities(
           TextList=detected_text, LanguageCode=lang)
   
       # To fold detected entities and entity types
       ents = []
       types = []
   
       # Get detected entities and types from the response returned by Comprehend
       for i in detect_ent_response['ResultList']:
           if len(i['Entities']) == 0:
               ents.append("N/A")
               types.append("N/A")
           else:
               sentence_ents = []
               sentence_types = []
               for entities in i['Entities']:
                   sentence_ents.append(entities['Text'])
                   sentence_types.append(entities['Type'])
               ents.append(sentence_ents)
               types.append(sentence_types)
   
       return ents, types
   ```

1.  検出されたテキストでキーフレーズ検出を実行するコードを記述します。

   ```
   # Detect key phrases
   def key_phrases_detection(detected_text, lang):
   
       comprehend = boto3.client("comprehend")
   
       key_phrases = []
       detect_phrases_response = comprehend.batch_detect_key_phrases(
           TextList=detected_text, LanguageCode=lang)
       for i in detect_phrases_response['ResultList']:
           if len(i['KeyPhrases']) == 0:
               key_phrases.append("N/A")
           else:
               phrases = []
               for phrase in i['KeyPhrases']:
                   phrases.append(phrase['Text'])
               key_phrases.append(phrases)
   
       return key_phrases
   ```

   これまでに作成したすべてのコードを呼び出す関数を作成する必要があります。関数は、 `DetectAnalyzeFileAsync.py` ファイルで作成した `DocumentProcessor` クラスを使用し、検出したテキストを変数に保存して、以前に作成した Amazon Comprehend を利用して 3 つの関数に入力します。この関数は、検出されたテキストと分析データを挿入する Pandas データフレームも構築する必要があります。最後に、Pandas データフレームは CSV ファイルとして保存されます。

1. Textract を使用して入力ドキュメントを処理し、検出されたテキストを Comprehend に渡すコードを記述します。

   ```
   def process_document(roleArn, bucket, document, region_name):
   
       # Create analyzer class from DocumentProcessor, create a topic and queue, use Textract to get text,
       # then delete topica and queue
       analyzer = DocumentProcessor(roleArn, bucket, document, region_name)
       analyzer.CreateTopicandQueue()
       extracted_text = analyzer.ProcessDocument()
       analyzer.DeleteTopicandQueue()
   
       # detect dominant language
       comprehend = boto3.client("comprehend")
       response = comprehend.detect_dominant_language(Text=str(extracted_text[:10]))
       print(response)
       print(type(response))
       lang = ""
       for i in response['Languages']:
           lang = i['LanguageCode']
       print(lang)
   
       # or you can enter language code below
       # lang = "en"
   
       print("Lines in detected text:" + str(len(extracted_text)))
       sliced_list = []
       start = 0
       end = 24
       while end < len(extracted_text):
           sliced_list.append(extracted_text[start:end])
           start += 25
           end += 25
       print(sliced_list)
   
       # Create lists to hold analytics data, these will be turned into columns
       all_sents = []
       all_scores = []
       all_ents = []
       all_types = []
       all_key_phrases = []
       all_pos_ratings = []
       all_neg_ratings = []
       all_neutral_ratings = []
       all_mixed_ratings = []
   
       # For every slice, get sentiment analysis, entity detection and key phrases, append results to lists
       for slice in sliced_list:
           slice_labels, pos_ratings, neg_ratings, neutral_ratings, mixed_ratings = sentiment_analysis(slice, lang)
           all_sents.append(slice_labels)
           all_pos_ratings.append(pos_ratings)
           all_neg_ratings.append(neg_ratings)
           all_neutral_ratings.append(neutral_ratings)
           all_mixed_ratings.append(mixed_ratings)
           slice_ents, slice_types = entity_detection(slice, lang)
           all_ents.append(slice_ents)
           all_types.append(slice_types)
           key_phrases = key_phrases_detection(slice, lang)
           all_key_phrases.append(key_phrases)
   
       # List comprehension to flatten multiple lists into a single list
       extracted_text = [line for sublist in sliced_list for line in sublist]
       all_sents = [sent for sublist in all_sents for sent in sublist]
       all_scores = [score for sublist in all_scores for score in sublist]
       all_ents = [ents for sublist in all_ents for ents in sublist]
       all_types = [types for sublist in all_types for types in sublist]
       all_key_phrases = [kp for sublist in all_key_phrases for kp in sublist]
       all_mixed_ratings = [kp for sublist in all_mixed_ratings for kp in sublist]
       all_pos_ratings = [kp for sublist in all_pos_ratings for kp in sublist]
       all_neg_ratings = [kp for sublist in all_neg_ratings for kp in sublist]
       all_neutral_ratings = [kp for sublist in all_neutral_ratings for kp in sublist]
   
       print(len(extracted_text))
       print(len(all_sents))
       print(len(all_ents))
       print(len(all_types))
       print(len(all_key_phrases))
   
       print("List of Recognized Entities:")
   
       # Create dataframe and save as CSV
       df = pd.DataFrame({'Sentences':extracted_text, 'Sentiment':all_sents, 'SentPosScore':all_pos_ratings,
                          'SentNegScore':all_neg_ratings, 'SentNeutralScore':all_neutral_ratings, 'SentMixedRatings':all_mixed_ratings,
                          'Entities':all_ents, 'EntityTypes':all_types,'KeyPhrases:':all_key_phrases})
       analysis_results = str(document.replace(".","_") + "_" + "analysis" + ".csv")
       df.to_csv(analysis_results, index=False)
   
       print(df)
       print("Data written to file!")
   
       return extracted_text, analysis_results
   ```

1. ドキュメントを処理するコードを記述し、結果のデータを S3 にアップロードします。以下のコードサンプル`roleArn`で、 の値を Amazon Textract で使用するように設定したロールの ARN に置き換えます。の値を、アカウントが運用されているリージョン`region_name`に置き換えます。最後に、 値をドキュメントを含む S3 バケット`bucket_name`の名前に置き換えます。

   ```
   def main():
   
       # Initialize S3 client and set RoleArn, region name, and bucket name
       s3 = boto3.client("s3")
       roleArn = ''
       region_name = ''
       bucket_name = ''
   
       # initialize global corpus
       full_corpus = []
   
       # to hold all docs in bucket
       docs_list = []
   
       # loop through docs in bucket, get names of all docs
       s3_resource = boto3.resource("s3")
       bucket = s3_resource.Bucket(bucket_name)
       for bucket_object in bucket.objects.all():
           docs_list.append(bucket_object.key)
       print(docs_list)
   
       # For all the docs in the bucket, invoke document processing function,
       # add detected text to corpus of all text in batch docs,
       # and save CSV of comprehend analysis data and textract detected to S3
       for i in docs_list:
           detected_text, analysis_results = process_document(roleArn, bucket_name, i, region_name)
           full_corpus.append(detected_text)
           print("Uploading file: {}".format(str(analysis_results)))
           name_of_file = str(analysis_results)
           s3.upload_file(name_of_file, bucket_name, name_of_file)
   
       # print the global corpus
       print(full_corpus)
   
   if __name__ == "__main__":
       main()
   ```

1. 「」セクションの前述のコードを Python ファイルに入れ、実行します。

Amazon Textract を使用してテキストを正常に抽出し、分析のためにテキストを Amazon Comprehend に送信し、その結果を Amazon S3 バケットに保存しました。