0
0

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サーバーレス設計】Textract × Step Functions × Lambdaによる帳票OCR自動抽出&API連携パイプライン

0
Posted at

📌 はじめに

紙帳票やスキャンされたPDFファイルを扱う業務システムにおいて、「ファイルのアップロード後に担当者が目視で値を確認し、基幹システムの画面へ手動入力する」という運用は、人的ミスの温床であり業務効率化の大きなボトルネックとなります。

今回は、自前の機械学習モデルを一切学習・運用せず(マネージドAIサービスの活用)、AWS Step Functions と AWS Lambda を組み合わせた完全サーバーレスな構成によって、帳票のテキスト・テーブル抽出から外部システムAPIへの自動登録までを低コストかつ最短納期で実現する標準アーキテクチャをまとめます。

1. 業務シナリオとコア課題の整理

業務背景

  • ユーザーがスキャンした帳票ファイル(PDF/画像)を Amazon S3 へアップロードし、メタデータを Amazon RDS に格納。
  • 現行の運用フローでは、S3 アップロード完了後に Amazon SNS 経由で運用チームへ通知され、担当者が画面上でファイルを開き、目視で項目を転記して外部システム API へ手動登録している。

コア課題と設計要件

  1. 完全自動化: 帳票受領からデータ抽出、外部 API 登録までを人の介在なし(ヒューマンエラーゼロ)で処理すること。
  2. 市場投入までの期間最小化 (Minimize Time to Market):
    • 独自モデルの学習、アノテーション、推論サーバー構築といった長期の開発期間を排除し、AWS が提供するターンキー(開箱即用)なマネージド AI サービスを採用すること。
  3. 長期的な運用オーバーヘッドの最小化 (Least Long-term Operational Overhead):
    • EC2 やコンテナ基盤(ECS/EKS)などのインフラ管理・OSパッチ適用・キャパシティプランニングを不要にするため、完全サーバーレス(Serverless) でワークフローをオーケストレーションすること。

2. アーキテクチャトポロジー

┌────────────────────────────────────────────────────────────────────────────────────────┐
│ ストレージ & イベント駆動レイヤー                                                      │
│                                                                                        │
│   [ エンドユーザー ] ──► [ スキャン帳票アップロード ] ──► [ Amazon S3 バケット ]        │
│                                                               │                        │
│                                                               │ S3 イベント / SNS 通知 │
│                                                               ▼                        │
│   ┌──────────────────────────────────────────────────────────────────────────────────┐ │
│   │ AWS Step Functions (サーバーレスワークフロー状態マシン)                          │ │
│   │                                                                                  │ │
│   │   [ Task 1: 非同期 OCR & 帳票抽出タスク ]                                        │ │
│   │        │                                                                         │ │
│   │        ▼                                                                         │ │
│   │   ┌──────────────────────────────────────────────────────────────────────────┐   │ │
│   │   │ Amazon Textract                                                          │   │ │
│   │   │  - テーブル構造(Tables)およびキー/値ペア(Key-Value Pairs)を自動抽出   │   │ │
│   │   │  - モデルの学習不要、マネージドAPI経由で即座に実行                       │   │ │
│   │   └────────────────────────────────────┬─────────────────────────────────────┘   │ │
│   │                                        │ 構造化データ(JSON形式)                │ │
│   │                                        ▼                                         │ │
│   │   ┌──────────────────────────────────────────────────────────────────────────┐   │ │
│   │   │ Amazon Comprehend                                                        │   │ │
│   │   │  - 自然言語処理 (NLP): 業務固有のエンティティ識別、テキスト分類、意味解析 │   │ │
│   │   └────────────────────────────────────┬─────────────────────────────────────┘   │ │
│   │                                        │                                         │ │
│   │        ┌───────────────────────────────┘                                         │ │
│   │        ▼                                                                         │ │
│   │   [ Task 2: データ永続化 & API連携タスク ]                                       │ │
│   │        │                                                                         │ │
│   │        ▼                                                                         │ │
│   │   ┌──────────────────────────────────────────────────────────────────────────┐   │ │
│   │   │ AWS Lambda 関数                                                          │   │ │
│   │   │  - 抽出結果 JSON を Amazon S3 にアーカイブ保存                            │   │ │
│   │   │  - リクエストペイロードを整形し、外部業務システム REST API へ POST 送信  │   │ │
│   │   └────────────────────────────────────┬─────────────────────────────────────┘   │ │
│   └────────────────────────────────────────┼─────────────────────────────────────────┘ │
└────────────────────────────────────────────┼───────────────────────────────────────────┘
                                             │ HTTPS POST (登録)
                                             ▼
                              ┌─────────────────────────────┐
                              │     外部基幹業務システム     │
                              │       (REST API)            │
                              └─────────────────────────────┘

3. なぜこの構成を選択するのか?(2大コアメカニズム)

① マネージド AI サービスの採用(Amazon Textract + Comprehend)

  • Amazon Textract の優位性:

  • 一般的なオープンソース OCR(Tesseract 等)は単純な文字コード変換にとどまり、レイアウト崩れや表のセル結合に対応できません。

  • Textract は、スキャン書類から 「キー/値のペア(例: 請求番号: 12345)」 や 「テーブル(行・列データ)」 を意味を理解した上でネイティブに抽出します。

  • 事前トレーニング不要のフルマネージド API として提供されるため、モデル開発にかかるリードタイムを完全にゼロ化できます。

  • Amazon Comprehend の補助:

  • 抽出されたテキストから、人名・組織名・住所などのエンティティを分類・検知し、データバリデーション(整合性検証)を自動化します。

