馬吉の構成

始めにお断りしておきますが、私はJRA-VANの「馬吉」のプログラムの開発に関しては部外者であります。
又、JRA-VANより「馬吉」のプログラムに関しての資料を請求した事もございませんし、資料の提出を受けた事もありません。
知りえた内容は、JRA-VANから公開版をダウンロードした内容に記載されている事のみです。
従って、以下に記載されている内容については、多くの推測も含んでおりますし、誤った解釈をしている部分も多々あると思います。

もし、記載されている内容が間違っていたために発生したいかなる事態につきましても私は責任を取る事は出来ません。
又、私が記載している内容についてJRA-VANに問い合わせる事も、JRA-VANは無関係ですから御遠慮いただきたいと思います。
誤った記載をしている内容は、直接メールで私にご連絡いただければ修正を行いたいと思います。
私としては善意のつもりで解析内容を記載(公開)している事を御理解いただきたいと思います。

●馬吉の構成

馬吉のプログラムは、13のフォームと9の標準モジュールと86のクラスと26のユーザーコントロールなどで構成されています。
基本画面は、frmBrowserが全て受け持っており、画面に表示する内容はユーザーコントロールを取り付けたり外したりしながら行っています。
メニュー画面のようにリモコン的な画面やオッズ関係など一部の画面のみが別画面(ウィンドウ)で表示を行うようになっています。
ほとんどの動作はクラス化されており、しかもクラス内でも役割分担が細かに行われております。
各プログラムの流れは、個々のクラス内部で引き継ぐ形で行われており、全ての処理が終えた後にfrmBrowserに内容を表示するようになっています。
処理中は画面の中央にプログレスバーが表示されますので、処理が途中で滞っている場合には、ずっとこの状態が続くようです。
画面表示を高速に行うように、ゲームプログラム的に裏画面での切り替え表示なども行っており、機能の便利さと裏腹に動作状態のチェックを難しくしております。

次に具体的な解説を行います。
【 フォーム 】
(1)frmAbout
ヘルプの馬吉についての表示を行った時に表示を行います。
(2)frmBrowser
表示の中枢を担うフォームで表示の基本画面となります。
画面の解像度に合わせてスクロールバーの表示や形状の設定を行います。
(3)frmConfig
JV-LABからダウンロードするデータの種類や画面の表示色などの設定を行います。
(4)frmConfigFirst
セットアップ時に行うダウンロードデータの設定を行います。
(5)frmDBMaintenance
データベースの再構築の進行状態を表示する画面です。
(6)frmDBPrompt
速報データの取得状態を示す画面です。
(7)frmDBRAKaiSel
馬吉専用の出馬表データの作成の進捗状態を表示します。
(8)frmDBUpdate
JRA-VANからのデータの取り込みデータの進捗状態の表示を行います。
(9)frmDirRef
データベースのフォルダの設定を行う画面です。
(10)frmMenu
馬吉の別画面での小型のメニュー画面です。
(11)frmNewFolder
データベースのフォルダ名を入力する画面です。
(12)frmSplash
起動時に表示するスプラッシュ画面です。
(13)frmWrappedJVLink
JV-LINKと接続状態を確認するための隠しフォームです。

【 標準モジュール 】
(1)basAPI
馬吉で使用するAPIを記載しております。
マウスの座標位置を調べたり、ini 関係のAPIやヘルプ表示関係のAPIが記載されています。
(2)basEnum
プログラムの動作モードが記載されています。 (3)basFlexgrid
フレックスグリッド(FlexGrid)の処理が記載されています。
(4)basIni
iniファイルの登録と読み込み処理が記載されています。
(5)basMain
プログラムの主要なコントロール処理が記載されております。
起動時はこのプログラムのMainから動作を開始います。
主な内容は多くのプログラムで使用するものやエラーが発生した場合のエラー内容の表示です。
(6)basReg
レジストリの書き込み、読み込み処理を行います。
(7)basSetDataFromByte
JRA-VANから取り込んだ内容(バッファ内容)の中身を細分化しております。
各レコードセット毎に用意されており、その中の個別なデータ内容を知る事ができるようにしています。
(8)basSetDataFromRS
データベースから取り込んだ内容(バッファ内容)の中身を細分化しております。
(9)JVLink_Stluct
JV-Linkから取り込んだ内容を構造体化しています。
例えば年月日をまとめたい場合は、個別に取り出してプログラム内で合成しなくてもYMDだけで得る事ができるようになります。

