Google App Engine を用いた Web アプリケーションの開発支援に関する研究
2007MI163 中澤祐斗 2008MI091 片岡久幸

2009SE044 服部圭太

指導教員：蜂巣吉成

1

はじめに

2

関連研究・関連技術

現在，多くのクラウドコンピューティングサービスが提 2.1 関連研究供されている．クラウドコンピューティングサービスは， [4] は Struts フレームワークで構成された Web アプリ
ユーザーがネットワークを利用する環境を用意するだけ ケーションを Slim3 フレームワークを利用した Web アプ
で，サービスを提供している企業のコンピューティング・ リケーションに変更を行い，GAE に移行を行うものであリソースの利用が可能になる．クラウドコンピューティ る．フレームワーク変更に伴う設定ファイルや Java コー
ングサービスを利用することで，サーバーの新規設置な ドの書き換え方法を示している．データアクセス部につどの設備投資やメンテナンスなどの管理コストをサービ いては，Like 句などの書き換えが必要であることを述べ
ス提供側に全て任せることができ，コストを削減するこ ているが，その方法については示していない．本研究でとができる．これまで自前でサーバーを用意し，その上 はデータアクセス部を RDB から KeyValue 型に書き換えで Web アプリケーションを開発・運用していたユーザー る方法を提案し，GAE への移行方法を示す．
もクラウド上に移行することでクラウドコンピューティ
2.2 データストア API
ングサービスの利点を受けることができる．
クラウドコンピューティングサービスでは，一般的にGAE ではデータストアを操作する API として JDO とKeyValue 型のデータストアが提供されている. KeyValue Low Level API が提供されている．GAE の Low Level型のデータストアは，これまで一般的に利用されていた API は，GAE 専用の API である．JDO は，データベーRDB と比べて負荷分散や可用性に優れており，拡張を行 スへアクセスを行う一般的な API であり，GAE にも利うことが容易である．データの増加による機能の低下が 用が可能である．GAE の JDO は，内部では Low Level
少なく，データの登録が多い Web アプリケーションの運 API の呼び出しに変換して処理を行なっている．
用にも向いている．しかし，KeyValue 型のデータストア
JDO はオブジェクトの永続化を管理する Persistenceは，テーブルへの JOIN コマンドが使えないこと，複雑な ManagerFactory の初期化に時間がかかり，一般に Low条件検索を行うことができないなどの違いがある．デー Level API よりもスピンアップ (GAE における Web アプ
タストアの構成自体が異なるので，RDB の設計の考え方 リケーションの起動) が遅い．GAE では数分間アクセスをそのまま用いることは相応しくない．RDB から移行を がない状態が続くと Web アプリケーションが終了してし行う場合は，互いのデータベースの違いを理解し，利用 まう (スピンダウンという)．これにより，GAE の Webするクラウドコンピューティングサービスに適した設計 アプリケーションはスピンアップが頻繁に行われることに再構成をする必要がある．クラウドコンピューティン になる．
グサービスを利用したことがないユーザーが Web アプリ
JDO と Low Level API を用いて家計簿のアプリケー
ケーションを移行をするには敷居が高い．
ションをサンプルとして実現し，スピンアップと登録，削本研究は，RDB を利用している Web アプリケーショ 除，更新，検索の実行時間を計測した (表 1)．
ンを KeyValue 型のデータストアを利用する Web アプ
表 1 JDO と Low Level API の実行時間 (ms)
リケーションへの書き換えを支援することを目的とする．
処理
JDO
Low Level API
スピンアップ
15246.0ms(674.1)
10151.7(253.1)
Web アプリケーションの機能を維持したままクラウドコ
登録(1件)
138.5(9.6)
127.3(10.3)
ンピューティングへ移行するための書き換え方法を提案す削除 (1 件)228.0(11.3)
187.8(15.5)
る．同じ機能を持つ Web アプリケーションをクラウドコ
更新 (1 件)202.5(19.6)
114.3(1.7)
ンピューティング上に再度構築する手間がなくなり，Web
検索 (1500 件)
67.0(19.4)
52.5(24.1)
アプリケーションのクラウドコンピューティングへの移
括弧内は標準偏差行を低コストで実現することができる．利用するクラウ
登録，削除，更新，検索は JDO と Low Level API では
ドコンピューティングサービスには，Google が提供して ほとんど差ないが，スピンアップでは JDO が Low Level
いる Google App Engine for Java[1][2](以下，GAE とい API に比べて，5 秒ほど遅いことが確認できた．
う) を用いる．書き換えを行う対象として，Java フレー
本研究では，上記の結果を考慮して，Web アプリケー
ムワーク Struts で作成された Web アプリケーションを ションの書き換えに Low Level API を用いる．JDO を用対象とする．Struts は基礎的な CRUD 機能を提供するフ いた書き換えについては，6.3 節の考察で詳細を示す．
レームワークであり，Web アプリケーションの開発においてクラウドコンピューティングの普及前から現在に至るまで多く利用されている．

