Mercurial > hg > Papers > 2017 > tatsuki-master
comparison jungle.tex @ 15:33d8077a5d45
commit
author | tatsuki |
---|---|
date | Thu, 09 Feb 2017 17:25:56 +0900 |
parents | e4da23b04260 |
children | d5306971efbf |
comparison
equal
deleted
inserted
replaced
14:e4da23b04260 | 15:33d8077a5d45 |
---|---|
1 \chapter{非破壊的木構造データベースJungle} | 1 \chapter{非破壊的木構造データベースJungle} |
2 本章では、当研究室で開発を行っているデータベース Jungle について記述する。 | 2 本章では、Jungleの基本的な解説を行う。 |
3 | 3 初めに Jungle の特徴である非破壊的木構造の説明をし、その後提供しているAPIについて述べる。 |
4 \section{概要} | 4 |
5 Jungleは、当研究室で開発を行っているデータベースで、Javaを用いて実装されている。 | |
6 Jungleは名前付きの複数の木の集合からなり、木は複数のノードの集合で出来ている。 | |
7 ノードは自身の子のリストと属性名と属性値の組でデータを持ち、データベースのレコードに相当する。 | |
8 通常のレコードと異なるのは、ノードに子供となる複数のノードが付くところである。 | |
9 Jungleでは、親から子への片方向の参照しか持たない。 | |
10 | |
11 通常のRDBと異なり、Jungleは木構造をそのまま読み込むことができる。例えば、XMLやJsonで記述された構造を、データベースを設計することなく読み込むことが可能である。 | |
12 また、この木を、そのままデータベースとして使用することも可能である。しかし、木の変更の手間は木の構造に依存する。 | |
13 %特に非破壊木構造を採用しているJungleでは木構造の変更にo(1)からo(n)の様々な選択肢がある。つまり、アプリケーションに合わせて木を設計しない限り、 | |
14 特に非破壊木構造を採用しているJungleでは、木構造の変更の手間はO(1)からO(n)となりえる。つまり、アプリケーションに合わせて木を設計しない限り、 | |
15 十分な性能を出すことはできない。逆に、正しい木の設計を行えば高速な処理が可能である。 | |
16 | |
17 Jungleは基本的にon memoryで使用することを考えており、一度、木のルートを取得すれば、その上で木構造として自由にアクセスして良い。 | |
18 Jungleは分散データベースを構成するように設計されており、分散ノード間の通信は木の変更のログを交換することによって行われる。 | |
19 持続性のある分散ノードを用いることでJungleの持続性を保証することができる。本論文では基本的に分散実装部分ではなく on memory DBの | |
20 部分について考察する。 | |
21 本章ではまず破壊的木構造と、非破壊的木構造の説明をし、その後Jungleの提供しているAPIについて述べる。 | |
22 | |
23 \newpage | |
24 | 5 |
25 \section{非破壊的木構造} | 6 \section{非破壊的木構造} |
26 Jungle は、非破壊的木構造という特殊な木構造を持つ。 | 7 Jungle は、非破壊的木構造という特殊な木構造を持つ。 |
27 本節では、初めに破壊的木構造と非破壊的木構造の編集・メリットデメリットについて記述する。 | 8 本節では、破壊的木構造と非破壊的木構造の編集・メリットデメリットについて記述する。 |
28 | 9 |
29 \vspace{0.3in} | 10 \vspace{0.3in} |
30 {\Large 破壊的木構造の編集} | 11 {\Large 破壊的木構造の編集} |
31 | 12 |
32 \vspace{0.1in} | 13 \vspace{0.1in} |
59 \caption{非破壊的木構造の編集} | 40 \caption{非破壊的木構造の編集} |
60 \label{fig:nondestractive} | 41 \label{fig:nondestractive} |
61 \end{center} | 42 \end{center} |
62 \end{figure} | 43 \end{figure} |
63 | 44 |
64 \newpage | |
65 非破壊的木構造においてデータのロックが必要となる部分は、木のコピーを作り終えた後に | 45 非破壊的木構造においてデータのロックが必要となる部分は、木のコピーを作り終えた後に |
66 ルートノードを更新するときだけである。 | 46 ルートノードを更新するときだけである。 |
67 データ編集を行っている間ロックが必要な破壊的木構造に比べ、編集中においてもデータの読み込みが可能であるが、 | 47 データ編集を行っている間ロックが必要な破壊的木構造に比べ、編集中においてもデータの読み込みが可能であるが、 |
68 書き込み時の手間は大きくなる。 | 48 書き込み時の手間は大きくなる。 |
69 | 49 |
101 以下にEitherクラスが提供しているAPI(表\ref{EitherAPI})を記す。 | 81 以下にEitherクラスが提供しているAPI(表\ref{EitherAPI})を記す。 |
102 \begin{table}[htb] | 82 \begin{table}[htb] |
103 \begin{center} | 83 \begin{center} |
104 \caption{Eitherに実装されているAPI} | 84 \caption{Eitherに実装されているAPI} |
105 \begin{tabular}{|p{15em}|p{24em}|} \hline | 85 \begin{tabular}{|p{15em}|p{24em}|} \hline |
106 {\tt boolean isA()} & EitherがAを持っているかどうかを調べる。持っている場合trueを返す。\\ \hline | 86 {\small{\tt boolean isA()}} & {\small EitherがAを持っているかどうかを調べる。持っている場合trueを返す。}\\ \hline |
107 {\tt boolean isB()} & EitherがBを持っているかどうかを調べる。持っている場合trueを返す。\\ \hline | 87 {\small{\tt boolean isB()}} & {\small EitherがBを持っているかどうかを調べる。持っている場合trueを返す。}\\ \hline |
108 {\tt A a()} & Aの値を取得する。\\ \hline | 88 {\small{\tt A a()}} &{\small Aの値を取得する。}\\ \hline |
109 {\tt B b()} & Bの値を取得する。\\ \hline | 89 {\small{\tt B b()}} &{\small Bの値を取得する。}\\ \hline |
110 \end{tabular} | 90 \end{tabular} |
111 \label{EitherAPI} | 91 \label{EitherAPI} |
112 \end{center} | 92 \end{center} |
113 \end{table} | 93 \end{table} |
114 | 94 |
123 | 103 |
124 \begin{table}[htb] | 104 \begin{table}[htb] |
125 \begin{center} | 105 \begin{center} |
126 \caption{Jungleに実装されているAPI} | 106 \caption{Jungleに実装されているAPI} |
127 \begin{tabular}{|p{15em}|p{24em}|} \hline | 107 \begin{tabular}{|p{15em}|p{24em}|} \hline |
128 {\tt JungleTree createNewTree(String treeName) } & Jungleに新しく木を生成する。木の名前が重複した場合、生成に失敗しnullを返す。 \\ \hline | 108 {\small {\tt JungleTree createNewTree(String treeName)}} &{\small Jungleに新しく木を生成する。木の名前が重複した場合、生成に失敗しnullを返す。} \\ \hline |
129 {\tt JungleTree getTreeByName(String treeName)} & JungleからtreeNameと名前が一致するtreeを取得する。名前が一致するTreeがない場合取得は失敗しnullを返す \\ \hline | 109 {\small {\tt JungleTree getTreeByName(String treeName)}} &{\small JungleからtreeNameと名前が一致するtreeを取得する。名前が一致するTreeがない場合取得は失敗しnullを返す。} \\ \hline |
130 \end{tabular} | 110 \end{tabular} |
131 \label{jungleAPI} | 111 \label{jungleAPI} |
132 \end{center} | 112 \end{center} |
133 \end{table} | 113 \end{table} |
134 | 114 |
135 | 115 |
136 \section{JungleTree} | 116 \section{JungleTree} |
137 Jungleは複数の木の集合で出来ている。 | 117 Jungleは複数の木の集合で出来ている。 |
138 Jungleの木は、変更を加えるためのEditor・検索を行うTraversreなどを保持しており、ユーザーはそれらを用いてデータにアクセスする。 | 118 Jungleの木は、自身の情報をTreeContext というオブジェクトに保持している。 |
139 過去のバージョンの木に対するアクセスや、特定のノードのPathを検索する機能も持っている。 | 119 TreeContextとは、木構造のデータ(表\ref{TreeContext1})を持つクラスである。 |
120 | |
121 \newpage | |
122 \begin{table}[htb] | |
123 \begin{center} | |
124 \caption{TreeContextが保持している値} | |
125 \begin{tabular}{|l|} \hline | |
126 {\tt } 自身のルートノード\\ \hline | |
127 {\tt } 1つ前のバージョンのTreeContext\\ \hline | |
128 {\tt } 編集のログ\\ \hline | |
129 {\tt } 木のuuid \\ \hline | |
130 {\tt } 木の名前 \\ \hline | |
131 {\tt } 木のversion \\ \hline | |
132 {\tt } 木の検索に使うTraverser \\ \hline | |
133 \end{tabular} | |
134 \label{TreeContext1} | |
135 \end{center} | |
136 \end{table} | |
137 | |
138 Jungle の木は、自身の木構造に編集を行う Editor や 検索に使用する Traverser を提供しており、ユーザーはそれを用いて木構造にアクセスする。 | |
139 また、過去のバージョンの木に対するアクセスや、特定のノードのPathを検索する機能も持っている。 | |
140 以下にJungleTreeクラスが提供しているAPI(表\ref{JungleTreeAPI})を記す | 140 以下にJungleTreeクラスが提供しているAPI(表\ref{JungleTreeAPI})を記す |
141 \begin{table}[htb] | 141 \begin{table}[htb] |
142 \begin{center} | 142 \begin{center} |
143 \caption{JungleTreeに実装されているAPI} | 143 \caption{JungleTreeに実装されているAPI} |
144 \begin{tabular}{|p{15em}|p{24em}|} \hline | 144 \begin{tabular}{|p{15em}|p{24em}|} \hline |
145 {\tt TreeNode getRootNode()} &木のルートノードを取得する。 \\ \hline | 145 {\small {\tt TreeNode getRootNode()}} &{\small 木のルートノードを取得する。} \\ \hline |
146 {\tt long revision()} & 木のバーションを取得する。初めは0から始まり、木への変更がCommitされる度に1上昇する。 \\ \hline | 146 {\small {\tt long revision()}} & {\small 木のバーションを取得する。初めは0から始まり、木への変更がCommitされる度に1上昇する。} \\ \hline |
147 {\tt JungleTreeEditor getJungleTreeEditor()} & 木へ変更を加えるEditorを取得する。\\ \hline | 147 {\small {\tt JungleTreeEditor getJungleTreeEditor()}} &{\small 木へ変更を加えるEditorを取得する。}\\ \hline |
148 {\tt Either<Error, JungleTree> getOldTree(long revision)} & 引数で指定したint revisionに等しいバージョンの木を取得する。 \\ \hline | 148 {\small {\tt Either<Error, JungleTree> getOldTree(long revision)}} & {\small 引数で指定したint revisionに等しいバージョンの木を取得する。} \\ \hline |
149 {\tt InterfaceTraverser getTraverser()} & 木の検索を行うTraverserを取得する。 \\ \hline | 149 {\small {\tt InterfaceTraverser getTraverser()}} & {\small 木の検索を行うTraverserを取得する。} \\ \hline |
150 {\tt Either<Error, TreeNode> getNodeOfPath(NodePath path)} & {\tt NodePathで指定した位置と値なるノードを取得する。} \\ \hline | 150 {\small {\tt Either<Error, TreeNode> getNodeOfPath(NodePath path)}} &{\small {\tt NodePathで指定した位置と値なるノードを取得する。}} \\ \hline |
151 {\tt NodePath getNodePath(TreeNode node)} & 引数で渡したノードの位置を表す{\tt NodePath}を返す。\\ \hline | 151 {\small {\tt NodePath getNodePath(TreeNode node)}} & {\small 引数で渡したノードの位置を表す{\tt NodePath}を返す。}\\ \hline |
152 \end{tabular} | 152 \end{tabular} |
153 \label{JungleTreeAPI} | 153 \label{JungleTreeAPI} |
154 \end{center} | 154 \end{center} |
155 \end{table} | 155 \end{table} |
156 | 156 |
162 | 162 |
163 \begin{table}[htb] | 163 \begin{table}[htb] |
164 \begin{center} | 164 \begin{center} |
165 \caption{TreeNodeに実装されているAPI} | 165 \caption{TreeNodeに実装されているAPI} |
166 \begin{tabular}{|p{15em}|p{24em}|} \hline | 166 \begin{tabular}{|p{15em}|p{24em}|} \hline |
167 {\tt Children getChildren()} & ノードの子供を扱うChildrenオブジェクトを返す。\\ \hline | 167 {\small {\tt Children getChildren()}} &{\small ノードの子供を扱うChildrenオブジェクトを返す} \\ \hline |
168 {\tt Attribute getAttribute()} &ノードが保持しているデータを扱うAttribteオブジェクトを返す。 \\ \hline | 168 {\small {\tt Attribute getAttribute()}} &{\small ノードが保持しているデータを扱うAttribteオブジェクトを返す。} \\ \hline |
169 \end{tabular} | 169 \end{tabular} |
170 \label{TreeNodeAPI} | 170 \label{TreeNodeAPI} |
171 \end{center} | 171 \end{center} |
172 \end{table} | 172 \end{table} |
173 | 173 |
175 これらを利用しノードが保持している値や、子供にアクセスする。 | 175 これらを利用しノードが保持している値や、子供にアクセスする。 |
176 \begin{table}[htbH] | 176 \begin{table}[htbH] |
177 \begin{center} | 177 \begin{center} |
178 \caption{Childrenに実装されているAPI} | 178 \caption{Childrenに実装されているAPI} |
179 \begin{tabular}{|p{15em}|p{24em}|} \hline | 179 \begin{tabular}{|p{15em}|p{24em}|} \hline |
180 {\tt int size()} & 子供の数を返す。\\ \hline | 180 {\small{\tt int size()}} & {\small 子供の数を返す。}\\ \hline |
181 {\tt <Either Error,TreeNode> at(int num)} &ノードが持つ子供の中から、 変数{\tt num}で指定された位置にある子ノードを返す。存在しない位置を指定した場合、{\tt Error} を返す。 \\ \hline | 181 {\small{\tt <Either Error,TreeNode> at(int num)}} &{\small ノードが持つ子供の中から、 変数{\tt num}で指定された位置にある子ノードを返す。存在しない位置を指定した場合、{\tt Error} を返す。} \\ \hline |
182 \end{tabular} | 182 \end{tabular} |
183 \label{Children} | 183 \label{Children} |
184 \end{center} | 184 \end{center} |
185 \end{table} | 185 \end{table} |
186 | 186 |
188 | 188 |
189 \begin{table}[htbH] | 189 \begin{table}[htbH] |
190 \begin{center} | 190 \begin{center} |
191 \caption{Attributeに実装されているAPI} | 191 \caption{Attributeに実装されているAPI} |
192 \begin{tabular}{|p{15em}|p{24em}|} \hline | 192 \begin{tabular}{|p{15em}|p{24em}|} \hline |
193 {\tt ByteBuffer get(String key)} &ノードが持つ値から、属性名 {\tt key}とペアの属性値を{\tt ByteBuffer}型で返す。ノードが保持していない{\tt key}を渡した場合エラーを返す。 \\ \hline | 193 {\small{\tt ByteBuffer get(String key)}} &{\small ノードが持つ値から、属性名 {\tt key}とペアの属性値を{\tt ByteBuffer}型で返す。ノードが保持していない{\tt key}を渡した場合エラーを返す。} \\ \hline |
194 {\tt String getString(String key)} &ノードが持つ値から、属性名 {\tt key} とペアの属性値を{\tt String}型で返す。ノードが保持していない{\tt key}を渡した場合エラーを返す。 \\ \hline | 194 {\small{\tt String getString(String key)}} &{\small ノードが持つ値から、属性名 {\tt key} とペアの属性値を{\tt String}型で返す。ノードが保持していない{\tt key}を渡した場合エラーを返す。} \\ \hline |
195 \end{tabular} | 195 \end{tabular} |
196 \label{Attribute} | 196 \label{Attribute} |
197 \end{center} | 197 \end{center} |
198 \end{table} | 198 \end{table} |
199 | 199 |
210 Attribute attribute = child.getAttribute(); | 210 Attribute attribute = child.getAttribute(); |
211 String value = attribute.getString("name"); | 211 String value = attribute.getString("name"); |
212 \end{lstlisting} | 212 \end{lstlisting} |
213 | 213 |
214 ソースコード\ref{getAttributeCode}の説明を行う。 | 214 ソースコード\ref{getAttributeCode}の説明を行う。 |
215 1行目から2行目で | 215 |
216 1行目で Jungle から木を取得し、 | |
217 2行目で、取得した木のルートノードを取得している。 | |
218 3 - 7行目でルートノードの1番目の子ノードを取得し、 | |
219 8 - 9行目で、ルートの1番目の子ノードから、属性名 "name" とペアの属性値を取得している。 | |
216 | 220 |
217 \section{木の編集API} | 221 \section{木の編集API} |
218 Jungleの木の編集は{\tt Default Jungle Tree Editor}クラスを用いて行われる。 | 222 Jungleの木の編集は{\tt Default Jungle Tree Editor}クラスを用いて行われる。 |
219 {\tt Default Jungle Tree Editor}クラスは、木に対する編集を行うAPIが定義されているJungle Tree Editorインターフェースを実装している。 | 223 {\tt Default Jungle Tree Editor}クラスは、木に対する編集を行うAPIが定義されているJungle Tree Editorインターフェースを実装している。 |
220 Default Jungle Tree Editorは、Jungle Tree から、{\tt getTreeEditor()}を用いて取得する。 | 224 Default Jungle Tree Editorは、Jungle Tree から、{\tt getTreeEditor()}を用いて取得する。 |
221 表\ref{editor}にJungle Tree Editorインターフェースに定義されているAPIを記述する。 | 225 表\ref{editor}にJungle Tree Editorインターフェースに定義されているAPIを記述する。 |
222 また、表\ref{editor}に記述しているAPIは全て、{\tt Either<Error,JungleTreeEditor>} を返す。 | 226 また、表\ref{editor}に記述しているAPIは全て、{\tt Either<Error,JungleTreeEditor>} を返す。 |
223 \newpage | |
224 | 227 |
225 \begin{table}[htb] | 228 \begin{table}[htb] |
226 \begin{center} | 229 \begin{center} |
227 \caption{Editorに実装されているAPI} | 230 \caption{Editorに実装されているAPI} |
228 \begin{tabular*}{\textwidth}{|p{15em}|p{22em}|} \hline | 231 \begin{tabular*}{\textwidth}{|p{15em}|p{22em}|} \hline |
229 {\small\tt addNewChildAt( NodePath path, int pos)} & | 232 {\small\tt addNewChildAt( NodePath path, int pos)} & |
230 {\tt path}で指定したノードの{\tt pos}番目の子の後にノードを追加する。\\ \hline | 233 {\small\tt path}で指定したノードの{\tt pos}番目の子の後にノードを追加する。\\ \hline |
231 {\small\tt deleteChildAt( NodePath path,int pos)} & | 234 {\small\tt deleteChildAt( NodePath path,int pos)} & |
232 {\tt path}で指定したノードの{\tt pos}番目の子ノードを削除する。 \\ \hline | 235 {\small\tt path}で指定したノードの{\tt pos}番目の子ノードを削除する。 \\ \hline |
233 {\small\tt putAttribute( NodePath path,String key,ByteBuffer value)} & | 236 {\small\tt putAttribute( NodePath path,String key,ByteBuffer value)} & |
234 {\tt path}で指定したノードに属性名 {\tt key} 属性値 {\tt value} のペアで値を挿入する。 \\ \hline | 237 {\small\tt path}で指定したノードに属性名 {\tt key} 属性値 {\tt value} のペアで値を挿入する。 \\ \hline |
235 {\small\tt deleteAttribute( NodePath path,String key)}& | 238 {\small\tt deleteAttribute( NodePath path,String key)}& |
236 {\tt path}で指定したノードが持つ、属性名 {\tt key}とペアで保存されている属性値を削除する。\\ \hline | 239 {\small\tt path}で指定したノードが持つ、属性名 {\tt key}とペアで保存されている属性値を削除する。\\ \hline |
237 {\small\tt moveChild( NodePath path,int num,String move)} & | 240 {\small\tt moveChild( NodePath path,int num,String move)} & |
238 {\tt path}で指定したノードの{\tt num}番目の子供を{\tt move}の方向に移動させる。 \\ \hline %あとで直す | 241 {\small\tt path}で指定したノードの{\tt num}番目の子供を{\tt move}の方向に移動させる。 \\ \hline %あとで直す |
239 {\small\tt pushPop()} & | 242 {\small\tt pushPop()} & |
240 ルートノードの上に新しいルートノードを追加する。線形の木を作る際に使用することで木の変更の手間をO(n)からO(1)にできる。\\ \hline | 243 ルートノードの上に新しいルートノードを追加する。線形の木を作る際に使用することで木の変更の手間をO(n)からO(1)にできる。\\ \hline |
241 {\small\tt success()} & | 244 {\small\tt success()} & |
242 木へ行った変更をコミットする。自分が編集を行っていた間に、他のJungleTreeEditorクラスによって木が更新されていた場合、コミットは失敗する。 \\ \hline | 245 木へ行った変更をコミットする。自分が編集を行っていた間に、他のJungleTreeEditorクラスによって木が更新されていた場合、コミットは失敗する。 \\ \hline |
243 \end{tabular*} | 246 \end{tabular*} |
245 \end{center} | 248 \end{center} |
246 \end{table} | 249 \end{table} |
247 | 250 |
248 | 251 |
249 | 252 |
250 編集後に返される{\tt JungleTreeEditor}クラスは、編集後の木構造を保持しているため、編集前の木構造を保持している{\tt JungleTreeEditor}クラスとは別のオブジェクトである。 | 253 編集後に返される{\tt Default Jungle Tree Editor}クラスは、編集後の木構造を保持しているため、編集前の木構造を保持している{\tt Default Jungle Tree Editor}クラスとは別のオブジェクトである。 |
251 編集を行った後は、関数{\tt editor.success()}で今までの編集をコミットすることができる。他の{\tt JungleTreeEditor}クラスによって木が更新されていた場合はコミットは失敗し、{\tt success()}は{\tt Error}を返す。 | 254 編集を行った後は、関数{\tt editor.success()}で今までの編集をコミットすることができる。他の{\tt Default Jungle Tree Editor}クラスによって木が更新されていた場合はコミットは失敗し、{\tt success()}は{\tt Error}を返す。 |
252 その場合は、木の編集を最初からやり直す必要がある。 | 255 その場合は、木の編集を最初からやり直す必要がある。 |
253 | 256 |
254 以下に{\tt JungleTreeEditor}クラスを用いて、木の編集を行うサンプルコードを記述する。 | 257 以下に{\tt JungleTreeEditor}クラスを用いて、木の編集を行うサンプルコードを記述する。 |
255 | |
256 \newpage | |
257 | 258 |
258 \begin{lstlisting}[frame=lrbt,numbers=left,label=editorCode] | 259 \begin{lstlisting}[frame=lrbt,numbers=left,label=editorCode] |
259 JungleTreeEditor editor = tree.getTreeEditor(); | 260 JungleTreeEditor editor = tree.getTreeEditor(); |
260 DefaultNodePath editNodePath = new DefaultNodePath(); | 261 DefaultNodePath editNodePath = new DefaultNodePath(); |
261 Either<Error, JungleTreeEditor> either = editor.addNewChildAt(editNodePath, 0); | 262 Either<Error, JungleTreeEditor> either = editor.addNewChildAt(editNodePath, 0); |
263 return either.a(); | 264 return either.a(); |
264 editor = either.b(); | 265 editor = either.b(); |
265 editor.success(); | 266 editor.success(); |
266 \end{lstlisting} | 267 \end{lstlisting} |
267 | 268 |
269 1行目で、木から Editor を取得している。 | |
270 2行目で、編集を行うノードの Path を作成している。Default Node Path は、生成時はルートノードを指しているため、今回はルートノードに対する変更であることがわかる。 | |
271 3行目で、実際にルートノードに対して、子ノードの追加を行っている。 | |
272 4行目以降で、編集が成功したかどうかを {\tt Either }を使って確かめ、成功していた場合7行目で変更を木に Commit している。 | |
273 | |
274 \begin{comment} | |
268 \begin{enumerate} | 275 \begin{enumerate} |
269 \item 関数{\tt tree.getEditor()}で編集を行う木から、{\tt JungleTreeEditor}クラスを取得する。 | 276 \item 関数{\tt tree.getEditor()}で編集を行う木から、{\tt JungleTreeEditor}クラスを取得する。 |
270 \item 次に変更するノードの場所を示す、{\tt NodePath}クラスを作成する。 | 277 \item 次に変更するノードの場所を示す、{\tt NodePath}クラスを作成する。 |
271 \item 関数{\tt editor.addNewChildAt()}を用いて、変数{\tt path}で指定したノードの子供の0番目に子ノードを追加する。 | 278 \item 関数{\tt editor.addNewChildAt()}を用いて、変数{\tt path}で指定したノードの子供の0番目に子ノードを追加する。 |
272 \item 返り値の変数{\tt either}が{\tt Error}クラスを保持していないか(編集に失敗していないか)を確認する。 | 279 \item 返り値の変数{\tt either}が{\tt Error}クラスを保持していないか(編集に失敗していないか)を確認する。 |
273 \item {\tt Error}クラスを保持していた場合{\tt Either.a()}でErrorを返す。 | 280 \item {\tt Error}クラスを保持していた場合{\tt Either.a()}でErrorを返す。 |
274 \item 編集に成功していた場合、編集後木を持った、{\tt JungleTreeEditor}クラスを取得する。 | 281 \item 編集に成功していた場合、編集後木を持った、{\tt JungleTreeEditor}クラスを取得する。 |
275 \item 取得した{\tt JungleTreeEditor}クラスを用いて木の変更をコミットする。 | 282 \item 取得した{\tt JungleTreeEditor}クラスを用いて木の変更をコミットする。 |
276 \end{enumerate} | 283 \end{enumerate} |
284 \end{comment} | |
277 | 285 |
278 また、木に対して行われた変更は、Logとして書き出される。 | 286 また、木に対して行われた変更は、Logとして書き出される。 |
287 | |
288 \section{Commit} | |
289 Jungle Tree Editor を用いて木に変更を加えた後は、Commit を行う必要がある。 | |
290 Commit は、前節で記述した Jungle Tree Editor が持つ関数 {\tt success()} を使用することで行われる。 | |
291 | |
292 Commit を行うと、Jungle Tree Editor が保持している編集後の木構造のデータを持つ TreeContext を作成する。 | |
293 そして、編集前の木が持つ TreeContext と 新しく作った TreeContext を置き換えることで Commit は完了する。 | |
294 TreeContext の置き換えは、編集を行っている他の Thread と競合した際に、木の整合性を保つために以下の手順で行われる。 | |
295 | |
296 \begin{enumerate} | |
297 \item 新しく作った TreeContext が持つ、1つ前のバージョンの TreeContext と、編集前の木構造の TreeContext を比較する。 | |
298 | |
299 \item 一致しなかった場合、他のが Thread が Commit をすでに行っているため、失敗する(競合に負けた)。 | |
300 | |
301 \item 一致した場合、TreeContext を Atomic に入れ替える(競合に勝った)。 | |
302 \end{enumerate} | |
303 | |
304 競合に負けた場合は、新しい木に対してもう一度同じ変更を行う必要がある。 | |
279 これらのAPIにより、Jungleは木構造を格納、編集する機能を持っている。 | 305 これらのAPIにより、Jungleは木構造を格納、編集する機能を持っている。 |
280 | 306 |
281 \section{Log} | 307 \section{Log} |
282 Jungle は、 Editor を用いて木に編集を加える際、使用した API に応じて対応する NodeOperation を作成する。 | 308 Jungle は、 Editor を用いて木に編集を加える際、使用した API に応じて対応する NodeOperation を作成する。 |
283 NodeOperation は NodePath とペアで扱わなければならず、このペアを TreeOperation という。 | 309 NodeOperation は NodePath とペアで扱わなければならず、このペアを TreeOperation という。 |
285 この TreeOperation の集まりを TreeOperationLog という。 | 311 この TreeOperation の集まりを TreeOperationLog という。 |
286 TreeOperationLogの仕様をソースコード\ref{src:treeoperationlog}に示す. | 312 TreeOperationLogの仕様をソースコード\ref{src:treeoperationlog}に示す. |
287 \begin{lstlisting}[frame=lrbt,label=src:treeoperationlog,caption=TreeOperationLogの仕様,numbers=left] | 313 \begin{lstlisting}[frame=lrbt,label=src:treeoperationlog,caption=TreeOperationLogの仕様,numbers=left] |
288 public interface TreeOperationLog extends Iterable<TreeOperation> | 314 public interface TreeOperationLog extends Iterable<TreeOperation> |
289 { | 315 { |
290 public TreeOperationLog add(NodePath _p,NodeOperation _op); | 316 public TreeOperationLog add(NodePath _p,NodeOperation _op); |
291 public TreeOperationLog append(TreeOperationLog _log); | 317 public TreeOperationLog append(TreeOperationLog _log); |
292 public int length(); | 318 public int length(); |
293 } | 319 } |
294 \end{lstlisting} | 320 \end{lstlisting} |
295 | 321 |
296 \verb|Iterable<TreeOperation>|を継承しているためIteratorによりTreeOperationを取り出せるようになっている。 | 322 \verb|Iterable<TreeOperation>|を継承しているためIteratorによりTreeOperationを取り出せるようになっている。 |
297 addやappendメソッドを使ってTreeOperationを積み上げていくことができる。 | 323 addやappendメソッドを使ってTreeOperationを積み上げていくことができる。 |
301 | 327 |
302 | 328 |
303 | 329 |
304 \section{検索API} | 330 \section{検索API} |
305 これまでに紹介したAPIにより、Jungleは木構造を構築できるようになった。 | 331 これまでに紹介したAPIにより、Jungleは木構造を構築できるようになった。 |
306 しかし、木に問い合わせを行う検索APIが実装されていなかったため、木の走査を行う{\tt Traverser}クラス内に、lambda式を用いて実装した。 | 332 しかし、木に問い合わせを行う検索APIが実装されていなかったため、木の走査を行う{\tt Interface Traverser}クラス内に、lambda式を用いて実装した。 |
307 以下に検索を行う関数{\tt find}の定義を記述する。 | 333 以下に検索を行う関数{\tt find}の定義を記述する。 |
308 \begin{lstlisting}[frame=lrbt,label=query,numbers=left] | 334 \begin{lstlisting}[frame=lrbt,label=query,numbers=left] |
309 public Iterator<TreeNode> find(Query query, String key, String searchValue); | 335 public Iterator<TreeNode> find(Query query, String key, String searchValue); |
310 \end{lstlisting} | 336 \end{lstlisting} |
311 | 337 |
312 関数{\tt find}は、第一引数には、探索の条件を記述する関数{\tt boolean comdition(TreeNode)}を定義した{\tt Query}を。 | 338 関数{\tt find}は、第一引数には、探索の条件を記述する関数{\tt boolean comdition(TreeNode)}を定義した{\tt Query}を、 |
313 第二、第三引数には、Indexを用いた絞込に使用する{\tt String key、String value}を取り、条件に一致したノードの{\tt Iterator}を返す。 | 339 第二、第三引数には、Indexを用いた絞込に使用する{\tt String key、String value}を取り、条件に一致したノードの{\tt Iterator}を返す。 |
314 {\tt 関数find}の使用例を以下に記す。 | 340 {\tt 関数find}の使用例を以下に記す。 |
315 | 341 |
316 \begin{lstlisting}[frame=lrbt,label=find,numbers=left] | 342 \begin{lstlisting}[frame=lrbt,label=find,numbers=left] |
317 InterfaceTraverser traverser = tree.getTraverser(true); | 343 InterfaceTraverser traverser = tree.getTraverser(true); |
318 Iterator<TreeNode> resultNodeIterator = traverser.find((TreeNode node) -> { | 344 Iterator<TreeNode> resultNodeIterator = traverser.find((TreeNode node) -> { |
319 String personId = node.getAttributes().getString("name"); | 345 String name = node.getAttributes().getString("name"); |
320 if (personId == null) return false; | 346 if (name == null) return false; |
321 return personId.equals("kanagawa"); | 347 return name.equals("kanagawa"); |
322 }, "belong", "ryukyu"); | 348 }, "belong", "ryukyu"); |
323 \end{lstlisting} | 349 \end{lstlisting} |
324 | 350 |
325 | 351 |
326 上記コードについて解説する。 | 352 上記コードについて解説する。 |
353 | |
354 1行目で検索対象の木から、検索に使用する {\tt Interface Traverser} を取得する。 | |
355 2行目で、検索を行う関数 {\tt find()} を使用する。 | |
356 今回は、Index を使って、属性名 {\tt "belong"} 属性値 {\tt "ryukyu"} を持つノード取得し、 | |
357 3 - 5行目で定義されたクエリに渡す。 | |
358 | |
359 そして、クエリの中で属性名 {\tt "name"} 属性値 {\tt "kanagawa"} を持つノードかどうかを確かめる。 | |
360 | |
361 結果として、属性名 {\tt "belong"} 属性値{\tt "ryukyu"}と、属性名 {\tt "name"} 属性値{\tt kanagawa}の2つのデータを持つノードの {\tt Iterator} が取得できる。 | |
362 | |
363 検索の際に使用する Index の実装については次節に記述する。 | |
364 | |
365 \begin{comment} | |
327 \begin{enumerate} | 366 \begin{enumerate} |
328 \item 木の走査を行う{\tt Traverser}クラスを取得する。 | 367 \item 木の走査を行う{\tt Traverser}クラスを取得する。 |
329 | 368 |
330 \item Indexから{\tt find}の第2、第3引数である、属性名 {\tt belong}、属性値 {\tt ryukyu}の組のデータを持つノードを取得し、Queryに渡す(ノードの絞込を行う)。 | 369 \item Indexから{\tt find}の第2、第3引数である、属性名 {\tt belong}、属性値 {\tt ryukyu}の組のデータを持つノードを取得し、Queryに渡す(ノードの絞込を行う)。 |
331 | 370 |
332 \item 引数のノードから関数{\tt getAttributes().getString("name")}で属性名 {\tt name}とペアになっている属性値を取得する。 | 371 \item 引数のノードから関数{\tt getAttributes().getString("name")}で属性名 {\tt name}とペアになっている属性値を取得する。 |
333 | 372 |
334 \item 属性値が{\tt null}だった場合、このノードには属性名が{\tt name}の組のデータは存在しないので、{\tt false}を返し次のノードの評価を行う。 | 373 \item 属性値が{\tt null}だった場合、このノードには属性名が{\tt name}の組のデータは存在しないので、{\tt false}を返し次のノードの評価を行う。 |
335 | 374 |
336 \item 属性値が{\tt null}でなかった場合、{\tt kanagawa}と一致するかどうかを調べ結果を返す。 | 375 \item 属性値が{\tt null}でなかった場合、{\tt kanagawa}と一致するかどうかを調べ結果を返す。 |
337 | 376 |
338 \end{enumerate} | 377 \end{enumerate} |
339 | 378 \end{comment} |
340 結果として、{\tt ryukyu}に所属する、名前が{\tt kanagawa}のデータを持つノードが取得できる。 | 379 |
341 | |
342 検索の際に使用する Index の実装については次節に記述する。 | |
343 | 380 |
344 \section{Index} | 381 \section{Index} |
345 Jungleは、非破壊的木構造というデータ構造上、過去の版の木構造を全て保持している。 | 382 Jungleは、非破壊的木構造というデータ構造上、過去の版の木構造を全て保持している。 |
346 よって、全ての版に独立したIndexが必要となるため、前の版のIndexを破壊すること無く、Indexを更新する必要がある。 | 383 よって、全ての版に独立したIndexが必要となるため、前の版のIndexを破壊すること無く、Indexを更新する必要がある。 |
347 既存のTreeMapでは、一度Indexの複製を行ない、その後更新する必要があったため、Indexの更新オーダーがO(n)となっていた。 | 384 既存のTreeMapでは、一度Indexの複製を行ない、その後更新する必要があったため、Indexの更新オーダーがO(n)となっていた。 |
362 | 399 |
363 \begin{lstlisting}[frame=lrbt,label=find,numbers=left] | 400 \begin{lstlisting}[frame=lrbt,label=find,numbers=left] |
364 Optional<TreeMap<String, List<TreeNode>>> indexOp = indexMap.get("name"); | 401 Optional<TreeMap<String, List<TreeNode>>> indexOp = indexMap.get("name"); |
365 if (!indexOp.isPresent()) | 402 if (!indexOp.isPresent()) |
366 return new NulIterator<TreeNode>(); | 403 return new NulIterator<TreeNode>(); |
367 TreeMap<String, List<TreeNode>> index = indexOp.get(); | 404 TreeMap<String, List<TreeNode>> index = indexOp.get(); |
368 Optional<List<TreeNode>> nodeListOp = index.get("kanagawa"); | 405 Optional<List<TreeNode>> nodeListOp = index.get("kanagawa"); |
369 if (!nodeListOp.isPresent()) | 406 if (!nodeListOp.isPresent()) |
370 return new NulIterator<TreeNode>(); | 407 return new NulIterator<TreeNode>(); |
371 return nodeListOp.get().iterator(); | 408 return nodeListOp.get().iterator(); |
372 \end{lstlisting} | 409 \end{lstlisting} |
373 | 410 |
374 | 411 1 - 4行目で IndexMap から 属性名 "name" に対する値を持つ Index を取得している。 |
375 \begin{enumerate} | 412 5 - 8行目で 取得した Index から、 属性名 "kanagawa" を持つノードの{ \tt Iterator}を取得している。 |
376 \item {\tt indexMap}に、今回検索で使用する属性名 {\tt name}を使用して{\tt get("name")}を行う。すると属性名 {\tt "name"}に対応したIndexが、{\tt Optional}クラスで包まれて返ってくる。 | 413 |
377 | 414 |
378 \item {\tt Optional}オブジェクトに対して、中身を保持しているか(属性名 {\tt name}に対応したIndexを木が持っているか)を調べる。 | 415 \begin{comment} |
379 | 416 \begin{enumerate} |
380 \item 持っていなかった場合、空の{\tt Iterator}オブジェクトを返す。 | 417 \item {\tt indexMap}に、今回検索で使用する属性名 {\tt name}を使用して{\tt get("name")}を行う。すると属性名 {\tt "name"}に対応したIndexが、{\tt Optional}クラスで包まれて返ってくる。 |
381 | 418 |
382 \item 持っていた場合、{\tt Optional}オブジェクトからIndexを取得する。 | 419 \item {\tt Optional}オブジェクトに対して、中身を保持しているか(属性名 {\tt name}に対応したIndexを木が持っているか)を調べる。 |
383 | 420 |
384 \item 取得したIndexに、検索で使用する属性値{\tt "kanagawa"}で{\tt get()}を行う。すると、属性名 {\tt "name"} 属性値{\tt "kanagawa"}の値を持つノードのリストが、{\tt Optional}クラスに包まれて返ってくる。 | 421 \item 持っていなかった場合、空の{\tt Iterator}オブジェクトを返す。 |
385 | 422 |
386 \item {\tt Optional}オブジェクトに対して中身を保持しているか(属性名 {\tt "name"} 属性値 {\tt "kanagawa"}を持つノードを木が持っているか)を調べる。 | 423 \item 持っていた場合、{\tt Optional}オブジェクトからIndexを取得する。 |
387 | 424 |
388 \item 持っていなかった場合、空の{\tt Iterator}オブジェクトを返す。 | 425 \item 取得したIndexに、検索で使用する属性値{\tt "kanagawa"}で{\tt get()}を行う。すると、属性名 {\tt "name"} 属性値{\tt "kanagawa"}の値を持つノードのリストが、{\tt Optional}クラスに包まれて返ってくる。 |
389 | 426 |
390 \item 持っていた場合{\tt Optional}オブジェクトからノードリストの{\tt Iterator}を返す。 | 427 \item {\tt Optional}オブジェクトに対して中身を保持しているか(属性名 {\tt "name"} 属性値 {\tt "kanagawa"}を持つノードを木が持っているか)を調べる。 |
391 | 428 |
392 \end{enumerate} | 429 \item 持っていなかった場合、空の{\tt Iterator}オブジェクトを返す。 |
393 | 430 |
394 JungleはこれらのAPIにより、木構造を格納、編集、検索する機能を持っている。 | 431 \item 持っていた場合{\tt Optional}オブジェクトからノードリストの{\tt Iterator}を返す。 |
395 | 432 |
396 \newpage | 433 \end{enumerate} |
434 \end{comment} | |
435 | |
436 JungleはこれらのAPIにより、木構造を格納、編集、検索する機能を持っている。 | |
437 | |
438 \newpage |