【 クラス 】
(1)clsApp
主要なアプリケーションクラスです。
ほとんどのプログラムはこのクラスを利用しております。
gApp.で記載されている部分は、このクラスで処理されています。
(2)clsCodeConverter
JRA-VANから提供されているデータのコードを実際の名称に変更するクラスです。
例えば競馬場コードの01をこのクラスに問い合わせる事で、札幌競馬場の名称を得る事ができます。
コード変換には数種類があって、競馬場コード01の場合を例にすると、札幌競馬場や札、札幌、SAPPOROなどから選択する事ができます。
コード化されている内容は数多くあり、コース(芝、ダート)や天候、馬場状態、曜日、レースグレード、牝馬と牡馬などその他にも多くあります。
(3)clsCreateMDB
データベース(Access)を構築する場合のテーブル内容やインデックス(Index)の設定を行います。
一部のコマンド(COMPRESSIONなど)は、データベースによっては使えないようです。
(4)clsDatabaseMgr
データベース関係全体の処理を行います。
「馬吉」の場合はデータベースを細分化して49ファイルを同時に扱っておりますから統合処理をするプログラムが必要となります。
(5)clsDataBN
馬主関係のデータをデータベースから読み込んで表示します。
(6)clsDataBR
生産者関係のデータをデータベースから読み込んで表示します。
(7)clsDataCH
調教師係のデータをデータベースから読み込んで表示します。
(8)clsDataFind
検索関係の処理を行います。
(9)clsDataHCSel
坂路調教関係のデータをデータベースから読み込んで表示します。
(10)clsDataHK
変更データ関係のデータをデータベースから読み込んで表示します。
(11)clsDataHN
繁殖馬関係のデータをデータベースから読み込んで表示します。
(12)clsDataKS
騎手関係のデータをデータベースから読み込んで表示します。
(13)clsDataOD
オッズ関係のデータをデータベースから読み込んで表示します。
(14)clsDataRA
レース関係(RACE、UMA_RACE)のデータをデータベースから読み込んで表示します。
(15)clsDataRaceChanger
タイトル画面のレース表示関係(コンボボックス内)の処理を行います。
(16)clsDataRAKaiSel
出馬表関係のデータをデータベースから読み込んで表示します。
このデータは「馬吉」独特のもので一般的なデータベース作成ソフトにはありません。
(17)clsDataRASel
出馬表で選択した内容を一日の開催レース内容(通常は2,3開催地の各12レース)にして表示します。
(18)clsDataRC
レコード(最高記録)のデータをデータベースから読み込んで表示します。
(19)clsDataRCSel
レコードのデータを更に細分化して表示します。
(20)clsDataSK
産駒関係のデータをデータベースから読み込んで表示します。
(21)clsDataTK
特別登録馬(出走予定馬)関係のデータをデータベースから読み込んで表示します。
(22)clsDataTKKaiSel
特別登録馬のデータを更に細分化して表示します。
(23)clsDataUM
競走馬関係のデータをデータベースから読み込んで表示します。
(24)clsGridData
フレックスグリッド(FlexGrid)の表示関係の処理を行います。
(25)clsGridItem
フレックスグリッド(FlexGrid)のアイテム関係の処理を行います。
(26)clsH1Iterator
3連単以外の票数の表示処理を行います。
(27)clsHistoryItem
履歴アイテムの表示処理を行います。
(28)clsHistoryMgr
履歴関係の表示処理を行います。
(29)clsIImport
JRA-VANからのデータの登録、変更、削除関係の共通項目の作成に使用したと思われます。
現在は必要のないものです。
単に削除するとプログラムのコンパイル時にエラーが出ますので、各プログラムに記載の Implements clsIImport を削除する必要があります。
(30)clsImportAV
出走取り消し馬や発走除外馬関係の処理を行います。
(31)clsImportBN
JRA-VANから馬主関係のデータベースの登録、追加、変更、削除を行います。
(32)clsImportBR
JRA-VANから生産者関係のデータベースの登録、追加、変更、削除を行います。
(33)clsImportCC
JRA-VANからコース変更関係のデータベースの登録、追加、変更、削除を行います。
(34)clsImportCH
JRA-VANから調教師関係のデータベースの登録、追加、変更、削除を行います。
(35)clsImportDM
JRA-VANからデータマイニング関係のデータベースの登録、追加、変更、削除を行います。
(36)clsImportH1
JRA-VANから3連単以外の票数関係のデータベースの登録、追加、変更、削除を行います。
(37)clsImportHC
JRA-VANから坂路調教関係のデータベースの登録、追加、変更、削除を行います。
(38)clsImportHN
JRA-VANから繁殖馬関係のデータベースの登録、追加、変更、削除を行います。
(39)clsImportHR
JRA-VANから配当関係のデータベースの登録、追加、変更、削除を行います。
(40)clsImportJC
JRA-VANから騎手変更関係のデータベースの登録、追加、変更、削除を行います。
(41)clsImportKS
JRA-VANから騎手関係のデータベースの登録、追加、変更、削除を行います。
(42)clsImportO1
JRA-VANから単勝、複勝、枠連オッズ関係のデータベースの登録、追加、変更、削除を行います。
(43)clsImportO2
JRA-VANから馬連オッズ関係のデータベースの登録、追加、変更、削除を行います。
(44)clsImportO3
JRA-VANからワイドオッズ関係のデータベースの登録、追加、変更、削除を行います。
(45)clsImportO4
JRA-VANから馬単オッズ関係のデータベースの登録、追加、変更、削除を行います。
(46)clsImportO5
JRA-VANから3連複オッズ関係のデータベースの登録、追加、変更、削除を行います。
(47)clsImportODDS
JRA-VANからのオッズ票数をデータベースではなくファイルに書き出す処理を行います。
(48)clsImportRA
JRA-VANからレース関係のデータベースの登録、追加、変更、削除を行います。
(49)clsImportRC
JRA-VANからレコード(最高記録)関係のデータベースの登録、追加、変更、削除を行います。
(50)clsImportSE
JRA-VANから馬毎レース関係のデータベースの登録、追加、変更、削除を行います。
(51)clsImportSK
JRA-VANから産駒関係のデータベースの登録、追加、変更、削除を行います。
(52)clsImportTC
JRA-VANから発走変更関係のデータベースの登録、追加、変更、削除を行います。
(53)clsImportTK
JRA-VANから特別登録馬(出走予定馬)関係のデータベースの登録、追加、変更、削除を行います。
(54)clsImportUM
JRA-VANから競走馬関係のデータベースの登録、追加、変更、削除を行います。
(55)clsImportWE
JRA-VANから天候・馬場状態のデータベースの登録、追加、変更、削除を行います。
(56)clsImportWH
JRA-VANから馬体重情報のデータベースの登録、追加、変更、削除を行います。
(57)clsImportYS
JRA-VANからレーススケジュールのデータベースの登録、追加、変更、削除を行います。
(58)clsIterator
日付の処理関係を行います。
(59)clsIViewerState
ビューアの共通処理に使用していた残骸と思われます。
現在は使用しておりませんが、単純に削除するとコンパイルエラーになります。
(60)clsKeyBN
馬主関係の各種検索キーの取得するために使用します。
(61)clsKeyBR
生産者関係の各種検索キーの取得するために使用します。
(62)clsKeyCH
調教師関係の各種検索キーの取得するために使用します。
(63)clsKeyHCSel
坂路調教関係の各種検索キーの取得するために使用します。
(64)clsKeyHN
繁殖馬関係の各種検索キーの取得するために使用します。
(65)clsKeyKS
騎手関係の各種検索キーの取得するために使用します。
(66)clsKeyRA
レース(RACE、UMA_RACE)関係の各種検索キーの取得するために使用します。
(67)clsKeyRAKaiSel
開催選択関係の各種検索キーの取得するために使用します。
開催選択データは「馬吉」が独自に作成したものです。
(68)clsKeyRC
レコード(最高記録)関係の各種検索キーの取得するために使用します。
(69)clsKeyRCSel
レコード(最高記録)のタイトル関係の各種検索キーの取得するために使用します。
(70)clsKeySK
産駒関係の各種検索キーの取得するために使用します。
(71)clsKeyUM
競走馬関係の各種検索キーの取得するために使用します。
(72)clsMSFlexData
フレックスグリッド(FrexGrid)の表示設定に使用します。
(73)clsKeySK
産駒関係の各種検索キーの取得するために使用します。
(74)clsPointer
マウスポインター(マウスの表示形状)の切り替えに使用します。
(75)clsRCSearch
レコード(最高記録)の検索キーの取得に使用します。
(76)clsStringConverter
コード化されているデータを所定の文字列に変換します。
年月日などを所定のファーマットに切換える等もしております。
(77)clsViewerBase
プログラム開発時にビューア関係の共通項目の設定に使用していたと思われます。
現在もコードが記載されておりますが、このクラスへの直接のアクセス無いと思います。(未確認)
(78)clsVSDate
日付をブラウザに表示するために使用しています。
(79)clsVSDateJyo
日付と場所(競馬場)をブラウザに表示するために使用しています。
(80)clsVSFind
検索コード(検索文字)モード(検索内容)を得るために使用しています。
(81)clsVSNothing
詳しくは確認していませんが、使用していない(不必要)と思います。
(82)clsVSOdds
オッズをブラウザ画面に表示するために使用します。
(83)clsVSTabOnly
フレックスグリッド(FlexGrid)のタブ情報の取得に使用しています。
(84)clsVSYearJyo
日付と場所(競馬場)の情報取得に使用するようですが、(79)とどちらがどのように違うのかは現在未確認です。

