インフォテーブルの操作
インフォテーブルはキャッシュ内の単一のオブジェクトとしてメモリに保存されます。このため、ThingWorx 8.5 以降では、予期しない動作やパフォーマンスの問題が発生する可能性があるので、インフォテーブルの直接操作はサポートされていません。Thing からインフォテーブルプロパティを読み込むと、プロキシオブジェクトが作成され、これが元のオブジェクトにトークバックします。直接変更はローカルコピーに対してのみ行われますが、関数呼び出しによって元のオブジェクトが更新されます。すべてのデータが更新されるまで変更がプロキシされないようにオブジェクトの完全なクローンを必要とする場合、リソースのクローンオプションを使用します。以下の単一行のインフォテーブルの例ではラッパーオブジェクトを使用していますが、複数行のインフォテーブルの場合、すべての行変更を更新するわけではないので、フルクローンオプションを使用します。
以下はローカルプロキシオブジェクトを作成します (メソッド呼び出しによって元のオブジェクトが更新され、キャッシュに保存されます)。
Things["data1"] は "data1" Thing を名前でサーチします。
Things["data1"].info "data1" Thing の "info" インフォテーブルプロパティ
var myinfo = Things["data1"].info
以下はフルクローンを作成し、変更は元のオブジェクトにプロキシされません。
var myinfo = Resources["InfoTableFunctions"].Clone({ t1: Things["data1"].info });
ThingWorx 8.5 以降のプロパティデータは、以前のリリースとは異なる方法で扱われます。すべてのデータが高可用性クラスタ環境でローカルまたはリモートで使用できるようにキャッシュレイヤーに保存されるようになりました。以前の環境では、保存されているデータは直接修正されていましたが、キャッシュレイヤーでは、データ変更時にキャッシュとの間で移動させなければなりません。クラスタ環境では、キャッシュは分散されるため、追加のネットワークの待ち時間とワイヤのシリアル化によって、要求が行われるたびに時間が長くなります。
大量のデータをプロパティにインフォテーブルとして保存することは、非常に費用がかかり、またクラスタ環境でシステムクラッシュを発生させる可能性があります。インフォテーブルは、変更時にプロパティに完全に読み書きされるようになりました。クラスタ環境では、完全なオブジェクトもシリアル化、逆シリアル化され、ワイヤ全体に送信されます。大規模なインフォテーブルは、1 つのプロパティに保存する代わりに、データベースに移動しなければなりません。これらは、ユーザー定義のテーブルに変換したり、データテーブルに配置したりできます。
クラスタ環境では、Apache Ignite が使用されます。大きいオブジェクトをプッシュすると、Ignite が応答しなくなる可能性があります。Ignite は書き込みとバックアップをキューに入れるため、大きな値がプッシュされると、その処理に時間がかかり、プロセスが停滞する可能性があります。バックアップが大きくなると、Ignite システムのスレッドはブロックを開始し、これによって Ignite が応答不能であると認識してノードをシャットダウンする可能性があります。データがさらに古くなる可能性があります。
クラスタ環境で適切に機能するように、場合によっては、プロパティに保存されるデータのサイズを削減するためにアプリケーションを変更しなければなりません。通常、これは数千行で構成されるインフォテーブルが原因で発生します。
例: インフォテーブルの並べ替え
この例は、キャッシュレイヤーが追加される前は機能していました。これはメモリ内のテーブルを直接更新するときに使用されていました。
var sort = new Object();
sort.name = yourFieldName;
sort.ascending = booleanValue;
me.yourInfoTable.Sort(sort);
ただし、現在ではこれは以下のように実行します。
ローカルインフォテーブルを作成し、変更を行ってから、Thing のインフォテーブルプロパティに再び割り当てます。
これにより、オブジェクトがキャッシュから取り出されてコピーが作成されます。その後、元のプロパティに影響を与えることなく、設定が完了するまでコピーを変更できます。
これが当てはまらない場合、インフォテーブルに対して変更を加えるとオブジェクト全体がキャッシュに書き戻され、パフォーマンスが低下します。
var localInfoTable = me.yourInfoTable;
var sort = new Object();
sort.name = yourFieldName;
sort.ascending = booleanValue;
localInfoTable.Sort(sort);
me.yourInfoTable = localInfoTable;
例: 単一行インフォテーブルでのフィールド値の更新
間違った方法:
このスクリプトの各行が、キャッシュからインフォテーブル全体を取得し、1 つの値を変更してからキャッシュに戻しています。インフォテーブル全体を毎回処理するので、キャッシュへのラウンドトリップには時間がかかります。これによってキャッシュの呼び出しが 6 回実行され、リモートシステムではスクリプトが非常に遅くなる可能性があります。
Things["data1"].info.v1 = 1;
Things["data1"].info.v2 = 2;
Things["data1"].info.v3 = 3;
正しい方法:
この例では、キャッシュからインフォテーブルのクローンを取得し、すべてのデータをローカルに更新してから、インフォテーブルをキャッシュに戻しています。キャッシュの呼び出しが 2 回だけに減っています。
var myinfo = Things["data1"].info
myinfo.v1 = 1
myinfo.v2 = 2
myinfo.v3 = 3
Things["data1"].info = myinfo
例: 単一行インフォテーブル全体のフィールド値の更新
以下の例では、インフォテーブルがローカル変数に割り当てられた場合、クローンになることを示しています。元のオブジェクトに対する変更は、クローンの値には反映されません。
// creates a clone of InfoTable
var myinfo = Things["data1"].info;
// sets value of v1 to 5 in local InfoTable
myinfo.v1 = 5;
// change the orignal data1's v1 field value to 4, will not update the local value, it is still 5
Things["data1"].info.v1 = 4;
// assigning local info table to data2 so its v1 will have a value of 5
Things["data2"].info = myinfo;
例: 複数行インフォテーブルでの動作の変更
以下では、インフォテーブルのクローンがまだプロキシオブジェクトであることがわかります。プロキシオブジェクトに対して呼び出されたメソッドは、メインオブジェクトに対して有効になります。以下はプロキシとは一貫していますが、ThingWorx 8.4 の動作とは異なります。ThingWorx 8.4 で me.p2 = prop2 を実行した場合、元のオブジェクトへの参照が失われます。ThingWorx 9 では、これらは同じオブジェクトプロキシとして扱われるので、参照は失われません。
// An InfoTable local object for the "v1" field
var newEntry = new Object();
newEntry.v1 = 1;
// creates a proxy object from local object prop1 -> me.p1
var prop1 = me.p1;
prop1.v1=4;
// creates a proxy object from local object prop2 -> me.p2
var prop2 = me.p2;
prop2.v1=5;
// updates the me.p1 object, this breaks the proxy between prop1 -> me.p1
me.p1=prop2;
// prop2 reference is unchanged, still proxied
me.p2=prop2;
// this will not change me.p1 since the reference was broken when the object assignement to prop2 was done
prop1.AddRow(newEntry);
// this will update me.p2, the object reference is the same
prop2.AddRow(newEntry);
例: 複数行インフォテーブルの構築
この例では、インフォテーブルに複数の行を追加します。
間違った方法:
これはデータベース AddRow に対してメソッドを使用しているので正しいように見えますが、実際にはループ内の各イテレーションで変更を元のオブジェクトにプロキシしています。これによって、ループの各イテレーションでインフォテーブルがキャッシュに書き込まれることになり、これは望ましい処理ではありません。
var myinfo = Things["data1"].info;
for (i=0; i < 10; i++) {
var row = new Object();
row.v1 = i;
row.v2 = i * 2;
row.v3 = i * 3;
myinfo.AddRow(row);
}
Things["data1"].info = myinfo;
正しい方法:
この例では、元のオブジェクトに再び割り当てるまでは、影響を与えることなく操作できるように、オブジェクトのクローンを作成しています。
var myinfo = Resources["InfoTableFunctions"].Clone({ t1: Things["data1"].info });
for (i=0; i < 10; i++) {
var row = new Object();
row.v1 = i;
row.v2 = i * 2;
row.v3 = i * 3;
myinfo.AddRow(row);
}
Things["data1"].info = myinfo;
以下の例も正しく機能します。プロキシオブジェクトのメソッドを使用していないので、割り当てられるまで元のオブジェクトは変更されません。
var myinfo = Things["data1"].info;
for (i=0; i < 10; i++) {
var row = new Object();
row.v1 = i;
row.v2 = i * 2* 10;
row.v3 = i * 3* 100;
myinfo.rows[i] = row;
}
Things["data1"].info = myinfo;
これは役に立ちましたか?