サイト内全文検索機能(SearchEstraierプラグイン)

SearchEstraierプラグインは、Hyper Estraierを利用したサイト内全文検索 (サイト内検索) 機能を提供します。 従来のSQLを使った複数条件指定検索に加え、数万ページでも高速に動作する全文検索機能を利用できるようになります。キーワードにマッチするコンテンツをスコア順に抽出できます。

このWebサイトのドキュメント検索機能は、このプラグインを利用して実装されています。

サイト内全文検索

設置とインストール

  • Hyper Estraier と MeCab(オプション)をインストールします。
  • estcmd のパスが /usr/local/bin/estcmd でない時、環境変数「searchestraier_estcmd_path」に estcmd のパスを追加します。
  • mecab のパスが /usr/local/bin/mecab でない時、環境変数「searchestraier_mecab_path」に mecab のパスを追加します。
  • プラグインを有効化します。
  • 検索対象のスコープのプラグイン設定で、インデックスのパスを入力し、「検索を有効化」にチェックを入れます。
  • tools/worker.phpを実行します。
  • ビューを作成します。サンプルは plugins/SearchEstraier/theme/views/ 以下に含まれています。
  • ビューに対する URLマッピングでアーカイブ種別を「インデックス」とし、ファイル出力を「ダイナミック」とします。

プラグイン設定

  • 検索を有効化(スコープでの全文検索を有効化します)
  • クッキーをスコープ固有にする(ユーザーの閲覧履歴を保存するクッキーをスコープ毎に設定します)
  • 動的ページを検索対象にする ※1 (URLマップのファイル出力が「ダイナミック」「オンデマンド」のコンテンツを検索対象にします)
  • インデックスのパス ※2 (CMSから書込み可能な検索インデックスを保存するディレクトリを指定します)
  • アーカイブ種別(検索対象とするアーカイブ種別を指定します)
  • 文書のタイトル(文書のタイトルをどこから取得するかを指定します。「自動」とするとアーカイブのタイトルを文書のタイトルとします)
  • サムネイルを作成 / 幅 ※3 (検索結果にアイキャッチとして表示させるサムネイルを作成する場合に指定します)
  • メタタグ ※4 (HTML文書の meta タグ名をカンマ区切りで指定することで検索インデックスに属性として保存します)
  • ※1 ダイナミックコンテンツを検索対象にする場合、コンテンツ更新時に内部的に再構築を行います。ダイナミック、オンデマンド指定のURLマップで、可能なものは静的に変更することをお勧めします。
  • ※2 <mt:property name="support_dir"> は、環境変数 support_dir で指定するパスです。指定のない時、アプリケーションの直下の support/ ディレクトリとなります。
    異なるスコープで同一のインデックスを指定することで、スコープをまたがった検索が可能となります。
  • ※3 metaタグ「og:image」がある場合はその画像、ない場合は本文エリアに出現する最初の img要素からサムネイルを作成します。SVGには対応していません。
  • ※4 保存した属性値を利用して <mt:estraiersearch> による検索時に絞り込むことが可能となります。

形態素解析エンジン MeCab を利用したキーワード抽出

MeCabがインストールされている時、文書内のキーワードを自動抽出して、レコメンドAPIによる「閲覧履歴による興味関心」の精度を上げることができます。
あわせて php-mecabのインストールを推奨します(必須ではありません)。

以下の環境変数を config.json の config_settings に記述します。

  • searchestraier_auto_keywords を true。
  • searchestraier_mecab_path に mecab コマンドのパス。
  • searchestraier_end_of_sentense(省略可能)に文章の終わりを識別する文字。デフォルトは「。」
  • searchestraier_min_word_len(省略可能)にキーワードの最小文字数。デフォルトは3文字以上。
  • searchestraier_min_word_cnt(省略可能)にキーワードの出現回数。デフォルトは3回以上出現したキーワードを対象にします。
  • searchestraier_word_multibyte_only(省略可能)に true もしくは false。抽出するキーワードをマルチバイト文字列のみとします。デフォルトは true。
  • searchestraier_mecab_userdic(省略可能)に mecabのユーザー辞書のパス。

noindex メタタグを使用した検索インデックス登録の除外

環境変数「searchestraier_skip_noindex」を true にすると、「<meta name=robots content=noindex>」に相当するタグが含まれる HTML 文書を検索インデックスに含めないようにします。

検索フォームと検索結果のビュー

以下のようなビューを作成します。

なお、以下サンプルでは後述のページネーション用のインクルード・モジュール「SearchEstraierPagination」を別途用意してインクルードを行っています。

<form method="GET" action="<mt:var name="current_archive_url">">
<div class="form-inline">
  <label> キーワード
  <input type="text" name="query" value="<mt:var name="query" escape>"></label>
  <label>
    <input type="radio" name="and_or" value="AND" <mt:if name="request.and_or" eq="AND">checked</mt:if>>
    AND
  </label>
  <label>
    <input type="radio" name="and_or" value="OR" <mt:if name="request.and_or" eq="OR">checked</mt:if>>
    AND
  </label>
  <button type="submit">検索</button>
</div>
</form>
<mt:var name="request.query" setvar="query">
<mt:estraiersearch phrase="$query" prefix="estraier_" and_or="AND" default_limit="10" snippet_width="200" workspace_ids="0,1">
  <mt:if name="__first__">
    <p>
    「<mt:var name="query" escape>」の検索結果( <mt:var name="estraier_hit">件ヒットしました )
    </p>
