annotate jungle.tex @ 37:14267d61122d

commit
author tatsuki
date Sun, 19 Feb 2017 10:19:11 +0900
parents 4365c210d1cb
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
25
kono
parents: 18
diff changeset
1 \chapter{非破壊的木構造データベースの利点}
kono
parents: 18
diff changeset
2 本章では、非破壊的木構造を選択した理由について述べる。
kono
parents: 18
diff changeset
3 従来の破壊的木構造は親から子へのポインタと子供から親へのポインタを持つ二重リンク構造を持っていた。
kono
parents: 18
diff changeset
4 これによりノードの挿入削除をO(1)で行うことができる。
kono
parents: 18
diff changeset
5 しかし、変更前の木を保存することとは両立せず、変更中に前の版の木を使用することはできない。
kono
parents: 18
diff changeset
6 そこで、子供から親へのポインタを無くし、木を共有しながら変更部分を付け加える非破壊的木構造を提案する。
kono
parents: 18
diff changeset
7 これにより、木の変更はO(n)になるが、並列実行向けの複数の版が存在できるデータベースを実現することができる。
2
tatsuki
parents:
diff changeset
8
14
tatsuki
parents: 11
diff changeset
9
25
kono
parents: 18
diff changeset
10 \section{破壊的木構造}
kono
parents: 18
diff changeset
11 破壊的木構造は親から子までのポインタとともに、子から親へのポインタを持つ。
kono
parents: 18
diff changeset
12 ノードの属性値を書き換える場合は、そのまま上書きすることが可能である。
kono
parents: 18
diff changeset
13 ノードの追加を行うときには、行う位置の親と子供の両方のポインタを変更する。
kono
parents: 18
diff changeset
14 この複数の変更を一つのトランザクションとして行う必要がある。
kono
parents: 18
diff changeset
15 変更中は親と子をロックする必要がある。
kono
parents: 18
diff changeset
16 平行度を上げるために、前の版の木にアクセスするためには複製を作る必要がある。
kono
parents: 18
diff changeset
17 一つの方法は、常に二つの木を用意し交互に変更を行うものである。
kono
parents: 18
diff changeset
18 変更自体はO(1)だが、平行実行下では複雑な工夫が必要になる。
2
tatsuki
parents:
diff changeset
19
14
tatsuki
parents: 11
diff changeset
20
25
kono
parents: 18
diff changeset
21 \section{非破壊的木構造}
14
tatsuki
parents: 11
diff changeset
22
25
kono
parents: 18
diff changeset
23 データの編集を一度生成した木を上書きせず、ルートから編集を行う位置までノードをコピーする{図\ref{fig:nondestractive})。
kono
parents: 18
diff changeset
24 この時に、子供からの親へのポインタは持たないとする。
kono
parents: 18
diff changeset
25 木のルートをAtomicに置き換えることで、木のアップデートを行う。
kono
parents: 18
diff changeset
26 変更前の木が残っているので、そのまま使用できる。
kono
parents: 18
diff changeset
27 変更されないノードは変更前と変更後のルートから共有されることになる。
kono
parents: 18
diff changeset
28
2
tatsuki
parents:
diff changeset
29
tatsuki
parents:
diff changeset
30 \begin{figure}[htpb]
tatsuki
parents:
diff changeset
31 \begin{center}
tatsuki
parents:
diff changeset
32 \includegraphics[scale=0.7]{figures/non_destructive_tree.pdf}
tatsuki
parents:
diff changeset
33 \caption{非破壊的木構造の編集}
tatsuki
parents:
diff changeset
34 \label{fig:nondestractive}
tatsuki
parents:
diff changeset
35 \end{center}
tatsuki
parents:
diff changeset
36 \end{figure}
tatsuki
parents:
diff changeset
37
25
kono
parents: 18
diff changeset
38 破壊的変更に比べて、ノードの作成量は増えるが複数の版が同時に存在できる(\ref{fig:nondestractive_merit})。
kono
parents: 18
diff changeset
39 したがって、現在および過去の木を分散ノードまたはディスクに安全に格納することができる。
kono
parents: 18
diff changeset
40 実際には、木自体ではなく木の変更Logを分散ノードまたはディスクに書き出すのが妥当である。
kono
parents: 18
diff changeset
41 変更の計算量は最悪O(n)になるので、大量の挿入を行うときには工夫が必要になる。
2
tatsuki
parents:
diff changeset
42
25
kono
parents: 18
diff changeset
43 木のルートの上に新しくノードを付け加える場合はO(1)となる。
kono
parents: 18
diff changeset
44 この場合は木は追加順と逆順の構成を持つことになる。
kono
parents: 18
diff changeset
45 木の末端に追加する場所を覚えておき、そこにAtomicにノードを追加するとO(1)で正順で追加することができる。
kono
parents: 18
diff changeset
46 この場合は木が破壊的に変更されているように見えるが、前の版の末端部分を超えてアクセスすることがなければ複数の版を同時に使用することができる。
kono
parents: 18
diff changeset
47 これをDifferential Treeと呼ぶ。
kono
parents: 18
diff changeset
48
kono
parents: 18
diff changeset
49 木構造自体をバランス木、例えば赤黒木とすることもできる。
kono
parents: 18
diff changeset
50 これにより、O(log n)で木の変更を行うことができる。
kono
parents: 18
diff changeset
51 しかし、この場合木構造自体を自由に構成することはできないが、赤黒木のKeyを用いて任意のノードにO(Log n)でアクセスすることができる。
14
tatsuki
parents: 11
diff changeset
52
tatsuki
parents: 11
diff changeset
53
2
tatsuki
parents:
diff changeset
54 \begin{figure}[htpb]
tatsuki
parents:
diff changeset
55 \begin{center}
tatsuki
parents:
diff changeset
56 \includegraphics[scale=0.7]{figures/non_destructive_merit.pdf}
tatsuki
parents:
diff changeset
57 \caption{非破壊的木構造による利点}
tatsuki
parents:
diff changeset
58 \label{fig:nondestractive_merit}
tatsuki
parents:
diff changeset
59 \end{center}
tatsuki
parents:
diff changeset
60 \end{figure}
tatsuki
parents:
diff changeset
61
18
d5306971efbf eng abst
tatsuki
parents: 15
diff changeset
62 また、過去の木を保持する場合、破壊的木構造は、木の複製後編集を行う必要がある。
14
tatsuki
parents: 11
diff changeset
63 一方、非破壊的木構造は過去の木を上書きしないため、過去の木のルートノードを保持するだけで良い。
tatsuki
parents: 11
diff changeset
64
25
kono
parents: 18
diff changeset
65
kono
parents: 18
diff changeset
66 \chapter{Jungleの構成要素}
kono
parents: 18
diff changeset
67 本章では、Jungleの構成要素について説明する。
kono
parents: 18
diff changeset
68 Jungleは名前を用いて木の生成と木の取得を行う。
kono
parents: 18
diff changeset
69 木の中の特定のノードにアクセスするには、木の中のノードの位置を表すNodePathを用いる。
kono
parents: 18
diff changeset
70 木の変更は非破壊的に行われ、木のルートを変更後の木に置き換えるAtomicOperationがトランザクションとなる。
kono
parents: 18
diff changeset
71 木の変更はLogとして記録され、分散ノードあるいはディスクに格納される。
kono
parents: 18
diff changeset
72 JungleのAPIは、Eitherを返すようになっており、Eitherの型をチェックすることにより成功と失敗がわかるようになっている。
2
tatsuki
parents:
diff changeset
73
tatsuki
parents:
diff changeset
74
tatsuki
parents:
diff changeset
75 \section{木の生成}
6
tatsuki
parents: 2
diff changeset
76 Jungleにおける木の生成について述べる。
2
tatsuki
parents:
diff changeset
77 Jungleは複数の木構造を、名前を利用して作成・編集・削除を行い管理している。
6
tatsuki
parents: 2
diff changeset
78 Jungleクラスが提供している木の生成・管理を行うAPIを表\ref{jungleAPI}に記す。
2
tatsuki
parents:
diff changeset
79
tatsuki
parents:
diff changeset
80 \begin{table}[htb]
tatsuki
parents:
diff changeset
81 \begin{center}
tatsuki
parents:
diff changeset
82 \caption{Jungleに実装されているAPI}
tatsuki
parents:
diff changeset
83 \begin{tabular}{|p{15em}|p{24em}|} \hline
15
tatsuki
parents: 14
diff changeset
84 {\small {\tt JungleTree createNewTree(String treeName)}} &{\small Jungleに新しく木を生成する。木の名前が重複した場合、生成に失敗しnullを返す。} \\ \hline
tatsuki
parents: 14
diff changeset
85 {\small {\tt JungleTree getTreeByName(String treeName)}} &{\small JungleからtreeNameと名前が一致するtreeを取得する。名前が一致するTreeがない場合取得は失敗しnullを返す。} \\ \hline
2
tatsuki
parents:
diff changeset
86 \end{tabular}
tatsuki
parents:
diff changeset
87 \label{jungleAPI}
tatsuki
parents:
diff changeset
88 \end{center}
tatsuki
parents:
diff changeset
89 \end{table}
tatsuki
parents:
diff changeset
90
tatsuki
parents:
diff changeset
91
tatsuki
parents:
diff changeset
92 \section{JungleTree}
tatsuki
parents:
diff changeset
93 Jungleは複数の木の集合で出来ている。
18
d5306971efbf eng abst
tatsuki
parents: 15
diff changeset
94 Jungleの木は、自身の情報をTreeContext という木構造のデータを持つ(表\ref{TreeContext1})オブジェクトに保持している。
15
tatsuki
parents: 14
diff changeset
95
tatsuki
parents: 14
diff changeset
96 \newpage
tatsuki
parents: 14
diff changeset
97 \begin{table}[htb]
tatsuki
parents: 14
diff changeset
98 \begin{center}
tatsuki
parents: 14
diff changeset
99 \caption{TreeContextが保持している値}
tatsuki
parents: 14
diff changeset
100 \begin{tabular}{|l|} \hline
tatsuki
parents: 14
diff changeset
101 {\tt } 自身のルートノード\\ \hline
tatsuki
parents: 14
diff changeset
102 {\tt } 1つ前のバージョンのTreeContext\\ \hline
tatsuki
parents: 14
diff changeset
103 {\tt } 編集のログ\\ \hline
tatsuki
parents: 14
diff changeset
104 {\tt } 木のuuid \\ \hline
tatsuki
parents: 14
diff changeset
105 {\tt } 木の名前 \\ \hline
tatsuki
parents: 14
diff changeset
106 {\tt } 木のversion \\ \hline
tatsuki
parents: 14
diff changeset
107 {\tt } 木の検索に使うTraverser \\ \hline
tatsuki
parents: 14
diff changeset
108 \end{tabular}
tatsuki
parents: 14
diff changeset
109 \label{TreeContext1}
tatsuki
parents: 14
diff changeset
110 \end{center}
tatsuki
parents: 14
diff changeset
111 \end{table}
tatsuki
parents: 14
diff changeset
112
tatsuki
parents: 14
diff changeset
113 Jungle の木は、自身の木構造に編集を行う Editor や 検索に使用する Traverser を提供しており、ユーザーはそれを用いて木構造にアクセスする。
tatsuki
parents: 14
diff changeset
114 また、過去のバージョンの木に対するアクセスや、特定のノードのPathを検索する機能も持っている。
2
tatsuki
parents:
diff changeset
115 以下にJungleTreeクラスが提供しているAPI(表\ref{JungleTreeAPI})を記す
tatsuki
parents:
diff changeset
116 \begin{table}[htb]
tatsuki
parents:
diff changeset
117 \begin{center}
tatsuki
parents:
diff changeset
118 \caption{JungleTreeに実装されているAPI}
tatsuki
parents:
diff changeset
119 \begin{tabular}{|p{15em}|p{24em}|} \hline
15
tatsuki
parents: 14
diff changeset
120 {\small {\tt TreeNode getRootNode()}} &{\small 木のルートノードを取得する。} \\ \hline
tatsuki
parents: 14
diff changeset
121 {\small {\tt long revision()}} & {\small 木のバーションを取得する。初めは0から始まり、木への変更がCommitされる度に1上昇する。} \\ \hline
tatsuki
parents: 14
diff changeset
122 {\small {\tt JungleTreeEditor getJungleTreeEditor()}} &{\small 木へ変更を加えるEditorを取得する。}\\ \hline
tatsuki
parents: 14
diff changeset
123 {\small {\tt Either<Error, JungleTree> getOldTree(long revision)}} & {\small 引数で指定したint revisionに等しいバージョンの木を取得する。} \\ \hline
tatsuki
parents: 14
diff changeset
124 {\small {\tt InterfaceTraverser getTraverser()}} & {\small 木の検索を行うTraverserを取得する。} \\ \hline
tatsuki
parents: 14
diff changeset
125 {\small {\tt Either<Error, TreeNode> getNodeOfPath(NodePath path)}} &{\small {\tt NodePathで指定した位置と値なるノードを取得する。}} \\ \hline
tatsuki
parents: 14
diff changeset
126 {\small {\tt NodePath getNodePath(TreeNode node)}} & {\small 引数で渡したノードの位置を表す{\tt NodePath}を返す。}\\ \hline
2
tatsuki
parents:
diff changeset
127 \end{tabular}
tatsuki
parents:
diff changeset
128 \label{JungleTreeAPI}
tatsuki
parents:
diff changeset
129 \end{center}
tatsuki
parents:
diff changeset
130 \end{table}
tatsuki
parents:
diff changeset
131
26
tatsuki
parents: 25
diff changeset
132 \section{Either}
tatsuki
parents: 25
diff changeset
133 Jungleは、失敗する可能性のある関数では返り値を{ \tt Either<A、B>}に包んで返す。
tatsuki
parents: 25
diff changeset
134 AにはError、Bには処理に成功した際の返り値の型が入る。
tatsuki
parents: 25
diff changeset
135 Eitherは、AかBどちらかの値しか持たない。
tatsuki
parents: 25
diff changeset
136 以下にEitherクラスが提供しているAPI(表\ref{EitherAPI})を記す。
tatsuki
parents: 25
diff changeset
137 \begin{table}[htb]
tatsuki
parents: 25
diff changeset
138 \begin{center}
tatsuki
parents: 25
diff changeset
139 \caption{Eitherに実装されているAPI}
tatsuki
parents: 25
diff changeset
140 \begin{tabular}{|p{15em}|p{24em}|} \hline
tatsuki
parents: 25
diff changeset
141 {\small{\tt boolean isA()}} & {\small EitherがAを持っているかどうかを調べる。持っている場合trueを返す。}\\ \hline
tatsuki
parents: 25
diff changeset
142 {\small{\tt boolean isB()}} & {\small EitherがBを持っているかどうかを調べる。持っている場合trueを返す。}\\ \hline
tatsuki
parents: 25
diff changeset
143 {\small{\tt A a()}} &{\small Aの値を取得する。}\\ \hline
tatsuki
parents: 25
diff changeset
144 {\small{\tt B b()}} &{\small Bの値を取得する。}\\ \hline
tatsuki
parents: 25
diff changeset
145 \end{tabular}
tatsuki
parents: 25
diff changeset
146 \label{EitherAPI}
tatsuki
parents: 25
diff changeset
147 \end{center}
tatsuki
parents: 25
diff changeset
148 \end{table}
tatsuki
parents: 25
diff changeset
149
tatsuki
parents: 25
diff changeset
150 {\tt Either<A、B>} の使い方は、{\tt isA()}を用いて関数が{\tt Error}を返していないかを調べる。
tatsuki
parents: 25
diff changeset
151 {\tt Error}でない場合は{\tt b()}で関数の返り値を取得する。
tatsuki
parents: 25
diff changeset
152
tatsuki
parents: 25
diff changeset
153
tatsuki
parents: 25
diff changeset
154
2
tatsuki
parents:
diff changeset
155
tatsuki
parents:
diff changeset
156 \section{TreeNode}
tatsuki
parents:
diff changeset
157 Jungleの木構造は、複数のノードの集合で出来ている。
18
d5306971efbf eng abst
tatsuki
parents: 15
diff changeset
158 ノードは、自身の子のリストと属性名と属性値の組でデータを持つ。
2
tatsuki
parents:
diff changeset
159 ノードに対するアクセスは、表\ref{TreeNodeAPI}に記述されているAPIを用いて行われる。
tatsuki
parents:
diff changeset
160
tatsuki
parents:
diff changeset
161 \begin{table}[htb]
tatsuki
parents:
diff changeset
162 \begin{center}
tatsuki
parents:
diff changeset
163 \caption{TreeNodeに実装されているAPI}
tatsuki
parents:
diff changeset
164 \begin{tabular}{|p{15em}|p{24em}|} \hline
15
tatsuki
parents: 14
diff changeset
165 {\small {\tt Children getChildren()}} &{\small ノードの子供を扱うChildrenオブジェクトを返す} \\ \hline
tatsuki
parents: 14
diff changeset
166 {\small {\tt Attribute getAttribute()}} &{\small ノードが保持しているデータを扱うAttribteオブジェクトを返す。} \\ \hline
2
tatsuki
parents:
diff changeset
167 \end{tabular}
tatsuki
parents:
diff changeset
168 \label{TreeNodeAPI}
tatsuki
parents:
diff changeset
169 \end{center}
tatsuki
parents:
diff changeset
170 \end{table}
tatsuki
parents:
diff changeset
171
tatsuki
parents:
diff changeset
172 Childrenクラスは表\ref{Children}に記述されたAPIを、Attributeクラスは表\ref{Attribute}に記述されたAPIを提供する。
tatsuki
parents:
diff changeset
173 これらを利用しノードが保持している値や、子供にアクセスする。
tatsuki
parents:
diff changeset
174 \begin{table}[htbH]
tatsuki
parents:
diff changeset
175 \begin{center}
tatsuki
parents:
diff changeset
176 \caption{Childrenに実装されているAPI}
tatsuki
parents:
diff changeset
177 \begin{tabular}{|p{15em}|p{24em}|} \hline
15
tatsuki
parents: 14
diff changeset
178 {\small{\tt int size()}} & {\small 子供の数を返す。}\\ \hline
tatsuki
parents: 14
diff changeset
179 {\small{\tt <Either Error,TreeNode> at(int num)}} &{\small ノードが持つ子供の中から、 変数{\tt num}で指定された位置にある子ノードを返す。存在しない位置を指定した場合、{\tt Error} を返す。} \\ \hline
2
tatsuki
parents:
diff changeset
180 \end{tabular}
tatsuki
parents:
diff changeset
181 \label{Children}
tatsuki
parents:
diff changeset
182 \end{center}
tatsuki
parents:
diff changeset
183 \end{table}
tatsuki
parents:
diff changeset
184
tatsuki
parents:
diff changeset
185
tatsuki
parents:
diff changeset
186
tatsuki
parents:
diff changeset
187 \begin{table}[htbH]
tatsuki
parents:
diff changeset
188 \begin{center}
tatsuki
parents:
diff changeset
189 \caption{Attributeに実装されているAPI}
tatsuki
parents:
diff changeset
190 \begin{tabular}{|p{15em}|p{24em}|} \hline
15
tatsuki
parents: 14
diff changeset
191 {\small{\tt ByteBuffer get(String key)}} &{\small ノードが持つ値から、属性名 {\tt key}とペアの属性値を{\tt ByteBuffer}型で返す。ノードが保持していない{\tt key}を渡した場合エラーを返す。} \\ \hline
tatsuki
parents: 14
diff changeset
192 {\small{\tt String getString(String key)}} &{\small ノードが持つ値から、属性名 {\tt key} とペアの属性値を{\tt String}型で返す。ノードが保持していない{\tt key}を渡した場合エラーを返す。} \\ \hline
2
tatsuki
parents:
diff changeset
193 \end{tabular}
tatsuki
parents:
diff changeset
194 \label{Attribute}
tatsuki
parents:
diff changeset
195 \end{center}
tatsuki
parents:
diff changeset
196 \end{table}
tatsuki
parents:
diff changeset
197
tatsuki
parents:
diff changeset
198 \newpage
14
tatsuki
parents: 11
diff changeset
199 以下にルートノードの2番目の子供から、属性名 {\tt name}とペアになっている属性値を取得するサンプルコード\ref{getAttributeCode}を記述する。
2
tatsuki
parents:
diff changeset
200 \begin{lstlisting}[frame=lrbt,numbers=left,label=getAttributeCode]
tatsuki
parents:
diff changeset
201 JungleTree tree = jungle.getTreeByName("TreeName");
tatsuki
parents:
diff changeset
202 TreeNode root = tree.getRootNode();
tatsuki
parents:
diff changeset
203 Children children = root.getChildren();
11
tatsuki
parents: 6
diff changeset
204 Either<Error,TreeNode> either = children.at(1);
2
tatsuki
parents:
diff changeset
205 if (either.isA())
tatsuki
parents:
diff changeset
206 return either.a();
tatsuki
parents:
diff changeset
207 TreeNode child = either.b();
tatsuki
parents:
diff changeset
208 Attribute attribute = child.getAttribute();
tatsuki
parents:
diff changeset
209 String value = attribute.getString("name");
tatsuki
parents:
diff changeset
210 \end{lstlisting}
tatsuki
parents:
diff changeset
211
14
tatsuki
parents: 11
diff changeset
212 ソースコード\ref{getAttributeCode}の説明を行う。
15
tatsuki
parents: 14
diff changeset
213
tatsuki
parents: 14
diff changeset
214 1行目で Jungle から木を取得し、
tatsuki
parents: 14
diff changeset
215 2行目で、取得した木のルートノードを取得している。
tatsuki
parents: 14
diff changeset
216 3 - 7行目でルートノードの1番目の子ノードを取得し、
tatsuki
parents: 14
diff changeset
217 8 - 9行目で、ルートの1番目の子ノードから、属性名 "name" とペアの属性値を取得している。
2
tatsuki
parents:
diff changeset
218
26
tatsuki
parents: 25
diff changeset
219
tatsuki
parents: 25
diff changeset
220 \section{NodePath}
tatsuki
parents: 25
diff changeset
221 Jungleでは、木のノードの位置を{\tt NodePath}クラスを使って表す。
tatsuki
parents: 25
diff changeset
222 {\tt NodePath}クラスはルートノードからスタートし、対象のノードまでの経路を数字を用いて指し示す。また、ルートノードは例外として-1と表記される。
tatsuki
parents: 25
diff changeset
223 {\tt NodePath}クラスを用いて{\tt< -1,1,2,3>}を表している際の例を図\ref{NodePath}に記す。
tatsuki
parents: 25
diff changeset
224
tatsuki
parents: 25
diff changeset
225 \begin{figure}[htpb]
tatsuki
parents: 25
diff changeset
226 \begin{center}
tatsuki
parents: 25
diff changeset
227 \includegraphics[scale=0.7]{figures/nodePath.pdf}
tatsuki
parents: 25
diff changeset
228 \caption{NodePath}
tatsuki
parents: 25
diff changeset
229 \label{NodePath}
tatsuki
parents: 25
diff changeset
230 \end{center}
tatsuki
parents: 25
diff changeset
231 \end{figure}
tatsuki
parents: 25
diff changeset
232
tatsuki
parents: 25
diff changeset
233 \newpage
tatsuki
parents: 25
diff changeset
234
tatsuki
parents: 25
diff changeset
235
tatsuki
parents: 25
diff changeset
236
2
tatsuki
parents:
diff changeset
237 \section{木の編集API}
tatsuki
parents:
diff changeset
238 Jungleの木の編集は{\tt Default Jungle Tree Editor}クラスを用いて行われる。
tatsuki
parents:
diff changeset
239 {\tt Default Jungle Tree Editor}クラスは、木に対する編集を行うAPIが定義されているJungle Tree Editorインターフェースを実装している。
6
tatsuki
parents: 2
diff changeset
240 Default Jungle Tree Editorは、Jungle Tree から、{\tt getTreeEditor()}を用いて取得する。
2
tatsuki
parents:
diff changeset
241 表\ref{editor}にJungle Tree Editorインターフェースに定義されているAPIを記述する。
14
tatsuki
parents: 11
diff changeset
242 また、表\ref{editor}に記述しているAPIは全て、{\tt Either<Error,JungleTreeEditor>} を返す。
11
tatsuki
parents: 6
diff changeset
243
18
d5306971efbf eng abst
tatsuki
parents: 15
diff changeset
244 \newpage
d5306971efbf eng abst
tatsuki
parents: 15
diff changeset
245
2
tatsuki
parents:
diff changeset
246 \begin{table}[htb]
tatsuki
parents:
diff changeset
247 \begin{center}
tatsuki
parents:
diff changeset
248 \caption{Editorに実装されているAPI}
14
tatsuki
parents: 11
diff changeset
249 \begin{tabular*}{\textwidth}{|p{15em}|p{22em}|} \hline
tatsuki
parents: 11
diff changeset
250 {\small\tt addNewChildAt( NodePath path, int pos)} &
15
tatsuki
parents: 14
diff changeset
251 {\small\tt path}で指定したノードの{\tt pos}番目の子の後にノードを追加する。\\ \hline
14
tatsuki
parents: 11
diff changeset
252 {\small\tt deleteChildAt( NodePath path,int pos)} &
15
tatsuki
parents: 14
diff changeset
253 {\small\tt path}で指定したノードの{\tt pos}番目の子ノードを削除する。 \\ \hline
14
tatsuki
parents: 11
diff changeset
254 {\small\tt putAttribute( NodePath path,String key,ByteBuffer value)} &
15
tatsuki
parents: 14
diff changeset
255 {\small\tt path}で指定したノードに属性名 {\tt key} 属性値 {\tt value} のペアで値を挿入する。 \\ \hline
14
tatsuki
parents: 11
diff changeset
256 {\small\tt deleteAttribute( NodePath path,String key)}&
15
tatsuki
parents: 14
diff changeset
257 {\small\tt path}で指定したノードが持つ、属性名 {\tt key}とペアで保存されている属性値を削除する。\\ \hline
14
tatsuki
parents: 11
diff changeset
258 {\small\tt moveChild( NodePath path,int num,String move)} &
15
tatsuki
parents: 14
diff changeset
259 {\small\tt path}で指定したノードの{\tt num}番目の子供を{\tt move}の方向に移動させる。 \\ \hline %あとで直す
14
tatsuki
parents: 11
diff changeset
260 {\small\tt pushPop()} &
2
tatsuki
parents:
diff changeset
261 ルートノードの上に新しいルートノードを追加する。線形の木を作る際に使用することで木の変更の手間をO(n)からO(1)にできる。\\ \hline
14
tatsuki
parents: 11
diff changeset
262 {\small\tt success()} &
2
tatsuki
parents:
diff changeset
263 木へ行った変更をコミットする。自分が編集を行っていた間に、他のJungleTreeEditorクラスによって木が更新されていた場合、コミットは失敗する。 \\ \hline
14
tatsuki
parents: 11
diff changeset
264 \end{tabular*}
2
tatsuki
parents:
diff changeset
265 \label{editor}
tatsuki
parents:
diff changeset
266 \end{center}
tatsuki
parents:
diff changeset
267 \end{table}
tatsuki
parents:
diff changeset
268
tatsuki
parents:
diff changeset
269
tatsuki
parents:
diff changeset
270
15
tatsuki
parents: 14
diff changeset
271 編集後に返される{\tt Default Jungle Tree Editor}クラスは、編集後の木構造を保持しているため、編集前の木構造を保持している{\tt Default Jungle Tree Editor}クラスとは別のオブジェクトである。
tatsuki
parents: 14
diff changeset
272 編集を行った後は、関数{\tt editor.success()}で今までの編集をコミットすることができる。他の{\tt Default Jungle Tree Editor}クラスによって木が更新されていた場合はコミットは失敗し、{\tt success()}は{\tt Error}を返す。
2
tatsuki
parents:
diff changeset
273 その場合は、木の編集を最初からやり直す必要がある。
tatsuki
parents:
diff changeset
274
tatsuki
parents:
diff changeset
275 以下に{\tt JungleTreeEditor}クラスを用いて、木の編集を行うサンプルコードを記述する。
tatsuki
parents:
diff changeset
276
tatsuki
parents:
diff changeset
277 \begin{lstlisting}[frame=lrbt,numbers=left,label=editorCode]
tatsuki
parents:
diff changeset
278 JungleTreeEditor editor = tree.getTreeEditor();
tatsuki
parents:
diff changeset
279 DefaultNodePath editNodePath = new DefaultNodePath();
tatsuki
parents:
diff changeset
280 Either<Error, JungleTreeEditor> either = editor.addNewChildAt(editNodePath, 0);
tatsuki
parents:
diff changeset
281 if (either.isA())
tatsuki
parents:
diff changeset
282 return either.a();
tatsuki
parents:
diff changeset
283 editor = either.b();
tatsuki
parents:
diff changeset
284 editor.success();
tatsuki
parents:
diff changeset
285 \end{lstlisting}
tatsuki
parents:
diff changeset
286
15
tatsuki
parents: 14
diff changeset
287 1行目で、木から Editor を取得している。
tatsuki
parents: 14
diff changeset
288 2行目で、編集を行うノードの Path を作成している。Default Node Path は、生成時はルートノードを指しているため、今回はルートノードに対する変更であることがわかる。
tatsuki
parents: 14
diff changeset
289 3行目で、実際にルートノードに対して、子ノードの追加を行っている。
tatsuki
parents: 14
diff changeset
290 4行目以降で、編集が成功したかどうかを {\tt Either }を使って確かめ、成功していた場合7行目で変更を木に Commit している。
tatsuki
parents: 14
diff changeset
291
tatsuki
parents: 14
diff changeset
292 \begin{comment}
2
tatsuki
parents:
diff changeset
293 \begin{enumerate}
tatsuki
parents:
diff changeset
294 \item 関数{\tt tree.getEditor()}で編集を行う木から、{\tt JungleTreeEditor}クラスを取得する。
tatsuki
parents:
diff changeset
295 \item 次に変更するノードの場所を示す、{\tt NodePath}クラスを作成する。
tatsuki
parents:
diff changeset
296 \item 関数{\tt editor.addNewChildAt()}を用いて、変数{\tt path}で指定したノードの子供の0番目に子ノードを追加する。
tatsuki
parents:
diff changeset
297 \item 返り値の変数{\tt either}が{\tt Error}クラスを保持していないか(編集に失敗していないか)を確認する。
tatsuki
parents:
diff changeset
298 \item {\tt Error}クラスを保持していた場合{\tt Either.a()}でErrorを返す。
tatsuki
parents:
diff changeset
299 \item 編集に成功していた場合、編集後木を持った、{\tt JungleTreeEditor}クラスを取得する。
tatsuki
parents:
diff changeset
300 \item 取得した{\tt JungleTreeEditor}クラスを用いて木の変更をコミットする。
tatsuki
parents:
diff changeset
301 \end{enumerate}
15
tatsuki
parents: 14
diff changeset
302 \end{comment}
2
tatsuki
parents:
diff changeset
303
tatsuki
parents:
diff changeset
304 また、木に対して行われた変更は、Logとして書き出される。
15
tatsuki
parents: 14
diff changeset
305
tatsuki
parents: 14
diff changeset
306 \section{Commit}
tatsuki
parents: 14
diff changeset
307 Jungle Tree Editor を用いて木に変更を加えた後は、Commit を行う必要がある。
tatsuki
parents: 14
diff changeset
308 Commit は、前節で記述した Jungle Tree Editor が持つ関数 {\tt success()} を使用することで行われる。
tatsuki
parents: 14
diff changeset
309
18
d5306971efbf eng abst
tatsuki
parents: 15
diff changeset
310 Commit を行うと、Jungle Tree Editor は、保持している編集後の木構造のデータを持つ TreeContext を作成する。
15
tatsuki
parents: 14
diff changeset
311 そして、編集前の木が持つ TreeContext と 新しく作った TreeContext を置き換えることで Commit は完了する。
tatsuki
parents: 14
diff changeset
312 TreeContext の置き換えは、編集を行っている他の Thread と競合した際に、木の整合性を保つために以下の手順で行われる。
tatsuki
parents: 14
diff changeset
313
tatsuki
parents: 14
diff changeset
314 \begin{enumerate}
tatsuki
parents: 14
diff changeset
315 \item 新しく作った TreeContext が持つ、1つ前のバージョンの TreeContext と、編集前の木構造の TreeContext を比較する。
tatsuki
parents: 14
diff changeset
316
tatsuki
parents: 14
diff changeset
317 \item 一致しなかった場合、他のが Thread が Commit をすでに行っているため、失敗する(競合に負けた)。
tatsuki
parents: 14
diff changeset
318
tatsuki
parents: 14
diff changeset
319 \item 一致した場合、TreeContext を Atomic に入れ替える(競合に勝った)。
tatsuki
parents: 14
diff changeset
320 \end{enumerate}
tatsuki
parents: 14
diff changeset
321
tatsuki
parents: 14
diff changeset
322 競合に負けた場合は、新しい木に対してもう一度同じ変更を行う必要がある。
2
tatsuki
parents:
diff changeset
323 これらのAPIにより、Jungleは木構造を格納、編集する機能を持っている。
tatsuki
parents:
diff changeset
324
6
tatsuki
parents: 2
diff changeset
325 \section{Log}
tatsuki
parents: 2
diff changeset
326 Jungle は、 Editor を用いて木に編集を加える際、使用した API に応じて対応する NodeOperation を作成する。
tatsuki
parents: 2
diff changeset
327 NodeOperation は NodePath とペアで扱わなければならず、このペアを TreeOperation という。
tatsuki
parents: 2
diff changeset
328 Jungle によるデータの編集は TreeOperation が複数集まった単位で commit されていく.
tatsuki
parents: 2
diff changeset
329 この TreeOperation の集まりを TreeOperationLog という。
tatsuki
parents: 2
diff changeset
330 TreeOperationLogの仕様をソースコード\ref{src:treeoperationlog}に示す.
tatsuki
parents: 2
diff changeset
331 \begin{lstlisting}[frame=lrbt,label=src:treeoperationlog,caption=TreeOperationLogの仕様,numbers=left]
tatsuki
parents: 2
diff changeset
332 public interface TreeOperationLog extends Iterable<TreeOperation>
tatsuki
parents: 2
diff changeset
333 {
15
tatsuki
parents: 14
diff changeset
334 public TreeOperationLog add(NodePath _p,NodeOperation _op);
tatsuki
parents: 14
diff changeset
335 public TreeOperationLog append(TreeOperationLog _log);
tatsuki
parents: 14
diff changeset
336 public int length();
6
tatsuki
parents: 2
diff changeset
337 }
tatsuki
parents: 2
diff changeset
338 \end{lstlisting}
tatsuki
parents: 2
diff changeset
339
tatsuki
parents: 2
diff changeset
340 \verb|Iterable<TreeOperation>|を継承しているためIteratorによりTreeOperationを取り出せるようになっている。
tatsuki
parents: 2
diff changeset
341 addやappendメソッドを使ってTreeOperationを積み上げていくことができる。
tatsuki
parents: 2
diff changeset
342 積み上げたLogをディスクに書き出すことで、Jungleは永続性を持つ。
tatsuki
parents: 2
diff changeset
343 分散版Jungleでは、Logを他ノードに送ることで、データの分散を行う。
tatsuki
parents: 2
diff changeset
344
tatsuki
parents: 2
diff changeset
345
tatsuki
parents: 2
diff changeset
346
2
tatsuki
parents:
diff changeset
347
14
tatsuki
parents: 11
diff changeset
348 \section{検索API}
2
tatsuki
parents:
diff changeset
349 これまでに紹介したAPIにより、Jungleは木構造を構築できるようになった。
15
tatsuki
parents: 14
diff changeset
350 しかし、木に問い合わせを行う検索APIが実装されていなかったため、木の走査を行う{\tt Interface Traverser}クラス内に、lambda式を用いて実装した。
2
tatsuki
parents:
diff changeset
351 以下に検索を行う関数{\tt find}の定義を記述する。
tatsuki
parents:
diff changeset
352 \begin{lstlisting}[frame=lrbt,label=query,numbers=left]
tatsuki
parents:
diff changeset
353 public Iterator<TreeNode> find(Query query, String key, String searchValue);
tatsuki
parents:
diff changeset
354 \end{lstlisting}
tatsuki
parents:
diff changeset
355
15
tatsuki
parents: 14
diff changeset
356 関数{\tt find}は、第一引数には、探索の条件を記述する関数{\tt boolean comdition(TreeNode)}を定義した{\tt Query}を、
2
tatsuki
parents:
diff changeset
357 第二、第三引数には、Indexを用いた絞込に使用する{\tt String key、String value}を取り、条件に一致したノードの{\tt Iterator}を返す。
11
tatsuki
parents: 6
diff changeset
358 {\tt 関数find}の使用例を以下に記す。
2
tatsuki
parents:
diff changeset
359
tatsuki
parents:
diff changeset
360 \begin{lstlisting}[frame=lrbt,label=find,numbers=left]
tatsuki
parents:
diff changeset
361 InterfaceTraverser traverser = tree.getTraverser(true);
tatsuki
parents:
diff changeset
362 Iterator<TreeNode> resultNodeIterator = traverser.find((TreeNode node) -> {
15
tatsuki
parents: 14
diff changeset
363 String name = node.getAttributes().getString("name");
tatsuki
parents: 14
diff changeset
364 if (name == null) return false;
tatsuki
parents: 14
diff changeset
365 return name.equals("kanagawa");
tatsuki
parents: 14
diff changeset
366 }, "belong", "ryukyu");
2
tatsuki
parents:
diff changeset
367 \end{lstlisting}
tatsuki
parents:
diff changeset
368
tatsuki
parents:
diff changeset
369
tatsuki
parents:
diff changeset
370 上記コードについて解説する。
15
tatsuki
parents: 14
diff changeset
371
tatsuki
parents: 14
diff changeset
372 1行目で検索対象の木から、検索に使用する {\tt Interface Traverser} を取得する。
tatsuki
parents: 14
diff changeset
373 2行目で、検索を行う関数 {\tt find()} を使用する。
tatsuki
parents: 14
diff changeset
374 今回は、Index を使って、属性名 {\tt "belong"} 属性値 {\tt "ryukyu"} を持つノード取得し、
tatsuki
parents: 14
diff changeset
375 3 - 5行目で定義されたクエリに渡す。
tatsuki
parents: 14
diff changeset
376 そして、クエリの中で属性名 {\tt "name"} 属性値 {\tt "kanagawa"} を持つノードかどうかを確かめる。
tatsuki
parents: 14
diff changeset
377
tatsuki
parents: 14
diff changeset
378 結果として、属性名 {\tt "belong"} 属性値{\tt "ryukyu"}と、属性名 {\tt "name"} 属性値{\tt kanagawa}の2つのデータを持つノードの {\tt Iterator} が取得できる。
tatsuki
parents: 14
diff changeset
379 検索の際に使用する Index の実装については次節に記述する。
2
tatsuki
parents:
diff changeset
380
15
tatsuki
parents: 14
diff changeset
381 \begin{comment}
tatsuki
parents: 14
diff changeset
382 \begin{enumerate}
tatsuki
parents: 14
diff changeset
383 \item 木の走査を行う{\tt Traverser}クラスを取得する。
tatsuki
parents: 14
diff changeset
384
tatsuki
parents: 14
diff changeset
385 \item Indexから{\tt find}の第2、第3引数である、属性名 {\tt belong}、属性値 {\tt ryukyu}の組のデータを持つノードを取得し、Queryに渡す(ノードの絞込を行う)。
2
tatsuki
parents:
diff changeset
386
15
tatsuki
parents: 14
diff changeset
387 \item 引数のノードから関数{\tt getAttributes().getString("name")}で属性名 {\tt name}とペアになっている属性値を取得する。
tatsuki
parents: 14
diff changeset
388
tatsuki
parents: 14
diff changeset
389 \item 属性値が{\tt null}だった場合、このノードには属性名が{\tt name}の組のデータは存在しないので、{\tt false}を返し次のノードの評価を行う。
tatsuki
parents: 14
diff changeset
390
tatsuki
parents: 14
diff changeset
391 \item 属性値が{\tt null}でなかった場合、{\tt kanagawa}と一致するかどうかを調べ結果を返す。
2
tatsuki
parents:
diff changeset
392
tatsuki
parents:
diff changeset
393 \end{enumerate}
15
tatsuki
parents: 14
diff changeset
394 \end{comment}
2
tatsuki
parents:
diff changeset
395
tatsuki
parents:
diff changeset
396
14
tatsuki
parents: 11
diff changeset
397 \section{Index}
2
tatsuki
parents:
diff changeset
398 Jungleは、非破壊的木構造というデータ構造上、過去の版の木構造を全て保持している。
11
tatsuki
parents: 6
diff changeset
399 よって、全ての版に独立したIndexが必要となるため、前の版のIndexを破壊すること無く、Indexを更新する必要がある。
2
tatsuki
parents:
diff changeset
400 既存のTreeMapでは、一度Indexの複製を行ない、その後更新する必要があったため、Indexの更新オーダーがO(n)となっていた。
18
d5306971efbf eng abst
tatsuki
parents: 15
diff changeset
401 その問題を解決するため、Java 上で関数型プログラミングを行えるライブラリである、 Functional Java の TreeMapを使用し、それを用いてIndexの実装を行った。
2
tatsuki
parents:
diff changeset
402 このTreeMapは、Jungleと同じようにルートから変更を加えたノードまでの経路の複製を行い、データの更新を行った際、前の版と最大限データを共有した新しいTreeMapを作成する。
tatsuki
parents:
diff changeset
403 Jungleとの違いは、木の回転処理が入ることである。
tatsuki
parents:
diff changeset
404 これにより複数の版全てに対応したIndexをサポートすることが可能になった。
tatsuki
parents:
diff changeset
405 以下にJungleにおけるIndexの型を記述する
tatsuki
parents:
diff changeset
406
tatsuki
parents:
diff changeset
407 \begin{lstlisting}[frame=lrbt,label=index,numbers=left]
11
tatsuki
parents: 6
diff changeset
408 TreeMap<String key,TreeMap<String attribute,List<TreeNode> nodeList> index> indexMap
2
tatsuki
parents:
diff changeset
409 \end{lstlisting}
tatsuki
parents:
diff changeset
410
tatsuki
parents:
diff changeset
411 JungleのIndexは{\tt IndexMap}内に保持されている。
tatsuki
parents:
diff changeset
412 属性名で{\tt IndexMap}に{\tt get}を行うと、対応したIndexが取得できる。
tatsuki
parents:
diff changeset
413 取得したIndexに属性値で{\tt get}を行うと、ノードのリストが返ってくる。
tatsuki
parents:
diff changeset
414 以下にIndexから属性名 name 属性値 kanagawaのデータを持つ、ノードのIteratorを取得するサンプルコードを記述する。
tatsuki
parents:
diff changeset
415
tatsuki
parents:
diff changeset
416 \begin{lstlisting}[frame=lrbt,label=find,numbers=left]
tatsuki
parents:
diff changeset
417 Optional<TreeMap<String, List<TreeNode>>> indexOp = indexMap.get("name");
tatsuki
parents:
diff changeset
418 if (!indexOp.isPresent())
tatsuki
parents:
diff changeset
419 return new NulIterator<TreeNode>();
15
tatsuki
parents: 14
diff changeset
420 TreeMap<String, List<TreeNode>> index = indexOp.get();
tatsuki
parents: 14
diff changeset
421 Optional<List<TreeNode>> nodeListOp = index.get("kanagawa");
2
tatsuki
parents:
diff changeset
422 if (!nodeListOp.isPresent())
tatsuki
parents:
diff changeset
423 return new NulIterator<TreeNode>();
tatsuki
parents:
diff changeset
424 return nodeListOp.get().iterator();
15
tatsuki
parents: 14
diff changeset
425 \end{lstlisting}
tatsuki
parents: 14
diff changeset
426
tatsuki
parents: 14
diff changeset
427 1 - 4行目で IndexMap から 属性名 "name" に対する値を持つ Index を取得している。
tatsuki
parents: 14
diff changeset
428 5 - 8行目で 取得した Index から、 属性名 "kanagawa" を持つノードの{ \tt Iterator}を取得している。
2
tatsuki
parents:
diff changeset
429
tatsuki
parents:
diff changeset
430
15
tatsuki
parents: 14
diff changeset
431 \begin{comment}
tatsuki
parents: 14
diff changeset
432 \begin{enumerate}
tatsuki
parents: 14
diff changeset
433 \item {\tt indexMap}に、今回検索で使用する属性名 {\tt name}を使用して{\tt get("name")}を行う。すると属性名 {\tt "name"}に対応したIndexが、{\tt Optional}クラスで包まれて返ってくる。
2
tatsuki
parents:
diff changeset
434
15
tatsuki
parents: 14
diff changeset
435 \item {\tt Optional}オブジェクトに対して、中身を保持しているか(属性名 {\tt name}に対応したIndexを木が持っているか)を調べる。
2
tatsuki
parents:
diff changeset
436
15
tatsuki
parents: 14
diff changeset
437 \item 持っていなかった場合、空の{\tt Iterator}オブジェクトを返す。
2
tatsuki
parents:
diff changeset
438
15
tatsuki
parents: 14
diff changeset
439 \item 持っていた場合、{\tt Optional}オブジェクトからIndexを取得する。
2
tatsuki
parents:
diff changeset
440
15
tatsuki
parents: 14
diff changeset
441 \item 取得したIndexに、検索で使用する属性値{\tt "kanagawa"}で{\tt get()}を行う。すると、属性名 {\tt "name"} 属性値{\tt "kanagawa"}の値を持つノードのリストが、{\tt Optional}クラスに包まれて返ってくる。
2
tatsuki
parents:
diff changeset
442
15
tatsuki
parents: 14
diff changeset
443 \item {\tt Optional}オブジェクトに対して中身を保持しているか(属性名 {\tt "name"} 属性値 {\tt "kanagawa"}を持つノードを木が持っているか)を調べる。
2
tatsuki
parents:
diff changeset
444
15
tatsuki
parents: 14
diff changeset
445 \item 持っていなかった場合、空の{\tt Iterator}オブジェクトを返す。
2
tatsuki
parents:
diff changeset
446
15
tatsuki
parents: 14
diff changeset
447 \item 持っていた場合{\tt Optional}オブジェクトからノードリストの{\tt Iterator}を返す。
2
tatsuki
parents:
diff changeset
448
15
tatsuki
parents: 14
diff changeset
449 \end{enumerate}
tatsuki
parents: 14
diff changeset
450 \end{comment}
2
tatsuki
parents:
diff changeset
451
15
tatsuki
parents: 14
diff changeset
452 JungleはこれらのAPIにより、木構造を格納、編集、検索する機能を持っている。
2
tatsuki
parents:
diff changeset
453
15
tatsuki
parents: 14
diff changeset
454 \newpage