Google App Engine(以下、GAE)のデータストア「Bigtable」は分散KVS(キー・バリューストア)ですが、分散KVSは特に条件検索での制約が多く、RDBには劣っている点も多いと言われています。
確かに集合関数が使用できないことをはじめとしてSQL機能では見劣りする点も多く、gaedirectの条件検索機能は、さらにそのサブセットになっています。これはJavaScriptでの直接アクセス方式によるgaedirectでは、Bigtableの複合インデックスを使用することが困難なことからやむを得ないとも言えます。
しかし、だからといって「gaedirectの条件検索は使えない」ということはありません。クラウド上で使用されるアプリケーションも多岐に渡り、それほど複雑な検索を必要としない場合もあり、特にソーシャルアプリでは検索方式も限られたもので間に合う場合も多いはずです。
要は、アプリケーションで要求される機能を仕様レベルで検討し、分散KVSでも十分対応可能という見込みを持ってアプリケーションを開発すればいいわけです。また、アプリケーションの工夫によって、条件検索をある程度限定してもユーザーにそれほど不自由を感じさせないようにすることも可能です。
ここから条件検索の具体例に入っていきます。最初に検索対象となる全てのエンティティを管理者画面から確認してみます。
図8と図9はkind名gmapsに属する全てのエンティティです。図3のマーカおよびクリックで表示される吹き出しに関する情報が全て登録されています。このエンティティを対象にgaedirectでの条件検索を実行してみます。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>Google Maps API</title> <script type="text/javascript" src="/jslib/gaedirect.js"></script> <script type="text/javascript" src="/jslib/jquery-1.5.min.js"></script> <script type="text/javascript"> $(function(){ var query = ginit(); query["kind"] = "gmaps"; query["key"] = "none"; query["id"] = "area,lon,lat,comment,type"; var tags = ""; var lon = 0.0, lat = 0.0, comment = "", type = ""; var kind = "gmaps"; var props1 ="pref,area,do:lon,do:lat,comment,type"; var props2 ="pref,area,lon,lat,comment,type"; var propsa = props2.split(","); //開始[1] プロパティ値一致で検索(prefが岩手県) $("#revcond1").click(function(){ var query = rinit(); query["EQUAL"] = "pref:岩手県"; $.get(gae(), query, function(resp){render(resp);}); }); //終了[1]プロパティ値一致で検索(prefが岩手県) //開始[2]緯度で降順ソート $("#revcond2").click(function(){ var query = rinit(); query["SORT"] = "lat:DESCENDING"; $.get(gae(), query, function(resp){render(resp);}); }); //終了[2]緯度で降順ソート //開始[3]3番目のエンティティから表示 $("#revcond3").click(function(){ var query = rinit(); query["SORT"] = "lat:DESCENDING"; query["OFFSET"] = "3"; $.get(gae(), query, function(resp){render(resp);}); }); //終了[3]3番目のエンティティから表示 //開始[4]3番目のエンティティから5つを表示 $("#revcond4").click(function(){ var query = rinit(); query["SORT"] = "lat:DESCENDING"; query["OFFSET"] = "3"; query["LIMIT"] = "5"; $.get(gae(), query, function(resp){render(resp);}); }); //終了[4]3番目のエンティティから5つを表示 //開始[5]緯度≧39.0のエンティティを表示 $("#revcond5").click(function(){ var query = rinit(); query["GREATER_THAN"] = "do:lon:141.0"; $.get(gae(), query, function(resp){render(resp);}); }); //終了[5]緯度≧39.0のエンティティを表示 //開始[6]39.0≦緯度<40.0のエンティティを表示 $("#revcond6").click(function(){ var query = rinit(); query["SORT"] = "lat:DESCENDING"; query["LESS_THAN"] = "do:lat:40.0"; query["GREATER_THAN_OR_EQUAL"] = "do:lat:38.5"; $.get(gae(), query, function(resp){ render(resp);}); }); //終了[6]39.0≦緯度<40.0のエンティティを表示 //開始[7]都県名が「宮城県」以外のエンティティを表示 $("#revcond7").click(function(){ var query = rinit(); query["NOT_EQUAL"] = "pref:宮城県"; $.get(gae(), query, function(resp){ render(resp);}); }); //終了[7]都県名が「宮城県」以外のエンティティを表示 //開始[8]都県名が「岩手県」「宮城県」のどちらかのエンティティを表示 $("#revcond8").click(function(){ var query = rinit(); query["IN"] = "pref:岩手県,宮城県"; $.get(gae(), query, function(resp){ render(resp);}); }); //終了[8]都県名が「岩手県」「宮城県」のどちらかのエンティティを表示 function rinit(){ var query = ginit(); query["kind"] = "gmaps"; query["key"] = "none"; query["id"] = "pref,area,lon,lat,moddate"; return query; } function render(resp){ var tags = ""; var pname = new Array(); pname[0] = "キー"; pname[1] = "都府県"; pname[2] = "市町村"; pname[3] = "経度"; pname[4] = "緯度"; pname[5] = "更新日"; var ents = resp.split("<e>"); for(var i = 0; i < ents.length; i++){ var props = ents[i].split("<p>"); tags += "<li>"; for (var j = 0; j < props.length -1 ; j++) { tags += " " + pname[j] + " : " + props[j] + " | "; } tags += "</li>"; } $("#out").html(tags); } $("#del1").click(function(){$("li").remove();}); }); </script> </head> <body> <h3>◆条件検索表示◆</h3> <p> <div><input type="button" id="revcond1" value=" 参照 "/>[1]プロパティ値一致で検索(prefが岩手県)</div> <div><input type="button" id="revcond2" value=" 参照 "/>[2]緯度で降順ソート</div> <div><input type="button" id="revcond3" value=" 参照 "/>[3]3番目のエンティティから表示</div> <div><input type="button" id="revcond4" value=" 参照 "/>[4]3番目のエンティティから5つを表示</div> <div><input type="button" id="revcond5" value=" 参照 "/> [5] 緯度≧39.0のエンティティを表示/div> <div><input type="button" id="revcond6" value=" 参照 "/>[6]39.0≦緯度<40.0のエンティティを表示</div> <div><input type="button" id="revcond7" value=" 参照 "/>[7]都県名が「宮城県」以外のエンティティを表示</div> <div><input type="button" id="revcond8" value=" 参照 "/>[8]都県名が「岩手県」「宮城県」のどちらかのエンティティを表示</div> <div><input type="button" id="del1" value=" クリア "/>表示フィールド クリア</div> </p> <p><ul id="out" type="square"></ul></p> </body> </html>
リスト2は今回のサンプルでの条件検索に関係する部分ですが、このリストを使用して見ていきます。条検検索はID値が「revcond1」から「revcond8」のボタンをクリックすると、対応する条件検索が実行されるので、順に見ていきます。
$("#revcond1").click(function(){ var query = rinit(); //(1)条件検索の初期化 query["EQUAL"] = "pref:岩手県"; //(2)一致プロパティ値の指定 $.get(gae(), query, function(resp){ render(resp); }); //(3)条件検索実行 });
gaedirectでの条件検索では最初に共通の処理を行います。リスト3では(1)でrinit関数を呼び出していて、rinit関数の内容はリスト4のようになっています。処理内容については前ページで触れているので問題ないでしょう。
function rinit(){ var query = ginit(); query["kind"] = "gmaps"; query["key"] = "none"; query["id"] = "pref,area,lon,lat,moddate"; return query; }
またリスト3の(3)は、全ての条件検索で共通のコード記述になっているので、結局検索での条件指定はリスト3の(2)だけになり、連想配列(query)のキーに「EQUAL」を指定し、バリューとして一致の対象となるプロパティ名(pref)と値(岩手県)を「:」で区切ります。
サンプルでの画面表示は共通のrendar関数(リスト5)で行っています。
function render(resp){ var tags = ""; var pname = new Array(); pname[0] = "キー"; pname[1] = "都府県"; pname[2] = "市町村"; pname[3] = "経度"; pname[4] = "緯度"; pname[5] = "更新日"; var ents = resp.split(""); for(var i = 0; i < ents.length; i++){ var props = ents[i].split(" "); tags += " "; for (var j = 0; j < props.length -1 ; j++) { tags += " " + pname[j] + " : " + props[j] + " | "; } tags += " "; } $("#out").html(tags); }
以下、検索条件と結果表示を見ていきます。
$("#revcond2").click(function(){ var query = rinit(); query["SORT"] = "lat:DESCENDING"; $.get(gae(), query, function(resp){render(resp);}); });
ソートではqueryキーに「SORT」を指定し、バリューでソート対象のプロパティ値と、昇順(ASCENDING)または降順(DESCENDING)の指定を「:」区切りで指定します。
$("#revcond3").click(function(){ var query = rinit(); query["SORT"] = "lat:DESCENDING"; //(4) query["OFFSET"] = "3"; //(5) $.get(gae(), query, function(resp){render(resp);}); });
リスト7では(4)で、緯度で降順ソートした後、(5)で先頭から3番目のエンティティからの表示を指定しています。
$("#revcond4").click(function(){ var query = rinit(); query["SORT"] = "lat:DESCENDING"; query["OFFSET"] = "3"; query["LIMIT"] = "5"; //(6) $.get(gae(), query, function(resp){ render(resp);}); });
リスト8では、リスト7の条件に(6)のLIMITを追加して、検索数を5件にしています。
$("#revcond5").click(function(){ var query = rinit(); query["GREATER_THAN"] = "do:lon:141.0"; //(7) $.get(gae(), query, function(resp){ render(resp);}); });
リスト9では、倍精度浮動小数点数(do)で経度(lon)が141.0より大きい(GREATER_THAN)エンティティを選択して表示しています。
$("#revcond6").click(function(){ var query = rinit(); query["SORT"] = "lat:DESCENDING"; //(8) query["LESS_THAN"] = "do:lat:40.0"; //(9) query["GREATER_THAN_OR_EQUAL"] = "do:lat:38.5"; //(10) $.get(gae(), query, function(resp){ render(resp);}); });
リスト10では、(8)のソート条件の他に「38.3≦緯度(lat)<40.0」を(9)と(10)で指定しています。
$("#revcond7").click(function(){ var query = rinit(); query["NOT_EQUAL"] = "pref:宮城県"; //(11) $.get(gae(), query, function(resp){render(resp);}); });
リスト11では、(11)でプロパティ名の都県名(pref)が「宮城県」以外のエンティティを検索・表示しています。
$("#revcond8").click(function(){ var query = rinit(); query["IN"] = "pref:岩手県,宮城県"; //(12) $.get(gae(), query, function(resp){render(resp);}); });
リスト12では、(12)で都県(pref)が「岩手県」、または「宮城県」のエンティティを抽出・表示しています。
以上がgaedirectでの条件検索の指定方式と、およその条件指定内容です。条件検索の指定方法に関してもgaedirectはシンプルで分かりやすいのではと思います。
次回は、いよいよgaedirectのセットアップの仕方を紹介する予定です。またEclipse環境およびコマンドライン環境への設定および基本的な操作方法とGAEクラウド環境へのアップロードについても紹介したいと思います。次回もぜひご期待ください。
@IT関連記事
本当はすごい、知られざるGoogle Maps APIたち!!
インタビュー特集:Google直伝!(3) 数多く存在するGoogle MapsのAPIや機能のうち、あまり知られていないものや新しいもの、とっておきをGoogle担当者に聞いた
「リッチクライアント & 帳票」フォーラム 2009/5/21
商業利用もOK! Google Mapsについて知りたいこと
インタビュー特集:Google直伝!(2) Google Mapsライセンス担当者インタビュー。問い合わせの多い質問から順に、意外と知らない利用規約を分かりやすくお伝えする
「リッチクライアント & 帳票」フォーラム 2009/5/11
クラウドで動くGPS連動スマホ用Webアプリを作る
たぶん1時間でできるマッシュアップ講座 Google App Engine用Webアプリ開発の環境を構築し、マップや位置情報取得、施設情報のWeb APIを組み合わせてみます
「Smart & Social」フォーラム 2010/11/4
携帯の醍醐味! 位置情報とGoogleマップを使うには
クラウドとフレームワークで超簡単ケータイ開発(終) Mobyletの機能で位置情報を取得し、Google Static Maps APIで地図画像を表示する方法について解説します
Smart & Social」フォーラム 2011/3/10
iPhoneアプリで位置情報と地図を使うための基礎知識
iOSでジオ(GEO)プログミラング入門(1) 利用が加速するジオメディアを使うための基礎としてCoreLocationとMapKitの2つのフレームワークの使い方を中心に解説します
「Smart & Social」フォーラム 2011/4/4
地図/位置情報/GPSを使うAndroidアプリを作るには
Androidで動く携帯Javaアプリ作成入門(16) Android Maps API Keyの取得方法を紹介し、その使い方やさまざまな設定/表示と操作方法、注意点を徹底解説します
「Smart & Social」フォーラム 2010/4/7
Copyright © ITmedia, Inc. All Rights Reserved.