0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWSでサーバレス感情分析API環境を作る

0
Posted at

構成イメージ

WindowsでPowershellを起動して、そこからcurlコマンドでAPI Gateway経由でLambdaをキックします。Lambdaの処理で受け取ったデータをComprehendに渡して感情分析をしてもらいます。実行結果はDynamoDBに格納します。またLambdaの実行ログとしてCloudwatchとも連携します。

aws04-ページ15.drawio.png

用語

Comprehend

AWS Comprehendは、文章から意味や傾向を自動で抽出するための自然言語処理(NLP)サービスです。
感情分析(ポジ/ネガなど)、キーフレーズ抽出、固有表現抽出、トピック分類などをAPIで実行できます。
機械学習の専門知識がなくても、アプリやログ分析にテキスト解析を組み込めます。

DynamoDB

Amazon DynamoDBは、AWSが提供するフルマネージドのNoSQLデータベースで、ミリ秒単位の低レイテンシで大規模トラフィックをさばけます。
サーバ管理が不要で、自動スケーリングやバックアップ、暗号化などが組み込まれています。
キー・バリュー/ドキュメント型のデータを扱え、セッション管理やIoT、ゲーム、イベントログなどに使われます。

構築

DynamoDB

DynamoDBの管理画面を開き、テーブルを作成していきます。
image.png

テーブル名をSentimentResultsとし、パーティションキーをidとします。
他はデフォルトの設定で作成していきます。
screencapture-ap-northeast-1-console-aws-amazon-dynamodbv2-home-2026-01-23-09_57_28.png

テーブルが作成されたことを確認します。
image.png

Lambda

1から作成を選択して、関数名をSentimentLambdaとします。
ランタイムはPython3.13にします。他はデフォルトの設定で作成していきます。
screencapture-ap-northeast-1-console-aws-amazon-lambda-home-2026-01-23-10_01_52.png

Lambdaがデプロイされたことを確認します。
設定タブの環境変数を押下します。編集ボタンを押下します。
image.png

キー:TABLE_NAME
値:SentimentResults
と設定して保存を押下します。
image.png

次にこのLambdaに紐づけるIAMRoleを作成していきます。
IAMのRoleを開いて、作成ボタンを押下します。
image.png

AWSのサービスを選択して、ユースケースはLambdaを選択。
次に進みます。
image.png

Policyをアタッチします。
ComprehendFullAccessとAmazonDynamoDBFullAccess_v2とCloudWatchLogsFullAccessにチェックを入れて次に進みます。
image.png

Roleの名前はSentimentLambdaRoleとしました。
アタッチされているPolicyが正しいことを確認して作成していきます。
screencapture-us-east-1-console-aws-amazon-iam-home-2026-01-23-10_20_33.png

作成されたことを確認します。
image.png

Lambdaの設定画面に戻ります。
設定タブのアクセス権限を押下します。デフォルトだと自動生成されたIAMRoleがアタッチされていますので、これを先ほど作成したRoleに差し替えます。
編集ボタンを押下します。
image.png

既存のロール部分を作成したSentimentLambdaRoleに変更して保存を押下します。
image.png

ロール名のところがSentimentLambdaRoleとなっていることを確認します。
image.png

コードタブを押下するとPythonでコーディングできる部分が表示されますので、以下のコードを入力します。

import os
import json
import uuid
from datetime import datetime, timezone

import boto3

dynamodb = boto3.resource("dynamodb")
comprehend = boto3.client("comprehend")

TABLE_NAME = os.environ["TABLE_NAME"]
table = dynamodb.Table(TABLE_NAME)

def response(status, body):
    return {
        "statusCode": status,
        "headers": {"Content-Type": "application/json"},
        "body": json.dumps(body, ensure_ascii=False)
    }

def lambda_handler(event, context):
    # 1) 入力取り出し
    try:
        body = event.get("body")
        if body is None:
            return response(400, {"message": "body is required"})
        if isinstance(body, str):
            body = json.loads(body)
        text = body.get("text", "")
    except Exception:
        return response(400, {"message": "Invalid JSON body"})

    # 2) バリデーション
    text = text.strip()
    if not text:
        return response(400, {"message": "text is required"})
    if len(text) > 1000:  # 授業用の安全上限(任意)
        return response(400, {"message": "text is too long (max 1000 chars for this demo)"})

    # 3) Comprehendで感情分析
    lang = "ja"
    result = comprehend.detect_sentiment(Text=text, LanguageCode=lang)
    sentiment = result["Sentiment"]
    scores = result["SentimentScore"]

    # 4) DynamoDBに保存
    item_id = str(uuid.uuid4())
    created_at = datetime.now(timezone.utc).isoformat()

    table.put_item(
        Item={
            "id": item_id,
            "createdAt": created_at,
            "language": lang,
            "text": text,
            "sentiment": sentiment,
            "scores": {k: str(v) for k, v in scores.items()},  # Decimal対策の簡易版
        }
    )

    # 5) 応答
    return response(200, {
        "id": item_id,
        "sentiment": sentiment,
        "scores": scores
    })

入力しましたらDeployを押下して、編集内容を保存します。
image.png

API Gateway

API Gatewayの管理画面を開きます。
APIを作成を押下します。
image.png

HTTP APIを選択して構築を押下します。
image.png

名前をSentimentAPIとします。
後はデフォルトのまま次に進みます。
image.png

ルートを設定は特に設定を入れずに次に進みます。
image.png

ステージについても同様にデフォルトのまま次に進みます。
image.png

