前回は MTSearchEntries タグと MTSplitVars タグを使って複数のキーワードを OR 検索する方法を紹介しました。 今回は、AND 検索をする方法を紹介します。なお、前回の OR 検索の記事をお読みいただいている前提で進めます。 今回のテンプレートの仕様 AND 検索以外は、前回の記事と同様です。 検索ワードはキーワード欄にカンマ区切りで指定する 複数のキーワードは AND...
前回は MTSearchEntries タグと MTSplitVars タグを使って複数のキーワードを OR 検索する方法を紹介しました。
今回は、AND 検索をする方法を紹介します。なお、前回の OR 検索の記事をお読みいただいている前提で進めます。
AND 検索以外は、前回の記事と同様です。
今回のサンプルに使ったブログには、次のような10本のブログ記事が公開されているとします。
この中で「つめ」「dynamicmtml」という2つのキーワードを両方含むブログ記事を、最大5本リストアップするようにします。「つめ」というキーワードは、普通ではあり得ませんが、結果を意図的に操作するためですので気にしないでください。
ブログ記事#10 : これはブログ「はじめての DynamicMTML ブログ」の10番目の記事です。
ブログ記事#09 : これはブログ「はじめての DynamicMTML ブログ」の9番目の記事です。
ブログ記事#08 : これはブログ「はじめての DynamicMTML ブログ」の8番目の記事です。
ブログ記事#07 : これはブログ「はじめての DynamicMTML ブログ」の7番目の記事です。
ブログ記事#06 : これはブログ「はじめての DynamicMTML ブログ」の6番目の記事です。
ブログ記事#05 : これはブログ「はじめての DynamicMTML ブログ」の5つめの記事です。
ブログ記事#04 : これはブログ「はじめての DynamicMTML ブログ」の4つめの記事です。
ブログ記事#03 : 3つ目の記事です。
ブログ記事#02 : これはブログ「はじめての DynamicMTML ブログ」の2つめの記事です。
ブログ記事#01 : これはブログ「はじめての DynamicMTML ブログ」の1つめの記事です。
赤字になっているブログ記事の「01, 02, 04, 05」が検索結果になります。
今回の記事の完成版のコードは次のようになります。強調されている部分が、前回の OR 検索との変更点になります。
※2012-01-23 MTLoop のところを少し修正しました。
<$mtml tag='mt:SetVars'$>
blog_id=<$mt:BlogID$>
entry_id=<$mt:EntryID$>
keywords=<$mt:EntryKeywords$>
keywords_length=<$mt:EntryKeywords regex_replace="/[^,]|\s/g","" cat="," count_characters="1"$>
limit=5
<$mtml tag='/mt:SetVars'$>
<mt:DynamicMTML>
<mt:SplitVars name="keyword" text="$keywords">
<$mt:Var name="__counter__" setvar="split_counter"$>
<$mt:Var name="keyword" trim="1" regex_replace="/\s| /g","%" setvar="keyword"$>
<mt:SearchEntries query="$keyword" blog_id="$blog_id" not_entry_id="$entry_id">
<$mt:EntryDate format="%Y%m%d%H%M%S" setvar="date"$>
<mt:If name="split_counter" eq="1">
<mt:SetVarBlock name="entries" key="$date">
<li><a href="<$mt:EntryPermalink$>"><$mt:EntryTitle$></a></li>
</mt:SetVarBlock>
<$mt:SetVar name="match_count" key="$date" value="1"$>
<mt:Else>
<mt:If name="entries" key="$date">
<$mt:SetVar name="match_count" key="$date" op="++"$>
</mt:If>
</mt:If>
</mt:SearchEntries>
<mt:If name="split_counter" eq="$keywords_length">
<mt:Loop name="entries">
<mt:If name="match_count" key="$__key__" eq="$keywords_length">
<$mt:SetVar name="result" key="$__key__" value="$__value__"$>
</mt:If>
</mt:Loop>
<mt:Loop name="result" sort_by="key reverse">
<mt:If name="__counter__" eq="1">
<ul>
</mt:If>
<mt:If name="__counter__" le="$limit">
<mt:Var name="__value__">
</mt:If>
<mt:If name="__counter__" eq="$limit">
</ul>
</mt:If>
</mt:Loop>
</mt:If>
</mt:SplitVars>
</mt:DynamicMTML>
以下、変更されている部分を見ていきます。
<mt:If name="split_counter" eq="1">
<mt:SetVarBlock name="entries" key="$date">
<li><a href="<$mt:EntryPermalink$>"><$mt:EntryTitle$></a></li>
</mt:SetVarBlock>
<$mt:SetVar name="match_count" key="$date" value="1"$>
<mt:Else>
<mt:If name="entries" key="$date">
<$mt:SetVar name="match_count" key="$date" op="++"$>
</mt:If>
</mt:If>
MTSearchEntries タグの中で、MTSplitVars のループの1回目とそれ以外とで動作を分岐します。変数 split_counter には、MTSplitVars タグのループの回数がセットされています(1から始まる)。この split_counter は、MTSplitVars タグの先頭で初期化してある必要があります(前回記事参照)。
MTSplitVars タグの最初のループ、つまり1つめのキーワードについては、そのまま MTSearchEntries を回しています。
ここでは、投稿日時(年月日時分秒)がキーであるハッシュ変数 entries に値を入れていきます。今回は AND 検索なので、最終的な検索結果は、この変数 entries から絞り込まれることになります。
さらに、同様に投稿日時がキーであるハッシュ変数 match_entries の各値に 1 をセットします。この entries と match_entries のキーを同じにしておくことがポイントとなります(後述)。
※これ以降の解説を読むと、ここでセットするキーは、投稿日時よりもエントリーID の方がしっくりくるのですが、最終的に出力するときに、投稿日時でソートするためにそのようにしています。
MTSplitVars タグの2回目のループ、つまり2つめのキーワード以降で、1つめのキーワードの検索結果の中にそのブログ記事があるかどうかを調べます。
<mt:If name="entries" key="$date">
<$mt:SetVar name="match_count" key="$date" op="++"$>
</mt:If>
もし該当するブログ記事が既に変数 entries にセットされているのであれば、変数 match_entries の値をインクリメント(1増やす)します。
つまり、この変数 match_entries の各キーに対応する値が、キーワードにマッチした回数ということになります。
最後に、MTLoop を2回まわしています。
1つめの MTLoop で変数 entries について、ループ中のブログ記事のキーワードにマッチした回数がキーワード数と同じもの、つまりすべてのキーワードにマッチしたものだけを、ハッシュ変数 result にセットします。このとき、ハッシュ変数 result の key と value は、元のハッシュ変数 entries の $__key__ と $__value__ を引き継ぎます。
<mt:Loop name="entries">
<mt:If name="match_count" key="$__key__" eq="$keywords_length">
<$mt:SetVar name="result" key="$__key__" value="$__value__"$>
</mt:If>
</mt:Loop>
ここで見て分かるように、entries と match_entries のキーを同じにしておけば、entries のループの時に、キー( __key__ )をそのまま match_entries のキーとして渡すことで、そのブログ記事のマッチ回数を調べることができます。
このマッチ回数がキーワード数(keyword_length : 先頭の MTSetVars でセット。こちらを参照)と同じであれば AND 検索の結果に該当(すべてのキーワードがマッチ)することになります。
そして、2つめの MTLoop で、先頭の MTSetVars でセットした limit の数だけ出力します。
以上です。複雑ですね。