【 ユーザーコントロール 】
「馬吉」は数多くのユーザーコントロールを持っております。
共通に使用する事の多い部分をユーザーコントロール化にしているのですが、なぜ基本画面(ブラウザ)に組み込んで表示をON、OFFにしていないのかは不明です。
プログラムの作成スタイルなのかも知れませんし、このプログラムの作成に何か特別なツールを使用したのかも判りません。

作成されているユーザーコントロールの大部分は、基本画面(frmBrowser)に貼り付けたり、外したりするものです。
その処理のために、基本画面とのやり取りのプログラムが必要になります。
その点で、このプログラムではユーザーコントロールは非常に重要な役割を担っており、メイン画面をアクセスして特定の処理を行わせる場合には、最初にユーザーコントロールが呼ばれます。
呼ばれるユーザーコントロールは、ctlV** のように頭の4文字に ctrV がついております。
例えば、ctrVRA が呼ばれた場合には RA はレース記号を表しておりますので、データベースの RACE、UMA_RACE を表示させるために使用する事が判ります。
CH なら調教師、KS なら騎手関係であるのは、DAta-Lab のプログラムを開発している人なら説明する迄も無いでしょう。

ちなみに、メニュー画面(HOME)が起動時に表示されますが、これも最初に ctlVHome が呼ばれているからです。
そこから出馬表を選択した場合は、開催一覧(ctlVRAKaiSel)が呼ばれ、そこから選択すると次に出馬表選択画面(ctlVRASel)が呼ばれ、最後に ctlVRA が呼ばれて出馬表が表示されます。
画面の処理の流れは比較的単純ですが、実際の処理を行うのはクラスモジュールですから、クラスモジュールの処理内容は把握しておく必要があります。

個々のユーザコントロールの処理の内容は、前述したようにファイル名で推察する事ができますし、コードの中にも詳しく解説されておりますので省略します。
ユーザーコントロールの中には、例えば ctlTitleBand のようにコンボボックス(ComboBox)を2個表示するだけのコントロールなども含まれております。
これらは、単にコンボボックスをユーザーコントロール化しただけと考えれば良いと思います。
コンボボックスをわざわざユーザーコントロール化しているのは、開発ツール使用の匂いを感じるのですが気のせいでしょうか。

●プログラムの流れ

「馬吉」のプログラムを起動した場合にどのような流れ(経路)に沿って動作するのかを説明します。
これを把握していないとプログラムの改造は出来ません。
起動時にどの部分から起動させるかの設定は、プロジェクトのプロパティに記載されています。
「馬吉」の場合は、Sub Main と記載されておりますので、標準モジュールの basMain のPublic Sub Main() のコードから全てが始まる事になります。

