この回答では、私が最終的に実装したソリューションを要約します。それは私の特定の問題に合うように特別に設定されているので、代替オプションについてはLucaGerettiとbdecafによる回答も参照することをお勧めします。
私が実装したもの
SQLiteはデータを1つのファイルに保存し、セットアップと処理が簡単だったため、データベースとしてSQLiteを選択しました。(sqlite3とsqlite-jdbc-3.7.2ドライバーを使用すると、インストールするものはそれほど多くなく、データベースはすべて1つの単純なファイルに含まれます。)
Matlab Database Toolboxは、シミュレーション中に作成されたMatlabから大量のデータをエクスポートするには遅すぎることが判明しました。したがって、データスナップショットをcsvファイルにダンプする「DataOutputManager」クラスを作成しました。
シミュレーション後、DataOutputManagerはSQLコマンドを含む2つのバッチファイルと2つのSQLテキストファイルを作成し、バッチファイルを実行します。最初のバッチファイルは、sqlite3.exe(www.sqlite.org)を実行し、最初のテキストファイルでSQLコマンドを指定してSQLiteデータベースを作成します。
データベースが作成された後、sqlite3は、2番目のバッチとテキストファイルを使用して、csvファイルからデータベースにデータをインポートするように指示されます。これは「きれいな」ソリューションではありませんが、データをcsvに書き込んでから、sqlite3を使用してこれらのファイルをデータベースにインポートする方が、DatabaseToolboxを使用するよりもはるかに高速でした。(xmlファイルを使用している人のことを聞いたことがあります)
シミュレーションデータがデータベースにアップロードされた後、データベースツールボックスをjdbcドライバー( sqlite-jdbc-3.7.2 )と一緒に使用して、SQLクエリをデータベースに送信します。これらのクエリから返されるデータはごくわずかであるため、DatabaseToolboxはここでのボトルネックではありません。
これらすべてを(Windows 7で)設定するには、検索とテストの割り当てが必要でした。完璧ではありませんが、誰かが似たようなことをしたい場合は、次のスニペットが役立つことを願っています。
SQLiteデータベースの作成とcsvからデータベースへのデータのインポート:
sqlite3を使用してデータベースを作成する最初の.batファイルは次のように構成されています。
sqlite3 DatabaseName.db <DatabaseNameStructure.sql
最初のテキストファイル(.sql)はDatabaseNameStructure.sqlと呼ばれ、次のように構成されています。
始める; テーブルTable1Name(Column1Name real、Column2Name real、Column2Name real);を作成します。テーブルTable2Name(Column1Name real、Column2Name real、Column2Name real);を作成します。専念;
sqlite3がcsvファイルをデータベースにアップロードできるようにする2番目の.batファイルは、次のように構成されています。
sqlite3 DatabaseName.db <uploadCsvToDatabaseName.sql
2番目のテキストファイル(.sql)はuploadCsvToDatabaseName.sqlと呼ばれ、次のように構成されています。
.separator "、"
.import Table1Data.csv Table1Name
.import Table2Data.csv Table2Name
。出口
これを機能させるには、システムパスにsqlite3.exeを含める必要があります(例:C:\ Windows \ System32に保存)。data / csvの設定に従ってMatlabでスティングを作成し、fprintf()を使用して上記の形式でファイルに書き込みます。次に、winopen()を使用してMatlabからbatファイルを実行します。
jdbcドライバーを使用してMatlabをSQLiteデータベースに接続します。
ブライアンダウニングによる次のビデオは、私がこれを開発するのに役立ちました: http ://www.youtube.com/watch?v= 5QNyOe79l-s
データベースに接続し、シミュレーション結果に対してすべての分析を実行するMatlabクラス(「DataAnalyser」)を作成しました。データベースとの通信を設定するためのクラスコンストラクタと接続関数は次のとおりです。(実装の中でそれほど重要ではない部分を切り取りました)
function Analyser=DataAnalyser()
% add SQLite JDBC Driver to java path
Analyser.JdbcDriverFileName='sqlite-jdbc-3.7.2.jar';
% Ask User for Driver Path
[Analyser.JdbcDriverFileName, Analyser.JdbcDriverFilePath] = uigetfile( {'*.jar','*.jar'},['Select the JDBC Driver file (',Analyser.JdbcDriverFileName,')']);
Analyser.JdbcDriverFilePath=[Analyser.JdbcDriverFilePath,Analyser.JdbcDriverFileName];
JavaDynamicPath=javaclasspath('-dynamic'); % read everything from the dynamic path
if~any(strcmp(Analyser.JdbcDriverFilePath,JavaDynamicPath))
disp(['Adding Path of ',Analyser.JdbcDriverFileName,' to java dynamic class path'])
javaaddpath(Analyser.JdbcDriverFilePath);
else
disp(['Path of ',Analyser.JdbcDriverFileName,' is already part of the java dynamic class and does not need to be added']);
end
Analyser.JdbcDriver='org.sqlite.JDBC';
% Ask User for Database File
[Analyser.DbFileName, Analyser.DbFilePath] = uigetfile( '*.db','Select the SQLite DataBase File ');
Analyser.DbFilePath=[Analyser.DbFilePath,Analyser.DbFileName];
Analyser.DbURL=sprintf('jdbc:sqlite:%s',Analyser.DbFilePath);
% Set Timeout of trying to connect with Database to 5 seconds
logintimeout(Analyser.JdbcDriver,5);
end
function [conn,isConnected]=connect(Analyser)
% Creates connection to database.
Analyser.Connection=database(Analyser.DbFilePath,'','',Analyser.JdbcDriver,Analyser.DbURL);
conn=Analyser.Connection;
isConnected=isconnection(Analyser.Connection);
end
接続されたSQLiteデータベースからMatlabにデータを取得する
また、SQLクエリが与えられたときにデータベースからデータを取得するDataAnalyserの関数も作成しました。私は2つの理由でそれの主要な部分をここに投稿しています。
すべてのデータを一度にインポートするのではなく、この関数のように部分的にインポートすると、データのインポートが高速になります。
Mathworksには、Database Toolbox(cursor.fetch)のドキュメントでこれを行う方法の提案があります。ただし、jdbcとSQLiteを使用すると、バグが原因でエラーが発生します。
Mathworksサポートからの引用:
レコードセットの最後にいる場合、SQLite JDBCドライバーは、レコードセットに関する特定のメタデータのクエリを許可しないことを以前に確認しました。ただし、JDBC仕様によれば、これは許可されるべきです。
この関数はその問題を回避します:
function OutputData=getData(Analyser,SqlQuery,varargin)
% getData(Analyser,SqlQuery)
% getData(Analyser,SqlQuery, setdbprefsString)
% getData(Analyser,SqlQuery,RowLimitPerImportCycle)
% getData(Analyser,SqlQuery,RowLimitPerImportCycle,setdbprefsArg1String,setdbprefsArg2String)
% getData(Analyser,SqlQuery,[],setdbprefsArg1String,setdbprefsArg2String)
%
% RowLimitPerImportCycle sets the Limit on howmany Data rows
% are imported per cycle.
% Default is RowLimitPerImportCycle = 6000
%
% setdbprefsArg1String Default 'datareturnformat'
% setdbprefsArg2String Default 'numeric'
% Hence setdbprefs('datareturnformat','numeric') is the Default
%
% function is partially based on cursor.fetch Documentation for
% Matlab R2012b:
% http://www.mathworks.de/de/help/database/ug/cursor.fetch.html
% Example #6 as of 10.Oct.2012
% The Mathworks' cursor.fetch Documentation mentioned above had
% some errors. These errors were (among other changes)
% corrected and a bug report was send to Mathworks on 10.Oct.2012
if isempty(Analyser.Connection)
disp('No open connection to Database found.')
disp(['Trying to connect to: ',Analyser.DbFileName])
Analyser.connect
end
% Get Setting
if nargin>2
RowLimitPerImportCycle=varargin{1};
else
RowLimitPerImportCycle=[];
end
if ~isnumeric(RowLimitPerImportCycle) || isempty(RowLimitPerImportCycle)
%Default
RowLimitPerImportCycle=5000;
end
if nargin>4
setdbprefsArg1String=varargin{2};
setdbprefsArg2String=varargin{3};
else
setdbprefsArg1String='';
setdbprefsArg2String='';
end
if ischar(setdbprefsArg1String) && ~isempty(setdbprefsArg1String) && ischar(setdbprefsArg2String) && ~isempty(setdbprefsArg2String)
setdbprefs(setdbprefsArg1String,setdbprefsArg2String)
else
%Default
setdbprefs('datareturnformat','numeric');
end
% get Curser
curs=exec(Analyser.Connection,SqlQuery);
if ~isempty(curs.Message)
warning('Model:SQLMessageGetData',[curs.Message, '/n while executing SqlQuery: ',SqlQuery])
end
% import Data
FirstRow = 1;
LastRow = RowLimitPerImportCycle;
firstLoop=true;
while true
curs = fetch(curs,RowLimitPerImportCycle);
if rows(curs)==0
if firstLoop == true
OutputData=[];
end
break
end
AuxData = curs.Data;
numImportedRows = size(AuxData,1);
if numImportedRows < RowLimitPerImportCycle
OutputData(FirstRow:LastRow-(RowLimitPerImportCycle-numImportedRows), :) = AuxData;
else
OutputData(FirstRow:LastRow, :) = AuxData;
end
FirstRow = FirstRow + RowLimitPerImportCycle;
LastRow = LastRow + RowLimitPerImportCycle;
firstLoop=false;
if rows(curs)<RowLimitPerImportCycle
break
end
end
end