確認画面が表示されるので、内容を確認して作成を押下します。
image.png

以下のような画面が表示されます。
SentimentAPIのルートの右に作成ボタンがあるので、これを押下します。
image.png

POST/analyzeと設定を入れて作成を押下します。
image.png

以下のような画面が表示されるようになると思いまうs。
統合の部分でアタッチを押下します。
image.png

統合を作成してアタッチを押下します。
image.png

統合タイプ:Lambda関数としSentimentLambdaを選択します。
アクセス許可を呼び出すをアクティブにして作成を押下します。
image.png

Lambdaと紐づいたことを確認します。
image.png

Lambda側の管理画面においてもAPI Gatewayがトリガーに表示されていることが確認できると思います。
image.png

動作確認

API Gatewayの画面からAPIのURLを確認します。
image.png

自分のPC(今回はWindows11)のPowershellを起動して以下のコマンドをコピペして実行します。
★で囲まれた部分は上記で控えたAPI GatewayのURLに置き換えてください。
今回は「このサービスはとても便利で助かります」という文章の感情分析をしてもらおうと思います。

$payload = '{"text":"このサービスはとても便利で助かります"}'
[System.IO.File]::WriteAllText("payload.json", $payload, (New-Object System.Text.UTF8Encoding($false)))
curl.exe -i -X POST "★APIのURL★/analyze" -H "Content-Type: application/json; charset=utf-8" --data-binary "@payload.json"

実行結果は以下となります。
HTTP/1.1 200 OKとなっていることと、{"id": ~}の出力があることを確認します。このidの部分が感情分析の結果となっています。

image.png

PS C:\Users\ohtsu> $payload = '{"text":"このサービスはとても便利で助かります"}'
PS C:\Users\ohtsu> [System.IO.File]::WriteAllText("payload.json", $payload, (New-Object System.Text.UTF8Encoding($false)))
    PS C:\Users\ohtsu> curl.exe -i -X POST "★APIのURL★/analyze" -H "Content-Type: application/json; charset=utf-8" --data-binary "@payload.json"
HTTP/1.1 200 OK
Date: Fri, 23 Jan 2026 03:00:11 GMT
Content-Type: application/json
Content-Length: 217
Connection: keep-alive
Apigw-Requestid: XniZFhl6NjMEMRg=

{"id": "b3905be6-66d8-437f-bc41-5b83d2c71356", "sentiment": "POSITIVE", "scores": {"Positive": 0.9995601773262024, "Negative": 0.0002331074356334284, "Neutral": 0.0002035265351878479, "Mixed": 3.2255238693323918e-06}}

Comprehendの項目と意味は以下になります。

項目 意味
id b3905be6-66d8-437f-bc41-5b83d2c71356 この解析結果(1リクエスト分)を一意に識別するID(UUID)。DynamoDBなどで保存・検索するためのキー。
sentiment POSITIVE 総合判定の感情ラベル。文章全体として「肯定的(ポジティブ)」と判定されたことを示す。
scores.Positive 0.9995601773262024 「肯定的」である確率(信頼度)。1に近いほど強くポジティブと判断。
scores.Negative 0.0002331074356334284 「否定的」である確率(信頼度)。0に近いほどネガティブではない。
scores.Neutral 0.0002035265351878479 「中立的」である確率(信頼度)。0に近いほど中立ではない。
scores.Mixed 3.2255238693323918e-06 「肯定・否定が混在している」確率(信頼度)。0に近いほど混在していない。
ラベル 日本語 どういうときに高くなるか
Positive 肯定的 褒める、満足、好意、嬉しい、便利、助かる等の表現が中心のとき
Negative 否定的 不満、批判、怒り、困る、最悪、使えない等の表現が中心のとき
Neutral 中立 感情が薄い事実説明・報告・手順の文章が中心のとき
Mixed 混在 褒めと不満が同時に書かれているなど、感情が混ざっているとき

Cloudwatch LogsでLambdaの実行ログが吐き出されていることを確認します。
image.png
image.png

またDynamoDBにもデータが溜まっていることを確認します。
今回作成したテーブルの管理画面を開いて、右上にあるテーブルアイテムの探索を押下します。
image.png

テーブルに表示されていることを確認します。
image.png
image.png

例えばComprehendに分析させる文言を以下にしてみます。

「便利で普段はとても助かっているのですが、時間帯によっては読み込みがかなり遅くなることがあって、そのたびに少しイライラしてしまいます。特に急いで作業しているときに待たされるとストレスが大きいので、動作が安定してもっとサクサク使えるようになると嬉しいです。」

$payload = '{"text":"便利で普段はとても助かっているのですが、時間帯によっては読み込みがかなり遅くなることがあって、そのたびに少しイライラしてしまいます。特に急いで作業しているときに待たされるとストレスが大きいので、動作が安定してもっとサクサク使えるようになると嬉しいです。"}'
[System.IO.File]::WriteAllText("payload.json", $payload, (New-Object System.Text.UTF8Encoding($false)))
curl.exe -i -X POST "★APIのURL★/analyze" -H "Content-Type: application/json; charset=utf-8" --data-binary "@payload.json"

結果としては以下のようになっていました。分析としては妥当のように思いますね。

{
"id": "f70aed3a-4ac3-4c44-941d-8440cf0d2b0d", 
"sentiment": "MIXED", 
"scores": 
    {
    "Positive": 0.0004430233675520867, 
    "Negative": 0.0035658443812280893, 
    "Neutral": 1.5062880265759304e-05, 
    "Mixed": 0.9959760308265686
    }
}
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?