<ul class="list-unstyled"></mt:if>
  <mt:if name="estraier_thumbnail_square">
    <mt:var name="estraier_thumbnail_square" setvar="thumbnail_url">
  <mt:else>
    <mt:setvarblock name="thumbnail_url"><mt:var name="theme_static">website/images/no-image.png</mt:setvarblock>
  </mt:if>
  <li class="mb-2"><div class="d-flex"><div class="thumbnail"><img src="<mt:var name="thumbnail_url" escape>" width="80"  height="80" alt=""></div>
  <div><a href="<mt:var name="estraier_uri" escape>"><strong><mt:var name="estraier_title" escape></strong></a>
  <p class="snippet"><mt:var name="estraier_snippet"></p></div></div>
  </li>
<mt:if name="__last__">
  </ul>
  <mt:setvar name="estraier_hit" value="search_hit">
  <mt:include module="SearchEstraierPagination">
</mt:if>
</mt:estraiersearch>
<mt:if name="query">
<mt:unless name="search_hit">
<p>「<mt:var name="query" escape>」にマッチするページはありませんでした。</p>
</mt:unless>
</mt:if>

インクルード・モジュール「SearchEstraierPagination」

ページネーション用のテンプレートは <mt:estraiersearch> タグ内でのみ利用可能な変数 ( estraier_* ) を用いて作成します。

<mt:if name="estraier_pagertotal" gt="1">
<mt:for from="1" to="$estraier_pagertotal">
<mt:if name="__first__">
<nav aria-label="ページネーション">
  <ul>
    <li>
      <a aria-label="先頭へ" href="<mt:var name="current_archive_url">?query=<mt:var name="query" escape encode_url="1"><mt:if name="request.and_or">&amp;and_or=<mt:var name="request.and_or" escape></mt:if>">
        &laquo;
      </a>
    </li>
    <mt:if name="request.offset">
      <a aria-label="前へ" href="<mt:var name="current_archive_url">?query=<mt:var name="query" escape encode_url="1">&amp;offset=<mt:var name="estraier_prevoffset"><mt:if name="request.and_or">&amp;and_or=<mt:var name="request.and_or" escape></mt:if>">
        &lsaquo;
      </a>
    </mt:if>
</mt:if>
    <li class="<mt:if name="__value__" eq="$estraier_currentpage"> active</mt:if>">
      <mt:var name="search_offset" value="$__index__">
      <mt:var name="search_offset" op="*" value="$estraier_limit">
      <a href="<mt:var name="current_archive_url">?query=<mt:var name="query" escape encode_url="1">&amp;offset=<mt:var name="search_offset"><mt:if name="request.and_or">&amp;and_or=<mt:var name="request.and_or" escape></mt:if>"><mt:var name="__value__"></a>
    </li>
<mt:if name="__last__">
    <mt:if name="estraier_nextoffset">
      <a aria-label="次へ" href="<mt:var name="current_archive_url">?query=<mt:var name="query" escape encode_url="1">&amp;offset=<mt:var name="estraier_nextoffset"><mt:if name="request.and_or">&amp;and_or=<mt:var name="request.and_or" escape></mt:if>">
        &rsaquo;
      </a>
    </mt:if>
    <li>
      <mt:var name="search_offset" value="$estraier_pagertotal">
      <mt:var name="search_offset" op="-" value="1">
      <mt:var name="search_offset" op="*" value="$estraier_limit">
      <a aria-label="最後へ" href="<mt:var name="current_archive_url">?query=<mt:var name="query" escape encode_url="1">&amp;offset=<mt:var name="search_offset">">
        &raquo;
      </a>
    </li>
  </ul>
</nav>
</mt:if>

属性による絞り込み

検索インデックスに登録された属性を利用して検索を絞り込むことができます。

<mt:estraiersearch> ~ </mt:estraiersearch> タグに属性を指定します。

  • ad_attr(s) : 属性検索対象の属性(単一もしくは配列)
  • add_condition(s) : 属性検索条件 (単一もしくは配列、詳細は https://dbmx.net//hyperestraier/uguide-ja.html を参照)
  • values(s) : 属性検索の値(単一もしくは配列)

検索インデックスに登録されている属性は、SearchEstraier プラグイン設定から確認できます。

プラグイン「SearchEstraier」にプラグイン設定画面から検索インデックスの状態を確認する機能を追加しました。

PowerCMS X ver.3.2 / 2.72リリースノート

属性による絞り込みのサンプル

<mt:ignore>
    - タイトル ( @title 属性 ) に 'ドキュメント' を含む
</mt:ignore>

<mt:var name="request.query" setvar="query">
<mt:estraiersearch phrase="$query" prefix="estraier_" and_or="AND" default_limit="10" snippet_width="200" ad_attr="@title" add_condition="STRINC" value="ドキュメント">
  <!-- do something  -->
</mt:estraiersearch>

複数の属性による絞り込みのサンプル

<mt:ignore>
  - モデル ( @model 属性 ) が 'entry' と等しい
  - ページの URL ( @uri 属性 ) が 'https://example.com/blog/' に前方一致する
</mt:ignore>

<mt:block from_json="search_attrs">["@model", "@uri"]</mt:block>
<mt:block from_json="search_conditions">["STREQ", "STRBW"]</mt:block>
<mt:block from_json="search_values">["entry", "https://example.com/blog/"]</mt:block>

<mt:var name="request.query" setvar="query">
<mt:estraiersearch phrase="$query" prefix="estraier_" and_or="AND" default_limit="10" snippet_width="200" ad_attrs="$search_attrs" add_conditions="$search_conditions" values="$search_values">
  <!-- do something  -->
</mt:estraiersearch>