そこには、JRA-VANとの接続に使用する接続コード(SID)やスプラッシュウィンドウ(起動時にバージョンやプログラム名を一瞬表示させる飾り画面)の起動などが記載されています。
細かい動作を記載しても頭が混乱するだけですので、ここでは主要な点だけを述べたいと思います。
まず、Set gApp = New clsApp、Set gCC = New clsCodeConverter、Set gSC = New clsStringConverter の記載は重要です。
これは、例えばプログラムの中に gAPP.***** と記入されていた場合には、クラスモジュール clsApp の ***** に動作コード(プログラム)が記載されている事を表しています。
こんな回りくどい事をしないで、直接コードをなぜ記載しないのかと思われると思いますが、少なくとも2名以上でプログラムを開発する場合にはプログラムの見通しが良くなる事や変更が楽な点で重要な事だと思います。
欠点としては、プログラムの設計書が無いとどのような処理を行っているのかいちいち調べなければならない点です。
それと動作上では、回り道をする分遅くなる点とメモリーを多く消費しますので環境によっては不安定になりやすい事です。
私のパソコンは4GBのメモリーを搭載しておりますが、テスト中にスタック領域が不足していますなどとエラーが出たりしました。

クラスモジュールの clsApp には共通で使用する事の多いコードが記載されておりますし、clsCodeConverter、clsStringConverter はコードで提供されているデータを実際の名前に変更するために重要なものですから、一度は全てに目を通しておくべきだと思います。
起動直後は、gApp.start と記載されておりますので、クラスモジュールの clsApp の start から動作が開始する事が判ります。

早速クラスモジュール clsApp の Public Sub start() に書いてあるコードを見ると、主要動作の部分には Call mBM.NewBrowser(gApp.R_HomeViewer, gApp.R_HomeKey) などと書いてあります。
これはなんだと言う感じで、根気の無い人はここで挫折してしまいそうです。
まず mBM. とは何かですが、このクラスモジュール clsApp の上部を見ると Private mBM As clsBrowserMgr の記載があることが判ります。
つまりは、mBM.NewBrowser とは このプログラムの内容は クラスモジュール clsBrowserMgr の NewBrowser にコードが記載されておりますよと言う事です。
普通に根気のある人で、なんとか踏み留まれた人もこんなにあちこちを行ったり来たりするのではとても無理だと思って脱落してしまうでしょう。
プログラム作成に必要なのは才能では無くて(中には才能を必要とするものもあるでしょうが)、人並み以上に根気が必要だと言う事です。

このように辿っていけば行けば起動時からの動作は全て理解できるのですが、判らない事があると直ぐに他人に聞きたがる人のために大まかな動作を記載しておきます。
起動時にはメニュー画面が表示されるのですが、このプログラムはメニュー画面をホーム(HOME)と呼んでいるようです。
実は起動時には、必ずしもホームを表示させるようにはなっていなくて、レジストリに起動時に立ち上げる画面が記載されており(初期設定はHOME)そこに記載されている内容の画面を表示させる事が出来ます。
推定ですが、起動時のメニュー画面を英語版なども用意をしておいて切り替えて使うのかなとも思ったりします。

ところで起動時の HOME とは何を示すのかですが、画面表示はユーザーコントロールで作成した画面を言います。
つまりは、HOME 画面を呼び出すと言う事は、ユーザーコントロールの ctlVHome を立ち上げる事に他なりません。
基本画面(frmBrowser)に色々な画面表示させるには、必ず ctlV のついたユーザーコントロールが必要となるのです。
これさえ理解出来れば、正常に動作しない場合にどこにトラップ(一時停止)をかければ良いのかが判明しますので、プログラムの開発(「馬吉」の改造)は格段に進歩する事になります。
とは言いましても、前述したようにプログラム開発は才能では無くて根気ですから、忍耐力のない人には無理でしょう。
このような人はプログラム開発だけでなく何をやっても満足な仕事は出来ないと思います。
年のせいかついつい余計な事まで書いてしまいます。

●メニュー画面

メニュー画面(HOME)を最初からいじる人は居ないと思います。
そこでメニュー画面の項目をクリックした場合に最初にどこにアクセスするかだけを記載しておきます。
レース情報をクリックした場合には以下のようになります。
(1)出馬表
ユーザーコントロールの ctlVRAKaiSel を最初に呼び出します。
このコントロールは開催一覧表を表示させます。
そこからレースを選択すると次に ctlVRASel に進みます。
これが青いバックカラーの出馬表選択画面になります。
そこからレースを選択すると、ctlVRA が呼ばれそこからクラスモジュールの clsDataRA に接続してデータベースの RACE や UMA_RACE の内容を画面に表示します。

出馬表の表示の流れをもう少し詳しく説明しますと、他もほとんど共通なのですが ctlVRAKaiSel の update から Call mData.Fetch(mKey) によって、clsDataRA の Fetch が最初に呼び出されます。
(update は、ctlVRASel が mKey を設定すると呼び出されます。)
Fetchのコードを見ると、最後にmAsyncCN_UMA_RACE_A.Execute strSQL, , adAsyncExecute の記載があることが確認できます。
これが何を意味するかと言いますと、プログラムの冒頭に Private WithEvents mAsyncCN_UMA_RACE_A As ADODB.Connection の記載があるのが味噌になっていてイベント処理が行われようになっています。
この記載によって、サブルーチンの mAsyncCN_UMA_RACE_A_ExecuteComplete が呼び出されて、そこの処理するプログラムが順番に記載されていると言う仕組みです。
Fwtch→mAsyncCN_UMA_RACE_A_ExecuteCompleteの動作で、一連のプログラム(clsDataRA)が終了するようになっています。
プログラム構成の流れを掴んでしまえば、ほとんど共通になっておりますので理解できるのですが、初めてこのプログラムを見た時は私にはさっぱり流れを掴み取れませんでした。
やはり独特のプログラムの作成方法で、プロのプログラマーはこのような書き方をするのが普通なのでしょうか。

