メインコンテンツへスキップ
見出し画像

Search Suggestions:検索候補は最初から出るわけではない


    検索欄に文字を打つと、下に候補が並ぶ。今では当たり前の動きです。ServiceNow にも Search Suggestions という仕組みがあり、専用のテーブルが用意されています。

    ところが実機を数えてみると、候補は 0件 でした。いっぽう「候補に出してはいけない語」のリストだけが 720件 入っています。守りだけが先に効いていて、中身は空。今回はこの非対称な状態から、検索候補という機能の性格を読み解きます。

    このシリーズのまとめ:4つの検索機能(AI Search / Zing / Now Assist / Contextual Search)の全体像と比較は ServiceNowの検索は2階層:エンジン(Zing / AI Search)と、その上に乗る機能 にまとめています。

    この記事は、ServiceNow の PDI(Personal Developer Instance、無料の個人検証環境)Zurich リリース・OOTB(初期設定)で確認した実測メモです。件数・項目は REST と実画面で確認しました(確認日 2026-07-26)。本番環境では設定が異なります。

    4つのテーブルのうち3つが空


    画像


    画像

    実測はこうでした。

    • sys_search_suggestion(候補)… 0件

    • sys_search_event(検索イベント)… 0件

    • sys_search_source_event(ソース別イベント)… 0件

    • sys_search_suggestion_blacklist(除外語)… 720件

    候補を出す側が空で、外す側だけが埋まっている。この形は偶然ではありません。

    除外リストが720件ある理由


    画像


    画像

    内訳を数えると、単語一致(WORD)が717件、正規表現(REGEX)が3件でした。言語は717件が en、残る3件は未設定です。

    中身を確認したところ、攻撃的・卑猥な語が並んでいました。伏せ字を混ぜた綴りも含まれます。この記事では具体的な語は載せません。

    なぜ標準で720件も入っているのか。理由は候補の作られ方にあります。検索候補は、利用者が実際に検索した語から育つ仕組みです。誰かが不適切な語を検索すれば、それが候補として他の利用者に表示されかねません。

    自社のポータルで、検索欄に文字を打った瞬間に不適切な語が並ぶ。想像するだけで避けたい事態です。だから 候補が1件も無い段階から、除外リストだけは効いている。守りを先に用意しておく設計でした。

    正規表現が3件だけ含まれているのも合理的です。同じ語の綴りの揺れをすべて単語登録するのは大変なので、パターンでまとめて捕まえます。

    type の表示ラベルは「Match one word exactly」でした。単語として完全に一致した場合だけ弾く、という指定です。部分一致にすると、正当な語の中にその文字列が含まれるだけで消えてしまいます。たとえば英単語の一部として偶然含まれる綴りまで巻き込む。完全一致にしておけば、その事故を防げます。

    言語が3件だけ未設定なのも意図的だと読めます。言語を問わず弾きたい語(記号の組み合わせなど)は、language を空にしておけば全言語で効きます。717件を en に限定しているのは、日本語や他言語では別のリストを用意する前提だからです。

    除外リストは誰が管理するか

    720件が最初から入っているとはいえ、これは英語圏向けの初期値です。運用に乗せるなら、誰がこのリストを管理するかを決める必要があります。

    情報システム部が管理するのが自然に見えますが、判断に迷う語も出てきます。社内でしか通じない略語、開発中の製品名、取引先の名前。これらは「不適切」ではないものの、候補に出したくない場合があります。

    除外リストは1つのテーブルですが、目的は2つに分けて考えると整理しやすくなります。不適切な語を弾く守りと、出したくない社内情報を隠す守り。前者は初期値のまま、後者は運用の中で足していく。description フィールドに理由を書いておけば、後から見た人が判断できます。

    候補は自分で育てる

    sys_search_suggestion のフィールドを見ると、候補が持つ情報が分かります。


    画像
    • name … 候補として出す文字列

    • score … 順位づけに使う点数

    • source … その候補の出どころ

    • language … 言語

    • group … 対象のユーザーグループ

    • active … 有効か

    • application_table / application_id … どのアプリの候補か

    score があるので、候補は単なる一覧ではなく順位づけされます。よく使われる語ほど上に出る、という並べ方ができます。

    group があるのも実務的です。情報システム部の人と営業部の人では、探すものが違います。グループごとに候補を分ければ、それぞれに合った語が出せます。

    source は候補の出どころを持つ項目です。自動生成なのか手動登録なのかを区別できる作りに見えますが、実データが0件のため、どんな値が入るかは確認できませんでした。

    application_table と application_id の組も入っています。テーブル名とレコードIDのペアで、どのアプリに属する候補かを指す形です。同じ「注文」という語でも、サービスカタログの候補と資産管理の候補では意味が違います。アプリごとに分けられる作りになっていました。

    active があるのも実務では効きます。候補を消すのではなく、いったん止める。季節限定のキャンペーン名や、終了した制度の名前は、消すのではなく無効にしておけば、必要になったときに戻せます。

    候補と検索結果は別の仕組み

    ここで整理しておきたいのが、「候補」と「検索結果」の違いです。

    検索結果は、入力を確定してから返ってくるものです。ServiceNow では Zing(旧来の全文検索)や AI Search がその役割を担います。対象はナレッジ記事、カタログ品目、レコードなど、実際のコンテンツです。

    いっぽう候補は、入力の途中で出るものです。対象はコンテンツではなく 語そのもの。「pass」と打った段階で「password reset」と出す。まだ検索していない状態で働きます。

    この違いは実装にも表れています。検索結果はコンテンツのインデックスを引きますが、候補は sys_search_suggestion という語のテーブルを引きます。別のテーブル、別の育て方です。

    候補が効くのは「言い方をそろえる」から

    候補の価値は、探す時間の短縮だけではありません。むしろ効くのは、利用者の言い方をそろえることです。

    同じ内容を、ある人は「パスワード再設定」、別の人は「パスワード忘れた」と検索します。コンテンツ側が「パスワードリセット」という表現しか持っていなければ、後者は何も見つけられません。

    候補で「パスワードリセット」を先に見せれば、利用者はその語を選びます。結果として、コンテンツが持っている表現に検索が寄っていく。これが候補のいちばん大きな効き目です。

    だから候補は、コンテンツ側が持っている表現に合わせて育てるのが筋になります。利用者の入力をそのまま候補にすると、この効果は薄れます。

    検索してもイベントが増えなかった

    候補が育つには、利用者の検索が記録されている必要があります。その記録先が sys_search_event です。

    実際に検索を実行して、増えるかどうかを確かめました。

    グローバル検索で「password」を検索し、旧来のテキスト検索で「incident」を検索しました。どちらも結果は表示されます。

    そのうえで、あらためて件数を数えました。


    画像

    結果は 0件のまま でした。sys_search_source_event も0件です。検索は動くのに、イベントが残りません。

    理由までは特定していませんが、AI Search の分析収集が有効になっていない状態と考えられます。この PDI では、検索の利用状況が記録されない設定になっているようです。

    検索が動くことと、検索が記録されることは別。 候補が育たない原因は、ここにありました。

    検索イベントが持つ情報は多い

    記録されていないとはいえ、sys_search_event のフィールド構成そのものは見応えがあります。


    画像

    分類すると8つの塊になりました。

    検索そのものでは、search_query(入力された語)だけでなく rewritten_search_query(書き換えられた語)を持ちます。同義語や表記ゆれを吸収した後の語が別に記録される作りです。

    has_results(結果があったか)と refinements(絞り込み直した回数)も別項目で持ちます。結果が0件だった検索は、そのままコンテンツの不足を示します。

    クリックの記録として click_rank があります。何番目の結果を選んだかです。1番目が選ばれ続けているなら並び順が正しく、5番目ばかりが選ばれるなら並べ方を見直す材料になります。

    Genius Result 系のフィールドが5本もあるのは、AI Search の要約回答に関する記録です。要約が出たか、どの設定が効いたか、何番目の要約がクリックされたか。

    言語処理では synonyms と stop_words を持ちます。どの同義語が効いて、どの語が無視されたか。検索がうまくいかないときの調査に使えます。

    これだけの項目が用意されているということは、検索の改善を継続的に回すことが前提の設計だと分かります。

    利用者まわりの項目も見逃せません。user と organization(→cmn_department)と geography があるので、「どの部署のどの地域の人が何を探しているか」まで分解できます。

    海外拠点を持つ組織なら、拠点ごとに探されているものが違うはずです。日本の拠点で頻繁に検索される語が、他の拠点では一度も検索されない。そうした差が見えれば、翻訳や地域別のコンテンツを用意する判断材料になります。

    session と conversation_id も持ちます。1回の検索だけでなく、一連のやり取りとして追える作りです。「最初にこう検索し、見つからず、言い方を変えて再検索した」という流れが再現できます。

    relevancy_model(→ml_solution)は、並び順を決める機械学習モデルへの参照です。どのモデルで並べた結果なのかが記録されるので、モデルを差し替えたときの効果を比較できます。

    実際に検索した画面を見る

    イベントは残りませんでしたが、検索そのものは正常に動いています。


    画像

    グローバル検索で「password」を検索すると、結果の画面が表示されました。ナレッジ記事やカタログ品目など、複数のソースをまたいだ結果が並びます。


    画像

    /textsearch.do は旧来のテキスト検索です。こちらも結果を返します。新旧2つの検索経路が並存している状態でした。

    利用者から見れば、どちらも「検索」です。しかし記録される先や、候補の出し方は違います。どの経路を主に使わせるかを決めておかないと、分析のときに数字が分散します。

    入口をひとつに寄せる。 検索を改善したいなら、まずこれが要ります。複数の入口を放置したまま候補を育てても、効果が測れません。

    検索を良くする順番

    実測から読み取れる、検索改善の進め方を整理しておきます。

    1. まず記録を有効にする

    イベントが残らなければ、何も分かりません。候補を手で作る前に、検索が記録される状態にするのが先です。

    この PDI のように、検索は動くがイベントは0件、という状態は気づきにくいものです。「候補が出ない」と相談されたら、まず sys_search_event の件数を数えるのが早道です。

    2. 結果0件の検索を見る

    has_results が false の検索を集めれば、「探されているのに無いもの」が分かります。ナレッジ記事を追加すべき対象が、そのまま一覧になります。

    3. 絞り込み直しの多い語を見る

    refinements が多い検索は、一発で目的にたどり着けていない検索です。並び順や同義語の設定を見直す候補になります。

    4. 候補を育てる

    ここまでの分析を経て、よく検索される語を候補として登録します。score で順位を付け、group で対象を絞る。

    5. クリックされた順位を見る

    click_rank を集計すると、並び順が合っているかが分かります。上位が選ばれているなら問題ありません。

    多くの検索で3番目や4番目がクリックされているなら、上位2件が的外れということです。並び順の設定か、コンテンツのタイトルの付け方を見直す材料になります。

    6. 除外リストを自社向けに足す

    標準の720件は英語の不適切語です。日本語環境で運用するなら、同じ趣旨の語を自分で足す必要があります。また、社外に出したくない社内用語(開発中の製品名など)を候補から外す用途にも使えます。

    ソース別のイベントという分け方

    sys_search_event のほかに sys_search_source_event というテーブルがありました。こちらも0件です。

    名前から読めるのは、1回の検索を「ソースごと」に分けて記録する仕組みだということです。ServiceNow の検索は、1回でナレッジ記事とカタログ品目とレコードを同時に探します。それぞれのソースで何件ヒットしたかを別々に持てば、より細かく分析できます。

    「検索は成功したが、ナレッジからは1件も出なかった」という状況は、記事の不足を示します。全体の件数だけを見ていると、この事実が埋もれます。

    イベントを2階層に分ける設計は、インポートセットやスキャン結果とも共通します。親に全体、子に内訳。 ServiceNow のログ設計でよく見る形です。

    実務で気をつけるところ

    候補は利用者の入力から育つ

    自動で候補が溜まる仕組みは便利ですが、そのまま出すと危険もあります。誰かの誤入力がそのまま候補になれば、他の利用者が同じ誤りを繰り返します。

    除外リストが標準で720件も用意されているのは、この危険への備えです。運用を始めたら、溜まった候補を定期的に見る時間を取ります。

    語の内容を扱うときの配慮

    除外リストの中身は、そのまま画面に出したり資料に貼ったりする種類のものではありません。設定の説明が必要なときは、件数と仕組みだけを示せば足ります。

    この記事でも、720件という数と type の内訳だけを載せ、語そのものは伏せました。

    日本語環境では追加が要る

    標準の717件は language が en です。日本語の不適切語は入っていません。日本語で運用するなら、同等のリストを自分で用意する必要があります。

    正規表現が使えるので、綴りの揺れをまとめて捕まえる書き方もできます。ただし広く取りすぎると、正当な語まで候補から消えます。

    グループごとの候補は後から効く

    group フィールドは、最初は使わなくても済みます。しかし部署ごとに検索する語が大きく違う組織では、後から効いてきます。

    候補の設計を始めるとき、グループで分ける可能性を頭に置いておくと、後で作り直さずに済みます。

    「候補が出ない」と言われたときの調べ方

    利用者から「検索候補が出ない」と相談されたとき、確認する順番があります。

    まず sys_search_suggestion の件数です。0件なら、そもそも出すものがありません。この PDI と同じ状態です。

    次に sys_search_event の件数を見ます。0件なら、候補が育つ材料が記録されていません。候補を手で登録することはできますが、自動で増えることは期待できません。

    候補もイベントも入っているのに出ない場合は、active と language と group を確認します。言語が合っていない候補や、別のグループ向けの候補は表示されません。

    最後に除外リストを見ます。720件の中に、その語が引っかかっていないか。正規表現の3件は広く効く可能性があるので、意図せず正当な語を巻き込んでいないかを確かめます。

    候補 → イベント → 属性 → 除外。 この順で見れば、原因はどこかで見つかります。

    検索を「使われている機能」として扱う

    検索は、設定して終わりにされがちな機能です。ナレッジ記事を入れ、検索欄を置き、そこで完了とみなす。

    しかし実際には、利用者が毎日使い、そのたびに「見つかった/見つからなかった」が起きています。その結果を記録して読まなければ、コンテンツが足りているのかも分かりません。

    sys_search_event に30以上のフィールドが用意されているのは、検索を継続的に測る対象として設計されているからだと読めます。0件のまま放置するのは、その設計を使っていないことになります。

    導入時のチェックリストに「検索イベントが記録されているか」を1行入れておく。それだけで、後から改善を始められる状態が保てます。

    どこから触るか

    • /sys_search_suggestion_list.do … 検索候補

    • /sys_search_suggestion_blacklist_list.do … 候補から外す語720件

    • /sys_search_event_list.do … 検索イベント

    • /sys_search_source_event_list.do … ソース別のイベント

    • /textsearch.do?sysparm_search=… … 旧来のテキスト検索

    • /now/nav/ui/classic/params/target/%24sn_global_search_results.do … グローバル検索の結果画面

    除外リストは type で並べ替えると、WORD と REGEX の違いが見比べやすくなります。件数が720あるので、language や active でも絞って見ると全体像がつかめます。

    まとめ

    検索候補の仕組みは、4つのテーブルでできていました。候補、検索イベント、ソース別イベント、そして除外リスト。

    実測では候補もイベントも0件で、除外リストだけが720件。守りを先に用意し、中身は運用で育てる。この順番が標準の姿でした。

    検索を2回実行してもイベントは増えず、収集が有効になっていない状態だと分かりました。候補が育たない環境では、まず記録が残っているかを確かめるのが最初の一歩になります。

    sys_search_event の項目構成を見ると、結果0件の検索、絞り込み直しの回数、クリックされた順位まで残せる設計でした。記録さえ残れば、検索の改善は数字で進められます。

    用語

    • 検索候補(sys_search_suggestion) … 検索欄に出す候補。name / score / group を持つ

    • 除外リスト(sys_search_suggestion_blacklist) … 候補に出してはいけない語。WORD と REGEX

    • 検索イベント(sys_search_event) … 検索1回ぶんの記録。AI Search の分析用

    • rewritten_search_query … 同義語などを吸収した後の検索語

    • has_results … その検索で結果が出たかどうか

    • click_rank … 利用者が何番目の結果を選んだか

    自分の環境で確認するときのURL

    • /sys_search_suggestion_list.do(候補・0件)

    • /sys_search_suggestion_blacklist_list.do?sysparm_query=ORDERBYtype(除外語720件)

    • /sys_search_event_list.do?sysparm_query=ORDERBYDESCsys_created_on(イベント・0件)

    • /textsearch.do?sysparm_search=incident(旧テキスト検索の実行)

    • /now/nav/ui/classic/params/target/%24sn_global_search_results.do?sysparm_search=password(グローバル検索の実行)

    実測の要点(再掲)

    • sys_search_suggestion / sys_search_event / sys_search_source_event はいずれも 0件

    • sys_search_suggestion_blacklist は 720件(WORD 717 / REGEX 3、language en 717)

    • 実際に2種類の検索を実行したが、イベントは 0件のまま

    • 検索候補は name / score / source / language / group / active を持つ

    • 検索イベントは30以上のフィールドを持ち、クリック順位や同義語の適用まで記録できる設計

    関連記事

    検証範囲とおことわり

    • 件数・項目は PDI(Zurich / OOTB)の実測です。本番環境の設定とは異なります。

    • sys_search_event が増えない理由は特定していません。AI Search の設定やライセンスの前提による可能性があります。

    • 候補が0件のため、除外リストが実際に候補を弾く挙動は確認できていません。

    • 除外リストの語そのものは、内容の性質から本文に掲載していません。件数と種別のみ示しています。

    • Genius Result や関連性モデルなど、AI Search の高度な機能は検証範囲外です。

    参考リンク

     
     
    ServiceNowのPDI(Personal Developer Instance)を実機で観察して、Noteに記事を書いています 実装・運用・教育の現場視点で淡々と記録中です リクエストがあればその記事も書きます 個人の観察日記です

    あなたへのおすすめ