メインコンテンツへスキップ

Zingの正体:いま実際に有効化されているテキスト検索エンジン


    前回、AI Search の設計図を読みました。そのとき1つ引っかかることがありました。AI Search の設定は一式そろっているのに、エンジン本体(glide.ais.enabled)が false だったのです。ではこの環境で、検索窓に文字を打ったとき、実際に答えを返しているのは誰なのか。

    答えは Zing でした。AI Search の前身にあたる、旧来のテキスト検索エンジンです。この記事は、その Zing が「本当に動いている」ことを実機で確かめ、仕組みを ts_* テーブルから読み解きます。

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

    この記事は、ServiceNow の PDI(Personal Developer Instance、無料の個人検証環境)Zurich リリース・OOTB(初期設定)で確認した実測メモです。件数・状態・プロパティ値はすべて REST で取得しました(確認日 2026-07-12)。本番環境やカスタマイズ済み環境では設定が異なります。

    まず、動いている証拠から

    「Zing が動いている」は印象論では困ります。プロパティで裏を取ります。

    • glide.ais.enabled = false(AI Search エンジンは未起動)

    • glide.ui.polaris.ais_ready = false(Next Experience 側も AIS 未準備)

    • glide.ts.query_mode = rdbms(Zing が rdbms モードで検索を実行)

    • glide.ts.global_search.parallelism = 4(グローバル検索が並列で回っている)

    • glide.ts.widget.top_search_tables =

    • kb_knowledge, problem, incident

    • change_request, sc_cat_item, live_message

    AI Search のフラグは軒並み false。一方 Zing のプロパティは実値を持ち、並列数やクエリモードまで具体的に設定されています。決め手はもう1つ、次に見るインデックスの状態です。

    インデックスが「作られている」という物理的な証拠

    Zing のテキストインデックス定義は ts_index_name にあります。実測で38件、すべて active。そしてこの一覧画面が、何より雄弁でした。


    画像

    State 列がすべて「Ready」。さらに「Indexed rows(索引済み行数)」「Unique terms(ユニーク語数)」「Total terms(総語数)」に実数が入っています。たとえば alm_asset は 2,819 行・ユニーク 10,070 語・総語 40,670。cmdb_ci_outage は 438 行・総語 2,330。これは設定だけの状態ではありません。Zing が実際にテーブルを読み、単語を数え、索引を組み終えているという物理的な証拠です。

    前回の AI Search では、インデックス統計(ais_datasource_stats)が 0 件でした。片や Zing は Ready で語数まで積み上がっている。同じ環境で、この差がすべてを語ります。ちなみに「Queries last day / 7 days / 30 days」はどれも 0。誰も最近この PDI で検索していないだけで、索引そのものは完成しています。

    「ユニーク語数」と「総語数」の違いにも触れておきます。総語数は、そのテーブルの索引に含まれる単語の延べ数です。ユニーク語数は、重複を除いた語彙の種類数を指します。たとえば alm_asset は総語 40,670 に対してユニーク 10,070。同じ語が平均で4回ほど出てくる計算です。この数字が大きいほど、検索でヒットしうる語の幅が広いことを意味します。索引が空(0)なら、そのテーブルはいくら検索しても引っかかりません。State と語数は、検索が効くかどうかの健康診断のように読めます。

    全体像:Global Search から物理インデックスまで

    Zing の構造を1枚にします。


    画像

    流れはこうです。利用者がグローバル検索窓に語を打つと、対象テーブル群(top_search_tables)に対して、それぞれのテキストインデックス定義(ts_index_name)が引かれます。各定義には物理インデックステーブル(ts_c_* や ts_v4_* という命名の実テーブル)が対応していて、そこに転置索引が入っています。どのフィールドを索引に含めるかは、sys_dictionary の属性(text_index)で項目ごとに決まる仕組みです。実測では、この text_index 属性を持つ辞書項目が 605件 ありました。

    公式ドキュメントによれば、Zing は検索結果を4つのフェーズで作ります。文書をシャード(かたまり)に分割し、シャードごとに検索してスコアを付け、最後にマージして1つの順位表にする、という流れです。シャード処理を同時にいくつ回すかを決めるのは glide.ts.query.parallelism で、この環境では 5 でした(後述のプロパティ一覧に載せています)。冒頭に挙げた glide.ts.global_search.parallelism=4 は、グローバル検索側の並列数を指す別のプロパティです。そして結果は、利用者がアクセスできるレコードだけに ACL で絞り込まれてから返ります。索引に入っていても、権限がなければ見えません。

    Incident・Problem・Change を検索したとき、それぞれ別のインデックスが引かれるわけではありません。3つは親テーブル task を共有していて、task の1つのテキストインデックス(実体は ts_c_33_7)でまとめて索引されます。1本の索引で3プロセスを賄う、効率的な設計です。

    テキストインデックス定義(ts_index_name)

    38件の対象テーブルを眺めると、検索して意味のあるものが選ばれているのが分かります。


    画像

    task(Incident/Problem/Change の親)、kb_knowledge(ナレッジ)、sc_cat_item(カタログ)、alm_asset(資産)などです。ほかに sla・sys_user・core_company・cmn_location・cmdb_ci_outage などもあります。ナレッジQ&A(kb_social_qa_*)や契約(ast_contract)まで入っています。Format 列は多くが v3、設定によっては v4 と、索引フォーマットの世代が混在していました。

    インデックスグループ(ts_index_group)

    複数テーブルの索引を束ねる単位が ts_index_group です。実測は2件。


    画像
    • portal_index_group(ポータル検索用)

    • sn_me_search_mobile_employee_index_group(Mobile Employee 検索用・命名からの推測)

    グローバル検索の実際の対象は、このグループよりも先ほどの top_search_tables プロパティが強く作用します。グループは特定の検索体験(ポータルやモバイル)向けのまとまり、と捉えると分かりやすいです。

    Zing の関連度の決め方:重みとプロパティ

    AI Search が機械学習で関連度を決めるのに対し、Zing は重み(weight)で並び順を作ります。ここが両者のいちばんの違いです。


    画像

    プロパティ一覧(glide.ts.* で絞って22件)から、要点を拾います。

    • glide.ts.field.default.weight = 1(フィールドの既定の重み)

    • glide.ts.attachment.default.weight = 0.1(添付本文は軽め)

    • glide.ts.attachment.title.default.weight = 1(添付のタイトルは本文より重い)

    • glide.ts.index.parallelism = 8 / glide.ts.query.parallelism = 5(索引作成・検索の並列数)

    • glide.ts.max_wildcard_expansion = 500(ワイルドカード展開の上限)

    • glide.ts.max_duration = 60(検索の最大秒数)

    添付ファイルの本文を 0.1 に抑えているあたりに、「タイトルや本文フィールドを優先し、添付は補助的に」という設計思想が出ています。関連度を人が数値で調整する世界です。


    画像

    同義語とスペル補正は「あるが、無効化されている」

    ここは正確に書きます。Zing には同義語やスペル補正の仕組みが用意されています。ただしこの環境では無効でした。


    画像

    同義語セット ts_synonym_set は実測29件、Dictionary はいずれも「Example synonym dictionary」でした。OOTB のサンプルは「AdSense, Advertise, CPC, AdWords」「Bitcoin, Digital wallet, Micropayments」です。Web・IT 用語のまとまりが入っています。ITSM 用語ではなくデモ用の例です。各セットの Active は true ですが、これを検索で有効化するスイッチ glide.ts.synonym.enabled は false。つまり辞書のレコードはあるが、検索時には展開されません。

    スペル補正(打ち間違いに「もしかして」を返す機能)も同様です。glide.ts.dym.enable_spell_correct と glide.ts.dym.enable_chain_suggest はどちらも false でした。公式ドキュメント上、Zing は "Did you mean" 提案や type-ahead 候補を持ちますが、このPDIではその一部が切られている、というのが実際のところです。

    ストップワード(索引から外す一般語)ts_index_stop は6件。broke, break, problem, broken, issue, trouble が登録されていました。よく見ると6件すべてが task テーブル向けで、Stop mode は「Neither Index nor Query(索引にもクエリにも使わない)」。problem や issue、trouble は、インシデントや問題のほぼ全件に出てくる語です。こうした語を索引から外さないと、検索してもほとんどのレコードがヒットしてしまい、絞り込みの役に立ちません。ありふれた語をあえて捨てることで、検索の切れ味を保つ工夫です。


    画像

    日本語の扱い

    日本語話者として気になるのが、単語の区切りです。英語はスペースで単語が切れますが、日本語は切れ目がありません。「サーバー障害」という文字列を「サーバー」「障害」と切るのか、別の切り方をするのか。この切り方(トークン分割)が検索の精度を大きく左右します。切り方を誤ると、探している語が索引に正しく登録されず、検索しても出てこない、ということが起きます。

    Zing 側には ts_japanese_token_dictionary(日本語トークン辞書)というテーブルが実在しました。日本語をどう単語に分割して索引するかを支える仕組みです。公式ドキュメントによれば、Zing の stemming(語幹化。walking を walk に戻すような処理)は英・仏・独が対象で、日本語はこのトークン分割の側で扱う建て付けになっています。英語のように語尾を丸めるのではなく、そもそもの区切りを辞書で補う、という考え方です。実際のトークン分割の挙動そのものは、対象レコードで検索を実行して確かめる必要があり、今回は検証範囲外とします。日本語環境で検索の当たりが悪いと感じたら、この辞書の存在を思い出すと切り分けの入口になります。

    Zing と AI Search の共存、そして移行

    面白いのは、この環境に Zing(ts_*)と AI Search(ais_*)の両方の定義が並んでいることです。Zing は 38 の索引定義、AI Search は 27 のデータソース・43 の検索ソース・15 のプロファイル。設定はどちらも充実しています。

    橋渡しの仕組みもありました。zing_to_ais_configuration というテーブルに、Zing の検索コンテキストと AI Search のコンテキストを対応づける移行マッピングが4件(active)。Next Experience Global Search、Global Search が並んでいます。ほかに Service Operations Workspace Search、Knowledge Center Global Search もあります。準備は整っているが、glide.ais.enabled を true にする最後の一歩を踏んでいない。だから今は Zing が現役、という状態です。

    インデックスの世代とメンテナンス

    テキストインデックスの一覧には、State のほかに「Format」という列があります。実測では多くが v3、設定によっては v4 でした。これは Zing の索引フォーマットの世代です。世代が上がると、索引の持ち方や検索の効率が変わります。同じ環境でも、テーブルによって世代が混在することがあります。この点は押さえておいてください。

    一覧画面の下には「Reset Text Search Caches」「View text_index Events」という関連リンクもありました。前者は検索キャッシュのリセット、後者は索引化のイベント(いつ、どのテーブルが索引されたか)の確認です。索引がうまく効かないときは、まずこの State と Events を見て、Ready になっているか、最近の索引イベントが流れているかを確かめます。索引は自動で更新されますが、大量投入の直後などは追いつくまでに時間がかかることもあります。

    State がずっと Ready にならない、あるいは新しいレコードが検索に出てこない。そんなときの一次切り分けは「定義(ts_index_name)は active か」「State は Ready か」「対象フィールドに text_index 属性が付いているか」の3点です。この記事で見た3つのテーブルを順にたどれば、原因の当たりはつきます。

    確認導線

    実機で開くときの入口です(URL形式は list.do 規約に基づきます。実クリック確認は今回の範囲外です)。

    • テキストインデックス … ts_index_name_list.do

    • インデックスグループ … ts_index_group_list.do

    • テキストインデックス設定 … ts_configuration_list.do

    • 同義語セット … ts_synonym_set_list.do

    • ストップワード … ts_index_stop_list.do

    利用者から見ると、どこで Zing に触れているか

    ここまで管理側のテーブルを見てきましたが、利用者は Zing という名前を意識しません。ではどこで触れているのか。いちばん身近なのは、画面上部の虫めがねアイコンから開くグローバル検索です。ここに語を打つと、先ほどの top_search_tables(ナレッジ・インシデント・問題・変更・カタログ・メッセージ)が横断で引かれ、種類ごとにまとまった結果が返ります。1つの窓から複数のテーブルを一気に探せるのが、グローバル検索の便利なところです。

    Service Portal の検索窓も、標準では Zing が背後にいます。ポータルでナレッジやカタログを探すとき、portal_index_group(先ほどのインデックスグループ)が働くわけです。さらに、リスト画面の各列の上にある検索ボックスや、参照フィールドの候補表示にも、テキストインデックスが関わる場面があります。つまり Zing は、派手な専用画面を持たないかわりに、製品のあちこちに溶け込んで働いている、というのが実態でした。

    この「溶け込み方」ゆえに、Zing は名前を知られないまま使われがちです。けれども、検索の当たり外れを左右しているのは、この記事で見た索引の State/フィールドの重み/text_index 属性の有無です。裏側の3つのテーブルを知っていると、「なぜこの記事が検索で上に出ないのか」に理由をつけられるようになります。

    Zing と AI Search、考え方の違い

    ここまで見てきた Zing と、前回の AI Search は、同じ「検索」でも思想が違います。次回以降の比較記事の前振りとして、要点だけ先に置いておきます。

    Zing は、管理者が重みを決める世界です。どのフィールドを重く見るか、添付にどれくらいの重みを与えるか。人が数値を振り、その通りに並びます。挙動が読みやすく、調整の因果関係がはっきりしているのが長所です。一方で、利用者がどの結果をよく開くか、といった行動は反映されません。改善はあくまで人の手作業になります。

    AI Search は、その調整を機械学習に寄せた設計でした。既定の関連度モデルがあり、利用者のクリックから並び順を学び直します。うまく回れば、手をかけずに精度が上がっていく。ただし学習にはデータが要ります。前回見たとおり、当PDIでは学習の実行実績はゼロでした。データが溜まる前は、既定モデルの実力勝負です。

    どちらが優れている、という単純な話ではありません。挙動を完全に制御したいなら重みの Zing、運用しながら育てたいなら学習の AI Search。そして現実には、多くの環境が Zing から AI Search への移行の途中にいます。この PDI がその一例でした。移行マッピングは用意され、けれどエンジンの最後のスイッチはまだ入っていない。この過渡期の見分け方を知っておくと、実機を触ったときに迷いません。

    まとめ

    Zing は、ts_index_name(索引定義)→ ts_c_*(物理インデックス)→ テーブルという構造で、重み(weight)を使って結果を並べるテキスト検索エンジンでした。そしてこの PDI では、AI Search が設定だけで止まっている裏で、Zing が実際にインデックスを組み、検索を返していました。

    「新しい AI Search が入っている」ことと「いま何が動いているか」は別の話です。プロパティとインデックスの State を見れば、どちらのエンジンが現役かは一目で分かります。移行を検討するときは、まずこの2つを確認するのが確実です。

    次回は、生成AIを使う Now Assist in Search を扱います。そのあと、フォーム入力を助ける Contextual Search、最後に各機能の比較へ進みます。

    その他、実機で確認した記録

    用語

    • Zing … ServiceNow 従来のテキスト検索エンジン。転置索引と重みで結果を並べる

    • テキストインデックス(ts_index_name) … どのテーブルに全文検索索引を張るかの定義。物理実体は ts_c_* / ts_v4_*

    • インデックスグループ(ts_index_group) … 複数テーブルの索引を束ねる単位

    • 重み(weight) … フィールドごとの重要度。Zing はこれで関連度を決める(既定 1、添付本文 0.1)

    • ストップワード … 索引から除外する一般語

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

    自分のインスタンス名を先頭に付けると、同じ画面が開けます。

    • /ts_index_name_list.do(テキストインデックス一覧・State や語数を確認)

    • /ts_index_group_list.do(インデックスグループ)

    • /ts_synonym_set_list.do(同義語セット)

    • /ts_index_stop_list.do(ストップワード)

    • /sys_properties_list.do?sysparm_query=nameLIKEglide.ts(Zing の挙動プロパティ)

    実測の要点(再掲)

    • 実働エンジンは Zing(glide.ts.query_mode=rdbms / glide.ais.enabled=false)

    • テキストインデックス 38(全 Ready・語数実数あり)/グループ 2/同義語セット 29(ただし機能 off)/ストップワード 6

    • 索引対象フィールド指定(sys_dictionary の text_index 属性)605/Zing→AIS 移行マッピング 4

    関連記事

    検証範囲とおことわり

    • この記事の件数・状態・プロパティ値・物理テーブルの実在は、PDI(Zurich / OOTB)の REST 実測です。

    • 実際の検索クエリ実行結果・スコアリングの中身・stemming や日本語トークン分割の挙動は未実行(検証範囲外)です。

    • sn_me_search_mobile_employee_index_group の用途は命名からの推測です。

    • list.do のURL形式は規約に基づくもので、実クリック確認は今回の範囲外です。

    • 本番やカスタマイズ済み環境では、数・設定・有効状態が異なります。

    参考リンク

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

    あなたへのおすすめ