2015年1月15日木曜日

【GAE】初級実装編2 第二ラウンド開始

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

さて、先週まで画面レンダリングツール「JsRender」について連載していましたが、
今週からは再びクラウド基盤「Google App Engine(以下、GAE)」の連載に復活しようと思います。

今までのおさらい

GAE連載の最後は以下でした。


GAEのデータベースである「BigTable」にデータを叩き混む所までは出来ているんですね。
しかし、データは入れただけでは何の意味も無く、出力出来なければなりません。

出力は以下の二段構えになります。

  • 検索する。
  • 画面に出す。

このうち、「画面に出す」はGAEの機能ではなく、上述の「JsRender」によりフルAjaxにより実現します。
「JsRender」の連載は「検索→表示」の記事を書く為の前フリだったわけです。

JsRendeの記事は以下にまとめていますので、未読の方はご一読下さい。


第二ラウンド開始

そんなわけでいよいよ本命のGAEの記事に戻るわけですが、かなり期間が空いてしまったので一旦仕切り直し。
ここからは第二ラウンド「初級実装編2」として連載を進めて行こうと思います。

この第二ラウンドで、無事にレコードの「登録⇒検索⇒表示」の一連の流れは完成して、初級実装編は卒業ということになります。

しかしながら、私が思うに、検索の方は登録よりも難しいです……。
以下にサラッと触りを記載します。

登録は簡単

以前の記事の転載になりますが、GAEというのは、「登録・更新」は簡単だと思いますよ。

ShohinDao dao = new ShohinDao();
dao.put(shohin);

これだけですから。

Shohin shohin = new Shohin();
Map map = new HashMap();
map.put("ID_0001",shohin);

これとソックリ。
Mapにデータを叩き込むだけ。

まあ、一意制約チェックとかを実現するには少々ステップを伴うこともありますが、
基本的にはこれだけです。

普通のDBであれば、「大量データを一括登録する為にバッチインサート文を作って……」とか「SELECT INSERTで一括して登録を……」みたいな感じに、
大量データ登録を高速化する為に色々と頭を捻ったりすることも無く、
ただボコボコとJavaのクラスそのまま叩き込んでいくだけのパワー勝負です。

しかし、検索は違います。
検索は非常にテクニカルでエンジニアの力量が試されます。

検索の制約

GAEの検索は制約が非常に多いです。

リレーショナルデータベースではない。

「データベースとはリレーショナルデータベースのことだ!!」くらいの勢いで考えているエンジニアは非常に多いと思いますが、
OracleやPostgreSqlみたいなリレーショナルデータベースではありませんので、その常識の根底が根こそぎ崩れます。

結合出来ない。

「SELECT * FROM table1,table2 WHERE TABLE1.id = TABLE2.id」みたいなselect文での結合はSQLの常識ですが、
リレーショナルデータベースではないGAEはsqlもありませんので、こういう結合は出来ません。

常に「table1ならtabe1だけ」という単表検索です。

早い話がJavaのMapみたいなものなんです。
Mapにmap同士を結合する機能なんかありませんよね?

結合させたい場合は、キーによる一意検索を乱射してロジックで結合させるのです。

インデックス検索

ここが重要。

普通のリレーショナルDBでは「インデックスを利用した検索」というテクニックがあります。
これを理解しているエンジニアとしていないエンジニアでは、SQLの検索速度が段違い!!
軽く数千倍の差が出ることも珍しくありません。

GAEの場合はこれに特化していまして、インデックス検索しか無いのです。

前方一致検索は出来ても後方一致検索は出来ない

「where table1.name lile '%tacy%'」みたいに前後方一致検索は普通のSQLでもありますが、
この場合、インデックスが効いていません。
よって検索は遅いです。

「where table1.name lile 'tacy%'」と、前方一致検索ならばインデックスが効きますので高速です。

これと同じことがGAEでも発生しまして、後者の前方一致検索であればGAEならではの高速検索が作動します。
前者の前後方一致検索は実行不能ですので、全件取得してJavaでフィルタリングする、という荒業を行うハメになります。

大量件数では実現出来ませんね。
このように、インデックスで実現出来ない検索は出来ないというのがGAEの基本です。

count(*)が無い

これが驚きなのですが、count(*)は無いのです!!
単純に検索条件で全部取得して、Javaで「++count」みたいに一件一件数えるしか無いです。

GAEの制約の中でもこれは結構ダメージが大きいかと。
「画面上に総件数を出す」みたいな要件への対応は難しいかと。

ORも無い

OR条件が出来ません。2回検索してJavaでマージする必要があります。




とまあ、ザッと目ぼしい所を挙げるだけでもGAEの検索にはこんなに沢山の制約があります。

これを乗り越える為には、

  • そもそも出来ないことを要件に入れないようにする。
  • テーブル設計を冗長化することにより結合を発生させない。
  • 検索キー専用のカラムを容易する。例えば後方一致検索を行う為に文字列を前後反転させて保存しておくなど

などなど、技術と言うよりサーカスと言った方が良いんじゃないかというような技を駆使することになります。

これを聞いただけでゲンナリする人もいらっしゃるかもしれませんが、いえいえ、諦めてはいけません。
Googleの誇るGoogle検索や、Google+や、このブログ、GMailなど、これらは全部そういう課題を乗り越えて作っているのですから。
頑張ればちゃんと出来るはずなのです。

気合入れて行きましょう!!

終わりに

というわけで、初級実装編2は、実質的には検索編となるでしょう。

来週から実際に色々と要件を決めてサンプルを実装していこうと思います。

0 件のコメント:

コメントを投稿