PowerCMS Xの検索で利用する新しい属性検索演算子「STRORINC」をAIに作成してもらう

公開

PowerCMS Xのサイト内全文検索機能(SearchEstraierプラグイン)で利用するHyper Estraierの属性検索演算子をAI(Claude Code)に作成してもらいました。

ちなみに、記事を執筆し読み返していると演算子名は「STRORINC」より「STRTOKENEQ」(トークン化 + 等価比較)の方が的確かなと思い始めました。

属性検索とは?

タイトル・カテゴリ・重要度など、本文以外のさまざまなデータをキーバリューのような形式で検索インデックスに格納しておき、検索に利用するものです。例えばcategory STREQ フルーツで検索すると、カテゴリに「フルーツ」が指定されている文書が抽出できます。詳細はUser's Guide of Hyper Estraier Version 1 (Japanese)をご覧ください。

遭遇した課題

以下のようなカテゴリ属性を持つ5つの文書があるとします。

# 文書1
categories=B787-8,Boeing

# 文書2
categories=777-300ER,Boeing

# 文書3
categories=A350-900,Airbus

# 文書4
categories=DHC8-Q400,Bombardier

# 文書5
categories=E170,EMBRAER

この時、BoeingもしくはAirbusが指定されている文書を抽出したいのですが、Hyper Estraierの既存の演算子…具体的にはSTRINCSTROREQでは抽出できませんでした。

  • STRINCstrstr(tval, oval) != NULLのように実装されており、単一の検索条件キーワードを部分一致で探しています。複数のキーワードを持つことは想定されていません。
  • STROREQは検索条件に複数のキーワードを指定することができるのですが、属性値(検索対象)を複数持つことが想定されていません。属性値全体が検索条件のいずれかと完全一致することが必要です。

STRORINCの実装

先の課題を解決するために、検索条件も属性値もカンマ区切り(もしくはスペース区切り)で複数指定できるSTRORINCがあれば良いと考えました。ただ、Hyper EstraierはCで記述されているのでWeb制作のエンジニアである私には改変が難しいです。estraier.cファイルに検索処理が書かれており、文字列の一致を確かめるような実装であることは理解できたので、Claude Codeに分析と実装を依頼しました。

> est_check_stroreq を参考に STRORINC を作成したい。
  `tval = "B787-8,Boeing"` 、`oval = "Boeing,Airbus"`でヒットさせたい。

簡易なプロンプトでしたが、Claude CodeがIDEと連携してestraier.cファイルを直接参照できたため、既存の実装パターンを理解して適切な実装を行ってくれました。具体的にはest_check_stroreqの実装を分析し、それをベースに新しい演算子の仕様を満たすest_check_strorincを作成してくれました。

⏺ Update Todos
  ⎿  ☐ Find a good location to add the STRORINC function declaration
     ☐ Add the STRORINC function declaration near est_check_stroreq
     ☐ Implement the est_check_strorinc function
     ☐ Find where STROREQ is used and add STRORINC support
     ☐ Test the implementation

(中略)

⏺ STRORINCの実装が完了しました。

  実装内容:
  1. estraier.h に ESTOPSTRORINC マクロを追加
  2. estraier.c に:
    - est_check_strorinc 関数の宣言と実装を追加
    - STROREQ と同様の処理箇所に STRORINC のサポートを追加

  est_check_strorinc関数は、tval内の各トークン(カンマまたはスペース区切り)がoval内のいずれか
  のトークンと完全一致するかをチェックします。

⏺ テストケースを追加して、STRORINCが正しく動作することを確認しましょう。引っかかる場合と引っか
  からない場合の両方をテストします。

⏺ Write(test_strorinc.c)
  ⎿  Wrote 151 lines to test_strorinc.c
     #include 
     #include 
     #include 
     static int est_check_strorinc(const char *tval, const char *oval){
       const char *tsp, *tep, *osp, *oep, *trp, *orp;
       assert(tval && oval);
       tsp = tval;
       while(*tsp != '\0'){
         while(*tsp == ' ' || *tsp == ','){
     … +141 lines (ctrl+r to expand)

⏺ Bash(gcc -o test_strorinc test_strorinc.c && ./test_strorinc)
  ⎿  === STRORINC Test Cases ===   

     【ヒットするケース】
     … +37 lines (ctrl+r to expand)

⏺ 完璧です!すべてのテストケースが期待通りに動作しています。

  テスト結果のまとめ:

  ヒットするケース ✓
  - 完全一致のトークンがある場合
  - 位置に関係なく(最初、中間、最後)一致
  - スペース区切り、カンマ区切り、混合でも動作
  - 特殊文字や日本語でも正常動作

  ヒットしないケース ✓
  - 部分一致だけでは不十分(完全一致が必要)
  - 空文字列の適切な処理
  - 前方・後方の部分一致では検出されない

  STRORINCは「tval内のいずれかのトークンがoval内のいずれかのトークンと完全一致」という条件で正
  しく動作しています。

仕様

  • 属性値を単語単位で分割
  • 検索条件の各キーワードと完全一致チェック
  • いずれかのキーワードと一致すればマッチ

既存演算子との比較

演算子 属性値の扱い 検索条件 例での結果
STRINC 全体を1つの文字列として扱う 単一キーワード(部分一致) 使用不可
STROREQ 全体を1つの文字列として扱う 複数キーワード可(完全一致) ヒットなし
STRORINC トークンに分割 複数キーワード可(トークン単位で完全一致) 文書1,2,3がヒット

インストール

改良前のHyper Estraier同様、makeしてインストールするだけです。

検索実行例

bash-5.2# estcmd search -va -attr 'categories STRORINC Boeing Airbus' casket 
--------[7365852B3E327430]--------
VERSION	1.0
NODE	local
HIT	3
HINT#1	[UVSET]	6
TIME	0.000438
DOCNUM	6
WORDNUM	14
VIEW	ATTRIBUTE

--------[7365852B3E327430]--------
@id=1
@title=B787-8
@uri=https://www.example.jp/test1.html
categories=B787-8,Boeing

--------[7365852B3E327430]--------
@id=2
@title=Boeing 777-300ER
@uri=https://www.example.jp/test2.html
categories=777-300ER,Boeing

--------[7365852B3E327430]--------
@id=3
@title=Airbus A350-900
@uri=https://www.example.jp/test3.html
categories=A350-900,Airbus

--------[7365852B3E327430]--------:END

PowerCMS Xのタグを利用して検索条件を指定すると、以下のような記述になります。

<mt:estraiersearch add_attr="categories" add_condition="STRORINC" value="Boeing Airbus">
  /* 検索結果一覧表示HTML */
</mt:estraiersearch>

まとめ

生成AIの活用により、今まではどうにもできなかったHyper Estraierへの機能追加を行うことができ、PowerCMS Xのサイト内全文検索機能を強化することができました。今後もClaude CodeやCursor等の生成AIを上手く活用していきたいです。