実際の処理は、タイマーによる裏動作の実行などもあって単純な流れではありませんが、この流れが理解できれば新しい項目を追加したり削除したりする事が出来るようになります。
SQLite では、「馬吉」で記載されているプログラムコードでは動かない部分が多かったのですが、MySQL ならそのままでも動くのではないでしょうか。
(2)特別登録馬
ユーザーコントロールの ctlVTKKaiSel を最初に呼び出します。
そこから、クラスモジュールの clsDataTKKaiSel に接続してデータベースの内容を画面に表示します。
(3)コースレコード
ユーザーコントロールの ctlVRCSel を最初に呼び出します。
そこから、クラスモジュールの clsDataRCSel に接続してデータベースの内容を画面に表示します。
(4)坂路調教
ユーザーコントロールの ctlVHCSel を最初に呼び出します。
そこから、クラスモジュールの clsDataHCSel に接続してデータベースの内容を画面に表示します。

メニューのマスター情報は全てが検索となります。
そこで、ユーザーコントロールの ctlVFind が最初に呼ばれます。
そこから検索内容に従って、例えば競走馬を選択した場合は clsDataUM が呼ばれて画面に表示されます。
データベースからデータを呼び出して画面に表示させる場合は、クラスモジュールの先頭には clsData となりますので判りやすいと思います。
その他に使用するクラスモジュールとしては、clsKey** でこれはデータ別に用意されています。
このクラスモジュールは、主に検索キーやアクセスキーの内容を問い合わせるだけのために使用されます。
共通に使われる事の多い他のクラスモジュールとして、clsApp、clsCodeConverter、clsStringConverter が必要なのは言うまでもありません。
標準モジュールの basMain に記載の内容も色々な場所で頻繁に使用されております。

今回はデータベースをマイクロソフトのアクセス(Access)から SQLite に変更しようとしたのですが、「馬吉」はアクセスでの使用に最適化されており、遅いと言われるアクセスにしては高速に動作しているようです。
アクセス専用のコマンド(関数)が数多く使われているおり SQLite ではそのままでは動作しない部分が多いようです。
現在でも、「馬吉」と比較すると処理が遅かったり、場合によっては固まったりしてしまいますので、全てが「馬吉」と同じ動作をさせるためには時間が掛かりそうです。
本来の目的は「馬吉」の改造ではなくてデータベースの動作確認ですので、時間が掛かるようなら機能を絞り込もうと考えております。

●データベースに取込まないデータ

「馬吉」はファイルの分散化によってアクセス(Access)の容量の壁を取り払っております。
この手法を用いれば、どんなデータでもデータベース化が出来るはずです。
しかし、「馬吉」はデータベースに取り込まないで、通常のファイルにしているデータがあります。
それは、3連単のオッズデータと票数データの全てです。
なぜ、データベース化にしていないのかは定かではありませんが、オッズデータも票数データも膨大なデータ量であることと検索対象にはなりにくい事は確かなので、その辺の関係があるのかも知れません。
いつパンクするか判らないデータは単純にファイル化しておいた方が安心だと言う考え方なのかも知れません。

私が迷ったのは、SQLite は折角単一構造のデータベースなので、「馬吉」のようにファイルを分散したのでは使い勝手を悪くしてしまうのではないかと考えたからです。
それではデータベースに取り込めば良いだろうと言う事になりますが、過去のオッズデータや票数データなどはめったに見る事が無いのに、膨大なデータベースの領域を占領してアクセス速度の低下を招くからです。
「馬吉」のように個別にファイル化するかどうかは兎も角として、同じデータベースに取り込むのだけは避けようと思いました。
JRA-VAN ソフトのターゲットでは、データベースを使用しないで個別にデータファイルを作成しています。
以前の私のソフトでは、ターゲットとファイル名やデータ構造の互換性取りながら時系列の速報データなどを作成しておりましたから、今回もそれにする事にしました。
こんな事をやっていては、いつまでたってもターゲットとのしがらみは残りますが、圧倒的なユーザー数の多いターゲットですから何らかのメリットもあるでしょう。
以下は「馬吉」の票数データと3連単のオッズ内容の読み取りのコードです。
ファイル名やファイルの構造が判ると思います。(単純にファイル化しているのを読み込むだけです。)

