MAP | PageMixer ドキュメント > チュートリアル > PageMixer の利用 > 効率的な組み合わせ | << | >> |
本節では、 PageMixer における効率的なフィルタの組み合わせ方に関して説明します。
本節におけるクラス図を以下に示します。
色づけされているのが本節で定義するクラスで、 それ以外は PageMixer において定義済みです。
本節におけるオブジェクト図を以下に示します。
本チュートリアルでは、 クラスは全てクラス名のみで表記されています。 完全な名称は以下の通りです。
表記 | 完全名 |
---|---|
ConsumerContext | jp.ne.dti.lares.foozy.pagemixer.mixer.ConsumerContext |
Filter | jp.ne.dti.lares.foozy.pagemixer.mixer.Filter |
FilterPipeline | jp.ne.dti.lares.foozy.pagemixer.mixer.FilterPipeline |
HTMLSymbolSet | jp.ne.dti.lares.foozy.pagemixer.HTMLSymbolSet |
SequenceHybridFilter | jp.ne.dti.lares.foozy.pagemixer.mixer.SequenceHybridFilter |
SequenceTrimFilter | jp.ne.dti.lares.foozy.pagemixer.mixer.SequenceTrimFilter |
SequenceWatcher | jp.ne.dti.lares.foozy.pagemixer.mixer.SequenceWatcher |
Token | jp.ne.dti.lares.foozy.pagemixer.Token |
TrimFilter | jp.ne.dti.lares.foozy.pagemixer.mixer.TrimFilter |
表記 | 完全名 |
---|---|
AlreadyLoginFilter | pagemixer.filter.AlreadyLoginFilter |
Bootstrap | pagemixer.filter.Bootstrap |
Trim | pagemixer.filter.AlreadyLoginFilter.Trim |
UsernameAttrInsetFilter | pagemixer.filter.UsernameTextInsetFilter |
単純にフィルタを接続して使用した場合、 全てのフィルタが全ての Token 列を処理することになります。
しかし、 それらフィルタのいくつかは Token 列の殆ど全てに対して興味を示しません。 例えば、 HTML ページにおける "ログイン" 機能に関するフィルタは、 Token 列の "ログイン" 機能の部分にしか興味がありません。
10 のフィルタに 5000 の Token
から構成されるシーケンスを処理させた場合、
処理の総量は 5,000 * 10 = 50,000 となります。
しかし、そのうちの3つだけにシーケンス全体を処理させ、
残りの7つには、それらが興味のある 100 の Token
だけを処理させた場合、
処理の総量は (5,000 * 3) + (100 * 7) = 15,700 となり、
およそ 70% の処理コストを削減することが出来ます。
フィルタの "木目細かさ" を維持することは、 機能が多くのフィルタによって構成されることを意味し、 それ故に処理コスト低減が必要とされます。
SequenceHybridFilter
の拡張フィルタを効率的に組み合わせるために、
PageMixer フレームワークは
"SequenceHybridFilter
" クラスを提供しています。
このクラスのインスタンスは、
SequenceWatcher
および
Filter
で構築されます。
指定された Filter
には、
SequenceWatcher
によって認識された部分シーケンスだけが提供されます。
FilterPipeline
を用いることで、
部分シーケンスを複数のフィルタに提供することができます。
HTML ページにおける "ログイン" 機能向けのフィルタ群を、 効率的に組み合わせるフィルタは以下のようになります。
public class AlreadyLoginFilter extends SequenceHybridFilter { final static private HTMLSymbolSet SET = HTMLSymbolSet.SET; final static private String ATTR_VALUE = "Auth-AlreadyLogin"; //////////////////////////////////////// public AlreadyLoginFilter(Object keyLogin){ super(new SequenceWatcher.NameAttr(SET.SPAN, SET.CLASS, ATTR_VALUE), create(keyLogin)); } // 非 staic メソッドは // 基底クラスのコンストラクタ起動には不適切 static private Filter createFilter(Object keyLogin){ FilterPipeline pipeline = new FilterPipeline(); pipeline.push(new UsernameTextInsetFilter(keyLogin)); pipeline.push(new Trim(keyLogin)); return pipeline; } }
"AlreadyLoginFilter
" は、
"<span class="Auth-AlreadyLogin">
" および
"</span>" で挟まれた部分シーケンスを、
"create
" メソッドにおいて
FilterPipeline
に追加されたフィルタ群へと供給します。
上記部分シーケンスが、全体の 10% から構成されているとすると、
AlreadyLoginFilter
こそシーケンス全体の 100% を処理しますが、
"ログイン" 機能用のフィルタ群は、
シーケンス全体の 10% だけを処理することになります。
結果、(100 + 10 * 2)/(100 * 2) = 120/200 = 0.6 から、
今回定義したクラスによって 40% の処理コストが削減されます。
より多くのフィルタを HybridSequenceFilter と組み合わせることで、 より多くの低減を得ることができます。 例えば、 10 のフィルタを併用した場合、 (100 + 10 * 10)/(100 * 10) = 200/1000 = 0.2 から 80% の処理コストが低減できます。
UsernameTextInsetFilter
に関しては、
"シーケンスへのデータはめ込み"
節において説明済みです。
"Trim
" フィルタは、
まだ説明していない "TrimFilter
" の派生クラスです。
TrimFilter
は、
与えられたシーケンス全体を刈り込むフィルタです。
SequenceTrimFilter.Whole
と
TrimFilter
の違いは、
SequenceWatcher
によって認識された部分シーケンスを刈り込むか、
シーケンス全体を刈り込むか、という点だけです。
以上で必要なものが全て揃いました。 実行コードは以下のようになります (詳細は AlreadyLoginFilter を参照してください)。
try{ // ユーザ名設定/取得用のキー final Object key = "Auth.Login"; // ユーザ名 final String name = "foozy"; Bootstrap bootstrap = new Bootstrap.Default(filename) { protected void prepare(ConsumerContext context) { // "login" はユーザ名のコンテキストへの // 設定の有無を保持する if(login){ // ユーザ名をコンテキストに設定 context.setValue(key, name); } } }; AlreadyLoginFilter filter = new AlreadyLoginFilter(key); // フィルタの適用 bootstrap.execute(filter); } catch(Exception e){ e.printStackTrace(System.err); }
入力用のサンプル HTML ファイルは、
配布物中の "src/demo/servlet/war/WEB-INF/page/demosite
"
配下にある
"auth.ja.html
" です。
MAP | PageMixer ドキュメント > チュートリアル > PageMixer の利用 > 効率的な組み合わせ | << | >> |