プロジェクト

全般

プロフィール

機能 #313

完了

ノーツレーダー6軸の細分化データモデル設計(弱点分析 #293 の前提整備)

機能 #313: ノーツレーダー6軸の細分化データモデル設計(弱点分析 #293 の前提整備)

エージェント ちゃん さんが17日前に追加. 17日前に更新.

ステータス:
完了
優先度:
通常
担当者:
対象バージョン:
開始日:
2026/06/19
期日:
進捗率:

100%

予定工数:

説明

目的

#293(弱点分析・地力推定パネル)の前提として、既存のノーツレーダー6軸(NOTES / PEAK / SCRATCH / SOFLAN / CHARGE / CHORD)を、より細かい音ゲー特性(単皿・連皿、LN拘束、最大1秒密度…等)へ細分化した内部データモデルの設計を先行検討する。本チケットの成果物は設計(採用方針の決定)であり、実装・パネル本体は別チケット(#293 ほか)で行う。

#293 ユーザーメモの「6軸を拡張したもっと細かい音ゲーデータを保持したほうがいいかもしれない。先にこちらを検討」を受けたもの。

スコープ

  • 対象: 細分化サブ軸の定義、データ取得方式、保持(スキーマ)方式、集計・正規化方式、既存6軸との関係、段階導入計画の決定。
  • 対象外: #293 の弱点分析パネルそのものの実装(未着手のまま保留)。弱点判定で比較する「全体平均」の定義は本設計確定後に #293 側で別途決定する(ユーザー指示)。

現状のデータパイプライン(調査結果)

6軸レーダー値は次の経路で算出・保持されている。

  1. beatoraja 本体が算出: bms.player.beatoraja.song.NotesRadarCalculator#calculate(BMSModel)NotesRadarFeature(約30フィールドの record)を生成。譜面ロード時 SongDataModelMapper#apply() で呼ばれる。
  2. SongData には最終6値のみ保持: featureNotesDensity / featurePeakDensity / featureScratchDensity / featureSoflan / featureCharge / featureChord(各 0〜200 にスケール済み)。NotesRadarFeature が持つ生メトリクス約24個は SongData に載らず破棄される
  3. plugin が伝送: bms.player.beatoraja.ir.IzuIRConnectionIRChartData)が上記6値を feature_* キーで ChartDataDto.valuesMap<String,String>)に詰めて送信。
  4. server が保持: ScoreService#upsertSong()chart.values() から feature_* を読み、songs テーブルの radar_notes / radar_peak / radar_scratch / radar_soflan / radar_charge / radar_chordDOUBLE PRECISION, マイグレーション V9__add_song_radar.sql)へ格納。エンティティは SongEntity
  5. 集計: PlayerNotesRadarAxis(enum, 軸→列マッピング)と PlayerNotesRadarQueryRepositoryaggregate / topEntries)が、mode='7' に限定し、各譜面の達成率 min(exscore/(notes*2), 1.0) で重み付けし、軸ごと上位10譜面を平均して 0〜200 値を返す。PlayerNotesRadarService#radar()/detail()

重要な含意: 細分化に必要な生データの多くは beatoraja 内部で既に計算されているが伝送・保持されていない。よって細分化は本質的に「解析の露出 → 伝送 → スキーマ → 集計」の拡張であり、新規の重い譜面解析はサブ軸の一部に限られる。

細分化サブ軸の提案とデータ源マッピング

ユーザー例の各サブ軸を、取得可能性で A: 既存計算の露出のみ / B: 新規解析が必要 に分類する。B は izu-ir 側で BMSModelTimeLine / Note / NormalNote / LongNote / Mode#isScratchKey)から追加算出する想定。

SCRATCH(皿)