3

移行における課題

3.1

データストアによる制約

RDB を利用している Web アプリケーションを GAEに移行する際に，データストアの違いによるクエリの機能の違いを考慮する必要がある．また，データストアの違いとクエリの機能の違いから作成するテーブルの構成を変更する必要がある．GAE の Bigtable では，データベースへのクエリは簡単な検索機能しか使うことができず，RDB で使用していた SQL クエリの一部の機能が利用できない．一般的な Web アプリケーションで使用されているもので，使用できない SQL クエリの機能には次のものがある [2][3]．

しかし，データストアへのアクセス回数に比例して実行時間やリソースの消費量が増加するので，クエリを何度も実行するのは望ましくない．対象プロパティの更新頻度が低ければ，表 3 のようにテーブルを非正規化し，一つのテーブルに情報をまとめておくことでクエリの回数を減らすことが可能である．
表 2 Key による外部テーブルの参照
買い物テーブル
keyxxxid
1

description
商品 A

category keyy

amount500year2013

month
1day10month
1day10

カテゴリテーブル
keyyid1

name
食費id1

description
商品 A

1. JOIN による複数テーブルの参照
2. 集約関数 (SUM，MAX，MIN，AVG，COUNT)
3. LIKE を用いた部分一致検索 (前方一致を除く)
4. 複数プロパティへの不等号記号を用いた検索5. OR による論理結合
6. GROUP BY 句を用いたグループ化
3.2

問題解決の必要性

GAE に Web アプリケーションを移行する場合，データストアへアクセスを行う API の変更だけでは不十分である．Web アプリケーションの機能を変更することなく移行を行うには，GAE で扱えないクエリを Web アプリ
ケーション側での処理や GAE で扱えるクエリを組み合わせて代替する必要がある．しかし，Java コードの追加や変更が必要な箇所が多く，実行時間なども考慮した場合は，データストアの違いを理解する必要がありコストがかかる．そこで，移行を行う際のテーブルの設計やクエリの代替方法を提案することで，Web アプリケーショ
ン移行の際の問題点を短時間で解決できる．

書き換え方法の提案

4表 3 テーブルの非正規化
keyxxxcategory name
食費

amount500year2013• 制約 2：集約関数 (SUM)
集約関数は，専用のテーブル (以下，集約エンティティという) を新たに定義し，計算結果を格納しておくことで対応が可能である．
図 1 は，集約関数 SUM を集約エンティティを用いて対応した例である．あらかじめ 1 件登録されているテーブルに 1 件追加した場合の集約エンティティの処理を示している．
purchasesテーブル
keyidx1

description category_id amount year month
商品Ayday500

2013

1103002013

115+xx2

商品B

yy

sumテーブル
sum = sum + amount
800 = 500 + 300

keysumz

800

3.1 節で述べた Bigtable の制約は，テーブルの再設計
図 1 集約関数 (SUM)とクエリの書き換えの 2 通りの対応方法がある．制約 1，2 は RDB として定義されたテーブルを Bigtable 用に再 4.2 SQL クエリの書き換え設計することで対応できる．制約 2，3，4，5 は SQL ク
本研究では，Low Level API を用いて SQL クエリの書
エリを Low Level API によるデータ取得処理と取得後のき換えを行う．SQL クエリの書き換えに必要な情報としリストに対する処理 (以下，Web アプリ処理) に書き換えて次のものがある．
ることで対応できる．制約 2 の集約関数は，テーブルの• 書き換えを行う SQL クエリ
再設計とクエリの書き換えの 2 つの方法で対応が可能なので，アプリケーションの処理内容に応じて使い分けが必要となる．

4.1

テーブルの再設計• 動的 SQL の変数または PreparedStatement の set メ
ソッド• テーブルの再設計によって得られた対応情報

SQL クエリを分割し，Low Level API が提供する機能• 制約 1：JOIN による複数テーブルの参照に置き換えることで単純な CRUD 機能は書き換えること
表 2 は，サンプルに利用した家計簿 Web アプリケーが可能である．また，テーブルの再設計を行ったことでションの元のテーブル構成である．Bigtable では，プロパティ名の変更や検索，更新処理の追加を行う必要
JOIN による複数テーブルからのデータ取得が出来がある場合もある．書き換えにはテーブルの再設計時にないので，表 2 のように外部キーを使用する場合は，得られた情報も利用しなければならない．
category key の値からカテゴリテーブルを取得する．

• 制約 5：OR による論理結合
1 つ目の条件に対して検索を行い，更に 1 つめの条件を除いた状態で 2 つ目の条件に対して検索を行う．
その後，それらの結果を結合する (図 5)．

