株取引の自動化、交通情報処理の高度化、クリックストリームの解析といった、高いレートで継続的に発生する情報をリアルタイムに解析し、瞬時にアクションを起こす技術の進展を背景に、高レートデータのリアルタイム処理を実現する、ストリームデータ処理が注目されている。ストリームデータ処理は、様々なデータ処理に適用可能な汎用ミドルウェア技術であるため、個別案件ごとにシステムを構築するのでは間に合わないようなビジネス環境の急激な変化にも応えつつ、実世界のデータをリアルタイムにビジネスに反映することを可能とする。このストリームデータ処理の原理、実現方式は非特許文献1に開示されている。
ストリームデータ処理では、時間軸上における点のデータの系列であるストリームを入力し、ウィンドウ演算によって生存期間を持つデータの集合であるリレーションに変換する。リレーション上の関係演算を実施し、その結果リレーションをストリーム化演算によってストリームに戻し、出力する。リレーションはストリームデータ処理における中間状態である。ストリーム上の個々のデータをストリームタプルと呼ぶ。ストリームタプルは関係データベースのレコードと同様に、複数のカラムの組合せを値とする他に、タイムスタンプを属性として持つことが特徴となっている。ストリーム上のストリームタプルは、タイムスタンプの昇順でストリームデータ処理に入力される。
例として、時刻t1〜t6のタイムスタンプが付いた6個のストリームタプルの系列を考える。各タプルの値は文字列idと整数値valの2つのカラムからなり、それぞれ(a,1),(a,2),(b,1),(a,1),(a,2),(b,3)を値としている。これに対し、ウィンドウ演算として、最大同時生存数を制限する個数ウィンドウを適用するとする。ここでは、同時生存数を3個に制限する。このとき、例えば1個目のタプルは、時刻t1を始点、4個目のタプルが到着するt4を終点とする期間生存するデータに変換される。なお終点丁度は生存期間に含めない。その他のウィンドウ演算には、生存期間を定数時間とする時間ウィンドウ、および、特定のカラムの値が同一のストリームタプルをグループ化し、各グループ別に最大同時生存数を制限するパーティションウィンドウが存在する。
上記のように生存期間を定めたデータの集合であるリレーションに対する関係演算として、カラムvalに対する集計演算SUMを適用する例を考える。ストリームデータ処理における関係演算では、演算に対する入力と結果のリレーションを時間軸上のある時刻で切った際の交点の集合が、従来の関係データベースの演算における入力と結果の関係と、同一になる。例えば、該例のリレーションを時刻t4で切った交点のデータ値は{(a,2),(b,1),(a,1)}となるので、その結果であるリレーションを同時刻で切った交点のデータ値は{(4)}となる。前者のデータ値集合を、従来の関係データベースの集計演算SUM(val)で処理した結果が、後者のデータ値集合になっている。同様の関係がどの時刻においても成り立つ。
ある2つのリレーションについて、全ての時刻で交点のデータ値の集合が同じ場合、両リレーションは互いに合同であるという。合同なリレーションに対する関係演算の結果は、やはり合同になる。
上記のような関係演算の結果に対し、ストリーム化演算として、IStreamという演算を適用する例を考える。ストリーム化演算は、ある時刻においてリレーションの交点のデータ値集合に増減があった場合に、該時刻をタイムスタンプにして、該増減のあったデータ値をストリームタプルとして出力する。IStreamは増加したデータ値を出力する。その他のストリーム化演算には、減少したデータ値を出力するDStream、および、定数時間毎に、生存するデータ値を出力するRStreamが存在する。本例における演算適用の結果は、時刻t1、t2、t3、およびt6に、それぞれ{(1)}、{(3)}、{(4)}、および{(6)}のストリームタプルが出力されることになる。ここで、時刻t4、およびt5においては、ストリームタプルは出力されない。これは、関係演算の結果リレーションの時刻t3〜t6における時刻で切った交点は、常に{(4)}、即ち唯一の要素を持つ集合で、その値に変化が無いためである。このように、ストリーム化演算はデータ値の増減に基づいて処理しているので、合同なリレーションからは同一のストリームが生成されることを保証できる。但し、ある時刻におけるリレーションの全ての増減が確定するまで待たないと、該時刻における結果タプルを出力することができないという制限がある。
次に、ストリームデータ処理におけるクエリのデータ処理の定義方法、および、一般的な実行制御方法を説明する。ここでの記法はCQL(Continuous Query Language)という宣言型言語に準ずる。CQLの文法は、関係データベースにおいて標準的に利用される、関係代数に基づくクエリ言語SQLに、ウィンドウ演算、およびストリーム化演算の記法を追加した形式をとる。CQLは非特許文献4に開示されている。
次は、クエリ定義の例である。
REGISTER STREAM s1(id VARCHAR(30), val INT);
REGISTER STREAM s2(id VARCHAR(30), val INT);
REGISTER QUERY q
RSTREAM[30 SECOND](
SELECT s1.id AS id1, s2.id AS id2, s1.val
FROM s1[RANGE 5 MINUTE], s2[ROWS 1]
WHERE s1.val = s2.val
);
ここで、「REGISTER STREAM」で始まる2つのコマンドは、データソースからのストリームを受け付ける入力を定義するコマンドである。
一番目のコマンドはs1という名前の入力ストリームを定義している。また、該入力ストリームで受取るデータが、idおよびvalという名称のカラムを持ち、その型がそれぞれ文字列型と整数型であることを定義している。二番目のコマンドはs2という名前の入力ストリームを定義している。カラムの定義は入力ストリームs1と同じである。3番目のコマンドはクエリを定義するコマンドである。該コマンドはqという名前のクエリを定義している。括弧“(”と“)”で囲まれた部分では、関係データベースにおけるデータ処理言語SQLと同じ文法でリレーション上の関係演算を定義する。この例では、ストリームs1とs2を、カラムvalの値の一致でジョインすることを指定している。FROM句には、前記入力ストリーム名、あるいは、他で定義されたクエリの名前を指定する。ストリーム名、あるいはクエリ名に続く“[”と“]”で囲まれた部分はウィンドウ演算を指定する記法である。例中の記述“s1[RANGE 5 MINUTE]”は、入力ストリームs1のストリームタプルを、時間ウィンドウによって生存時間5分のデータに変換することを指定している。一方、“s2[ROWS 1]”は、入力ストリームs2のストリームタプルを、個数ウィンドウによって同時生存データを最新の1個に制限することを指定している。この他に、パーティションウィンドウを指定する記法である“[PARTITION BY カラム名リスト ROWS 個数]”、および、生存期間を実時間未満の論理的な微小時間、即ち瞬間だけに制限する記法“[NOW]”が存在する。括弧“(”と“)”で囲まれた部分の前に位置するのは、ストリーム化演算を指定する記法である。例中の記述“RSTREAM[30 SECOND]”は、RStreamの使用を指定しており、30秒ごとに生存するリレーションのデータ値をストリームタプルとして出力する。この他に、IStreamを指定する記法“ISTREAM”および、DStreamを指定する記法“DSTREAM”が存在する。
ストリームデータ処理では、上記のような記法で定義されたクエリを、実行木と呼ばれるデータ構造に変換して処理する。実行木は、要素データ処理を実施するオペレータの間をデータキューで連結した木構造であり、オペレータ間でパイプライン的にデータを送受することで処理を実現する。リレーション上のデータは生存期間を持つので、1データにつき生存開始と生存終了を表す2つのタプルが送受される。前者をプラスタプル、後者をマイナスタプルと呼ぶ。
実行木の処理においては、データ処理の順番をタイムスタンプ通りに厳守するための時刻順保証制御を実施する。例えば、前記クエリ例におけるジョインのように、2つのリレーションを対象とする演算は、実行木上では二入力のオペレータとなる。このようなオペレータは左右のキューに入力されたタプルのタイムスタンプを比較し、早い方のタプルを先に処理しなければならない。一方、2つのデータソースのうち片一方からのデータの到来が滞ると、この比較ができず、もう一方のデータの処理も停滞してしまうことになる。このような現象をストールと呼ぶ。ストールを回避するために、データソースからデータが来ない間も、時刻が進んだことを知らせるためのハートビートタプルを、実行木の葉(入力)となるオペレータから送信するのが、ストリームデータ処理において広く認知されている方法である。ハートビートを利用した実行制御方法は、非特許文献2で開示されている。
二項演算のみでなく、時間ウィンドウ、あるいはRStreamといった時限発火でタプルを出力するオペレータにおいても、ハートビートタプルが必要となる。例えば、前記クエリ例における、入力ストリームs1に対する時間ウィンドウオペレータが、9:03’10にプラスタプルを受取ると、その5分後の9:08’10の時刻に、マイナスタプルを出力する必要がある。もし、該入力ストリームs1に対するデータが滞ると、このマイナスタプルを出力することができない。ハートビートタプルがこれを解決する。仮に、ハートビートタプルの送信間隔を1分とすると、該マイナスタプルは、9:09’00のハートビートタプルによって、出力することができる。前記クエリ例におけるRStreamについても同様である。30秒毎にタプルを出力する指定なので、例えば9:02’30のストリームタプルは、9:03’00のハートビートタプルが到来することで出力される。この時点では、9:03’00のストリームタプルを出力することはできない。先に述べたように、ストリーム化演算は、ある時刻(この場合9:03’00)のタプルが全て到来しないと結果を出力できないという制限があることを鑑みると、ハートビートタプルの後に続いて、さらに9:03’00の何らかのタプルが来る可能性があるため、この時点での出力は不可となっている。
ストリームデータ処理では、単純に一つの入力から受取ったタプルを処理して次に流すデータフィルタ的な処理のみでなく、二項演算オペレータ、および時間ウィンドウ、RStreamのような精密な時刻制御を必要とする処理が存在する。ハートビートタプルは、このようなオペレータに対して、どこまでの時刻の処理を実行してよいか、即ち、実行可能時刻を通知する役割を持つ。
非特許文献3には、時刻情報に基づき実行木中から実行可能なオペレータを探索するアルゴリズムとして、単なるラウンドロビンや、実行可能なうち最早のタプルを出力するオペレータの実行を優先する技術が開示されている。
ストリームデータ処理を、今後重要となる低レイテンシ処理に適用する際に、従来のハートビートタプルによる実行方式では課題があることを、図3、および図4を用いて示す。
図3は、株取引クエリの単純化した例である。コマンド301で登録される入力ストリームmarketは株価情報を表し、カラムstock_idは銘柄ID、priceは株価を表す。コマンド302で登録される入力ストリームresource_streamは資金を表し、カラムvalは額面を表す。コマンド303で登録される入力ストリームstock_streamは保有株を表し、カラムidは銘柄ID、numは株数、priceは買値を表す。クエリ311は、ストリームresource_streamをリレーション化し、最新の資金額を保持する。クエリ314は、ストリームstock_streamをリレーション化し、銘柄毎に最新の保有株情報を保持する。クエリ310は、株価が一定水準を下回った銘柄があった場合、もし保有しておらず、購入資金があれば、買い注文を出す。クエリ313は、5分間の移動平均が買値より値を上げている保有株があれば、売り注文を出す。クエリ316は、買い注文と売り注文をマージし、30秒間隔のタイミングで発注する。
図4は、図3に示したクエリの実行木を示す。実行木470,471,473,474,476は、それぞれオペレータ400〜407,410〜411,430〜437,440〜441,460〜463より構成され、それぞれクエリ310,311,313,314,316に対応している。オペレータ間の太線はストリームを送受するキュー、細線はリレーションを送受するキューである。また、図ではデータが下から上に向かって流れることを想定している。
オペレータ400,410,430,440はscanオペレータであり、これらから1分間隔でハートビートタプルを送信する。図の時点で、ストリームデータ処理が持つ時計であるシステムタイムは9:15’00であり、各scanオペレータからは、該時刻までのハートビートタプルが送信されている。
ハートビートタプルを利用する第1の問題は、データタプルの処理タイミングが、ハートビートタプルの送信間隔に律速される点である。例えば、プラスタプル490の5分後の9:14’24のタイムスタンプで時間ウィンドウオペレータ431から出力されるマイナスタプル491は、9:15’00のハートビートタプルが到来するまで待たされることになるため、36秒の処理タイミングの遅れとなっている。これは、クエリ313の売り注文を出すタイミングの遅れを意味する。一方、RStreamオペレータ463においても、ストリームタプル495,496の出力タイミングは、ハートビートタプル497が到来するまで待たされる。タプル495,496それぞれに関して60秒、30秒の処理タイミングの遅れとなっている。また、30秒間隔で出力されるべきタプルが、1分間隔で同時に2個出力される動作になっている。これは、クエリ316の売り買い両注文を出すタイミングの不正を意味する。以上のように、平均してハートビートタプル送信間隔の半分の時間が、レイテンシとして現れてしまう。
第2の問題は、オペレータ間で処理タイミングの齟齬が発生する点である。例えば、二項オペレータ462の右側の入力は、データタプル493のタイムスタンプである9:13’30まで進んでいる一方、左側の入力は、データタプル490のタイムスタンプである9:09’24までしか進んでいない。該二つのタイムスタンプのずれは、タプル490の処理の遅れが少なくとも両時刻の差である4分6秒溜まっていることを意味している。また、左側の入力の処理が進むまで、タプル493の処理が停滞する。このようなオペレータ間の処理タイミングのズレも、やはりレイテンシとして現れてしまう。
第3の問題は、ハートビートタプルの処理コストのオーバヘッドである。データタプルと異なり、ハートビートタプルは実データではないため、その処理は本来無駄なコストである。特に、第1の問題を解決するためにハートビートの送信間隔を狭めると、CPU負荷の増大やスループットの低下を招く可能性もある。
したがって、ハートビートタプルを用いずに、上記問題を解決しようとすると、あるオペレータが処理完了するたびにどのオペレータが次実行するべきかを特定しなければならない。
また、非特許文献3は、また、ストリームデータの分析結果をリアルタイムにビジネスに活用するためには、外部からの入力などの変化に対するアクションのみでなく、それに伴うストリームデータ処理システム内のデータ処理結果を含む内部状況の変化を迅速に反映して、次のアクションを決定する必要がある。このような処理を、従来のハートビートタプルによる実行方式で実現することが困難であることを、図5、および図6を用いて示す。
図5は、図3のクエリにおいて、購買に伴う資金の変化を反映するクエリを示す。図3のクエリと異なるのは、クエリ512で買い注文に伴う費用を資金から減じ、クエリ311に入力して最新の資金額として反映する点である。また、コマンド502では初期資金を入力するストリームinitial_resourceを定義し、クエリ512で資金変化とマージしている。以上により、買い注文に必要な資金額の情報を、当の買い注文の結果に基づいて変化させている。こういった、あるクエリの結果を生成するために、そのクエリ自身の結果を利用するクエリは、再帰クエリと呼ばれる。
図6は、このクエリの実行木を示す。実行木670,671,672,674は、それぞれオペレータ600〜607,610,620〜626,640〜641より構成され、それぞれクエリ310,311,512,314に対応している。該実行木におけるscanオペレータ600,620,640からは、データタプルやハートビートタプルが出力される。しかし、これらのタプルは、それぞれ二項オペレータ605,625,604によって停滞する。原因は、これらのオペレータにおける他方の入力が、オペレータ610−604−605−606−607−622−623−624−625−626−610で形成される閉ループのパス上にあり、該ループ上を一切タプルが流れないことにある。
再帰クエリの実行木はこのように必ずループを持つことになる。ハートビートタプルを利用する従来の実行制御方法では、二項演算においては両入力のタプルが揃って、両タプルのタイムスタンプを比較してからでないと処理を進めることができないため、再帰クエリは実行できないことになる。
また、先に述べたように、ストリーム化演算はある時刻のタプルが全て到来しないと結果を出力できないという制限があるため、このような再帰クエリは、そのままでは実行不可能である。この問題を、図7を用いて示す。
図7は、図5のクエリを実行する際の、タプルの値、タイムスタンプ、生存期間を示している。なお、オペレータ602,604,625の処理については、煩雑になるため本図には含めていない。時刻t0においてresource_streamに3000000の値を持つストリームタプルが入力されると、個数ウィンドウオペレータ610によって、最新の資金額を表すresourceリレーションに変換される。ここで、時刻t1において、入力ストリームmarketにストリームタプルが入力されると、ウィンドウオペレータ601によって、論理的な微小時間の生存期間を持つリレーションに変換される。これと、リレーションresourceがジョインオペレータ605によって結合され、射影オペレータ606、ストリーム化演算607を介して、買い注文を表すストリームbuy_eventのタプルとして出力される。該タプルは、オペレータ622,623,624を介してリレーションresourceと結合され、買い注文を反映した新たな資金額2520000を表すリレーションとして出力される。該リレーションはストリーム化演算626によって、時刻t1のタプルとしてストリームresource_streamに追加される。
しかし、実際には以上の説明のようには動作せず、処理がデッドロックする。理由は、ストリーム化演算607の出力が自分自身の入力に戻っているためである。ストリーム化演算626についても同様である。但し、もしこのデッドロックが発生しないとすると、2520000という値が時刻t1における新たな資金額となり、再びストリームmarketとジョインされ、処理を再び一周し、その過程で全く同じ買い注文を出して、今度は2040000という資金額に更新される。そして、再びストリームmarketとジョインする、というように、買い注文および資金の減少が過剰に発生することになる。
以上のように、再帰的なクエリは、ハートビートタプルによる実行制御方法の問題、およびストリーム化演算の制限によって実行できない。
本発明の目的は、従来の実行制御方法におけるレイテンシに関する課題を解決する実行制御方式を用いたストリームデータ処理方法、及びそのシステムを提供することにある。
本発明の他の目的は、従来の実行制御方法における再帰クエリを実現できないという課題を解決し、更にはストリーム化演算の制限を回避する実行制御方式を用いたストリームデータ処理方法、及びそのシステムを提供することにある。
本願において開示される発明のうち、代表的なものの概要を簡単に説明すれば、次の通りである。
クエリ実行の前段階において、複数のクエリの実行木を連結した単一のオペレータグラフを形成し、このオペレータグラフの外部からタプルを入力する外部発火オペレータ、および、時間ウィンドウ、 RStream といった内部発火オペレータを抽出する。本明細書では、外部発火オペレータと内部発火オペレータの両者を合わせて発火オペレータと呼ぶ。
そして、オペレータグラフに属する全オペレータ集合上に全順序を定める。この順序は、オペレータ間の入出力関係における出力側のオペレータが入力側のオペレータより大となるような順序付けとする。そして、本明細書においては、この順序をオペレータ実行順序と呼ぶ。
また、クエリ実行においては、各発火オペレータが次回実行された際に出力するタプルのタイムスタンプを、発火オペレータの発火時刻と呼ぶ。
このとき、本発明においては、以下のような処理のループによって、クエリの実行を制御する。
(1)発火オペレータ群において、最も早い発火時刻のオペレータを選択する。選択されたオペレータを実行オペレータと呼ぶ。また、その発火時刻を実行時刻と呼ぶ。
(2)(1)で選択した実行オペレータを起点として、オペレータ実行順序の昇順に、オペレータグラフの出口までオペレータを順次実行する。
(3)この実行時刻をタイムスタンプとするタプルの処理を全て実行し、オペレータグラフ上から該当する発火時刻のタプルが無くなったら(1)に戻る。
また、本発明においては、オペレータグラフがループを含む場合には、オペレータ実行順序を定めることができないので、グラフを強連結成分に分解する。強連結成分とは、有向グラフにおいて、互いに到達し合う関係にあるノードの集合である。これにより成分間にはループが存在しなくなるので、成分間の実行順序を決定することができる。さらに、成分内のオペレータ実行順序を決定するアルゴリズムを提供する。
本願において開示される発明のうち、代表的なものによって得られる効果を簡単に説明すれば以下のとおりである。
全オペレータの処理を実行時刻ごとに完結しつつ実行を進めるため、処理の各ループにおいて各オペレータの実行可能時刻が自ずと決まるので、ハートビートが不要である。従って、従来の実行制御方法における、レイテンシに関する課題を解決する。即ち、
(1)レイテンシを律速する要因はない。
(2)オペレータ間で処理タイミングにズレがないため、オペレータの実行順の非決定性によるレイテンシが発生しない。
(3)データタプル以外の無駄なタプルを処理するオーバヘッドは存在しない。
また、再帰クエリの実行可能性に関して、実行木がループを持つため、従来のハートビートを利用する実行制御では実現不可であったが、本発明ではハートビートが不要となったことで実行が可能となる。
以下、本発明の実施の形態を図面に基づいて詳細に説明する。なお、実施の形態を説明するための全図において、同一の部材には原則として同一の符号を付し、その繰り返しの説明は省略する。
まず、図8A、8B、8Cを用いて、本発明の基本原理を説明する。図8Aは、図4の実行木中の各オペレータに対して、四角枠で囲む数字を付与している。この値は、後で詳述するオペレータの実行順を表している。図4と異なり、クエリの別を無視して単一の大きなオペレータグラフと捉え、該グラフ上での実行順を定めている。該実行順は自然数で、出力側のオペレータに付けられる値が入力側に付けられる値より大になるという条件を満たしている。
図8Bは、システムタイムが9:13’30になった際の実行の様子を示している。丁度このとき、scanオペレータ440にストリームタプル493が到来すると、そのタイムスタンプは9:13’30と付けられる。同時に、時間ウィンドウ431には、タイムスタンプ9:14’24のデータタプル491が、ストリーム化演算463には、タイムスタンプ9:13’30のデータタプル800が保持されている。オペレータ440は外部発火オペレータであり、発火時刻は9:13’30となる。オペレータ431、および463は内部発火オペレータであり、それぞれの発火時刻は9:14’24、および9:13’30となる。これら発火時刻の中で最早の値が実行時刻となるので、この場合は9:13’30となり、該時刻と同刻の発火時刻をもつ発火オペレータ440、および463が実行オペレータとなる。該オペレータ群を起点として、四角枠内のオペレータ実行順序に従って実行していく。この例では、オペレータ440を起点として太曲線の矢印のパスに沿って処理が進む。ここでは、オペレータ435でデータがフィルタされ、オペレータ436,437,461の処理が実行されないと想定している。
実行オペレータ440を起点とする処理の過程で、もう一つの実行オペレータである463も含まれるので、該オペレータ463を起点とする処理が別途実行されることは無い。ここで、実行オペレータ440を起点とする処理に先んじて、実行オペレータ463を起点とする処理を実行することはできない。理由は、オペレータ463がストリーム化演算であり、実行時刻である9:13’30の全オペレータが入力に揃わないとタプルを出力することができないためである。このような、ストリーム化演算の制限を保証するために、オペレータ実行順序を、前記条件を満たすように決定する必要がある。
図8Cは、システムタイムが9:14’26になった際の実行の様子を示している。scanオペレータ410には、タイムスタンプ9:14’25のストリームタプル498が到来している。このとき、外部発火オペレータ410の発火時刻が9:14’25、内部発火オペレータ431の発火時刻が9:14’24となるので、その中で最早である9:14’24が実行時刻、オペレータ431が実行オペレータとなって、該オペレータを起点として太曲線の矢印のパスに沿って処理が進む。
以上のように、システムタイムの変化と同時に、該時刻で実行すべきオペレータの処理を全て完結する。
次に、図1および図2を用いて、本発明を実現するためのストリームデータ処理システムの基本構成を説明する。
図1に示すように、ネットワーク106にストリームデータ処理サーバ100と計算機107、109、110が接続されている。ストリームデータ処理サーバ100は、図2に示すように、記憶部であるメモリ101、処理部である中央処理部(CPU)102、ネットワークI/F103、記憶部であるストレージ104、およびそれらを結合するバス105によって構成される計算機である。メモリ101上に、ストリームデータ処理の論理動作を定義するストリームデータ処理システム900を配置する。ストリームデータ処理システム900は、後で詳述するようにCPU102によって解釈実行可能な実行イメージである。ストリームデータ処理サーバ100は、ネットワークI/F103を介して外部のネットワーク106に接続される。
ネットワーク106に接続された計算機107上で動作するクエリ登録コマンド実行インタフェース108を介して、ユーザによって定義されたクエリ950、およびクエリグループ定義951を、ストリームデータ処理サーバ100が受取ると、ストリームデータ処理システム900は、この定義に従ってストリームデータ処理を実行可能な実行木を自身の内部に構成する。この後、ネットワーク106に接続された計算機109上で動作するデータソース952によって送信されるデータを、ストリームデータ処理サーバ100が受取ると、この実行木に従って処理し、結果データを生成する。この結果データは、ネットワーク106に接続された計算機110上で動作する結果利用アプリケーション953に送信する。ストレージ104は、ストリームデータ処理システム900の他、一度受取ったクエリ950、およびクエリグループ定義951を保存する。ストリームデータ処理システム900は、起動時にストレージ104からこの定義をロードし、実行木を構成することも可能である。
続いて、第一の実施例のストリームデータ処理システムを図9〜図18に従い説明する。
図9に第一の実施例のストリームデータ処理システム900の詳細を示す。このストリームデータ処理システム900は、図2に示したCPU102によって解釈実行される。ストリームデータ処理システム900中、クエリ定義保存部902、クエリグループ定義保存部903、クエリ実行木保存部905、オペレータグラフ保存部907、実行制御情報保存部909、実行時刻保存部914、実行オペレータリスト915、実行オペレ−タフラグ配列917、クエリ実行ワークエリア919は、記憶部であるメモリ101やストレージ104上に適宜形成される。クエリ構文・意味解析部904、オペレータグラフ構築部906、オペレータグラフ解析部908、実行オペレータ抽出部913、オペレータ実行制御部916、クエリグループ実行木構築部918の各機能は、CPU102で実行される。コマンド受付インタフェース901、ストリームタプル入力インタフェース920、ストリームタプル出力インタフェース921は、ネットワークI/F103に対応する。
さて、ストリームデータ処理システム900は、コマンド受付インタフェース901を介して、ユーザによって定義されたクエリ950を受取る。この情報は、クエリ定義保存部902に保持される。一方、クエリ950のうちどのクエリを、本システムの実行制御方法の対象とするか定義する、クエリグループ定義951もユーザによって与えられる。この定義は、クエリグループ定義保存部903に保持される。なお、クエリグループ定義は、明示的にユーザが与えるのではなく、別形態で定義することも可能である。例えば、同一ファイル中に定義された複数クエリの集合を暗黙でクエリグループとする、再帰クエリを成す複数のクエリをクエリグループとする、実行スレッドが分かれるクエリを互いに疎なクエリグループとする、クエリ定義においてアノテーションで囲った部分をクエリグループとする、といったバリエーションをとることもできる。
個々のクエリ定義は、クエリ構文・意味解析部904によって実行木903に変換後、クエリ実行木保存部905に格納される。オペレータグラフ構築部906は、クエリグループ定義保存部903に保存されたクエリグループ定義951を参照し、一つのグループを成すクエリ群の実行木から、該実行木群を連結した単一のオペレータグラフ931を形成し、オペレータグラフ保存部907に格納する。
オペレータグラフ解析部908は、オペレータグラフ931におけるオペレータ間の入出力関係、およびオペレータの種別に基づき、外部発火オペレータリスト910、内部発火オペレータリスト911、オペレータ実行順表912を作成し、実行制御情報保存部909に格納する。クエリグループ実行木構築部918は、該クエリグループに属する実行木群とオペレータグラフに基づき、該クエリグループに属するオペレータ全てを要素とする単一の実行木である、クエリグループ実行木932を構築し、クエリ実行ワークエリア919に格納する。
クエリ実行時は、実行オペレータ抽出部913が、発火オペレータリストを構成する外部発火オペレータリスト910および内部発火オペレータリスト911を参照し、クエリグループ実行木932中の発火オペレータの発火時刻から、実行時刻と実行オペレータ群を求め、それぞれ実行時刻保存部914、および実行オペレータリスト915に格納する。それに続き、オペレータ実行制御部916が、実行時刻保存部914、実行オペレータリスト915、およびオペレータ実行順表912を参照し、ワークエリアとして実行オペレータフラグ配列917を使用し、クエリグループ実行木932のオペレータの実行を制御する。このように、実行オペレータ抽出部913と、オペレータ実行制御部916の処理を交互に実施することで、クエリを実行する。
ストリームデータ処理システム900の外部のデータソース952からのデータは、ストリームタプル入力インタフェース920で受取り、クエリ実行ワークエリア919に渡す。一方、クエリの実行結果は、クエリ実行ワークエリア919から、ストリームタプル出力インタフェース921を介して、ストリームデータ処理システム900の外部の結果利用アプリケーション953に送出する。
次に、図8A、B、Cの実行木を例にし、図10〜14を用いて本実施例におけるオペレータ実行順序の決定方法を説明する。
図10に示したオペレータ間入出力関係表1000は、図8A、B、Cに示した実行木における、各オペレータと、その出力先となるオペレータ(複数の場合もある)の対応を表している。オペレータグラフ保存部907のオペレータグラフ931から得られる。
図11は、図8A、B、Cに示した実行木における、発火オペレータのIDをリストで表している。1100は外部発火オペレータリスト、1101は内部発火オペレータリストである。
図12は、オペレータグラフ解析部908で、オペレータ実行順序を決定するアルゴリズムのフローチャートである。また、図13Aは、該フローチャートにおいて使用するデータ構造である。
まず、図12の処理1201にて、オペレータ番号を1に初期化する。この値は、オペレータ番号保存領域1310に格納する。フローの処理中にオペレータグラフをトラバースする過程で、オペレータの実行順が決まる度にインクリメントする。続く処理1202にて、全ての外部発火オペレータを、トラバーススタック1340にプッシュする。図8A、B、Cの実行木に対するトラバーススタック1340は、外部発火オペレータリスト1100を参照することで、図13Aのように初期化される。続く処理1203にて、オペレータ間入出力関係表よりトラバース未達入力数表を初期化する。図8A、B、Cの実行木に対する未達入力数表は、オペレータ間入出力関係表1000の出力先オペレータIDの列に、各オペレータが登場する回数として求めることができる。結果として表1330のように初期化される。フローの処理中にオペレータをトラバースする過程で、あるオペレータの入力となるオペレータに達すると、前者のオペレータの未達入力数をデクリメントする。
続く処理1204のループを、トラバーススタック1340が空になるまで繰り返す。まず、処理1205にて、トラバーススタック1340より一つのオペレータをポップする。続く処理1206にて、該オペレータの実行順を、その時点でオペレータ番号保存領域1310に格納されている値に定め、オペレータ実行順表912に格納する。オペレータ番号1310はインクリメントし、オペレータ番号保存領域1310に再保存する。続く処理1209にて、該ポップしたオペレータの出力先となるオペレータを、図10のオペレータ間入出力関係表1000から引き、トラバース未達入力数表1330における、全ての該出力先オペレータの未達入力数をデクリメントする。このとき、未達入力数が0になったオペレータがあれば、続く処理1210にてトラバーススタックにプッシュする。以上の処理を、トラバーススタックが空になるまで繰り返す。
図13B、および図13Cは、図12のフロー処理におけるデータ構造の状態遷移を示している。図13Bの状態1350は、トラバーススタック1340からオペレータ430をポップしてから、オペレータ431までトラバースし、該オペレータの出力先であるオペレータ433の未達入力数をデクリメントする1209までを処理した状態を表している。該処理1209において、出力先433の未達入力数は0にならなかったので、トラバーススタックには積まれない。オペレータ実行順表1400は、オペレータ430,431の実行順を決定した状態となる。オペレータ番号は3までインクリメントされている。
同図の状態1351は、トラバーススタック1340からオペレータ440をポップしてから、オペレータ432までトラバースし、該オペレータの出力先であるオペレータ433の未達入力数をデクリメントし、該値が0になったのでトラバーススタック1340に積む1210までを処理した状態を表している。この過程で、オペレータ403の未達入力数も0になっているので、トラバーススタック1340に積まれている。オペレータ実行順表1400は、実行順5まで決定し、オペレータ番号は6までインクリメントされている。
図13Cの状態1352は、トラバーススタック1340からオペレータ433をポップしてから、オペレータ461までトラバースし、該オペレータの出力先であるオペレータ462の未達入力数をデクリメントする1209までを処理した状態を表している。オペレータ実行順表1400は、実行順11まで決定されている。
同図の状態1353は、トラバーススタック1340からオペレータ403をポップし、該オペレータの出力先であるオペレータ404の未達入力数が0にならないので、続いて、トラバーススタック1340からオペレータ400をポップしてから、オペレータ402までトラバースし、該オペレータの出力先であるオペレータ405の未達入力数をデクリメントする1209までを処理した状態を表している。オペレータ実行順表1400は、実行順15まで決定されている。この状態において、トラバーススタック1340に残っているオペレータ410をポップしてからの処理では、トラバース未達入力数表1330の未達入力数が全て1なので、連続してトラバースされる。
図14の表1400は、図8A、B、Cに示した実行木の例に対して、該アルゴリズムで最終的に決定されるオペレータ実行順表(図9の表912に対応)あり、実行順は図8A、B、C中の四角枠で囲む数字と同一である。
次に、図15は、図9の実行オペレータ抽出部913の動作を説明するフローチャートである。まず、処理1501にて、実行時刻をシステムタイムに初期化する。続く処理1502のループを、外部発火オペレータリスト910、および内部発火オペレータリスト911の各オペレータを対象に繰り返し、全発火オペレータを処理する。
まず、処理1503にて、そのループにおける対象オペレータが、出力すべきタプルを保持しているかをチェックする。保持していない場合は、該対象オペレータに関する処理を終了する。保持している場合は、該出力すべきタプルのタイムスタンプを発火時刻とし、続く処理1504,1505にて、その時点における実行時刻と前後を比較する。該発火時刻の方が実行時刻より遅い場合は、該対象オペレータに関する処理を終了する。該発火時刻と実行時刻が同時である場合には、処理1507にて、その時点における実行オペレータリスト915に該対象オペレータを加える。該発火時刻の方が実行時刻より早い場合は、処理1506にて、該発火時刻を新たな実行時刻とし、その時点における実行オペレータリスト915を空にして、処理1507にて、該対象オペレータのみを実行オペレータリスト915に入れる。
図16は、図15のフローに従った処理における状態遷移の様子を示す。
状態1610は、図8Bに示すシステムタイム9:13’30の実行木において、処理1501を実行した状態である。状態1611は、外部発火オペレータリスト910について、フロー実施後の状態である。出力すべきタプルを保持し、実行時刻9:13’30と同じ発火時刻を持つオペレータ440が実行オペレータリスト1601(図9のリスト915に対応)に格納される。状態1612は、内部発火オペレータリスト911について、フロー実施後の状態である。出力すべきタプルを保持するが、発火時刻が実行時刻より遅いオペレータ431は実行オペレータリスト1601に入らず、発火時刻と実行時刻が同時刻であるオペレータ463は入る。
状態1613は、図8Cに示すシステムタイム9:14’26の実行木において、処理1501を実行した状態である。状態1614は、外部発火オペレータリスト910について、フロー実施後の状態である。出力すべきタプルを保持し、元の実行時刻9:14’26より早い発火時刻9:14’25を持つオペレータ410が実行オペレータリスト1601に格納される。実行時刻は該発火時刻に更新されている。状態1612は、内部発火オペレータリスト911について、フロー実施後の状態である。オペレータ431を処理1502のループで処理すると、出力すべきタプルを保持し、元の実行時刻9:14’25より早い発火時刻9:14’24を持つので、処理1503,1504は共にYesと判定され、処理1506にてその時点の実行オペレータリスト1601がクリアされ、実行時刻が9:14’24に更新され、処理1507にて、該オペレータ431のみが実行オペレータリスト1601に残ることになる。
続いて、図17は、図9のオペレータ実行制御部916の動作を説明するフローチャートである。オペレータ実行制御部916が実行時に利用するワークエリアである、実行オペレータフラグ配列917は、オペレータグラフ上のオペレータ数と同じ要素数を持つ、真理値の配列である。なおインデクスの開始は1からとする。まず、初期化処理1701にて、実行オペレータ抽出部913の処理の結果、実行オペレータリスト1601に格納されているオペレータの、オペレータ実行順序をインデクスとする配列要素をTrue、それ以外の配列要素を全てFalseに初期化する。その後、処理1702のループを、インデクスをインクリメントしつつ全ての配列要素について繰り返す。まず、処理1703にて、配列要素がTrueか否かを判定する。Falseである場合は、そのインデクスに関する処理を終了する。Trueの場合は、処理1704にて、該インデクスの値を実行順序とするオペレータのIDを、オペレータ実行順表から取得し、該オペレータの処理を実行する。該オペレータの処理の結果、出力結果が生成されたか否かを、処理1705にて判定する。出力結果が無い場合は、該インデクスに関する処理を終了する。出力結果がある場合は、処理1706にて、出力先のオペレータに付与されたオペレータ実行順序をインデクスとする、実行オペレータフラグ配列917の配列要素をTrueにする。
図18は、図17のフローに従った処理における状態遷移の様子を示す。
状態1810は、図8Bに示すシステムタイム9:13’30の実行木において、処理1701を実施した状態である。実行オペレータリスト1601には、オペレータ440、よび463が格納され、オペレータ実行順表1400より、それぞれのオペレータ実行順序は3、および24であることが分かるので、実行オペレータフラグ配列1800の3番目と24番目の要素のみをTrueとする。状態1811は、処理1702のループにおけるインデクス4の処理1704にて、該インデクスをオペレータ実行順序に持つオペレータ441の処理を実行し、出力結果があったため、処理1706を実施した状態である。オペレータ441の出力先である、オペレータ432、および403それぞれのオペレータ実行順序である、5番目、および12番目の配列要素がTrueとなる。
状態1812は、処理1702のループにおけるインデクス8の処理1704にて、該インデクスをオペレータ実行順序に持つオペレータ435の処理を実行したところ、出力が無かった状態である。処理1702のループにおけるインデクス9,10,11の処理は、処理1703でNoと判定されるので何も実施されない。状態1813は、その後のインデクス12の処理の結果である。状態1814は、処理1702のループを全て終了した状態である。
複数のクエリを一つのクエリとみなして、実行木を構築し、データタプルの時刻情報が所定の条件を満たす場合に、実行される所定のオペレータの処理を契機として、入力タプルを構築された実行木を順に実行し、処理を完了する。
所定のオペレータ(発火オペレータ)を含む複数のオペレータ間の実行順序をあらかじめ特定し、発火オペレータの処理実行開始可否を制御し、全体の実行木の処理を管理する。ある所定の条件を満たしているか監視し、所定の条件を満たした場合は、発火オペレータが処理を開始する。開始した場合は、そのオペレータが、開始時刻に対応するタプルについて処理を行い、処理が完了後、後続のオペレータも開始時刻に対応するタプルの処理を順次開始する。それによって、実行木内のオペレータが処理する対象のデータの時刻が一致するため、障害時のトレースが容易にできる。
また、本実行制御方法で構築される実行木は、登録されている複数のクエリがそれぞれScanオペレータを先頭に有し、Storeオペレータを末尾に有するクエリである場合、それらのクエリ間で接続される場合、前のクエリの末尾のStoreオペレータと後のクエリのScanオペレータを削除し、一つのクエリとして実行木を再構築してもよい。この場合、元のクエリ間のキューを削減でき、キュー排他による性能への影響を軽減する。
以上示したように、図17のフローは配列を用いた実行制御方法である。本実施例に限らずオペレータ実行順序を守る実行制御方法として、例えば、オペレータを実行する度に、その出力先に位置するオペレータを全て記憶し、その中で最小の実行順序を持つオペレータを実行することを繰り返す方法、オペレータ実行順序を付与する対象をストリーム化演算だけに絞り、実行制御を柔軟化する方法がある。
以下では、第二の実施例として、再帰クエリの実行制御を行うストリームデータ処理システムについて説明する。
図19は、図7において、ストリーム化オペレータ626の後に、ストリームタプルのタイムスタンプを未来にずらす、遅延オペレータである遅延演算1900を挿入した様子を示している。時刻の遅延が挟まることで、ストリーム化演算の出力は、自分自身の入力に時間がずれて戻ることになるため、時刻t1におけるリレーションの増減に対し、該ストリーム化演算自身の出力が影響を持つことは無くなる。このように、再帰クエリの途中に遅延演算を挟むことによって、ストリーム化演算のデッドロックを回避し、再帰クエリを実現することが可能となる。
遅延演算1900により、最後の出力タプルのタイムスタンプが、t1より微小時間εだけ未来にずれてストリームresource_streamに戻る。該微小時間は、ウィンドウ演算NOWで定める生存期間と同じとする。個数オペレータ610の結果であるリレーションresourceにおいて、資金額の変化を反映したリレーション2520000は、時刻t1+εから始まる。ストリームmarketに対して、ウィンドウオペレータ601で与えられる生存期間は、丁度t1+εで終了するため、該リレーションとの結合は起こらず、過剰な買い注文は発生しない。
クエリに対する遅延演算の挿入は、自動であっても構わないし、明示的にクエリ定義の一部として挿入しても構わない。図20は、明示的に遅延演算を挿入したクエリの例である。クエリ2012の最後に加えた“<”と“>”で囲まれた“NOW”が、図5のクエリ512との差分であり、ストリーム化演算IStreamの結果を微小時間未来にずらすことを指定している。ずらす時間の幅は、1秒、1分などの具体値であっても構わない。このように、遅延演算は、時限発火のタプルを保持するオペレータであるので、時間ウィンドウやRStreamに次ぐ、第三の内部発火オペレータである。
図21は、図20のクエリの実行木であり、オペレータ2127として遅延演算を含んでいる。この実行木はループを含んでおり、オペレータ間の入出力関係が相互再帰になっているため、図10〜14を用いて説明したアルゴリズムでは、オペレータ実行順序を定めることができない。図21の四角枠内に示すオペレータ実行順序は、ループ上に位置しないオペレータである2100,2101,2102,2120,2121,2140,2141,2103の8個については定まるが、それ以外は定義できないことを示している。
この問題に対し、本実施例では、ループ中に存在する遅延演算を利用して、オペレータ実行順を定める方法を提供する。該方法の基本的な考え方を、図22A、Bを用いて説明する。遅延演算は、ある実行時刻における処理の終点と捉えることが可能である。理由は、該実行時刻のタイムスタンプが付いたタプルが遅延演算で処理されて出力されると、該実行時刻より未来になるため、該実行時刻における処理対象から外れるからである。このことを利用し、ループ中に含まれる遅延演算を、オペレータ実行順序の起点、および終点とすることで、ループ上での同時刻タプルの処理が実現可能となる。
図22Aの実行木2201は、図21の実行木において、遅延演算2127を、仮想的な遅延演算2200と分離している。2127は遅延演算からの出力、2200は該遅延演算への入力のみを持つオペレータである。実行木2201のグラフは、実行木2202のグラフと同型であるが、遅延演算を分離することで実行木がループを含まなくなることをより直感的に示している。ループが無くなることで、オペレータ実行順序を定義することが可能となる。最終的に、図22Bの四角枠で囲む数字で示すオペレータ実行順序が定まる。以上のように、一つの遅延演算を分離してループを持たない実行木に変換することを、遅延演算でのループの展開と呼ぶ。
なお、図21において、ストリーム化演算は2つあるため、どちらの先に遅延演算を入れても、あるいは両方に入れても構わない。但し、オペレータ2107の先だけに入ると、オペレータ2123〜2127と2110により構成されるループ中に遅延演算が存在しないことになってしまうので、オペレータ2126の後には必須である。遅延オペレータの挿入数を最小化するように、挿入位置を最適化してもよい。
続いて、第三の実施例として、より複雑なループを持つ実行木の例を、図23A、B〜図32を用いて説明する。
図23A、Bは、図20のクエリにおいて、売り注文処理も再帰クエリで定義した例である。クエリ2315は、買い注文と売り注文による保有株情報の変化をマージする。これにより、注文による保有株情報の変化を、投資行動に迅速に反映することができる。遅延演算はクエリにおいて明示的に定義している。
図24は、同クエリの実行木を示している。二つの遅延演算2427、および2457が存在する。この実行木は、オペレータ2400,2401,2402,2420,2421,2430,2431,2450,2451の9個のオペレータを除いて巨大なループを形成している。有向グラフにおいて、このように互いに到達し合う関係にあるノードの集合を強連結成分と呼ぶ。
図25Aは、該強連結成分に含まれない9個のオペレータについてオペレータ実行順を付与している。具体的には、1番目がオペレータ2430、2番目がオペレータ2431、3番目がオペレータ2450、4番目が、オペレータ2451、5番目がオペレータ2400、6番目がオペレータ2401、7番目がオペレータ2402、8番目がオペレータ2420、9番目がオペレータ2421である。各オペレータの右下の四角で囲まれた数字が、それぞれのオペレータの実行順番を示す。
図25Bは、遅延演算2457で強連結成分を展開した実行木を示している。但し、破線2501に囲まれた11個のオペレータは、なお強連結成分を形成している。該強連結成分を一つの仮想的なオペレータと捉えると、オペレータ実行順序10〜20、および32〜34については、定めることが可能である。破線2501内のオペレータには21〜31の実行順序が付く。図25Cは、該強連結成分を遅延演算2427で展開し、21〜31の実行順序を定めた様子を示している。最終的には、実行木に属する全オペレータの実行順序が、図26の四角枠で囲む数字で示すように定まる。クエリ実行時において、オペレータ2427が実行オペレータとなった場合、該オペレータを起点とするオペレータの実行は、太曲線矢印のパスに沿って進行することになる。
図27A、Bを用いて、より複雑なオペレータグラフにおいても同様に実行順序が定まることを示す。オペレータグラフ2700は、a〜nの14個のオペレータからなり、太丸は遅延演算を表す。まず、オペレータaでグラフ2700を展開することで、ネストした強連結成分2701、および2702が抽出される。該成分をそれぞれ一つの仮想的なオペレータと捉えると、オペレータa,b,l,nについて、オペレータ実行順序1,6,13,14が定まる。オペレータeで強連結成分2701を展開することで、オペレータe,c,m,dについて、オペレータ実行順序2,3,4,5が定まる。オペレータgで強連結成分2702を展開することで、ネストした強連結成分2703が抽出される。該成分を一つの仮想的なオペレータと捉えると、オペレータg,h,fについて、オペレータ実行順序7,8,12が定まる。オペレータiで強連結成分2703を展開することで、オペレータi,j,kについて、オペレータ実行順序9,10,11が定まる。最終的に、14個全オペレータの実行順序が定まる。
以上の処理において、各強連結成分を展開するために選択する遅延演算は任意で構わない。もし、各強連結成分が遅延演算を含まない場合は、クエリ定義のエラーとする、あるいは警告を出す、あるいは自動で挿入する、その何れであっても構わない。自動で挿入する場合には、遅延オペレータの挿入数を最小化するように、挿入位置、あるいは各強連結成分の分解における遅延演算の選択を最適化してもよい。
図28A、Bを用いて、オペレータ実行順序を定める図12のアルゴリズムを、ループを含む一般のオペレータグラフに適用できるよう拡張したアルゴリズムの、フローチャートを示す。
まず、処理2801にて、実行順序0番が付くダミーオペレータを一つ作成し、対象となるオペレータグラフのオペレータ間入出力関係表に、該ダミーオペレータの出力先オペレータとして全ての外部発火オペレータを登録する。また、オペレータ番号を0に初期化する。
続く処理2802にて、サブルーチン2810を呼び出す。該サブルーチンには、該ダミーオペレータを含む全てのオペレータを要素とするリストを成分オペレータリストの引数に、該ダミーオペレータをスタートノードの引数に与える。
次に、サブルーチン2810の処理を示す。まず処理2811にて、引数に与えられた成分オペレータリストの要素のみからなる、部分グラフのオペレータ間入出力関係表を作成する。該表は、実行木全体のオペレータ間入出力関係表において、該成分オペレータリストの要素に関する登録のみを抽出し、該抽出した登録の出力先オペレータ列に該リストの要素以外が登場している場合はそれを削除することで、作成することができる。続く処理2812にて、該部分グラフのオペレータ間入出力関係表の出力先に、スタートノードが登場している場合は、全て削除する。
続く処理2813にて、該部分グラフを強連結成分に分解し、成分間の入出力関係表を作成する。任意の有向グラフを互いに疎な強連結成分に分解する方法は、Tarjan によって考案された古典的アルゴリズムなどを利用して実現可能である。成分間入出力関係表には、ある強連結成分に属する一つ以上のオペレータから、別の強連結成分に属する一つ以上のオペレータに向かって入出力関係がある場合に、該前者成分の出力先成分として該後者成分を登録する。続く処理2814にて、サブルーチン2820を呼び出す。該サブルーチンには、該成分間入出力関係を成分間入出力関係表の引数に、該スタートノードをスタートノードの引数に与える。
次に、サブルーチン2820の処理を示す。サブルーチン2820のフローは、図12に示したフローと類似している。トラバースするグラフにおける個々のノードが、単一のオペレータのみでなく、複数のオペレータから構成される強連結成分である点が異なる。特に、単一のオペレータも強連結成分の一種である。
まず、処理2821にて、スタートノードを、トラバーススタックにプッシュする。続く処理2822にて、引数に与えられた成分間入出力関係表よりトラバース未達入力数表を初期化する。フローの処理中に成分をトラバースする過程で、ある成分の入力となる成分に達すると、前者の成分の未達入力数をデクリメントする。
続く処理2823のループを、トラバーススタックが空になるまで繰り返す。まず、処理2824にて、トラバーススタックより一つの成分をポップする。続く処理2825にて、該ポップした成分が単一のオペレータである場合は、処理2826にて、該オペレータの実行順を、その時点のオペレータ番号の値に定め、オペレータ実行順表に格納する。オペレータ番号はインクリメントする。処理2825にて、該ポップした成分が複数のオペレータからなる強連結成分である場合は、処理2827にて、該成分に属するオペレータのうち遅延演算を一つ選択し、続く処理2828にて、サブルーチン2810を呼び出す。該サブルーチンには、該成分に属する全オペレータのリストを成分オペレータリストの引数に、処理2827にて選択した該遅延演算をスタートノードの引数に与える。続く処理2829にて、該ポップした成分の出力先となる成分を、成分間入出力関係表から引き、トラバース未達入力数表における、全ての該出力先成分の未達入力数をデクリメントする。このとき、未達入力数が0になった成分があれば、続く処理2830にてトラバーススタックにプッシュする。以上の処理を、トラバーススタックが空になるまで繰り返す。
つまり、(3−1)ストリームデータ処理システム900は、複数のオペレータで構成されるオペレータグラフをそれぞれノードに展開し、tree構造から一以上のオペレータにより閉路(再帰)になっている箇所をコンポーネント化する。図25や図26中の強連結成分や部分グラフが、コンポーネントやサブコンポーネントに対応し、仮想的なオペレータである。(3−2)次に、ストリームデータ処理システム900は、生成したコンポーネント単位で、コンポーネント間の入出力関係を特定する。(3−3)ストリームデータ処理システム900は、特定された入出力関係で、コンポーネントごとの実行順序を定義する。(3−4)ストリームデータ処理システム900は、各コンポーネントに対してオペレータが複数含むかを判断し、複数含む場合は、データタプルの入力遅延を設定するDelayStreamを構成するオペレータを閉路に追加する。(3−5)さらにストリームデータ処理システム900は、各コンポーネント内(閉路部分)のノードを新たなサブコンポーネントとして再展開し、同様の(3−2)ないし(3−4)の処理を繰り返す。
次に、図29〜32を用いて、図24のオペレータグラフを図28のフローで処理した場合の動作を例示する。
図29の表2900は、図24のオペレータグラフにおけるオペレータ間入出力関係表である。処理2801によってダミーオペレータも登録されている。
図30A〜Gは、図28に示したアルゴリズムの処理における、データ構造の状態遷移を表している。
図30Aは、サブルーチン2820の初回の呼び出しにおいて、処理2823のループに入る前の状態を示している。表3020は、引数に与えられる成分間入出力関係表である。成分ID3000は、リスト3001に示したオペレータから構成される強連結成分である。それ以外は、単一のオペレータであり、成分IDはオペレータIDと一致する。成分(オペレータ)2402,2421,2431,2451については、それぞれの出力先オペレータ2405,2425,2433,2453が、リスト3001に含まれているので、該表における出力先成分は3000となる。
表3030は、処理2822によって作成されるトラバース未達入力数表である。ある成分IDの未達入力数は、表3020の出力先成分に該成分IDが登場する回数となる。オペレータ番号保存領域3010に格納されたオペレータ番号は、この時点では処理2801にて0に初期化されたままである。トラバーススタック3040には、処理2821にて、スタートノード引数に与えられたダミーオペレータがプッシュされる。
図30Bは、サブルーチン2820の初回の呼び出しにおいて、処理2823のループ処理中の状態遷移を示している。
状態3050は、処理2824にてダミーオペレータをトラバーススタック3040からポップし、続く処理2825にてオペレータと判断され、続く処理2826にて、オペレータ番号0を該ダミーオペレータに付与してオペレータ実行順表3100に格納し、オペレータ番号をインクリメントし、続く処理2829にて、成分間入出力関係表3020において出力先成分に登録されている成分2400,2420,2430,2450について、トラバース未達入力数表3030の値をデクリメントし、続く処理2830にて、該表3030の未達入力数が0になった成分2400,2420,2430,2450をトラバーススタックにプッシュした状態を示している。
状態3051は、トラバーススタック3040から成分2430をポップしてから、成分2431までトラバースし、該成分の出力先である成分3000の未達入力数をデクリメントする2829までを処理した状態を表している。該処理2829において、出力先3000の未達入力数は0にならなかったので、トラバーススタックには積まれない。オペレータ実行順表3100は、オペレータ2430,2431の実行順を決定した状態となる。オペレータ番号は3までインクリメントされている。
状態3052は、トラバーススタック3040に積まれている全ての成分2450,2400,2420について処理が終了し、成分3000の未達入力数が0になったので、トラバーススタックにプッシュされた状態を表している。オペレータ実行順序は9まで決定し、オペレータ実行順表3100に格納され、オペレータ番号は10までインクリメントされている。
この後、続く処理2823のループでは、処理2824にて成分3000をトラバーススタック3040からポップし、続く処理2825にて該成分がNoと判断され、続く処理2827にて成分3000に属するオペレータから一つの遅延演算2457を選択し、続く処理2828にて、成分3000に属するオペレータのリスト3001を成分オペレータリストの引数に、該遅延演算2457をスタートノードの引数に与えて、サブルーチン2810を呼ぶ。
該サブルーチン呼び出しの処理では、処理2811にて、引数に与えられた成分オペレータリスト(この場合、リスト3001)の要素であるオペレータのみで構成される、部分グラフのオペレータ間入出力関係表を作成する。
図30Cに示す表2901が、該作成された表である。続く処理2812にて、引数に与えられたスタートノードである遅延演算2457が、表2901においてオペレータ2456の出力先に含まれているので、削除する。続く処理2813にて、図30Dに示す成分間入出力関係表3021を作成する。続く処理2814にて、該表を成分間入出力関係表の引数に、遅延演算2457をスタートノードの引数に与えて、サブルーチン2820を呼び出す。
図30Dは、該サブルーチン呼び出しにおいて、処理2822までを実行した状態を表す。図30Eに示す状態3053は、トラバーススタック3041から成分2457をポップし、成分2453までトラバースし、該オペレータの出力先であるオペレータ2455の未達入力数をデクリメントした状態を表している。この過程で、オペレータ2403の未達入力数も0になっているので、トラバーススタック3041に積まれている。オペレータ実行順表3100は、実行順19まで決定している。
状態3054は、トラバーススタック3041から成分2403をポップし、処理2826まで処理し、処理2829にて該成分の出力先である成分3002の未達入力数をデクリメントし、該値が0になったので、処理2830にて成分3002をトラバーススタック3041にプッシュした状態を表している。
この後、続く処理2823のループでは、処理2824にて成分3002をトラバーススタック3041からポップし、続く処理2825にて該成分がNoと判断され、続く処理2827にて成分3002に属するオペレータから一つの遅延演算2427を選択し、続く処理2828にて、成分3002に属するオペレータのリスト3003を成分オペレータリストの引数に、該遅延演算2427をスタートノードの引数に与えて、サブルーチン2810を呼ぶ。
該サブルーチン呼び出しの処理では、処理2811にて、引数に与えられた成分オペレータリスト(この場合、リスト3003)の要素であるオペレータのみで構成される、部分グラフのオペレータ間入出力関係表を作成する。図30Fに示す表2902が、該作成された表である。続く処理2812にて、引数に与えられたスタートノードである遅延演算2427が、表2902においてオペレータ2426の出力先に含まれているので、削除する。続く処理2813にて、成分間入出力関係表3022を作成する。続く処理2814にて、該表を成分間入出力関係表の引数に、遅延演算2427をスタートノードの引数に与えて、サブルーチン2820を呼び出す。
図30Fは、該サブルーチン呼び出しにおいて、処理2822までを実行した状態を表す。状態3055は、トラバーススタック3042から成分2427をポップして、成分2426までトラバースし、全ての成分のオペレータ実行順序が決定され、トラバーススタック3042が空になった状態を表す。オペレータ実行順表3100は、実行順31まで決定している。
サブルーチン2820の処理は以上で終了し、呼び出し元の処理2814に返る。サブルーチン2810の処理は以上で終了し、呼び出し元の処理2828に返る。続く処理2829にて、成分3002の出力先である成分2454の未達入力数をデクリメントすると0になるので、続く処理2830にて該成分をトラバーススタック3041にプッシュする。図30Gに示す状態3056は、ここまでの処理が完了した状態を表す。
状態3057は、トラバーススタック3041から成分2454をポップして、成分2456までトラバースし、全ての成分のオペレータ実行順序が決定され、トラバーススタック3041が空になった状態を表す。
サブルーチン2820の処理は以上で終了し、呼び出し元の処理2814に返る。サブルーチン2810の処理は以上で終了し、呼び出し元の処理2828に返る。成分間入出力関係表3020において、成分3000の出力先成分は存在しないので、続く処理2829,2830は何も実行されない。この時点で、トラバーススタック3040は空になる。
サブルーチン2820の処理は以上で終了し、呼び出し元の処理2814に返る。サブルーチン2810の処理は以上で終了し、呼び出し元の処理2802に返る。続く処理2803にて、オペレータ間入出力関係表、およびオペレータ実行順表から、ダミーオペレータについての登録を削除する。以上で、該フローチャートの処理が完了する。
図31の表3100は、図24に示した実行木の例に対して、該アルゴリズムで最終的に決定されるオペレータ実行順表である。
また、図32は、図24に示した実行木における、発火オペレータのIDをリストで表している。3200は外部発火オペレータリスト、3201は内部発火オペレータリストである。内部発火オペレータリストには、遅延演算である2427、および2457が含まれる。
以上説明した、ループを含むオペレータグラフに対するオペレータ実行順序の決定アルゴリズムは、ループを含まないオペレータグラフにも適用できることは明らかである。図28のフローチャートで示したアルゴリズムは、図12のフローチャートで示したアルゴリズムの一般化である。
なお、クエリ実行時に動作する図15、および図17に示したフローチャートは、再帰クエリと非再帰のクエリに共通して適用可能である。
以上詳述した本発明のストリームデータ処理におけるオペレータ実行制御方法により、低レイテンシのデータ処理を実現することが可能である。特に、再帰クエリを含む一般のクエリに適用可能である。また、数々の実施例に基づき具体的に説明したが、本発明はこれらの実施例に限定されるものではなく、その要旨を逸脱しない範囲で種々変更可能であることはいうまでもない。
本発明は、自動株取引、交通情報解析、製造機器の制御、クリックストリーム解析といった、安定した低レイテンシでのデータ解析が必要となる技術において、株取引における株価、あるいは交通情報処理における車間距離といった外部情報のみならず、資金額の変化、車両位置の変化といった、内部状態の変化も、解析処理の対象として迅速に反映する必要がある場合の、データ解析技術に適している。