サブ軸 定義(案) 区分 データ源 / 備考
単皿 孤立した皿の量 B 皿総数 scratchTotal から連皿分を除く。新規判定要
連皿 短間隔で連続する皿の密度 A寄り scratchPeakWindowNotes(3秒窓内皿数)を流用可。窓定義の精緻化は B
皿複合 皿と鍵盤が同時/近接する密度 B 皿タイムライン近傍の鍵盤数。新規解析
終盤皿 譜面終盤(末尾x%)の皿密度 B 「終盤」の定義(末尾何%か)要決定
皿直後鍵盤 皿の直後一定時間内の鍵盤量 B 皿後ms窓の鍵盤カウント。新規解析

CHARGE(LN/CN)

サブ軸 定義(案) 区分 データ源 / 備考
LN数 LN/CN 総本数 A longNoteTotal
LN拘束 LN の累積拘束時間 A longNoteSecondsTotal
LN中鍵盤 LN保持中に押す通常鍵盤量 A/B chargeNotesDuringLongNote(鍵盤/皿合算)。鍵盤のみへ分離は B
LN中皿 LN保持中の皿量 B 上記から皿のみ分離。新規解析
LN終端密度 LN終端付近のノーツ密度 B LN終端ms窓の密度。新規解析

PEAK(密度ピーク)

サブ軸 定義(案) 区分 データ源 / 備考
最大1秒密度 1秒窓の最大ノーツ数 B 既存は3秒窓 peakWindowNotes。1秒窓は新規
最大5秒密度 5秒窓の最大ノーツ数 B 新規窓
最大10秒密度 10秒窓の最大ノーツ数 B 新規窓
終盤ピーク 譜面終盤のピーク密度 B 「終盤」定義に依存
局所難率 局所的な難所の集中度 B 指標定義要決定(密度分散/上位窓比など)

SOFLAN / CHORD も同様に細分化余地あり(soflan* 系メトリクス、chordTimelineCount / maxChordSize / chordPeakWindowNotes 等)。本チケットで全軸の最終サブ軸セットを確定する。

データ取得の実現方式(要決定)

  • 案A: beatoraja の生メトリクスを SongData 経由で露出
    • NotesRadarFeature の生フィールドを SongData に載せ、plugin で feature_* に追加する。
    • 長所: 既存計算の再利用。短所: beatoraja 本体の改変に依存し、izu-ir が特定 beatoraja ビルドに強く結合する(脆い)。サブ軸の一部(B分類)はそもそも未計算。
  • 案B: izu-ir plugin 側に独自アナライザを実装(推奨)
    • plugin 内に NotesAnalyzer を新設し、beatoraja の BMSModel 系モデルクラスから全サブ軸を izu-ir 独自に算出
    • 長所: 軸定義を izu-ir が完全制御でき、beatoraja 内部実装に非依存。A/B 双方のサブ軸を一元的に扱える。短所: 解析ロジックの新規実装コスト。
    • 要確認(重要): スコア送信時に plugin が BMSModel(または BMS ファイル)へアクセスできるか。アクセス不可なら譜面ロード時にキャッシュして送信時に参照する設計が必要。

保持(スキーマ)方式(要決定)

  • 案1: songsradar_* 列を追加し続ける — 既存踏襲だが、〜15+列で列爆発・マイグレーション肥大。
  • 案2: 正規化テーブル song_chart_feature(song_sha256, axis_key, value, updated_at)(EAV) — 軸追加がデータ行追加で済み、集計クエリも axis_key で汎用化。推奨
  • 案3: songs.chart_features JSONB — 柔軟だが集計クエリ・型保証が弱い。

伝送層は ChartDataDto.values(任意キーの Map)が既に汎用なので、いずれの案でも plugin→server 互換性は高い。

集計・正規化方針

  • 既存同様、各サブ軸を 0〜200 アンカーテーブル方式でスケールし、達成率 min(exscore/(notes*2), 1.0) 重み付け+軸ごと上位N平均を踏襲。
  • 既存6軸は親カテゴリとして残し、サブ軸はそのドリルダウンとして表現(後方互換・UI 段階導入)。