• 制約 2：集約関数 (SUM)
全件取得後，合計したいプロパティを抜き出し，for
文による繰り返しで合計値を求める (図 2)．
select sum(プロパティ) from テーブル where 条件

select * from テーブル where A > 10 or B < 100

Query query = new Query("テーブル");
query.addFilter(条件);//Filter1 一つ目の条件に対して検索
Query query = new Query("テーブル");
query.addFilter("A", FilterOperator.GREATER_THAN, 10);
List<Entity> list1 = ds.prepare(query).asList(OPT);

List<Entity> list = ds.prepare(query).asList(OPT);
int amount = 0;for(Entity entity: list){
int value = Integer.valueOf(entity.getProperty(プロパティ).toString()).intValue();amount = amount + value;}//Filter2 2つ目の条件に対して検索//(1つ目の条件は除く)
省略
list2.add(filterlist);}}

図 2 SUM 関数• 制約 3：Like 演算子//検索結果を結合
List<Entity> result = new ArrayList<Entity>();result.addAll(list1);
result.addAll(list2);

一度全件取得した後，Pattern クラス及び Matcher
クラスを用いてキーワードを含むエンティティのみを抜き出すことで部分一致検索を実現する (図 3)．

図 5 OR による論理結合

select * from テーブル where プロパティ like 検索ワード//全件取得Query query = new Query("テーブル");
List<Entity> rs = ds.prepare(query).asList(OPT);//キーワードを含むもののみを抜き出す
for(Entity entity: rs){
String str = entity.getProperty("プロパティ").toString();
Pattern pattern = Pattern.compile("検索ワード");
Matcher matcher = pattern.matcher(str);
if(matcher.find()){//キーワードを含んでいればリストに追加
list.add(entity);}}

図 3 Like 演算子• 制約 4：複数のプロパティに対する不等号を用いた検索
Bigtable には，一つのプロパティに対してしか不等号による検索を行えないという制限が存在する．複数のプロパティに対して不等号を用いる場合，まず一つのプロパティに対して検索した後，for 文による繰り返しで 2 つ目以降のプロパティを抜き出し，if
文で対象エンティティのみを取得する (図 4)．
select * from テーブル where A > 10 and B < 100

Query query = new Query("テーブル");
query.addFilter("A", FilterOperator.GREATER_THAN, 10);
List<Entity> filterlist = ds.preparety(query).asList(OPT);
List<Entity> list = new ArrayList<Entity>();for(Entity entity: filterlist){//int型に変換
int value = Integer.valueOf(entity.getProperty("B").toString()).intValue();if(value < 100){list.add(filterlist);}}

図 4 複数プロパティへの不等式検索

5

評価

5.1

評価方法

本研究で提案したクエリの書き換えの方法を用いて，Web アプリケーションの書き換えを行う．評価には次の2 つの Web アプリケーション [5] を用い，Web アプリケーションの稼働成否及び実行速度の比較を行う．

• 家計簿アプリケーション• ショッピングサイトアプリケーション
4.1 節のテーブルの再設計方法について，正規化したまま外部テーブルを利用する方法と，非正規化を行いテーブルに関連した情報を 1 つのエンティティにまとめる方
法の実行速度の比較を行う．外部テーブルの参照を行う
場合，アプリケーション側でキャッシュを利用することで，一度取得したデータを再び参照を行う必要がなくなる．
制約 2 の集約関数は，Web アプリ処理で代替する方法と集約エンティティを利用する方法に分けて比較を行う．
5.2

評価結果

評価に利用した 2 つのアプリケーションは，本研究で提案した書き換え方法を利用して，移行前と同様に動作することを確認できた．
表 4 と表 5 に，書き換えを行った Web アプリケーショ
ンの実行時間の平均時間の結果を示す．
表 4 の更新処理は，4.1 節の表 2 のカテゴリテーブルのname プロパティと表 3 の category name プロパティを変更する処理であり，登録された件数の３分の１を更新している．表 5 の登録処理は，どれも 1 件のデータを登録にかかった実行時間である．

表 4 実行時間結果：テーブル設計 (ms)(500 件)(1500 件)

検索
更新
検索
更新

外部テーブル213.2(85.4)
101.5(15.0)
1023.0(121.8)
125.8(33.2)

PersistenceManager pm = PMF.get().getPersistenceManager();
Query query = pm.newQuery("クラス.class");
query.setFilter("A < 10");

非正規化
96.2(46.2)
6017.5(838.9)
59.7(35.0)21564.5(4023.2)

List<クラス> filterlist = (List<クラス>)query.execute();;List<クラス> list = new ArrayList<クラス>();for(クラス entity: filterlist){
int value = entity.getB();if(value < 100){
list.add(filterlist);}}

