ハイライト
iOS 18 の Core Spotlight はセマンティック検索をネイティブサポート。ユーザーが類義語で検索してもターゲットにヒット——開発者が独自検索モデルを構築する必要はありません。
主要内容
Core Spotlight は iOS で app コンテンツをシステム Spotlight にインデックスする標準方式でした。しかし弱点がありました:検索は完全一致。ユーザーが「旅行」で検索してもタイトルが「出游」のメモは見つからず、「画像」では「写真」にマッチしません。Spotlight グローバル検索では多くの最適化がありましたが、app 内検索では完全一致がユーザーを苛立たせがち。多くの app が独自のあいまい検索やサードパーティライブラリを導入——開発コストは低くありません。
iOS 18 の Core Spotlight はセマンティック検索(semantic search)をネイティブサポート。ユーザーの検索語は Spotlight の query understanding モデルで処理され、「意味が近い」検索語でもターゲットにヒット。セマンティック検索はデフォルトで有効——追加設定不要、モデル訓練不要、Natural Language フレームワーク統合不要、バックエンド不要。コンテンツを正しく Spotlight に donate するだけで、app 内検索体験が飛躍的に向上します。
セッションは付帯インフラも紹介:batch indexing と client state で大量データのインデックスを効率化、新 CoreSpotlight Delegate Extension でデバイスアイドル時に re-index をトリガー、新 ranked results API で Spotlight と同様の Top Hits 表示、engagement signal でユーザー行動に応じて検索ランキングを継続最適化。すべてデバイスローカルで実行——インデックスデータはデバイス外に出ず、他 app もインデックス内容を見られません。
詳細
検索可能 Item の作成
第一に Spotlight に検索可能コンテンツを donate。CSSearchableItem 作成時に一意識別子、任意の domain 識別子、属性セットを提供(2:14):
// Creating searchable items for donation
let item = CSSearchableItem(uniqueIdentifier: uniqueIdentifier, domainIdentifier: domainIdentifier, attributeSet: attributeSet)
uniqueIdentifierは app の永続化スキームに保存し、後で完全データを復元domainIdentifierは任意で、検索可能 item のグループ管理に使用
次に CSSearchableAttributeSet を作成し、有効な contentType を設定(2:28):
// Creating searchable content for donation
let attributeSet = CSSearchableItemAttributeSet(contentType: UTType.text)
attributeSet.contentType = UTType.text.identifier
contentTypeがセマンティックインデックスの処理方法を決定- テキスト item には
titleとtextContentを設定——両方がセマンティックインデックスで処理 - 画像/動画 item には
contentURLでリソースファイルパスを設定 - 添付や Web コンテンツは独立 item として donate し、
relatedUniqueIdentifierでソース item と関連付け
Batch Indexing と Client State
大量データのインデックスには iOS 18 の batch indexing + client state(3:31):
// Batch indexing with client state
let index = CSSearchableIndex(name: "SpotlightSearchSample")
index.fetchLastClientState { state, error in
if state == nil {
index.beginBatch()
index.indexSearchableItems(items)
index.endIndexBatch(expectedClientState: state, newClientState: newState) { error in
}
}
}
- 名前付き
CSSearchableIndexを作成しfetchLastClientStateで前回インデックス状態を取得 beginBatch()とendIndexBatch()でインデックス操作をラップ、newClientStateで進捗を記録- client state で重複 donate を防止しパフォーマンス問題を回避
- 新
isUpdateフラグで必要な更新のみ donate(3:56):
// Make it an update to avoid overwriting existing attributes
item.isUpdate = true
CoreSpotlight Delegate Extension
Spotlight がインデックス移行やデータ破損からの復旧を必要とする場合、app に re-index を要求。iOS 18 の新 CoreSpotlight Delegate Extension テンプレートで、デバイスアイドル時(スリープや未使用時)に re-index 要求をスケジュールし、段階的にデータ移行——既存検索機能への影響を最小化。
設定:Xcode で File > New > Target、「CoreSpotlight Delegate extension」テンプレートを検索。デバッグは mdutil コマンドラインツールで bundle ID への re-index 要求をシミュレート。
クエリ設定とセマンティック検索
セマンティック検索はデフォルト有効。CSUserQueryContext でクエリを設定(7:19):
// Configure a query
let queryContext = CSUserQueryContext()
queryContext.fetchAttributes = ["title", "contentDescription"]
fetchAttributesは UI 表示に必要な属性のみ設定し、不要なデータ読み取りを削減
ranked results を有効化し Top Hits を表示(7:33):
// Ranked results
queryContext.enableRankedResults = true
queryContext.maxRankedResultCount = 2
- ranked results は Spotlight と同じ機械学習モデルでソート
- 結果返却後は
compareByRankソーターでソート
検索候補を設定(7:47):
// Suggestions
queryContext.maxSuggestionCount = 4
filter queries でコンテンツタイプをフィルタ(7:55):
// Filter queries
queryContext.filterQueries = ["contentTypeTree=\"public.image\""]
- filter queries は metadata 構文で特定タイプのみに結果を限定
- タブ切替(画像のみなど)やパンくずナビに適する
クエリ実行と結果処理
CSUserQuery で検索を実行(8:23):
// Query for searchable items and suggestions
let query = CSUserQuery(userQueryString: "windsurfing carmel", userQueryContext: queryContext)
for try await element in query.responses {
switch(element) {
case .item(let item):
self.items.append(item)
break
case .suggestion(let suggestion):
self.suggestions.append(suggestion)
break
}
}
CSUserQueryはユーザー入力の検索文字列と query context を受け取る- 結果は async responses で返却、item と suggestion を分けて処理
- suggestion は
localizedAttributedSuggestionで表示 - ユーザーが suggestion をタップしたら検索バー内容を suggestion テキストに置換し新検索をトリガー
セマンティック検索は ML モデルをデバイスにダウンロードし app プロセス内で実行。メモリ節約のためモデルは随時ロード/アンロード。検索 UI 表示前に毎回 CSUserQuery.prepare を呼びリソースを確保(8:56):
// Preparing for queries
CSUserQuery.prepare
CSUserQuery.prepareWithProtectionClasses
Engagement Signal でランキング向上
ユーザーがコンテンツを閲覧したり検索結果をタップしたりすると、app は engagement signal を Spotlight に送信し将来の検索ランキングを最適化(9:50):
// Set the lastUsedDate when the user interacts with the item
item.attributeSet.lastUsedDate = Date.now
item.isUpdate = true
検索結果や候補とのインタラクション時にマーク(10:00):
// Interactions with items and suggestions from a query
query.userEngaged(item, visibleItems: visibleItems, interaction: CSUserQuery.UserInteractionKind.select)
query.userEngaged(suggestion, visibleSuggestions: visibleSuggestions, interaction: CSUserQuery.UserInteractionKind.select)
lastUsedDateは freshness シグナル——ユーザーが最近 item を使用userEngagedは engagement シグナル——どの結果がタップされたか、当時表示されていた他の結果リストを含む- 両シグナルが Spotlight ランキングモデルのユーザー嗜好学習を支援
重要ポイント
-
何をするか:既存 Core Spotlight 統合に ranked results と検索候補を追加。なぜ価値があるか:ranked results は Spotlight と同じ ML ソートモデルで Top Hits エリアを直接表示——検索体験が「リスト羅列」から「スマート推薦」へ。始め方:既存
CSUserQueryContextにenableRankedResults = trueとmaxRankedResultCountを設定、返却後compareByRankでソート。 -
何をするか:逐次インデックスを batch indexing + client state に置換。なぜ価値があるか:client state が前回インデックス進捗を記録し、app 再起動や Spotlight re-index 要求時に断点再開——全量再 donate によるパフォーマンス問題を回避。始め方:名前付き
CSSearchableIndexを作成、fetchLastClientStateで状態確認、beginBatch/endIndexBatch間で一括インデックス、カーソルをnewClientStateに保存。 -
何をするか:検索結果タップ時に engagement signal を送信。なぜ価値があるか:Spotlight ランキングモデルがユーザー行動から継続学習——よくタップされる item は将来の検索で上位に。始め方:コンテンツ閲覧時に
lastUsedDateを設定しisUpdate = trueでインデックスに書き戻し;検索結果タップ時にquery.userEngaged()を呼び、タップ item と当時表示されていた結果リストを渡す。 -
何をするか:CoreSpotlight Delegate Extension でインデックス復旧をサポート。なぜ価値があるか:システムアップグレードやデータ破損時に Spotlight インデックス再構築が必要——delegate extension なしでは検索が失効し、ユーザーが手動で app 再起動するまで再インデックス不可。始め方:Xcode で CoreSpotlight Delegate extension テンプレートから target 作成、
reindexAllItemsとreindexItemsWithIdentifiersを実装、mdutilでデバッグ。
関連セッション
- Bring your app to Siri — App Intents で app 機能を Siri と Apple Intelligence に公開、Spotlight インデックス統合含む
- What’s new in App Intents — App Intents フレームワーク新機能、Transferable API、ファイル表現、Spotlight インデックス
- Bring your app’s core features to users with App Intents — App Intents フレームワーク核心概念:intents、entities、queries
- Design App Intents for system experiences — Spotlight、Siri、Controls 等のシステム体験向け App Intents 設計
コメント
GitHub Issues · utterances