' ' 機能: DBからH1レコードを取得する ' ' 備考: H1のデータ取得は、この関数を用いて行う ' Public Function GetH1(Key As String) As String On Error GoTo Errorhandler Dim intFileNum As Integer Dim Year As String Dim MonthDay As String Dim JyoRace As String Dim Path As String Dim filename As String Dim buf As String Year = Mid$(Key, 1, 4) MonthDay = Mid$(Key, 5, 4) JyoRace = Mid$(Key, 9, 2) & Mid$(Key, 15, 2) Path = gApp.R_DBPath & "\ODDS\H1" & Year filename = Year & MonthDay & JyoRace intFileNum = FreeFile If Dir(Path & "\" & filename) <> "" Then Open Path & "\" & filename For Binary Access Read As intFileNum buf = String$(65535, " ") Get #intFileNum, , buf Close intFileNum GetH1 = buf End If Exit Function Errorhandler: gApp.ErrLog End Function ' ' 機能: DBからO6レコードを取得する ' ' 備考: O6のデータ取得は、この関数を用いて行う ' Public Function GetO6(Key As String) As String On Error GoTo Errorhandler Dim intFileNum As Integer Dim Year As String Dim MonthDay As String Dim JyoRace As String Dim Path As String Dim filename As String Dim buf As String Year = Mid$(Key, 1, 4) MonthDay = Mid$(Key, 5, 4) JyoRace = Mid$(Key, 9, 2) & Mid$(Key, 15, 2) Path = gApp.R_DBPath & "\ODDS\O6" & Year filename = Year & MonthDay & JyoRace intFileNum = FreeFile If Dir(Path & "\" & filename) <> "" Then Open Path & "\" & filename For Binary Access Read As intFileNum buf = String$(83285, " ") Get #intFileNum, , buf Close intFileNum GetO6 = buf End If Exit Function Errorhandler: gApp.ErrLog End Function

ファイルを読み込む前に buf = String$(83285, " ") している点が少し変わっています。
バッファ領域を最大分確保してから読み込むとメモリー領域が固定されてアクセスの点で有利になるのでしょうか。

●過去レース数の表示

「馬吉」には出馬表の表示画面の中に過去走のタブがあって過去走を表示する事が出来ます。
その過去走の表示画面の中で表示数を設定する事が出来ます。
私が初めてこの機能を見た時に感じた事はなんだこの機能はと言うものでした。
過去走の表示は少なければ意味が無いでしょうし、かと言って30走も50走も表示する必要も無いでしょう。
恐らく適性な表示は10走前後だと思います。
なぜ固定にしなかったのかと思ったのですが、次の理由が考えられると思います。
(1)目新しい機能と思っている。
単純に面白いだろうと思ってつけた。
競馬をあまり理解していなかったので、1〜99走まで切り替えられると面白いのではないかと思ってつけた。
(2)処理速度の関係で切り替える必要があった。
過去走の表示は表示項目も多いだけに処理が重いです。
表示数を10走まで表示させると時間がかかり過ぎるので切り替える必要があった。
つまり、過去走の表示を重要と思わない人は表示数を少なくして速度優先にし、そうでない人は待ち時間が多くなるが我慢してもらう。

私は競走馬の過去走が100走にもなる馬はいないと思っているので、競馬のプログラマーが面白半分に作成したのではないかと考えている。
ただ、処理速度の件は全く考慮していないのかと言われると自信は無い。
「馬吉」の場合は標準の過去走を5レースにしているのだが、私は5レースでは少ない気がしたので10レース固定にして切り替え機能はつけないようにしようと考えていたのだが、単純に機能を削ると出来ないから削ったのだろうと言われかねないので無駄だと思ったがそのまま残す事にしました。
基本表示数を10レースにして、従来のように1レースから99レースまで設定する事ができる。
この処理に関する「馬吉」のコードは以下の通りになっている。

切り替えはユーザーコントロールの ctlVRA で制御しておりコードは以下の通りである。

' ' 機能: 条件別データ取得完了通知イベント ' ' 備考: なし ' Private Sub mData_FetchedJokenBetu(GridData As clsGridData) On Error GoTo ErrorHandler gApp.Log "Fetch JokenBetu" Call flexTab(4).InsertGrid(GridData) Call flexTab(4).AutoSize(0, flexTab(4).Grid.Cols - 1, False, False, 1) ' 条件別グリッド With flexTab(4).Grid flexTab(4).Grid.TextMatrix(0, 0) = " " flexTab(4).Grid.TextMatrix(0, 1) = " " flexTab(4).Grid.TextMatrix(0, 2) = " " .MergeRow(0) = True .MergeCells = flexMergeFree .FixedCols = 0 .FixedRows = 2 End With paneTab(4).Mode = 2 mstTab.TabEnabled(4) = True Exit Sub ErrorHandler: gApp.ErrLog End Sub

切り替えはタイマー(tmrKako)で行っています。
そのコードは以下の通りです。

' ' 機能: 過去n走の表示は、nの切り替え毎に裏の取得を中止し、新しい値での取得をします。 ' ' 備考: なし ' Private Sub tmrKako_Timer() On Error GoTo ErrorHandler Call mData.CancelKakoFetching If Not mData.NowKakoFetching Then tmrKako.Enabled = False mData.FetchKako End If Exit Sub ErrorHandler: gApp.ErrLog End Sub

過去走のレース数はレジストリーに記載されており、clsApp に以下の記載があります。

' ' 機能: レジストリから、表示過去走数の値を取り出す ' ' 備考: なし ' Public Property Get R_KakoNum() As Long Dim lngOut As Long If mblnKakoNum = False Then lngOut = CLng(LoadRegSub("ViewerState", "KakoNum", "5")) mlngKakoNum = lngOut mblnKakoNum = True Else lngOut = mlngKakoNum End If R_KakoNum = lngOut End Property

競馬プログラムで、過去走の表示にここまで凝る人は余りいないと思います。

●「馬吉」のリンク方法

「馬吉」ではデータにリンクが張られている場合は、フレックスグリッド(FlexGread)をクリックするとそのデータへリンクします。
これはどういう方法で行っているかと言うと、ユーザーコントロールの中に flexTab_Click があってそこで判定しています。
流れは以下の通りです。
(1)マウスの座標を得る。
クリックしたグリッド内のマウスのx、y座標を取得します。
(2)リンクコードを取り出す。
フレックスグリッドのリンクネームとコードを取り出します。
リンクネームは、RA(RACE)とか KS(KISYU) とか2文字で、コードはレースであれば開催年月日や場所、レース名などですし、騎手であれば騎手コードになります。
リンクネームがどのような意味があるのかと言うと、ユーザーコントロールの呼び出し名として使われております。
つまり、ctlVTKKaiSel を呼び出したければ、リンクネームは TKKaiSel になります。
ctlV の部分は、プログラム内で補っているのです。
これは判り難いですよね〜。
リンクコードを呼び出すサブルーチンは SetItem になります。
(3)ChangeTo イベントを発行します。
ブラウザ(frmBrowser)にChangeTo コマンドを発行します。
ブラウザは、GoToNextViewer をコールして画面が切り替わります。
更に詳しく言えば、GoToNextViewerの中からChangeViewerを呼び出したりして少々ごちゃごちゃしています。
データが無かった場合は、前の画面に戻るのではなくていきなりメニュー画面に戻ってしまいます。

「馬吉」のバグなのか「馬吉」公開版のバグだと思っているのですが、レコードマスター(RECORD)の TokuNum_SyubetuCD に「馬吉」は6文字割り当てております。
供給されるデータは4文字なので2文字余るのですが、大は小を兼ねなくて結構プログラム内で悪さをしています。
「馬吉」の場合は6文字に合わせるようにしてプログラムを組んでおりますので正常に動くのですが、移植を行う場合は正規の4文字にするとレコードマスターはまともには動きません。
この部分はテーブル名も一般的なものではありませんし、私も悩まされましたが、これに嵌ってしまった人は多いのではないかと思います。
移植をされる方はくれぐれもご注意ください。
自分が苦労したので教えたくは無いのですが、修正する箇所は clsKeyRC 内だけですから簡単な事です。
【後記】
TokuNum_SyubetuCDの件に関しては、「馬吉」では、TokuNum と SyubetuCD のテーブルをまとめて1つにしていると考えるのが良いようです。
なぜこのようにしているのかは判りません。

●どのデータが容量を必要とするか

データベースを SQLite に変更して使い込んでくると、逆にマイクロソフトアクセス(Access)の良さを再認識する事になります。
特に感じるのが、適切なインデックスを作成した時のアクセスの検索速度の速さです。
競馬でデータベースを作成した時は、レースデータの他に騎手データや調教師データ、競走馬データなど様々なデータを同時に開かなければなりませんので、検索速度が遅いのは致命的になります。
SQLite の検索も非常に高速ですが、検索時は大量のメモリーを消費するらしく、OSの動作にも影響を与えるようです。
一言で言えば、SQLite は利用できるメモリーは徹底的に利用すると言った感じでしょうか。
この点が、アクセスやMySQL などとはかなり異なっているように思います。
この仕様は私には不都合に感じる事の方が多いので、何とかして欲しいです。

それと、データの中身を簡単に確認できるのもアクセスの最大の利点です。
データ量が100万件あっても、見るまでに多少の時間はかかりますがデータの中身は確認できます。
これがSQLite だと、フリーのGUIソフトも色々ありますが、表示までに気が遠くなるような時間が掛かったり、途中でハングアップしてしまいます。
もし、アクセスにファイル容量の壁がなかったなら、まだまだ使い続けれれるデータベースです。
マイクロソフトでは後継のSQLサーバーの使用を推奨しておりますから、このデータベースには期待が持てます。
私は、SQLサーバーの有料版も所持しておりますので、実験はいつでも出来るのですが、これがどんなに優れたデータベースだったとしても、データベースが有料故に使ってくれる人は限定されるでしょう。
月々2000円弱のJRA-VANのDataLabの使用でさえも、お金が勿体ないと考えている人がわんさと居るのです。
人生は金儲け(お金を貯める事)だと考えている人が何と多いことでしょうか。

お金は大切ですが、適切に使われてこそお金の価値が活きてくるのであって、棺おけの中にお金を入れたまま死んでしまうのでは喜ぶのは子孫だけです。
それでも子孫がりっぱな人間に成長してくれるのなら良いですが、大抵は金持ちの道楽息子と呼ばれるような、社会のゴミみたいな存在になる人が多いようです。
やたらお金を残して死ぬと争いの種になる事も多いうようですし、生きている間も命を狙われる事さえあります。
ところで、お金を儲けたいだけの人はギャンブルには向いていないと思っているのは私だけでしょうか。
私の場合は、欲を出して買った馬券よりも、無欲で買った馬券の方がなぜか的中するようです。
ついつい、くだらない話を書いてしまいました。

「馬吉」では、アクセスの容量の壁に対処するために、データベースを分散させている事は以前にも書きました。
ここでは、その「馬吉」でデータベースを構築した場合に、そのデータが容量を必要とするのかを調べたいと思います。
西暦2001年からのデータを現在(2009年12月)まで蓄積した場合の容量を大きい順に記載します。
(1)subHANRO.mdb(坂路データ 3,703,534件)579MB
(2)subUMA.mdb (競走馬データ 130,828件)543MB
(3)subUMA_RACE_A.mdb (馬毎レースデータ 分割A 755,841件)538MB
(4)subUMA_RACE_B.mdb (馬毎レースデータ 分割B 755,842件)529MB
(5)subRACE.mdb(レースデータ 62,780件)248MB
(6)subODDS_WIDE.mdb(ワイドオッズデータ 30,457件)151MB
(7)subSANKU.mdb(産駒データ 302,822件)119MB
(8)subODDS_UMAREN.mdb(馬連オッズデータ 30,457件)81MB
(9)subHARAI.mdb(配当データ 30,845件)61.3MB
(10)subODDS_SANREN5.mdb(3連複オッズ分割5 3,645件)54.4MB
(11)subODDS_SANREN4.mdb(3連複オッズ分割4 3,276件)54.4MB

以下は主要データのみ
subBANUSI.mdb(馬主データ 6515件)7.94MB
subCHOKYO.mdb(調教師データ 1,209件)2.83MB
subCHOKYO_SEISEKI.mdb(調教師成績データ 3,627件)14.3MB
subHANSYOKU.mdb(繁殖馬データ 129,463件)76.0MB
subKISHU.mdb(騎手データ 1,223件)5.28MB
subKISHU_SEISEKI.mdb(騎手成績データ 3,669件)14.5MB
subODDS_TANPUKUWAKU.mdb(オッズ単複枠データ 30,859件)28.5MB

容量の必要なデータのトップは、坂路調教データで連日多くの馬が調教を行っておりますから、必然的に多くなります。
それでも、実際に坂路データの無い競走馬も多く、何度も書いておりますが、このデータ程当てにならない無駄なデータは無いと私は感じております。
他のサイトを見ても、同様の考えを持つ人が大部分で、調教のタイムや回数を比較する事と競争結果とが結びつくことは極めて稀であると言えます。
調教データの記載の無い馬が、大楽勝で勝つのを見ていると、特にその感を強く持ちます。
調教状態は、今のような単純なタイムデータの取り方ではなく、全体的な要素を取り入れる必要があるのでしょうが、無理でしょう。
坂路データは、競馬予想には悪影響を与える場合の方が多いと言う事だけは述べておきます。

最大の容量を必要とするのは、馬毎レースデータ(UMA_RACE)で、「馬吉」はこのデータを2分割する事によってファイルの容量の増大を防いでおります。
それでも1ファイルが530MB前後もあります。
競走馬のデータが多いのは、レースには出走しない高齢馬なども含んでいるからです。
10歳を越えてもレースに出走する馬は極端に少ないですし、成績が悪くて登録を抹消しているような馬も多いですから、競馬予想のデータベースには本来登録する必要のない馬が多いです。
競走馬は登録と抹消を繰り返しておりますから、単純に登録抹消馬を除外はできませんが、13万頭を越える競走馬のなかでJRAの登録馬を調べたら、8016頭に過ぎませんでした。
今後は2歳馬などが登録されるでしょうが、常時活躍している馬は1万頭以下でしょう。

オッズデータが膨大な容量を必要とするのは想像がつきます。
ここには登録しておりませんでしたが、3連単は組み合わせの多さから考えて膨大な容量を必要とします。
「馬吉」では3連複と馬単を9分割して対策しております。
分割しない場合は、3連複は400MB近く、馬単は170MB近くの容量を必要とします。
このぐらいなら分割しなくても良さそうですが、検索速度なども考慮しているのでしょうか。

レース数と配当データ数が極端に異なるのは、レースデータには地方のレースが含まれているからです。
この数も半端ではないので、データの異なる地方レースは除外したいのですが、最近は中央の馬が地方レースに参加する場合が多く、除外すると競走馬のローテーションがめちゃくちゃになってしまいます。
データでは1年振りで出走しているように見えても、その間は外国に行ったり地方に行ったりしていて休養明けではない事が多くなります。
そうすると、休養明けの馬の評価を下げて配点しているような競馬予想では、評価が低くなりがちですから、地方レースは全て取り込むようにしております。
この場合の泣き所は、外国のレースや地方のレースでは馬体重などのデータはありますが、上がり3ハロンがどうだったとかのデータは無く、能力比較が難しくなる事です。
やはり競馬予想とは、アバウトで判断するしかないものなのです。
アバウトしか予想出来ないものなのに、1点買いでも的中できるなどと言っている人(組織)のなんと多い事でしょうか。
競馬プログラムを作成している者なら、有料競馬予想の提供サイトの予想もアバウトでしか判断できない事を十分理解していますから、インチキ競馬予想会社に引っかかる事はありません。

話が逸れてしまいましたが、競馬予想に絶対に必要なデータは限られており、「馬吉」のようにJRA-VAMから提供されるデータは、何が何でも取り込まなければならないものではありません。
基本的には大は小を兼ねると言う事なのですが、多くのデータを取り込んだ事によるデータベースの肥大化は、極端に検索スピードを低下させます。
jRA-VANでは、この問題に対処するために、今週のデータと言う今週のレースに出走する競走馬や騎手などに絞ったデータも提供しています。
これを利用している競馬予想ソフトも大変多いのですが、私が以前調べた時には競走馬の過去のレース数も5レース程度までと少ないようです。
競馬新聞並のデータ量ではあるのですが、私が今まで経験した感じでは過去走も5レースは少なすぎる感じで、最低でも過去10レースの内容は見る必要があると思います。
人間の目でみるのは、競馬新聞のように5レース程度が限界でしょうが、コンピュータの世界では、10レースでも20レースでも可能です。
とは言っても、数年前のデータが今日行うレースに影響があるかと言うと、馬も生き物ですから変化している事が多いので、多くても15レース前程度まで確認すれば十分だろうと思います。

「馬吉」のデータベースの蓄積方法はJRA-VANから提供されたデータをそのままで蓄積しているようです。
私のデータベースでは何回も言うように、データベースに蓄積する時に最適化を行っています。
例えば、データに不要なスペースがあれば、それを削除しておりますし、0(ゼロ)が連続しているようなデータは0を1個にして記録しております。
この程度でも、データベースの肥大化を防止する効果は大きく、私のイメージでは容量が6割程度に減少します。
データベースから取り出す時に不要なスペースを削除するぐらいなら、多少は時間が掛かっても記録する時に削除しておくべきものでしょう。
この方がデータの表示時間も短くなりますので一挙両得だと私は考えております。

[戻る]