レベル: 初級 安達 宜隆, IM 開発 & サービス / ソフトウェア開発研究所,
IBM
2007年 11月 23日 IBM OmniFind Enterprise Edition(以下OmniFind)は、イントラネットに存在する様々な情報を検索可能にするエンタープライズ向けサーチシステムを提供するソフトウェアです[文献1, 2, 3]。エンドユーザーはOmniFindのESSearchApplicationというWebアプリケーションを通じて、必要な情報を簡単に検索することが可能になります。このESSearchApplicationは、製品として利用可能なWebアプリケーションであると同時に、開発者が自由にカスタマイズできるようにソースコードも付属しております。開発者は、エンドユーザーの要望に添うようにアプリケーションを書き換え、よりビジネスニーズにあった検索ソリューションを提供することが可能になっています。本稿では、このESSearchApplicationの概要を紹介するとともに、実際の処理の流れを追いながらコードの解説を行っていきます。
ESSearchApplicationの概要
ESSearchApplicationはSIAPI(Search and Indexing API, [文献3])を通じて検索機能を提供するOmniFind付属のWebアプリケーションです。OmniFindをインストールしますと、検索サーバー上のIBM WebSphere Application ServerにESSearchApplicationがデプロイされます。OmniFindの管理コンソールからコレクション作成や検索サービスの起動などの設定を行った後で、ブラウザーからhttp://<検索サーバーのホスト名またはIPアドレス>/ESSearchApplication/にアクセスすると、すぐにOmniFindによる検索を使用することできます。
図 1. 検索画面
図 2. 検索結果
OmniFindのフロントエンドを担うESSearchApplicationをカスタマイズする方法は2つ用意されています。
1つは検索カスタマイザーを使用する方法で、表示させるフィールドの設定やイメージの変更などをノンプログラミングでカスタマイズすることが可能です。しかし、提供されている機能以上の細かいカスタマイズを行うことはできません。
図 3. 検索カスタマイザー
もう1つの方法は、SIAPIを使用して直接プログラミングを行う方法です。幸い、ESSearchApplicationのソースコードは製品に付属しています。そのため、ユーザーはゼロからアプリケーションを構築する必要はなく、ESSearchApplicationを拡張するだけで、簡単に機能追加を行うことが可能になっています。
コード概要
ESSearchApplicationのソースコードは、OmniFindをインストールしたディレクトリーの下、samples/ESSearchApplicationにあります。JavaのソースコードとJSPファイル、コンパイルに必要なライブラリー・ファイル(jarファイル)、それにRational Application Developer用のプロジェクト一式を含んだzipファイルが用意されています。
ESSearchApplicationの基本構造は、MVCアーキテクチャーによるApache Struts(以下Struts、[文献5])アプリケーションになっています。JSPファイルが表示部分を担当し、各ActionクラスがController部分を担当しています。また、SIAPIを用いて検索サーバーにアクセスする処理など、ロジックを担当するHelperクラスが用意されています。Actionクラスは、Helperクラスを経由して検索処理を行います。
Javaファイルの各パッケージの役割は以下の通りです。
表1. Javaパッケージと役割
| com.ibm.es.searchui.actions | MVCアーキテクチャーのControllerを担当するActionクラスが入っています。各クラスはcom.ibm.es.searchui.actions.BaseActionを継承し、BaseActionはorg.apache.struts.action.Actionクラスを継承しています。 |
|---|
| com.ibm.es.searchui.filters | RequestをUTF-8で読み込むように設定する、ServletのFilterであるSetEncodingFilterクラスが入っています。 |
|---|
| com.ibm.es.searchui.helpers | SIAPIを用いて検索を行うクラスや、ユーザー管理用API(IMC API)を使用してユーザー管理を行うクラスなど、実際の処理を行うクラスが入っています。 |
|---|
| com.ibm.es.searchui.tags | JSPのカスタムタグの実装が入っています。 |
|---|
| com.ibm.es.searhcui.validation | ユーザーの入力を検証するSearchActionValidationクラスが入っています。 |
|---|
| com.ibm.es.searchui.valueObjects | 各種の値を格納する専用のクラスが入っています。いわゆるPOJO(Plain Old Java Object)です。 |
|---|
Strutsの設定はWebContent/WEB-INF/struts-config.xmlで行っています。このファイルによって、ActionによるController部分と、JSPによるView部分の仲立ちを行っています。
表示を担当するJSPファイルに関しては、Struts Taglib及びStruts Tilesの機能を用いています[文献6,7]。それらに加えて、ESSearchApplication独自のJSPカスタムタグも使用しています。Tilesの設定ファイルはWebContent/conf/tiles-def.xmlにあり、Tilesでベースとして使用するレイアウトのJSPファイルは、WebContent/layoutsディレクトリーにまとめられています。また、カスタムタグはcom.ibm.es.searchui.tagsパッケージにて実装されています。
キーワード入力から検索結果表示までのコード解説
それでは実際に、ESSearchApplicationがどのように動くのか、具体的なコードを見ていきましょう。ここでは、検索ボックスにキーワードを入力してから、結果が表示されるまでのコードを追ってみたいと思います。
ESSearchApplicationの基本検索画面を表示させるには、http://<検索サーバーのホスト名またはIPアドレス>/ESSearchApplication/search.do?command=searchLinkにアクセスします。このとき行われる処理は、struts-config.xmlにある
<action path="/search" type="com.ibm.es.searchui.actions.SearchAction" … >
<forward name="resultsPage" path="/searchRender.do"/> … |
により、com.ibm.es.searchui.actions.SearchActionクラスで実行されることがわかります。SearchActionはcom.ibm.es.searchui.actions.BaseActionクラスを継承し、BaseActionクラスは、Strutsのorg.apache.struts.action.Actionクラスを継承していますので、Strutsフレームワークの規則により、このとき行われる処理はSearchActionクラスのexecuteメソッドになります。
SearchActionクラスのexecuteメソッドでは、
DynaActionForm theForm = (DynaActionForm) form;
String command = (String) theForm.get("command"); |
で入力されたcommandパラメーターを受け取り、その値によって処理を分けます。今回は、search.do?command=searchLinkというURLでアクセスしましたので、command変数の中には”searchLink”が入ります。
続く、if文で場合分けがされていますが、"searchLink"の場合には特に該当するものはありませんのでそのまま最後まで処理がスキップされ、最終行の
return mapping.findForward("searchRender"); |
にたどりつきます。ここから、次の処理はsearchRenderに遷移することがわかります。
実際にsearchRenderが何を表すのか、struts-config.xmlを見てみますと、
<action-mappings>
<action path="/searchRender" type="com.ibm.es.searchui.actions.SearchRenderAction" … >
<forward name="resultsPage" path="results.main"/> … |
とありますので、次はcom.ibm.es.searchui.actions.SearchRenderActionクラスのexecuteメソッドに処理が移ることになります。
SeachRenderActionクラスもSearchActionクラスと同様、commandパラメーターによって処理の場合分けを行います。commandの値が"searchLink"だった場合には、以下のコードが実行されます。
String targetPage = getTargetPage(request);
…
String queryString = (String) theForm.get("q");
if (command == null || command.equals("") || command.equals("searchLink")) {
if (queryString == null || queryString.equals("")) {
// Do not process query if no queryString and selected the Search tab
theForm.set("command", "search");
return mapping.findForward(targetPage);
}
} |
まずgetTargetPageメソッドを使って、次に遷移するページを決定します。今回のように基本検索を直接クリックした場合は、targetPage="resultsPage"となります。そしてifによる条件判定に入るのですが、command=”searchLink”であり、かつqueryStringには何も入っていませんので、上述のif文の条件式がtrueとなり、ブロック内の処理が行われます。ここでcommandに"search"が設定され、targetPageすなわち"resultsPage"に遷移することになります。
struts-config.xmlでは、searchRenderアクションの下に、resultsPageが返された場合のforward設定がなされています。
<action path="/searchRender" type="com.ibm.es.searchui.actions.SearchRenderAction" … >
<forward name="resultsPage" path="results.main"/> … |
ここから次の遷移先が、results.mainであることがわかります。
results.mainはTilesの設定ファイルであるWEB-INF/conf/tiles-def.xmlにて次のように設定されています。
<definition name="results.main" extends="tiles.search">
<put name="body" value="/search.jsp" />
</definition> |
これを見ますと、tiles.searchを拡張していることがわかります。tiles.searchは次のように定義されています。
<definition name="tiles.search" page="/layouts/baseLayout.jsp">
<put name="palette" value="/palette.jsp" />
<put name="banner" value="/banner.jsp" />
<put name="body" value="/index.jsp" />
</definition> |
baseLayout.jspを元に、banner.jspやsearch.jspが挿入されて、画面が表示されることがわかります。
このようにして、図1の検索画面が表示されました。この画面からキーワードを入力し、検索を開始することができます。それでは次に、検索ボックスにキーワードを入力してから、実際に検索結果が表示されるまでの流れを追ってみます。
検索ボックス自体は、queryPrompt.jspファイルの中で、次のように定義されています。
<html:text property='<%="q" + suffix%>' size="60" styleId="prompt.search"
onkeypress="submitFormWhen(event, 13, 'search');" /> |
ここにキーワードを入力しリターンを押すと、javascriptのsubmitFormWhen関数が呼び出されます。submitFormWhenはWebContent/scripts/util.jsの中で定義されています。結論から言いますと、この関数によって、commandパラメーターに"search"が、qパラメーターに入力された検索キーワードがセットされて、フォームが送信されることになります。フォーム自体は、search.jspに、
<html:form action="/search.do"> |
と記述されています。これより、次の処理はsearch.doになります。
search.doは先ほど見ましたとおり、SearchActionクラスに対応しています。executeメソッド内ではcommandパラメーターの値によって処理が変わるのですが、今回のcommand="search"も特に記述がされていませんので、そのままSearchRenderActionに処理が移ります。
SearchRenderActionでは、command="search"のときに、processQueryActionメソッド
が呼び出されます。このメソッドはBaseActionクラスで定義されています。このメソッドの中で、検索キーワードをクエリとして発行し、検索結果を取得します。
processQueryAction(mapping, queryString, collections, languages, sources, types, scopes,
null, null, form, errors, request); |
processQueryActionメソッド内では、HelperクラスであるSiapiHelperのインスタンスを使用して検索を行います。
SiapiHelperクラスを用いて実際に検索を行う前に、検索を行うクエリの作成、具体的にはSIAPIのcom.ibm.siapi.search.Queryクラスのインスタンスの作成を行います。このクラスには、入力された検索キーワードの他に、言語や文書の日付など様々な検索条件が格納できます。SiapiHelperクラスでは、getDisplayQueryStringメソッドや、buildQueryStringメソッドを用いて検索キーワードを変換した後、createQueryメソッドを用いてQueryクラスのインスタンスを作成します。
こうして作成されたQueryクラスのインスタンスを引数として、SiapiHelperクラスのsearchメソッドを呼び出し、実際に検索処理を行います。
String displayQueryString = helper.getDisplayQueryString(queryString, site,
showResultsWithParameters);
String builtQueryString = helper.buildQueryString(displayQueryString, languages, sources,
types, scopes, customFilters, categoryID, synonymExpansion, showResultsWithParameters,
userFeedBack, userFeedBackConcepts);
query = helper.createQuery(builtQueryString, parameters, calculatePageControl(form),
request.getLocale());
ResultSet results = helper.search(query,selectedCollectionIDs); |
searchメソッドによって得られた検索結果は、BaseActionクラスのstoreQueryResponseメソッドによって、HttpServerRequestに格納されます。後ほど説明しますsearchResults.jspの中で、このRequestに格納されたResultSetを取り出し、結果を表示させることになります。
request.setAttribute("results", results); |
processQueryActionメソッド終了後、SearchRenderActionのexecuteメソッドに戻り、残りの2行を実行します。
theForm.set("command", "search");
return mapping.findForward(targetPage);
|
targetPageには、”resultsPage”が格納されていますので、そのまま検索結果の表示画面に遷移します。
実際の検索結果を表示させるJSPファイルは、search.jspファイルの中でincludeされているsearchResults.jspになります。
searchResults.jspの中で、検索結果を表示させている箇所は、<!-- Search results -->というコメントの下からになります。この部分で、
<logic:iterate id="searchResult" name="results" property="results"
indexId="searchResultIndex" type="com.ibm.siapi.search.Result"> |
<logic:iterate id="searchResult" name="results" property="results" indexId="searchResultIndex" type="com.ibm.siapi.search.Result">
として、storeQueryResponseメソッド内でHttpServletRequestに格納した検索結果を1つずつ取り出して、順番に表示処理させていきます。
検索結果の表示項目をカスタマイズしたい場合には、このsearchResults.jspファイルを編集することになります。
このようにして、図2のような検索結果画面が表示されることになります。
まとめ
ESSearchApplicationの概要とともに、キーワード入力から検索結果が表示されるまでのコードを解説しました。他の機能に関してもほぼ同様の処理になっていますので、この記事を参考に、他の部分のコードも読み進めていってほしいと思います。
今回解説したように、ESSearchApplicationはStrutsフレームワーク上に構築されたMVCアーキテクチャーのWebアプリケーションになっています。そのため、表示部分を変更する場合はJSPファイルを変更、ロジック部分を変更する場合はJavaファイルを変更といったように、表示部分(View)とロジック部分(Controller)を明確に分けて開発することが可能です。
ぜひ、ESSearchApplicationを改良して、エンドユーザーの要望にあったアプリケーションを作ってください。
参考文献
著者について  | |  | 安達 宜隆は、ソフトウェア開発研究所のソフトウェア・エンジニアであり IBM OmniFind Enterprise Edition の開発・保守に携わっています。休日も含め毎日キーボードをバシバシ叩く生活を送っています。潤いがほしい今日この頃です。 |
記事の評価
|