括弧内は標準偏差表 5 実行時間結果：集約関数 (ms)(500 件)(1500 件)

登録
検索
登録
検索

Web アプリ処理
197.3(61.9)
240.2(71.7)
136.5(33.2)
297.7(8.0)

集約エンティティ
191.2(67.9)
37.8(1.0)
225.8(34.5)
47.2(4.9)

図 6 JDO を用いた書き換え例

7

おわりに

括弧内は標準偏差

本研究では，RDB を利用している Web アプリケーショ
ンを KeyValue 型のデータストアを利用する Web アプ
6.1 テーブル再設計に対する考察
リケーションへの書き換えを支援することを目的として，4.1 節のプロパティの更新頻度に関わるテーブルの設計 データストアの違いを考慮したデータベースのテーブルについて，検索処理は非正規化を行う方が速く，更新処 の再設計方法の提案とクエリの書き換え方法の提案を行っ
理では外部テーブルを利用する方が速い．しかし，正規 た．異なるデータストアへの移行の際に問題となるクエ化した場合の検索処理に比べて，非正規化した場合の更 リの機能の差については，元のクエリの機能を代替する手
新処理の実行時間はデータの件数が増えるほど大幅に遅 段を GAE のクエリの組み合わせや Web アプリケーショくなる．一般的な Web アプリケーションであれば正規化 ン側で実装を行うことで対応を行った．書き換えのサンしたテーブルでの実装を行う方が全体的な実行時間では プルに用いた Web アプリケーションで出現したクエリの望ましい．しかし，更新処理をほとんど行わない場合や， 機能は実装することができた．
検索処理の実行時間を重視する場合では，非正規化を行
しかし，本研究では SQL の集約関数の 1 つであるう方が望ましいことがある．
GROUP BY 句を記述していた場合の SQL クエリの対応ができていない．また，アプリケーションの内容によっ
6.2 集約関数に対する考察てはデータアクセス部以外の書き換えが必要となる．例
集約関数への対応方法について，集約エンティティを として，Basic 認証を用いたログイン機能が存在した場
利用する方法が Web アプリ処理を行う方法に比べて，検 合，ローカル環境と GAE では実装方法が大きく異なる．
索処理が大幅に速いことが確認できた．登録処理につい 加えて，Struts 以外のフレームワークが併用されていたては，Web アプリ処理を行う方法が速いが，大きな差は 場合もデータアクセス部の書換えのみでは対応出来ないない．扱うデータの件数が増加した場合，Web アプリ処 可能性があり，Struts 以外のフレームワークで構成され理を行う方法の検索処理は，集約エンティティを用いる た Web アプリケーションに書き換え方法を適用した場合
方法の登録処理よりも実行時間の増加量が大きくなると の有効性について検討が必要であると考えられる．
考えられる．集約関数の機能を代替する場合は，集約エ
今後の課題としては，SQL クエリの集約関数の 1 つでンティティを用いた書き換えが優位である．しかし，条 ある GROUP BY 句を使用した SQL 文，及びデータア件を指定しての検索などあらかじめ取得範囲を決めてお クセス部以外への対応方法の考案が挙げられる．
くのが困難なクエリを想定した場合は，Web アプリ処理参考文献を行う方法が望ましいと考える．

6

考察

6.3

JDO を用いた書き換え方法の考察[1] Google Dvelopers，
Google App Engine Google Developers,
https://developers.google.com/appengine/，2012．

4.2 節では，SQL クエリに Low Level API を用いた書き換え方法を提案したが，JDO を用いた書き換えについて考察する．SQL クエリの書き換え方法は，データスト [2] 中田秀基，すっきりわかる Google App Engine forJava クラウドプログラミング，SoftBank Creative，アからのデータ取得処理と取得したリストに対する処理
2010．に大きく分けられる．データ取得処理は JDO を用いても記述できる．Low Level API によるデータ取得ではテー [3] ひがやすお，小川信一，Slim3 on Google App Engine
for Java，秀和システム，2010.
ブルを指定し，データに対する条件をフィルタとして設定する．宣言的 JDO でも同様にテーブルを指定し，条件 [4] 倉持和彦，原田雅史， Struts アプリケーションのパをフィルタとして設定して，データを取得することがで
ブリッククラウド (Google App Engine) への移行にきる [2]．データ取得後の処理は，Low Level API と JDO
対する考察， 情報処理学会全国大会講演論文集第 72
でエンティティクラスの名前などに違いがあるが，リス回平成 22 年 (1)，pp.343-344，2010.
トに対する処理は同じである．図 4 の処理を JDO に書き [5] 高安厚思，西川麗，Struts による Web アプリケーショ
換えた例を図 6 に示す．1 行目から 3 行目が JDO による
ンスーパーサンプル，SoftBank Creative，2010．
データ取得で，5 行目以降がリストに対する処理である．