SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Zend Framework入門

Zend Framework入門(20):
PHPテキスト検索エンジン - Zend_Search_Luceneの詳細 -

Zend Frameworkによる実践的なPHPアプリケーション開発 20

検索の詳細

 前回の記事ではZend_Search_Lucenefindメソッドを利用して検索をすることには触れました。このfindメソッドにクエリ条件を表すテキスト、ないしZend_Search_Lucene_Search_Queryのオブジェクトを渡し、その戻り値が検索の結果となっていました。

 ここではこの検索を、さらに細かく制御する方法について見ていきます。具体的には検索結果の並び順と、クエリ生成の詳細について説明します。

検索結果の並び順

 検索の結果は、デフォルトでは検索クエリに対しての各文書の「点数」(スコア)の順に並べて表示されます。この点数は、例えばクエリに含まれる単語の文書中での登場頻度などのいくつかの要素によって計算されたもので、クエリに対して文書がどれだけ合っているかを示しています。

 検索結果の並び順はZend_Search_Lucenefindメソッドに、追加で引数を与えることで変更することができます。追加で与える引数は、並べ替えに使うフィールド名と比較の方法、並び順の順で指定します。

[リスト3]並べ変えの順位を指定した検索
$hits = $index->find($query [,field名1 [,比較の方法1 [,並び順1]]]
                            [,field名2 [,比較の方法2 [,並び順2]]]
                            [,field名3 [,比較の方法3 [,並び順3]]]
                            ...);

 比較方法、並び順の指定には、それぞれ以下の値を指定します。

比較方法の設定値
設定値 概要
SORT_REGULAR(デフォルト) 通常の比較を行う
SORT_STRING 文字列として比較を行う
SORT_NUMERIC 数値として比較を行う
並び順の設定値
設定値 概要
SORT_ASC(デフォルト) 昇順
SORT_DESC 降順

  具体的なコードは、以下に示します。

[リスト4]結果の順番の変更
// (1) - フィールド path を文字列として比較し、昇順に並べる
$hits = $index->find($query, 'path', SORT_STRING, SORT_ASC);

// (2) - 上に追加で、スコアを数値として比較し、降順に並べる
$hits = $index->find($query, 'path', SORT_STRING, SORT_ASC,
                             'score', SORT_NUMERIC, SORT_DESC);

// (3) - 比較方法・順番は省略も可能
$hits = $index->find($query, 'path',
                             'score', SORT_NUMERIC, SORT_DESC);

 このようにフィールドを追加したり、引数を省略することも可能です。

クエリの生成の詳細

 ここまでの例では、検索のためのクエリは直接文字列から生成してきましたが、この方法以外にもクエリはプログラム的に生成することもできます。これは、クエリの部品ごとに一つのオブジェクトとして作成し、そのオブジェクトを組み合わせることで一つのクエリを作成する方法です。少し例を見てみましょう。

[リスト5]クエリの生成の比較
//(1)- テキストから直接生成
$hits = index->find('date:([2009-01-01 TO 2009-12-31]) AND Code*');

// ここららは上と同じ意味のクエリをプログラム的に生成

//(2)- 範囲
$fromterm = new Zend_Search_Lucene_Index_Term('2009-01-01', 'date');
$to_term = new Zend_Search_Lucene_Index_Term('2009-12-31', 'date');
$range = new Zend_Search_Lucene_Search_Query_Range($from_term, $to_term, true);

//(3)- ワイルドカード
$pattern_term = new Zend_Search_Lucene_Index_Term('Code*');
$wildcard = new Zend_Search_Lucene_Search_Query_WildCard($pattern_term);

//(4)- 組合せ
$query = Zend_Search_Lucene_Search_Query_Boolean();
$query->addSubquery($range, true);
$query->addSubquery($wildcard, true);

$hits = $index->find($query);

 リスト5で紹介した(1)と(2)- (4)は、どちらも同じ意味で、

  • 「date」フィールドが2009年1月1日から2009年12月31日の間で、
  • いずれかのフィールドに「Code」から始まる単語が含まれている

 文書に合うクエリとなっています。このうち、(1)は直接テキストからの生成、(2)~(4)はプログラム的な生成になっています。

 このように、テキストから直接でもプログラム的な方法でも同じクエリを生成することができます。原則としては

  • 人間が直接入力したクエリはテキストから解析
  • それ以外の場合はプログラム的な方法

 でクエリを生成することが奨励されています。

 プログラム的なクエリの生成に関するクラスは次のようなものがあります。

プログラム的なクエリの生成に関するクラス(接頭辞であるZend_Search_Lucene_Search_Query_は省略)
クラス名 コンストラクタ引数 説明
Term $word, $field 特定の単語$wordをフィールド$fieldに含んでいるかを調べる。$filedは省略可能で、標準ではすべての$fieldについてみる
Fuzzy $term, $similarity Termオブジェクト$termに似ている文字列があるかを調べる。$similarityはどこまで似ているかものも許容するかを、0から1の間の小数で指定する
Range $from, $to, $include_edges Termオブジェクト$fromからTermオブジェクト$toまでの範囲にある文字列があるかを調べる。$include_edgesは末端を含むかどうかの指定
Wildcard $term Termオブジェクト$termにあるワイルドカードを解釈し、あてはまる文字列があるかを調べる
Phrase $terms, $offsets, $field 配列$termsに含まれるTermオブジェクトが$offsetsで指定された順番でフィールド$field内に並んでいるかを調べる
MultiTerm $terms, $signs 配列 $term 内のTermオブジェクトが文書に含まれているかを調べる。$termsと$signsは両方とも配列で、中は true, false か null
Boolean $subqueris, $signs 複数のクエリを組み合わせる。$termsと$signsは両方とも配列で、中は true, false か null

 このうち、Phraseは$termsでTermを、$offsetsでその位置を指定します。例えば「PHP is * to」という並び(「*」は何でも良い)を調べたい場合はリスト6のように書くことができます。

[リスト6]Zend_Search_Lucene_Search_Query_Phraseの使い方
$phrase =
  new Zend_Search_Lucene_Search_Query_Phrase(array('PHP', 'is', 'to'),
                                             array(    0,    1,    3));

 ここで「*」に相当する「2」番目は飛ばし、「to」に対応する部分は 3になっています。

 また、MultiTermとBooleanでは$signsで各要素が必要なのか(true)、あった場合はマッチしないのか(false)、それともどちらでも良いのか(null)を指定することができます。例えば、「PHP」という単語を含んでおり、「is」という単語を含んでいない文書を調べたい場合にはリスト7のように記述します。

[リスト7]Zend_Search_Lucene_Search_Query_MultiTermの使い方
$phrase =
  new Zend_Search_Lucene_Search_Query_Multiterm(array('PHP',  'is',  'to'),
                                                array( true, false,  null));

 なお、ここで「null」が指定されている「to」は、検索結果を絞り込むのには利用されませんが、並び換えのためのスコアを計算するためには利用されます。

次のページ
Apache Luceneとの連携

この記事は参考になりましたか?

Zend Framework入門連載記事一覧

もっと読む

この記事の著者

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

WINGSプロジェクト 風田 伸之(カゼタ ノブユキ)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/3947 2009/06/15 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー