複数参加者マッチングの処理と関数
標準ライブラリのみの単一ファイルデモです。候補の属性から説明可能なスコアを算出し、 2〜5人のグループを貪欲に構成します。DB・HTTP・Event 生成は含みません。
(資格フィルタ)
(2人の相性点)
(チーム編成)
(結果表示)
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)
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(チーム編成)
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. 実行方法
関連:
シナリオ解説 A〜E ·
想定構成 ·
やさしい解説 ·
本番対応 backend/app/services/matching_service.py(マッチングサービス)