Skip to content

Places API ランキング取得

概要

項目内容
ステータス🔵 提案中
Issue-
担当-

Google Places API(Text Search)を使用して、キーワードごとの検索ランキングを取得する機能。既存のスクレイピング方式と並列運用し、処理対象データは mappy_gbp_locationsdata_source で区別する(1 = Places API、2 = Scraping)。

項目内容
方式Google Places API (New) — Text Search
費用$0(Field Mask: places.id のみ → Basic SKU)
対象全3システム(MAPPY / GCOR / PIPIT)
頻度1日1回(スクレイピングと同タイミング)
実行Python スクリプト(main.py

提案内容

背景・課題

  • 既存のスクレイピング方式はPlaywrightでGoogle検索を実行しており、reCAPTCHA・タイムアウト・アンチ検出対策が複雑
  • ヘッドレスブラウザのサーバーリソース消費が大きい
  • Google検索のDOM・レイアウト変更により結果が不安定になるリスクがある
  • ランキングの信頼性を高めるため、補助的な取得手段が必要

提案するソリューション

Google Places API (New) の Text Search を使用し、place_id でランキングを取得する。スクレイピングと並列運用し、同一 mappy_* テーブルに保存する。

主な特徴:

  • シンプルなHTTP POST呼び出し(ブラウザ不要)
  • Field Mask を places.id のみに限定 → Basic SKU($0)
  • raw_json に既存の placeIdmetadata.placeId)で正確にマッチング
  • reCAPTCHA・DOM変更の影響を受けない

機能一覧

#機能名説明優先度
1placeId 抽出mappy_gbp_locations.raw_jsonmetadata.placeId を取得
2Text SearchランキングAPIを呼び出し、結果内の place_id 位置を特定
3ランキング値マッピング位置をそのまま保存(1-based)、0=圏外、997=エラー
4マルチAPIキー複数APIキー対応。キーごとに --threads スレッド。合計=threads×キー数
5レート制限--min_interval によるAPI呼び出し間隔制御(スレッドごと独立)
6429リトライ--max_retries による自動リトライ
7data_source フィルタdata_source=1(API)のロケーションのみ処理

技術スタック

項目技術選定理由
言語Python 3.10+既存スクレイピングと同じ言語、requestsで簡潔にAPI呼び出し可能
HTTPrequests軽量、同期処理でスレッドと相性が良い
DBSQLAlchemy + PyMySQL既存スクレイピングと同じORM、共有DBプール対応
ログアップロードboto3S3へのログファイルアップロード
実行環境Docker (Amazon ECS)既存スクレイピングと同じインフラ、1 CPU / 2GB RAM
スケジューラAmazon EventBridge日次バッチトリガー(既存と同じ)

Docker構成

dockerfile
FROM python:3.10-slim-bookworm

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV TZ=Asia/Tokyo