#293 への接続

  • サブ軸の average を「親軸グループ平均」または「本人全サブ軸平均」と比較して弱点サブ軸を抽出する余地が生まれる。
  • 「全体平均」の具体定義(本人内平均 / 全プレイヤー横断平均)は、本設計でサブ軸セットが確定した後に #293 側で決定する。

段階導入計画(案)

  • Phase 1: A分類(既に算出済み or 軽微な算出)サブ軸の露出・伝送・保持・集計。
  • Phase 2: B分類(皿直後鍵盤・終盤系・1/5/10秒窓・局所難率・LN終端密度・LN中皿)の新規解析実装。
  • 各 Phase は別 機能 チケットとして起票予定。

未解決の検討事項(Open Questions)

  • plugin がスコア送信時に BMSModel / BMS ファイルへアクセスできるか(案B の前提)。
  • 「終盤」の定義(末尾何 % / 何秒か)。
  • 「局所難率」の具体指標定義。
  • スキーマ案(1/2/3)の最終選択。
  • 既存 songs 行のバックフィル方針(新サブ軸は再プレイ/再ロードまで NULL になる扱い)。
  • 全軸の最終サブ軸セット(SOFLAN/CHORD 含む)の確定。

テスト方針(将来実装時)

  • plugin: NotesAnalyzer 単体テスト(既知譜面で各サブ軸値の境界・期待値)。
  • server: 集計クエリ/正規化の境界テスト、コントローラ 404。
  • web: パネル描画・i18n(#293 側)。

関連するチケット 2 (0件未完了2件完了)

関連している beatoraja - 機能 #145: ノーツレーダー機能完了いづ さん2026/06/09

操作
次のチケットに先行 beatoraja - 機能 #314: ノーツレーダー細分化 Phase 1: A分類サブ軸の露出・IR伝送・EAV保持・集計完了いづ さん2026/06/222026/06/22

操作

エージェント ちゃん さんが17日前に更新 操作 #2

設計方針 : データ生成はユーザー自身の beatoraja 本体側で実施

ユーザーより、レーダー系データはユーザー自身が管理する beatoraja 本体で生成しているため、細分化(サブ軸の解析・算出)も本体側で検討する方針。

この決定による前提の変化:

  • 「データ取得の実現方式」は 案A(beatoraja 本体で生メトリクスを算出 → SongData 経由で露出 → plugin が feature_* キーで送信)が自然な選択肢となる。本体を管理下に置けるため、案Aの短所として挙げた「beatoraja 本体改変依存で脆い」は実質解消。izu-ir 側に独自アナライザ(案B)を新設する必要性は低下。
  • 役割分担: 細分化サブ軸の定義・解析実装は beatoraja 本体側。izu-ir 側の責務は 伝送(ChartDataDto.values の任意キー拡張)・保持(スキーマ)・集計・正規化・#293 への接続 に絞られる。
  • 「現状のデータパイプライン」の調査結果(NotesRadarCalculatorNotesRadarFeatureSongData の最終6値のみ保持)はそのまま有効。本体側で SongData に追加フィールドを載せ、plugin がそれを feature_* に詰めれば izu-ir まで流れる。

izu-ir 側に残る検討事項(本チケットで継続):

  • 保持スキーマ案(1: radar_* 列追加 / 2: EAV song_chart_feature / 3: JSONB)の最終選択 ― サブ軸が増える前提では 案2(EAV)推奨は変わらず。
  • 集計・正規化(0〜200 スケール、達成率重み付け)の踏襲。
  • 既存 songs 行のバックフィル方針(新サブ軸は再プレイ/再ロードまで NULL)。
  • 本体側で確定したサブ軸キー名と izu-ir の axis_key / 列名の対応。

本体側でのサブ軸定義が固まり次第、izu-ir 側の Phase 1(伝送・保持・集計)を 機能 チケットとして起票する。

いづ さん さんが17日前に更新 操作 #3

  • トラッカーリファクタ から 機能 に変更
  • プロジェクト18 から beatoraja に変更
  • 対象バージョン0.3.0 から 1.1.3 に変更

いづ さん さんが17日前に更新 操作 #4

  • 関連している 機能 #145: ノーツレーダー機能 を追加

エージェント ちゃん さんが17日前に更新 操作 #5

  • ステータス未着手 から 実装中 に変更
  • 進捗率0 から 10 に変更

実装に着手しました。

  • ブランチ: feature/313
  • 対応方針: 現状データパイプラインを精査の上、ノーツレーダー6軸の細分化サブ軸の最終セット・各サブ軸の数値定義・データ源(A:既存露出 / B:新規解析)・保持スキーマ(案2 EAV)・集計/正規化・バックフィル方針・段階導入計画を確定する設計ドキュメントを docs/ に作成する(成果物は設計のみ。実装は Phase 1/2 別チケット)。

エージェント ちゃん さんが17日前に更新 操作 #6

設計方針 : 細分化タクソノミーを確定(パターン軸の新設=ハイブリッド)

設計ドキュメントを docs/notes-radar-subdivision-design.md として作成・コミットしました(feature/313)。本チケットの成果物は設計のみで、実コードは別チケット(#293 / Phase 1・2)。

コード調査による現状訂正(重要)

  • 本チケット本文の調査記述「生メトリクス約24個は SongData に載らず破棄される」は 現状と食い違う古い記述でした。実際には本体 songdata.dbSongData とも 29特徴量列すべてを保持・round-trip 済みSQLiteSongDatabaseAccessor / SongDataResultSetHandler、自動ALTER対応)。未対応なのは IR伝送(IRChartData は最終6値のみ送信)・server保持(radar_ 6列)・集計(6軸)* と、パターン系サブ軸の新規解析のみ。
  • スコア送信時(MusicResult.IRSendStatus)は SongDataBMSModel 双方にアクセス可 → 未解決事項「plugin が BMSModel へアクセスできるか」は アクセス可 で確定。
  • BSS 専用型は存在しない(LongNote は UNDEFINED/LONGNOTE/CHARGENOTE/HELLCHARGENOTE)→ **BSS は「scratch lane の LongNote」**で検出と確定。

方向性の転換(ユーザー確認済み)
現状 NotesRadarCalculator は「各 TimeLine の縦方向集計」のみで、レーン音符時系列を追跡せず 横方向のパターン認識指標が皆無。チケット当初案のサブ軸は既存密度/構造メトリクスの窓違い・内訳分離に偏り、地力傾向(乱打・縦連・トリル・階段・デニム・軸・ガチ押し・皿種別・ソフラン種別・リズム難)を捉えていませんでした。よって 物量/密度系は既存露出で安価に細分化しつつ、本命としてパターン認識軸を新規解析で追加するハイブリッドを採用。#293 の弱点分析に直結します。

確定した採用方針

論点 決定
データ取得 案A: 本体 NotesRadarCalculator で全サブ軸算出
保持スキーマ 案2 EAV song_chart_feature(song_sha256, axis_key, value, updated_at)
伝送 IRChartData.valuesfeature_<axis_key> 追加(最終6値→全 feature_*)
集計・正規化 既存踏襲(0–200アンカー・達成率 min(exscore/(notes*2),1.0) 重み・上位N平均)
既存6軸 親カテゴリとして温存・ドリルダウン+新規パターン親軸(後方互換)
バックフィル #145 同方式(楽曲全更新で再計算→songdata.db を IR 取り込み)
数値しきい値 粒度先行・実データ分布を見て後決め

確定サブ軸タクソノミー(粒度)

  • NOTES: density / density_peak_1s / density_peak_10s / local_hardness / endgame
  • PEAK: density / burst_1s / sustained_3s
  • CHORD: density / max_size / gachioshi / denim / jika(軸)
  • PATTERN(新規親): randa(乱打) / jack(縦連) / trill / kaidan(階段)
  • SCRATCH: density / single(単皿) / ren(連皿) / complex(皿複合) / bss
  • SOF-LAN: soflan / accel / decel / stop / visual
  • RHYTHM(新規親): 24th / henpyoshi(変拍子) / irregular(不規則間隔)

A=既存露出 / B=新規解析の分類、各サブ軸の定義・データ源・正規化、新規パターン解析プリミティブ(per-lane 音符時系列・間隔ヒストグラム)のアルゴリズムスケッチと暫定閾値、段階導入計画(Phase 1=A分類の露出/伝送/保持/集計、Phase 2=B分類の新規解析)、本体側の変更接点、テスト方針は設計ドキュメントに収録。

残課題(実データ依存で後決め): 全パターン軸の 0–200 アンカー、ジャック等の閾値を固定msかBPM相対か、乱打エントロピー閾値、皿複合窓、デニム/ガチ押しsize閾値、リズムoff-grid許容、集計上位N、soflan細分の二重計上回避係数、パターン軸の本体正規化 vs server正規化。

Phase 1/2 は別 機能 チケットとして起票予定。

エージェント ちゃん さんが17日前に更新 操作 #7

  • 次のチケットに先行 機能 #314: ノーツレーダー細分化 Phase 1: A分類サブ軸の露出・IR伝送・EAV保持・集計 を追加

エージェント ちゃん さんが17日前に更新 操作 #8

  • ステータス実装中 から 完了 に変更
  • 進捗率10 から 100 に変更

対応が完了しました。

概要

#293(弱点分析)の前提として、ノーツレーダー6軸を細分化する内部データモデルの**設計(採用方針の決定)**を確定し、設計ドキュメントとして追加した。成果物は設計のみで、実コードは含まない(実装は #314 Phase 1 / #315 Phase 2)。

変更点

  • 設計ドキュメント docs/notes-radar-subdivision-design.md(新規)を追加。
    • 方向性の転換: 現状 NotesRadarCalculator は縦集計のみでパターン認識が皆無 → 物量/密度系は既存露出で安価に細分化しつつ、本命はパターン認識軸(乱打/縦連/トリル/階段/デニム/軸/ガチ押し/皿種別/ソフラン種別/リズム難)の新規解析追加というハイブリッド方針。
    • 採用方針: データ生成=本体(案A)/保持=EAV song_chart_feature(案2)/伝送=IRChartData の feature_* 全送信化/集計=既存0–200アンカー踏襲/バックフィル=#145同方式。
    • 確定タクソノミー: NOTES/PEAK/CHORD(+ガチ押し)/PATTERN/SCRATCH/SOF-LAN/RHYTHM のサブ軸を A(既存露出)/B(新規解析)で分類。新規パターン解析プリミティブ(per-lane 音符時系列・間隔ヒストグラム)のアルゴリズムスケッチ・暫定閾値・段階導入・本体変更接点・テスト方針・実データ後決め項目を収録。
  • 現状訂正: チケット記載「生メトリクスは破棄」は古い記述で、実際は本体SQLite・SongDataとも20特徴量を保持・round-trip済み(未対応はIR伝送・server保持・集計・パターン解析のみ)。
  • 変更ファイル: docs/notes-radar-subdivision-design.md 1件(新規)。

テスト

  • コード変更がないため Gradle ビルド/テストは対象外(設計ドキュメントのみ)。claude-review は PASS(指摘なし)。技術的主張は実コードで検証済み。

後続チケット

  • #314 Phase 1: A分類サブ軸の露出・IR伝送・EAV保持・集計
  • #315 Phase 2: B分類(パターン認識)サブ軸の新規解析実装

関連 MR

  • !67 (feature/313 → develop)

エージェント ちゃん さんが17日前に更新 操作 #9

訂正: 上の完了コメント中「本体SQLite・SongDataとも20特徴量を保持」は誤記で、正しくは 29特徴量(最終6値+生メトリクス23)です。設計ドキュメント docs/notes-radar-subdivision-design.md 本体は正しく29と記載されています。

他の形式にエクスポート: PDF Atom