② ステートマシンによる回復性の高いオーケストレーション(Step Functions + Lambda)

  • 非同期タスクと待機処理の標準化:

  • 複数ページに及ぶスキャン PDF の処理では、Textract の非同期 API(StartDocumentAnalysis ➔ GetDocumentAnalysis)を呼び出し、完了をポーリングして待つ必要があります。

  • AWS Step Functions を利用することで、指数関数的バックオフを含むリトライ制御や待機状態(Wait 状態)をノーコードで定義できます。

  • Lambda をグルー(接着剤)として最小限に活用:

  • Lambda は「抽出結果の JSON 整形」「S3 への格納」「外部 REST API のコール」という単一責務の処理のみに集中させます。サーバーのプロビジョニングや待機コストが発生しないため、リクエストがない時間帯はコストが完全にゼロとなります。

4. Step Functions 定義例 (Amazon States Language)

非同期で Textract を呼び出し、完了を待機して Lambda で外部 API へ連携する Step Functions の状態マシン定義例です。

{
  "Comment": "Automated Form Extraction and API Ingestion Pipeline",
  "StartAt": "StartTextractAnalysis",
  "States": {
    "StartTextractAnalysis": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:textract:startDocumentAnalysis",
      "Parameters": {
        "DocumentLocation": {
          "S3Object": {
            "Bucket.$": "$.detail.bucket.name",
            "Name.$": "$.detail.object.key"
          }
        },
        "FeatureTypes": ["TABLES", "FORMS"]
      },
      "ResultPath": "$.TextractJob",
      "Next": "WaitForTextract"
    },
    "WaitForTextract": {
      "Type": "Wait",
      "Seconds": 5,
      "Next": "GetTextractResults"
    },
    "GetTextractResults": {
      "Type": "Task",
      "Resource": "arn:aws:states:::aws-sdk:textract:getDocumentAnalysis",
      "Parameters": {
        "JobId.$": "$.TextractJob.JobId"
      },
      "ResultPath": "$.TextractOutput",
      "Next": "CheckJobStatus"
    },
    "CheckJobStatus": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.TextractOutput.JobStatus",
          "StringEquals": "SUCCEEDED",
          "Next": "PostDataToExternalAPI"
        },
        {
          "Variable": "$.TextractOutput.JobStatus",
          "StringEquals": "IN_PROGRESS",
          "Next": "WaitForTextract"
        }
      ],
      "Default": "JobFailed"
    },
    "PostDataToExternalAPI": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "arn:aws:lambda:ap-northeast-1:123456789012:function:IngestFormToAPI",
        "Payload": {
          "JobId.$": "$.TextractJob.JobId",
          "Blocks.$": "$.TextractOutput.Blocks"
        }
      },
      "End": true
    },
    "JobFailed": {
      "Type": "Fail",
      "Cause": "Textract Document Analysis Failed",
      "Error": "TextractError"
    }
  }
}

5. 後続処理用 Lambda 実装例 (Python 3.x)

import json
import urllib.request
import boto3
import os

s3 = boto3.client('s3')

def lambda_handler(event, context):
    payload = event.get('Payload', {})
    blocks = payload.get('Blocks', [])
    job_id = payload.get('JobId', 'unknown')
    
    # 1. TextractのブロックからKey-Valueをパース (簡易例)
    extracted_data = {}
    for block in blocks:
        if block.get('BlockType') == 'KEY_VALUE_SET' and 'KEY' in block.get('EntityTypes', []):
            # 実際の実装ではリレーションシップIDを辿って値を取得
            pass

    # テスト用のモック抽出データ
    result_payload = {
        "document_id": job_id,
        "status": "APPROVED",
        "extracted_fields": {
            "invoice_number": "INV-2026-0901",
            "total_amount": 128000
        }
    }

    # 2. 結果を S3 にアーカイブ保存
    s3.put_object(
        Bucket=os.environ['OUTPUT_BUCKET'],
        Key=f"results/{job_id}.json",
        Body=json.dumps(result_payload),
        ContentType='application/json'
    )

    # 3. 外部業務システム REST API への POST 連携
    target_api_url = os.environ['TARGET_API_URL']
    req = urllib.request.Request(
        target_api_url,
        data=json.dumps(result_payload).encode('utf-8'),
        headers={'Content-Type': 'application/json'},
        method='POST'
    )
    
    with urllib.request.urlopen(req) as res:
        response_code = res.getcode()
        print(f"API delivery completed with status: {response_code}")

    return {"status": "SUCCESS", "code": response_code}

6. まとめ

  • 市場投入までの期間短縮: 自前での OCR エンジン開発や深層学習モデル構築を行わず、Amazon Textract を採用することで、高精度な帳票構造化を即座に導入可能。
  • 運用保守負荷の最小化: Step Functions × Lambda のサーバーレスアーキテクチャにより、待機ポーリングやリトライ処理をマネージドで抽象化し、インフラ運用のオーバーヘッドを排除。
  • 高アジリティ: 業務ルールの変更や外部 API 仕様の更新時にも、Lambda 関数と状態マシンの修正のみで迅速に適応可能。
0
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?