RUN apt-get update && \
    apt-get install -y --no-install-recommends tzdata && \
    ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && \
    echo $TZ > /etc/timezone && \
    apt-get clean && rm -rf /var/lib/apt/lists/*

WORKDIR /code
COPY requirements.txt /code/
RUN pip install --upgrade pip && pip install -r requirements.txt
COPY . /code/

CMD ["python", "main.py", "--threads", "4", "--type_keyword", "all", "--min_interval", "500"]
# requirements.txt
PyMySQL==1.1.2
SQLAlchemy==2.0.44
SQLAlchemy-Utils==0.42.0
python-dotenv==1.0.1
requests==2.32.5
cryptography==46.0.3
boto3==1.38.0

実行例:

bash
# ローカル
docker build -t places-api-ranking .
docker run --env-file .env places-api-ranking

# 引数オーバーライド
docker run --env-file .env places-api-ranking \
  python main.py --threads 8 --type_keyword normal

# ECS タスク定義(既存スクレイピングと同構成)
# CPU: 1024 (1 vCPU), Memory: 2048 (2GB)
# Override command: ["python", "main.py", "--threads", "4", "--type_keyword", "all"]

AWSインフラ構成

既存のスクレイピングと同じAWSアカウント(881980194724)・リージョン(ap-northeast-1)を使用する。

ECR(コンテナレジストリ)

項目
リポジトリpython310 (既存)
URI881980194724.dkr.ecr.ap-northeast-1.amazonaws.com/python310
タグ:latest
bash
# ビルド&プッシュ
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 881980194724.dkr.ecr.ap-northeast-1.amazonaws.com
docker build -t places-api-ranking .
docker tag places-api-ranking:latest 881980194724.dkr.ecr.ap-northeast-1.amazonaws.com/python310:latest
docker push 881980194724.dkr.ecr.ap-northeast-1.amazonaws.com/python310:latest

Batch Job Definition

既存の scraper_def を参考に、新しいジョブ定義を作成する。

項目
名前places_api_def
タイプcontainer
プラットフォームFargate / LINUX / X86_64
イメージ881980194724.dkr.ecr.ap-northeast-1.amazonaws.com/python310:latest
vCPU1.0
メモリ2048 MB
実行ロールecsTaskExecutionRole (既存と同じ)
タイムアウト21600秒(6時間)
ネットワークassignPublicIp: ENABLED
コマンド[] (Lambda側で指定)

EventBridge(スケジューラ)

項目
ルール名places-api-ranking-daily
スケジュール既存スクレイピングと同タイミング(日次)
ターゲットLambda関数(sync_database → Batch submit → sync_result の既存フローに統合)

※ 環境変数(PLACES_API_KEYS 等)はLambda関数からBatchジョブをsubmitする際にcontainerOverridesで渡す(既存スクレイピングと同じ方式)。

構成図

環境変数

変数名必須説明
GOOGLE_PLACES_API_KEYSYesGoogle Places APIキー(カンマ区切り)。各キーは別GCPプロジェクト推奨
GOOGLE_PLACES_API_KEYYes*単一APIキー(GOOGLE_PLACES_API_KEYS 未設定時のフォールバック)
PLACES_API_BASE_URLNoエンドポイントURL上書き(デフォルト: https://places.googleapis.com
SCRAPER_MYSQL_HOSTYesMySQL ホスト
SCRAPER_MYSQL_DATABASEYesMySQL データベース名
SCRAPER_MYSQL_USERYesMySQL ユーザー
SCRAPER_MYSQL_PASSWORDYesMySQL パスワード
SCRAPER_MYSQL_PORTNoMySQL ポート(デフォルト: 3306)
SCRAPER_ACCESS_KEY_IDYesS3アップロード用AWSアクセスキー
SCRAPER_SECRET_ACCESS_KEYYesS3シークレットキー
SCRAPER_SCRAPING_BUCKETYesログアップロード先S3バケット

注意: 各APIキーは別GCPプロジェクトから取得すること。同プロジェクトのキーはQPM制限を共有する(複数キーの効果なし)。

全体フロー

ランキング値マッピング

Text Search APIの結果をそのまま位置(1-based)で保存する。

結果ランク値意味
位置Nで発見N (1〜60)実際の順位
未検出(60件以内)0圏外
APIエラー(リトライ後)997予期しないエラー

スクレイピングとの違い: スクレイピングはLocal Pack上位3件に-11/-12/-13を使用。Places APIはLocal Packを区別せず、実際の順位をそのまま保存する。

ランキングステータス

定数意味
1STATUS_SUCCESS結果内で発見
2STATUS_OUT_OF_RANGE未検出(ranking = 0)
3STATUS_UNEXPECTED_ERRORAPIエラー(ranking = 997)

データベース設計

戦略: 既存 mappy_* テーブルを共用

Places APIとスクレイピングは同じテーブルに書き込む。各システムは mappy_gbp_locations.data_source により処理対象のロケーションが分かれているため、競合しない。

テーブル役割備考
mappy_search_ranking_update_logs日次実行ログ1レコード/日
mappy_search_ranking_processesプロセス追跡(normal/reverse)type: 0=normal, 1=reverse
mappy_temp_search_rankingsランキング生データ(1レコード/キーワード)メインデータ
mappy_search_ranking_exportsエクスポートデータ集約(1レコード/ロケーション)JSON配列、最大8キーワード

既存テーブルの拡張

mappy_gbp_locationsdata_source カラムを追加し、各システムの処理対象ロケーションを分ける。ランキング結果の区別ではない。

定数意味
1DATA_SOURCE_APIPlaces APIが処理するロケーション
2DATA_SOURCE_RANK_SEARCHスクレイピングが処理するロケーション
  • Places API はキーワードクエリ時に data_source = 1 のロケーションのみ取得
  • スクレイピングは data_source = 2 のロケーションのみ取得
  • 両者のランキング結果は同じ mappy_temp_search_rankingsmappy_search_ranking_exports に保存される

placeId の取得元

mappy_gbp_locations.raw_jsonmetadata.placeId から取得する。新規カラム追加は不要。

python
import json

# raw_json からの抽出例
raw = json.loads(raw_json)
placeId = raw["metadata"]["placeId"]  # "ChIJg9Jc9EiHGGARCDHlvl19Coo"
lat = raw["latlng"]["latitude"]        # 35.6928321
lng = raw["latlng"]["longitude"]       # 139.9285475

検索座標の決定

優先順位:

  1. ユーザー設定: mappy_user_settings.settingskeywordSettings.locations[location_id]
  2. raw_json: mappy_gbp_locations.raw_jsonlatlng.latitude/longitude
  3. デフォルト: 東京エリア (35.6441649, 139.347756) — 上記2ソースがない場合のフォールバック

ER図

テーブル定義: mappy_temp_search_rankings

Noカラム名(論理)カラム名(物理)データ型NULLキー説明
1IDidintNOPK自動採番
2実行ログIDupdate_log_idintNOIDXmappy_search_ranking_update_logs.id
3プロセスIDprocess_idintNOIDXmappy_search_ranking_processes.id
4ユーザーIDuser_idintNOIDXmappy_users.id
5ロケーションIDgbp_location_idintNOIDXmappy_gbp_locations.id
6キーワードIDkeyword_idintNOIDXmappy_keywords.id
7システムIDsystem_idintNO-1:MAPPY / 2:GCOR / 3:PIPIT
8ランキングrankingintYES-位置 (1-60)、0=圏外、997=エラー
9ランキングステータスranking_statustinyintYES-1:成功 / 2:圏外 / 3:エラー
10ランキング日付ranking_atdateNO-何日分のランクか
11API実行日時search_atdatetimeNO-実際にAPI呼び出しした日時
12作成日時created_atdatetimeNO-レコード作成日時
13更新日時updated_atdatetimeNO-レコード更新日時

テーブル定義: mappy_search_ranking_exports

エクスポートデータは1ロケーションあたりのJSON配列で、最大8キーワードとtop 3/10/20統計を含む。

Noカラム名(論理)カラム名(物理)データ型NULLキー説明
1IDidintNOPK自動採番
2実行ログIDupdate_log_idintNO-mappy_search_ranking_update_logs.id
3プロセスIDprocess_idintNOIDXmappy_search_ranking_processes.id
4ユーザーIDuser_idintNOIDXmappy_users.id
5ロケーションIDgbp_location_idintNOIDXmappy_gbp_locations.id
6システムIDsystem_idintNO-1:MAPPY / 2:GCOR / 3:PIPIT
7ランキング日付ranking_atdateNO-
8データdatalongtextNO-JSON配列(下記構造参照)
9作成日時created_atdatetimeNO-
10更新日時updated_atdatetimeNO-

JSON data 構造:

json
[
  "2026-04-07T10:30:00",   // datetime
  "user_login_id",          // login_id
  "store_001",              // store_code
  123,                      // gbp_location_id
  "1234567890",             // location_name_id
  "店舗名",                  // display_name
  1,                        // flag
  4,                        // keyword_count
  "kw1", "kw2", "kw3", "kw4", "", "", "", "",  // 8 keyword slots
  35.6595,                  // lat
  139.7004,                 // lng
  null,                     // reserved
  3, 15, 0, null, null, null, null, null,  // 8 ranking slots
  null,                     // reserved
  1, 2,                     // has_top3, top3_count
  1, 3,                     // has_top10, top10_count
  1, 4,                     // has_top20, top20_count
  1                         // system_id
]

1キーワード処理フロー

CLI引数

bash
python main.py [options]
引数デフォルト説明
--threadsint4APIキーごとのスレッド数。合計=threads×キー数
--type_keywordstrallall (normal+reverse) / normal / reverse
--min_intervalint500APIリクエスト間の最小間隔(ms、スレッドごと独立)
--max_retriesint3429エラー時のリトライ回数
--retry_delayint5000リトライ前の待機時間(ms)
--max-groupsint0処理グループ数の制限(0=無制限、テスト用)

重要: --threadsキーごとのスレッド数。合計=threads×キー数。例: 3キー + --threads 4 = 12スレッド。

Text Search API リクエスト仕様

エンドポイント

POST {PLACES_API_BASE_URL}/v1/places:searchText

デフォルトは PLACES_API_BASE_URL=https://places.googleapis.com。環境変数でモックサーバーURLに上書き可能。

ヘッダー

Content-Type: application/json
X-Goog-Api-Key: {API_KEY}
X-Goog-FieldMask: places.id,nextPageToken

リクエストボディ

json
{
  "textQuery": "渋谷 歯医者",
  "languageCode": "ja",
  "locationBias": {
    "circle": {
      "center": {
        "latitude": 35.6595,
        "longitude": 139.7004
      },
      "radius": 5000.0
    }
  }
}

レスポンス例

json
{
  "places": [
    { "id": "ChIJ..." },
    { "id": "ChIJ..." },
    { "id": "ChIJ..." }
  ],
  "nextPageToken": "..."
}

ランキング算出ロジック

python
def find_ranking(places, place_id):
    """結果内のplace_id位置を検索。

    Returns:
        位置 (1-based)。見つからなければ0。
    """
    if not places or not place_id:
        return 0
    for index, place in enumerate(places):
        if place.get("id") == place_id:
            return index + 1
    return 0

シーケンス図

エラーハンドリング

エラーHTTPステータス対応
Quota超過429retry_delay ms待機後リトライ(最大 max_retries 回)、全リトライ失敗 → ranking=997 + ERRORログ
認証エラー401PlacesAPIError type=AUTH_ERROR、ranking=997
ブロック403PlacesAPIError type=BLOCKED、ranking=997
サーバーエラー5xxPlacesAPIError type=UNEXPECTED、ranking=997
タイムアウト-PlacesAPIError type=TIMEOUT、ranking=997
接続エラー-PlacesAPIError type=UNEXPECTED、ranking=997

DBエラー処理: get_db() コンテキストマネージャがrollback後にre-raise。

マルチAPIキー・スレッド処理方式

スレッドモデル

--threadsキーごとのスレッド数。合計=--threads × キー数。

bash
# 1キー + 4スレッド/キー = 4スレッド合計
GOOGLE_PLACES_API_KEYS=keyA  --threads 4
  Thread-0 keyA    Thread-1 keyA
  Thread-2 keyA    Thread-3 keyA

# 3キー + 4スレッド/キー = 12スレッド合計
GOOGLE_PLACES_API_KEYS=keyA,keyB,keyC  --threads 4
  chunk 0→keyA  chunk 1→keyB  chunk 2→keyC  chunk 3→keyA
  chunk 4→keyB  chunk 5→keyC  chunk 6→keyA  chunk 7→keyB
  chunk 8→keyC  chunk 9→keyA  chunk 10→keyB chunk 11→keyC

スケールアップ方法: 環境変数にキーを追加 → 合計スレッド自動増加。コード変更不要。

グループ化と均等分配

全キーワードを一括取得し、user_id × gbp_location_id × system_id でグループ化後、連続チャンクに分割(ラウンドロビンではない)。

合計: 120グループ、12スレッド(3キー × 4スレッド/キー)
chunk_size = ceil(120/12) = 10

  Thread-0:  group 0-9     (keyA)
  Thread-1:  group 10-19   (keyB)
  Thread-2:  group 20-29   (keyC)
  Thread-3:  group 30-39   (keyA)
  ...
  Thread-11: group 110-119 (keyC)

利点:

  • グループの分断なし(全件取得→グループ化→分配のためシンプル)
  • normalとreverseが連続実行(同一ロケーションで request_timer を共有)
  • 各スレッドが独立したrate limiterを持つ
  • 1つの共有DBプール(pool_size=15max_overflow=10、最大25接続)

レート制限とクォータ

Google Places Text Search API のデフォルトQPMは 600 QPM。ただし実測値から、バースト制限**~10 req/秒**も適用されていることが判明。

実績データ(2026/03/25): 4バッチ合計ピーク約395 req/分(600未満)でも429エラー発生。 原因: 4バッチ × 3.41 req/秒 = 13.65 req/秒 → 10 req/秒のバースト制限を超過

min_interval の動作

各API呼び出し前(ページネーションも含む):
  elapsed = now - request_timer
  if elapsed < min_interval:
      sleep(min_interval - elapsed)
  request_timer = now
  • request_timer は同一グループ内の normal と reverse で共有
  • 各スレッドは独立した request_timer を持つ
  • ページネーション(2〜3ページ目)もレート制限対象

スループット見積もり

キー数--threads--min_interval合計スレッド合計 req/s合計 QPM評価
14500ms48480初期構成・推奨
24500ms816960推奨
34500ms122414402GB RAMで安定動作の上限
14300ms4~13~800バースト制限に近い

429リトライフロー

試行 1 → 429 → retry_delay待機 → 試行 2 → 429 → 待機 → ... → 試行 max_retries+1
  • リトライごとに WARNING ログを出力
  • 全リトライ失敗時は ranking=997、ERROR ログを出力
  • sleep(retry_delay) 後に request_timer をリセット

スループット向上策

APIキーの追加(推奨)

各Google Cloudプロジェクトに個別のレート制限(約10 req/秒)があるため、GOOGLE_PLACES_API_KEYS にキーを追加するだけで効果がある。

bash
# 初期構成(1キー × 4スレッド = 4スレッド)
GOOGLE_PLACES_API_KEYS=keyA  --threads 4       # ~8 req/s

# スケールアップ(3キー × 4スレッド = 12スレッド)
GOOGLE_PLACES_API_KEYS=keyA,keyB,keyC  --threads 4  # ~24 req/s
キー数threads/key合計スレッドレート上限処理時間(49,912 req)RAM
14410 req/秒83分~160MB
24820 req/秒42分~240MB
341230 req/秒28分~320MB
441640 req/秒21分~400MB

レート制限の引き上げリクエスト

Google Cloud Console から Quotas の引き上げをリクエスト可能。IDs Only SKU(無料)はGoogleの収益に影響しないため承認されやすい。

組み合わせ: 3キー × quota引き上げ1,200 QPM/キー = 60 req/秒 → 49,912 req を 14分 で処理可能。

ログ

ログファイル

  • ディレクトリ: log/debug_aws/
  • 統合ログ: {YYYY-MM-DD_HH-MM-SS}_total.log(全スレッド)
  • キー別ログ: {YYYY-MM-DD_HH-MM-SS}_key{suffix}.log(キーでフィルタ)
  • S3アップロード先: s3://{bucket}/log/apigoogle/{filename}

ログフォーマット

2026-04-07 10:30:18,015 [INFO][T1][...a1b2] [1/1212] location='渋谷歯科', keywords=8
2026-04-07 10:30:18,378 [DEBUG][T1][...a1b2] [uid=1 sys=1 loc=123]   [N][1/8] '渋谷 歯医者': rank=1, results=60
2026-04-07 10:30:18,900 [WARNING][T2][...c3d4] [uid=2 sys=1 loc=456]   [R][3/8] '歯医者 渋谷': 429 rate limited (attempt 1/4), waiting 5000ms...
2026-04-07 10:30:23,910 [INFO][T2][...c3d4] [uid=2 sys=1 loc=456]   [R][3/8] '歯医者 渋谷': retry succeeded (attempt 2/4)
フィールド意味
[T{n}]スレッド番号
[...{suffix}]APIキーの末尾4文字
[uid=X sys=Y loc=Z]コンテキスト: user_id, system_id, gbp_location_id
[N]/[R]Normal / Reverse
[i/total]グループ内の i 番目のキーワード
attempt X/Y合計 Y 回中の X 回目の試行

リソース制限(1 CPU / 2GB RAM)

GILとI/Oバウンド

このワークロードは I/Oバウンド のため、GIL下でもスレッドが有効。

各キーワード:  ~293ms(実測平均)  Google API HTTP レスポンス待ち
              ~5〜10ms           DB 書き込み
              < 1ms              Python コード(JSON パース、ランク計算)

→ CPUは実質約98%の時間アイドル → 複数スレッドで効率的に並列実行可能。

リソース見積もり

リソース見積もり
RAM / スレッド~15〜20MB
RAM ベースプロセス~80MB
RAM(4スレッド、1キー)~80 + 4×20 = ~160MB
RAM(12スレッド、3キー)~80 + 12×20 = ~320MB
平均 CPU< 20%
DB 接続数pool_size=15、max_overflow=10、最大 25

推奨構成

キー数--threads合計スレッドRAM合計 QPM評価
144~160MB480初期構成・推奨
248~240MB960推奨
3412~320MB14402GB RAMで安定上限
4416~400MB1920QPM quota引き上げ要

初期推奨設定: GOOGLE_PLACES_API_KEYS=key1 + --threads 4 --min_interval 500

ソースコード構造

places_api/
├── main.py                    # エントリポイント: CLI引数、オーケストレーション、スレッド管理
├── services/
│   └── places_api.py          # Google Places APIクライアント (search_text, find_ranking)
├── database/
│   ├── database.py            # SQLAlchemyエンジン、セッション、get_db()コンテキストマネージャ
│   ├── models.py              # ORMモデル (mappy_* テーブル)
│   └── repositories.py        # DBクエリ (CRUD操作)
├── logger.py                  # 構造化ログ(スレッド別・キー別ファイルハンドラ)
├── migrations/
│   └── gplaces_tables.sql     # 新テーブルDDL
├── Dockerfile
├── requirements.txt
└── .env.example

テスト項目

#テスト内容確認方法
1placeId 抽出raw_jsonmetadata.placeId から正しく取得できること
2ランキング発見ranking値が実際の位置(1-based)で保存されること
3圏外60件内に見つからない場合 ranking=0、status=2 になること
4APIエラーmax_retries後 → ranking=997、status=3 になること
5ページネーションnextPageToken で最大3ページ取得されること
6429リトライ429応答時に max_retriesretry_delay でリトライされること
7マルチAPIキーキーがラウンドロビンでチャンクに割り当て(chunk_idx mod キー数)
8スレッドモデル合計スレッド = --threads × キー数
9レート制限min_interval でリクエスト間隔制御(ページネーションも対象)
10normal/reverse各グループでnormal→reverseが連続実行、request_timer 共有
11チャンク分配グループが連続チャンクでスレッドに分配されること
12data_source フィルタdata_source=1 のロケーションのみ処理されること
13エクスポートデータJSON配列が正しいフォーマット(8 keyword slots、top 3/10/20統計)
14S3ログ統合ログ + キー別ログがS3にアップロードされること
15update_log status開始時にRUNNING設定、process がSUCCEEDED/FAILED設定
16--max-groupsテスト時にグループ数が正しく制限されること
17get_db() 例外処理DBエラーがrollback後にre-raiseされること

非機能要件

#項目要件
1費用$0/月(Field Mask: places.id → Basic SKU 無料)
2処理性能初期: 1キー4スレッド 480 QPM。キー追加でリニアにスケール
3リソース1 CPU / 2GB RAM — 1キー4スレッド ~160MB、3キー12スレッド ~320MB
4可用性Google Places API のSLA(99.9%)に依存
5データ保持ランキング履歴は無期限保持
6セキュリティAPIキーはサーバー側環境変数で管理
7監視ログS3アップロード、キー別ログファイルでデバッグ
8スケーラビリティ環境変数にキー追加 → 自動的にスレッド・スループット増加

前提条件・制約事項

前提条件

  • Google Cloud Projectで Places API (New) が有効化されていること
  • APIキーが作成済みで、Text Search へのアクセス権限があること(複数プロジェクトのキーを推奨)
  • mappy_gbp_locations.raw_jsonmetadata.placeId に有効な値が含まれていること
  • mappy_gbp_locationsdata_source カラムが追加済み(1=API, 2=scraping)
  • Python 3.10+ と requirements.txt のライブラリが利用可能であること
  • AWS S3 認証情報(ログアップロード用)

制約事項

  • Text Search APIではKnowledge Panel(-1 / -2)を判定できない
  • 検索結果は最大60件(20件×3ページ)まで — 61位以降は圏外扱い
  • locationBias の半径は5000m固定
  • スクレイピングとPlaces APIの結果は完全一致しない可能性がある(検索エンジンとPlaces APIはランキングロジックが異なる)
  • エクスポートデータは最大8キーワード/ロケーション(9番目以降はexportに含まれないが、mappy_temp_search_rankings には保存される)
  • Slack通知は未実装(TODO)

概算工数

体制

役割人数担当内容
設計者1名要件確認 → 設計書作成 → レビュー → 製造へ指示
製造者1名ISSUEを元に作成 → コードレビュー → テスト実施 → デプロイ

工数内訳

#作業項目工数(人日)担当
1要件確認・設計書作成1.0設計者
2DBマイグレーション(data_source追加・インデックス)0.5製造者
3コアロジック: Text Search API+ランキング算出1.5製造者
4マルチAPIキー+スレッド+CLI+レート制限1.0製造者
5エクスポートデータ+エラーハンドリング1.0製造者
6ログ出力+S3ログアップロード0.5製造者
7結合テスト1.0製造者
8デプロイ・動作確認0.5製造者
合計7.0

スケジュール

タスク担当日数4/74/84/94/104/114/124/134/144/154/164/17
要件確認・設計書作成設計者1d
DBマイグレーション(data_source+インデックス)製造者1d
設計レビュー・製造指示設計者1d
コアロジック: API+ランキング製造者2d
マルチAPIキー+スレッド+レート制限製造者1d
エクスポートデータ+エラー処理製造者1d
ログ出力+S3アップロード製造者1d
結合テスト製造者1d
デプロイ・動作確認製造者1d