内部状態を持つグラフの状態変化を1つのログテーブルで扱う

最近悩んでいた問題から。

以下のような性質を持つシステムを考えます。

  • システムはノードから構成される。
  • 各ノードは内部状態を持つ。
  • ノードはネットワークも持つ。ただし、ループはないものとする。
  • この時に、ノードやネットワークの変化を検出したい。
  • 子ノードが変化したときも親ノードの状態変化として検出したい。

図で時間は上から下に流れおり、t=t1ではネットワークの変化が、t=t2ではAノードの変化が検出されています。

普通に考えると、SQL のテーブルは以下のようになるかと思います。

CREATE TABLE node (id INTEGER PRIMARY KEY NOT NULL, name VARCHAR(1024) NOT NULL;
CREATE TABLE content (id INTEGER PRIMARY KEY NOT NULL, node_id INTEGER NOT NULL, content VARCHAR(1024) NOT NULL); 
CREATE TABLE graph (id INTEGER PRIMARY KEY NOT NULL, parent_id INTEGER NOT NULL, child_id INTEGER NOT NULL);
CREATE TABLE node_log (id INTEGER PRIMARY KEY NOT NULL, contents_id INTEGER, state INTEGER DEFAULT 1, created_at DATETIME);
CREATE TABLE graph_log (id INTEGER PRIMARY KEY NOT NULL, graph_id INTEGER, state INTEGER DEFAULT 1, created_at DATETIME); 

しかし、この方法には2つの問題があります。

  • 変化を検出するのに、node_log, graph_log 2つのテーブルを見る必要がある。
  • node, graphテーブルの状態変化がすぐには分からない。

まず、1つのテーブルで済むようにするのに、一番安易な回答は2つのテーブルの OR をとったテーブルを作ることでしょう。

CREATE TABLE system_log (id INTEGER PRIMARY KEY NOT NULL, content_id INTEGER, graph_id INTEGER, state INTEGER DEFAULT 1, created_at DATETIME);

2番目の問題を解決するには LEFT JOIN を使用します。

例えば、現在のノード状態を算出する SQL は以下のようになります。

SELECT status FROM system_log LEFT JOIN content c ON c.id=system_log.content_id
    LEFT JOIN node n0 ON n0.id=c.node_id
    LEFT JOIN graph g ON g.id=system_log.graph_id
    LEFT JOIN node n1 ON g.child_id=n1.id
    LEFT JOIN node n2 ON g.parent_id=n2.id
    WHERE n0.id=:node_id AND n1.parent_id=n0.id AND n2.child_id=n0.id
    ORDER BY id DESC
    LIMIT 1;

ノードやグラフに変化があったときは status > 1 として system_log に書き込むだけで済みます。

投稿者について
みのしす

小さいときは科学者になろうとしたのに、その時にたまたま身に着けたプログラミングで未だに飯を食っているしがないおじさんです。(年齢的にはもうすぐおじいさん)

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です