Reference · matching_demo.py

複数参加者マッチングの処理と関数

標準ライブラリのみの単一ファイルデモです。候補の属性から説明可能なスコアを算出し、 2〜5人のグループを貪欲に構成します。DB・HTTP・Event 生成は含みません。

1
入力 候補・場所・プロフィール
2
除外 filter_eligible
(資格フィルタ)
3
ペア採点 score_pair
(2人の相性点)
4
グループ form_groups
(チーム編成)
5
出力 print_report
(結果表示)

1. 概要

目的は「いま空きがある学生同士を、意図・時間・場所などの要因でマッチさせ、 閾値を満たすグループだけを返す」ことです。本番の matching_service.run_matching(マッチング実行の公開入口)と同型の流れを、依存なしで追えるようにしています。
flowchart LR
  IN["Scenario シナリオ
candidates 候補一覧
beacons 場所カタログ
profiles プロフィール"] --> CORE["run_matching
マッチング実行"] CORE --> E["exclusions
除外一覧"] CORE --> P["pair_scores
ペア点数"] CORE --> G["groups
採用グループ"] E --> OUT["print_report
結果レポート出力"] P --> OUT G --> OUT IN --> OUT

図 1 — 入力から標準出力(stdout)への報告までの全体像

2. ファイル構成(8 ブロック)

flowchart TB
  FILE["matching_demo.py"]
  FILE --> B1["① CONFIG
設定定数(重み・閾値)"] FILE --> B2["② TYPES
型定義(dataclass)"] FILE --> B3["③ SCENARIOS
埋め込みシナリオ A〜E"] FILE --> B4["④ TIME UTILS
時間ユーティリティ"] FILE --> B5["⑤ SCORING
採点関数群"] FILE --> B6["⑥ PIPELINE
処理パイプライン"] FILE --> B7["⑦ REPORT
レポート出力"] FILE --> B8["⑧ main
起動入口"] B1 --> B6 B2 --> B6 B3 --> B8 B4 --> B5 B5 --> B6 B6 --> B7 B7 --> B8

図 2 — 依存は下位(設定・純関数)からパイプライン、最後に CLI(コマンドライン起動)

CONFIG(設定)

準備15分、最小イベント30分、ペア閾値0.60、グループ閾値0.70、人数2〜5、要因重み合計1.00。

PAIR_SCORE_THRESHOLD(ペア合格点)など

TYPES(型)

Candidate(候補)/ Beacon(場所)/ Profile(プロフィール)/ FactorScores(要因点)/ PairScore(ペア点)/ MatchingResult(結果一式)。

@dataclass(frozen=True) 不変データクラス

PIPELINE(処理本体)

除外 → 全ペア採点 → 貪欲グループ。公開入口は run_matching(マッチング実行)。

filter_eligible / score_pair / form_groups

REPORT(出力)

参加者属性・除外・ペア(factors 要因値 / weighted 重み寄与 / inputs 入力比較)・グループ。

print_participants / print_report

3. 実行パイプライン

sequenceDiagram
  participant CLI as main(起動)
  participant Run as run_matching(実行)
  participant Gate as filter_eligible(資格)
  participant Pair as score_pair(ペア採点)
  participant Form as form_groups(編成)
  participant Rep as print_report(表示)

  CLI->>Run: scenario(シナリオ入力)
  Run->>Gate: candidates(候補一覧)
  Gate-->>Run: eligible(通過者)+ exclusions(除外)
  loop 全ペア
    Run->>Pair: (a,b) + profiles(プロフィール)+ beacons(場所)
    Pair-->>Run: PairScore(ペア点)または None
  end
  Run->>Form: edges(合格ペア)+ duplicate sets(重複集合)
  Form-->>Run: MatchedGroup(採用グループ)
  CLI->>Rep: scenario + MatchingResult(結果一式)
  Rep-->>CLI: stdout 4セクション(標準出力)
        

図 3 — 呼び出し関係

4. 除外ゲート filter_eligible(資格フィルタ)

スコア計算の前に、個人単位で参加資格を判定します。ここで落ちた候補はペア採点に入りません。
flowchart TD
  C["Candidate
候補1人"] --> Q1{"expires_at > now?
有効期限が現在より後か"} Q1 -->|No| X1["inactive_status
期限切れ"] Q1 -->|Yes| Q2{"intervals あり?
空き時間区間があるか"} Q2 -->|No| X2["NO_AVAILABILITY
空き時間なし"] Q2 -->|Yes| Q3{"prep 後の残り ≥ 30分?
準備時間後も30分以上あるか"} Q3 -->|No| X3["insufficient_remaining_time
残り時間不足"] Q3 -->|Yes| Q4{"適合 Beacon が存在?
使える場所があるか"} Q4 -->|No| X4["no_suitable_beacon
適合場所なし"] Q4 -->|Yes| Q5{"singleton が duplicate でない?
単独重複ブロックでないか"} Q5 -->|No| X5["duplicate_candidate_event
重複候補イベント"] Q5 -->|Yes| OK["eligible
通過(採点対象)"]

図 4 — 個人ゲート(グループ単位の duplicate=重複集合チェックは form_groups 側)

5. ペア採点 score_pair(2人の相性点)

共通時間が最小イベント長に満たない、または適合 Beacon(場所)がない場合は None(辺なし=ペア不成立)。 それ以外は 7 要因を重み付き合計し、0.00〜1.00 の matching_score(マッチング総合点)を返します。 辺として採用されるのは ≥ 0.60(ペア合格閾値)のペアです。

要因重み(合計 1.00)

intent(意図)
0.30
time(時間)
0.25
location(場所)
0.15
interest(興味)
0.10
capacity(定員適合)
0.10
department(学科)
0.05
friend(友人)
0.05
flowchart LR
  A["Candidate A
候補A"] --> S["score_pair
ペア採点"] B["Candidate B
候補B"] --> S S --> F["FactorScores × weights
要因点×重み"] F --> T["matching_score
総合点"] T --> G{"≥ 0.60?
ペア合格閾値"} G -->|Yes| EDGE["pair_score_map に登録
合格ペア辞書へ"] G -->|No| DROP["グループ候補の辺にしない"]

図 5 — ペア辺(合格した2人関係)の生成

要因 算出の要点
intent(意図一致) 集合の重なり係数(共通 / min(|A|,|B|))
time(時間一致) prep(準備時間)後の共通分: <30→0、30–59→0.50、60–89→0.75、90+→1.00
location(場所一致) 同一 Beacon(場所)1.00 / 同一建物 0.70 / 同一キャンパス 0.30 / 別 0.00 / 不明 0.50
interest(興味一致) デモでは常に unknown(不明)→ 0.50 固定
department(学科一致) 同一 1.00 / 異 0.00 / 未設定 0.50
friend(友人関係) 承認済み友人なら 1.00、それ以外 0.00
capacity(定員適合) 選定 Beacon(場所)の定員帯(5未満は不適格)

6. グループ形成 form_groups(チーム編成)

サイズ 2〜5 の全組合せを列挙し、全ペア辺が閾値以上・共通時間・Beacon(場所)・ グループ点 ≥ 0.70 を満たすものだけを提案します。その後 selection_score(選定用スコア=総合点+人数ボーナス)降順で貪欲に採用し、 同一実行内で学生を再利用しません。
flowchart TD
  E["eligible + pair edges
通過者+合格ペア辺"] --> C["combinations size 2..5
2〜5人の全組合せ"] C --> D{"集合が duplicate?
重複候補集合か"} D -->|Yes| Skip["skip スキップ"] D -->|No| V{"全ペア ≥ 0.60
共通時間・Beacon OK
group score ≥ 0.70?
グループ総合点"} V -->|No| Skip V -->|Yes| Rank["selection_score でソート
選定スコア順"] Rank --> Pick["貪欲採用・非再利用"] Pick --> G["MatchedGroup[]
採用グループ配列"]

図 6 — グループ候補の列挙と貪欲選択

selection_score(選定スコア) = matching_score(総合点) + size_bonus(人数ボーナス) (2人で +0.00、以降1人あたり +0.02、最大 +0.06)。

7. 関数一覧

時間ユーティリティ

関数 役割
merge_intervals(区間結合) 重複・隣接する空き時間区間を結合
intersect_intervals(区間交差) 2系列の空き時間が重なる部分だけ残す
clip_intervals_after(時刻以降に切る) 指定時刻より前を切り捨て
total_minutes(合計分数) 区間合計の分数
common_minutes_after_prep(準備後の共通分) prep(準備15分)後に何分共有できるか
remaining_minutes_after_prep(準備後の残り分) 個人の prep 後に残る分数

スコアリング

関数 役割
overlap_coefficient(重なり係数) 意図などの集合がどれだけ重なるか
time_match_score ほか *_match_score(各要因スコア) 各要因を 0〜1 の点数にする
is_beacon_suitable(場所適否) MICRO(短時間イベント)対応 / 定員 / 並行上限の可否
select_beacon_for_members(場所選定) 近接0.70 + 定員0.30 で開催場所を選ぶ
mean_factors(要因平均) ペア要因の平均(グループ点の再計算用)
FactorScores.weighted_total(重み付き合計) 7要因に重みをかけて総合点にする

パイプライン / I/O(入出力)

関数 役割
filter_eligible(資格フィルタ) 個人単位の除外ゲート
score_pair(ペア採点) 2人1組の相性点を計算
form_groups(グループ編成) グループ候補の列挙と貪欲選択
run_matching(マッチング実行) 公開入口(上記を接続)
print_participants(参加者表示) 空き時間・場所・プロフィールなどの属性表示
print_pair_inputs(ペア入力比較) 要因計算に使った生属性の比較表示
print_report(結果レポート) 4セクションの stdout(標準出力)
main(起動入口) argparse(引数解析)による起動

8. 出力セクション(現行)

flowchart TB
  R["print_report
結果レポート"] --> S1["[1] Participants 参加者
空き時間・場所・学科・友人・重み"] R --> S2["[2] Exclusions 除外
reason_code 理由コード"] R --> S3["[3] Pair scores ペア点
factors 要因 / weighted 寄与 / inputs 入力"] R --> S4["[4] Groups グループ
members メンバー / scores 点数 / beacon 場所"]

図 7 — 検証しやすいよう属性と寄与を明示

セクション 確認できること
[1] Participants(参加者) intent(意図)/ availability(空き時間・prep後残り)/ location(場所)/ department(学科)/ friends(友人)/ ELIGIBLE(通過)判定
[2] Exclusions(除外) ゲートで落ちた学生と reason_code(理由コード)
[3] Pair scores(ペア点) factors(要因値)、weighted(重みかけ後の寄与)、 inputs(比較に使った生属性)
[4] Groups(グループ) 最終グループ、matching(総合点)/ selection(選定スコア)、 選定 Beacon(場所)

9. 埋め込みシナリオ

A

意図・時間・場所が揃い、グループが1つできる成功パス。

B

prep(準備時間)後の残り不足で全員除外。

C

6人。貪欲選択で複数グループ+あまりが出る。

D

duplicate_student_sets(重複候補集合)により 全ペア/トリオが不採用。

E

友人・学科要因の差がペア点に表れる。

10. 実行方法

# シナリオ一覧 python matching_demo.py --list # 成功パス(属性・寄与つき) python matching_demo.py --scenario A # ゲート除外の確認 python matching_demo.py --scenario B

関連: シナリオ解説 A〜E · 想定構成 · やさしい解説 · 本番対応 backend/app/services/matching_service.py(マッチングサービス)