ワールドカップをRDBに記録していきたい
この記事は スターフェスティバル スターフェスティバル Advent Calendar 2022の22日目の記事です。
この1ヶ月ほどサッカーのことばかり考えていたので、なかなか頭が切り替わっておりません。ここでもサッカーの話をさせてください。
サッカーの試合の詳細なデータを知ろうとするならば、情報はそこら中に落ちています。検索すれば試合に関する大抵の情報を得ることができるのですが、手に入るものはといえばビジュアライズに特化されているものがほとんどです。分析というほど高度なことをしないまでも、複数の試合に横串を通して、ちょっとした法則性のようなものを考える用途には向いていません。
どうせならデータを手元に置いて自由にクエリを投げたいなどと思い立ち、試みにローカルのRDBにデータを保存しはじめました。この記事では、私がワールドカップを楽しむために密かに用意していた、サッカーの大会・選手・試合に関するテーブル設計の一部を紹介します。
このテーブル設計は主にFIFAワールドカップカタール2022の試合・選手・スタッツに焦点を当てていいますが、今後のレギュラーシーズンや別の国際大会でも使えるように汎用的なものにしていきたいと思います。
大会前編
選手・チーム・国籍
まずは選手周辺から考えはじめました。
今回はクラブチームは無視して代表チームに限った話をしますが、クラブチームと代表チームの抽象としてteam
という概念を使いたかったので、クラブチームも一時的に登場させています。
国籍
世界では複数の国籍を持つ選手の存在が当たり前です。選手はある国のA代表(年齢制限のない代表チーム、いわゆる代表)として公式戦に出場するまでの間、複数の国の代表選手としてプレーすることが可能です。親善試合や世代別代表では別の国籍だった選手が、A代表を選択する際に最もアイデンティティを感じる(あるいはそうでない)国の代表選手となるケースも多いです。選手:代表チーム
はN:N
にしておきます。
世代別代表
ひとつの国でも、A代表の他に複数の世代別代表チームを組織しています。日本にも、U-15からU-23までの世代別代表チームがあります。各世代での国際舞台での経験はその選手の経歴を見る上で重要な情報であるため、世代別代表での出場歴は是非とも記録したいところです。オリンピックなどの世代別国際大会にも対応できるように、国:代表チーム
を1:N
としておきます。
国
イギリスは特殊なケースです。イギリスにはサッカー協会が4つあるので、countries
テーブルにはイングランド・スコットランド・ウェールズ・北アイルランドの4レコードを保存することになります。しかしオリンピックでは協会ごとに別れずに「イギリス代表」となります。ここでは世代別代表とA代表を区別する構造になっているので、4つのレコードに加えて「イギリス」も追加しても問題なさそうです。
大会
大会/Competition
大会はcompetitions
というテーブルで保存します。ここではワールドカップのようなトーナメント形式のみならず、リーグ戦やカップ戦など、すべての大会の抽象概念として扱います。代表チームは一つの大会に専念しますが、クラブチームは数々のコンペティションを並行して戦います。同時に複数の大会にエントリーできるような構造になっている必要があります。
背番号
出場チームとその登録選手のテーブルには、背番号などの大会ごとに確定する情報を保存してみます。
代表チームの背番号は、ワールドカップなどの国際大会においては固定されていますが、親善試合や強化試合では固定されていません。親善試合は1試合を1大会とみなし、competitions
テーブルにレコードを増やすことで対応できそうでうす。
また、クラブチームの背番号は、シーズン中(つまり大会中)にもまれに変更されることもあります。さらにシーズン途中の移籍マーケットで入れ替わりがあると、背番号も変動することになります。今回はワールドカップ限定のモデルなので考慮しませんでしたが、厳密にするならばもう少し工夫が必要そうです。
試合編
試合前の準備
いよいよ試合です。まずは試合開始前に判明している情報を考えていきます。
Phase
phase
という概念を用いました。これは、ワールドカップで言えば「グループステージMatch1」「準々決勝」「決勝」などのような、大会のフェーズを保存するテーブルです。レギュラーシーズンのリーグ戦ならば「第x節」のようなものが、カップ戦ならば「x回戦」のようなものが保存されます。
試合メンバー
出場チームは試合ごとにベンチ入りメンバーを確定するので、「試合メンバー」テーブルにそれを保存します。出場時間を計算しやすいように、出場開始/終了時間を記録します。出場開始minutesが0分になっているものをスタメンとみなします。
これだけだとアディショナルタイムでの交代に対応できません。前半45+2分と後半47分を区別する必要があります。また、後半アディショナルタイムに投入された選手の、その試合における出場時間は何分になるのか?という疑問も残ります。それを記録するにはアディショナルタイムが実際に何分行われたかまで記録する必要があります。細かすぎるので今回は省略しましたが、今の構造では表現しきれそうにありません。
試合中
一番おもしろいのがこの試合中のデータです。目まぐるしく変化するサッカーの試合では、テクノロジーの発達により膨大な量のデータ収集が可能となっています。残念ながらそのすべてを保存するのは、私1人の力ではどうにも骨が折れそうなので、今回は試合を見てなくても後から集められる情報のみを保存することにします。
MatchEvent
試合中に起こったことは、すべてをmatch_events
として抽象化します。イベントは、それが起こった時間だけを持っています。具体的なイベントは下記のようなものを定義しました。
- ゴール
- PK
- 交代
- イエローカード
- レッドカード
ゴール
サッカーの試合観戦のカタルシスは、ゴールシーンに集約されています。最も大切にしたいこのゴールイベントでは、得点を決めた選手IDの他に、得点したチームのIDを保存します。当初は得点を決めた選手のIDだけを保存していたのですが、不幸なオウンゴールを記録するためには得点したチームのIDも必要となることがわかりました。
PK
今大会でもPKがよく話題になりましたが、PKには試合の流れを変える力があります。成功した場合のみを記録するのであればゴールイベントと一緒に記録すれば十分ですが、どちらかといえば試合に大きな影響を与えるのは失敗したほうのPKです。ゴールイベントと密接に関わりますが、イベント同士がリレーションを持つような構造になってしまうのを本能的に避けてしまいました。イベント同士の整合性を保ついい考えが浮かんだら試してみたいと思います。
交代
広大なピッチで指揮官が意思表示をする方法として、声を張り上げる以上に重要な役割を果たすのが選手交代です。交代イベントもベンチ入りメンバーのところで定義した出場時間テーブルとの整合性を担保する必要はありますが、リレーションでそれを実現するのがどうにも難しそうなので諦めました。
試合後
試合後には、よくあるスタッツ表のようなものを保存したくなります。スコアやボール支配率、ファウル数、オフサイド数など、調べればすぐ出てくる程度のものだけをとりあえず保存しておきます。
得点やイエローカードなど、イベントと重複しているものもあります。しかしスタッツはただ表示するだけで集計にあまり使わないと思うので、非正規化しておいても特に問題ないと判断しました。
今回含めなかった要素
考え始めるとまだまだ盛り込みたい要素はたくさんあります。今回含めなかったけどいずれは考えたいものの一部を紹介します。
フォーメーション
フォーメーションだけをみて何かを判断する危険性は理解しつつも、机上で試合内容を想像する材料としては是非とも欲しい情報です。試合開始時点でのフォーメーションのみならず、試合中の変更、選手交代後の変更、退場者が出たあとの変更など、試合展開に応じて変化するフォーメーションを記録しておきたいところです。
監督
サッカーの試合をみるうえで、誰が采配を取っているのかはとても重要な要素です。国際大会の進行中に監督が交代することは滅多にありませんが、レギュラーシーズンでは監督交代は珍しいことではありません。
開催地・スタジアム
どのスタジアムで試合が行われたのか、というのが重要になる場合があります。日本代表もアウェイの地でのアジア予選は苦戦していますし、歴史と伝統を誇る世界的なビッグクラブはホームスタジアムで絶大な力を発揮します。
主審
望ましいことではありませんが、時には主審が主役になってしまう最悪の試合があります。過去にどの試合で笛を吹いたのか、カードを何枚出したのか、そういった情報を知っておくと、試合がより味わい深くなります。
総括
以上、かなり雑ではありましたが、大会丸ごと記録したいという目的へ一歩踏み出せたような気がします。もう少し丁寧に検討するべきところはたくさんありますし、ツッコミどころも満載かと思いますが、時間があれば一緒に考えていただければと思います。
考えるのはまずまず楽しかったのですが、これらのテーブルに実際のデータを入れるのはとても大変です。大会前にちまちまと設計したものの、ほとんど使うことはありませんでした。サッカーを観るときにデータ入力をしている余裕などありません。
最後に、この記事で扱ったものすべてを盛り込んだ図を載せておきます。
Discussion