大多数浏览器和
Developer App 均支持流媒体播放。
-
使用 Core Spotlight 支持语义搜索
了解如何使用 Core Spotlight 在 App 中提供语义搜索结果。探索如何让自己 App 的内容出现在用户的设备端私有索引中,以便用户可以使用自然语言来搜索项目。我们还将介绍如何安排索引编制活动来优化 App 的性能。 为了充分利用好本次讲座,我们建议你先查阅 Apple Developer 网站上的 Core Spotlight 文档。
章节
- 0:00 - Introduction
- 1:37 - Searchable content
- 5:05 - Demo: Creating an index delegate extension
- 6:56 - Results and suggestions
- 9:18 - Ranking
- 10:17 - Wrap-up
资源
相关视频
WWDC24
WWDC21
-
下载
大家好 我叫 Jennifer 是聚焦团队的工程师 我们非常关注搜索 今天 我非常高兴能向大家介绍 聚焦中的所有新 API 它们可帮助你在自己的 App 中 打造强大的搜索体验 CoreSpotlight 框架 可让你的 App 向聚焦提供可搜索内容 然后通过查询来检索这些内容 这是增强 App 的搜索持久存储 解决方案的绝佳方式 你的 App 提供的可搜索内容 存储在一个私有的 本地索引中 这个索引永远不会离开设备 用户可以在聚焦中搜索你的内容 但其他 App 将无法看到这些数据 借助 CoreSpotlight 你可以轻松地在 App 中 根据搜索栏中输入的自然语言搜索词 提供搜索结果和建议 今年 CoreSpotlight 支持通过语义搜索理解查询 在这之前 聚焦可以搜索 你的 App 中的内容 但搜索词必须完全匹配 有了语义搜索 用户能够 以自己的方式在 App 中搜索内容 并且搜索词只需含义相似即可 借助聚焦的查询理解模型 无论你使用什么搜索方式 都能找到正确的结果 今天我们将了解如何在 App 内 打造全方位的搜索体验 首先是向搜索索引提供内容 并遵循数据迁移和恢复的最佳实践 我们将了解如何检索结果和建议 以及如何提升 与用户最相关的搜索结果 的排名 我们将构建一个 App 可让用户搜索自己撰写的手记条目 你可以在下面的链接中找到 这个示例 App 的完整代码
构建出色搜索体验的第一步 是向聚焦提供可搜索内容 这些内容代表了用户 想要在 App 中搜索的内容 在手记 App 中 用户可以搜索所有手记条目 每个手记条目都是一个可搜索项目 为此 你需要为项目建立索引 使项目能够通过查询进行检索 并直接填充用户界面的视图 目前 语义搜索最适合文本 或媒体资源 例如图像和视频 为了获得最佳结果 你需要确保 可搜索项目具有恰当的内容类型 并且尽可能使用系统定义的属性 要创建 CSSearchableItem 请提供唯一标识符、 可选的域标识符和属性集 唯一标识符应存储在 App 的持久存储解决方案中 以便能够恢复完整的项目数据 接下来创建 CSSearchableAttributeSet 并务必设置有效的内容类型 查看我们的文档 获取 支持的 UT 类型的完整列表 或了解如何创建 你自己的自定内容类型 提供可搜索的文本项目时 务必要设置 title 和 textContent 这些属性会在语义索引中进行处理 如果你的项目代表图像或视频资源 务必将 contentURL 设置为 资源的路径 这可确保资源可从 App 的沙盒化容器 的语义索引中进行处理
如果项目引用附件或网页内容 请考虑将它们 作为单独的项目提供给索引 并设置它们自己的内容类型和属性 你可以使用 relatedUniqueIdentifier 来维持与源项目的关系
设计好可搜索项目后 你需要在聚焦中创建可搜索索引 并提供这些索引 我们新推出了一些好用的 API 可让你通过 App 的设计 更高效地提供索引 包括使用客户端状态 和项目更新来批量建立索引 首先创建一个命名的 CSSearchableIndex 获取并验证你发送到聚焦的 最后一个客户端状态 然后 为可搜索项目建立索引 这里注意 索引调用包围在 开始一批提供的项目的调用 和结束一批提供的项目的调用中 这里可以发送下一个客户端状态
客户端状态对于 管理大量项目非常有用 还可用于保持 App 与聚焦之间的 数据完整性 客户端状态还可用于 防止过度提供项目 这会影响 App 性能 与新的 isUpdate 标记 搭配使用时 可以确保 App 始终只提供需要的内容 为了构建一致的搜索体验 迁移和恢复是非常重要的组成部分 你的聚焦索引是完全本地和私密的 因此你需要采取措施 来确保你的可搜索内容 在聚焦中保持最新状态 当聚焦需要迁移索引时 或是需要从数据损坏、 中断或其他问题中恢复时 它将向你的 App 请求 重新建立所有项目的索引 或重新建立部分特定项目的索引 为了响应这些请求 你的 App 可以 在 App 正在实时运行时 采用代理协议 同时实现 聚焦可从你的 App 单独调用的代理扩展 索引代理扩展允许 聚焦将请求安排在 在有利的设备条件下 比如当设备处于睡眠或空闲状态时 这样就可以逐步迁移项目 而几乎不改变 App 现有的搜索功能 设置索引代理扩展非常简单 只要你使用新的 Xcode 文件目标 我们来看看具体怎么做 首先从手记 App 中开始 它已经配置为 使用套装 ID 提供可搜索内容: 第一步是创建新目标: 打开“文件”菜单 选择“新建”>“目标”
选择扩展的平台 这里我们从 macOS 开始 然后搜索新的 CoreSpotlight 代理扩展模板
点击“下一步”配置这个新目标 点击“完成” 将这个新目标添加到项目中
添加后 激活新扩展
现在我们来看看存根实现
由于聚焦将代表我们启动这一过程 我们可以使用一个便捷的 命令行工具来进行调试 现在我们来试一试
首先 在 reindexAll 方法中 设置一个断点 这样我们就可以尝试 在代码中捕捉到这个点 确保调用 acknowledgmentHandler 以避免拦截调用方
接下来 我们需要重建 App 来添加这个新的 App 扩展 选择 App 的目标 然后 打开“产品”菜单 选择“构建”
然后切换回扩展目标 在“调试”菜单中 选择“附加到流程”
现在我们可以开始调试 这时我们需要启动终端 App 来运行工具命令
mdutil 工具让我们能够 模拟向套装 ID 发出的请求 以便进行调试 我们可以运行命令
然后返回 Xcode 中的项目 查看是否已到达断点 我们现在可以完成相应的实现 包括为所有项目重新建立索引、 为部分项目重新建立索引、 添加拖放支持 以及针对关键提供路径 的限流场景进行响应 你已经为可搜索项目建立了索引 现在可以在你的用户界面中 支持搜索体验 你可以对查询进行配置 以便最好地支持你的用户界面需求 语义搜索默认启用 但也可以配置查询使查询返回 采用先进的机器学习模型 进行排名的结果 而这些模型正是聚焦所使用的 你还可以将查询配置为 支持 App 中的建议菜单 使用 CSUserQueryContext 配置适合用户界面的查询 务必设置针对查询返回的每个项目 获取的属性列表 这些获取的属性通常仅包含需要 在用户界面中展示的内容 可使用一个标记启用排名结果 并且可以限制排名结果的数量 这些结果通常显示在 单独的“最佳搜索结果”部分中 在返回所有结果后 必须在 App 中将结果排序 可以使用新的 compareByRank 比较运算符来进行排序
建议也可以按数字配置或停用 建议会按排名顺序返回 但顺序也可在排序时恢复 使用元数据语法的结构化查询 是根据 App 的用户界面 定制搜索结果的最佳方式 例如 如果用户选择 仅显示图像的标签页 可以使用像这样的筛选查询来指定 结果集仅包含图像 筛选查询还可用于 你希望仅显示在聚焦中的内容 例如可引导至 App 特定部分 的路径指引导航 查看我们的文档 了解如何使用元数据语法 构建自定筛选查询
最后一步是创建 CSUserQuery 需要使用搜索栏中的用户查询字符串 以及你的查询上下文 结果和建议会在异步响应中返回 项目结果会以异步方式分批返回 因此如果启用了排名 请务必在显示之前对项目进行排序 建议通常以用户键入的 字符串的补全形式返回 CSSuggestion 提供属性字符串 可以显示在建议菜单中 如果用户选择了某个建议 则将搜索栏文本替换为 这个字符串以触发新的搜索
语义搜索需要使用 必须下载到设备上的 机器学习模型 这个模型将在 你的 App 的进程中运行 这些模型可以随时载入或退出 以便在运行时 保留 App 的存储空间 这就是为什么你每次都需要 在搜索界面显示前 调用这个类方法 这样才能确保在用户开始搜索时 所有资源都可用 现在搜索可以正常使用 你需要开始考虑不断改善搜索体验 为此你可以提供信号来改善 用户最关心的内容的排序 在提供自适应的排序体验时 互动和新鲜度是非常重要的信号 用户可能会浏览 与可搜索项目相关的内容 或者主动进行搜索 然后滚动浏览结果集中的各个项目 最后选择一个结果来查看详细信息 在每种情况下 你的 App 都可以向聚焦 发出互动信号 从而改善它在未来搜索中的排名
当用户浏览与 CSSearchableItem 相关的内容时 在项目属性集上设置 lastUsedDate 属性 并将它提供给索引作为更新 当用户选择某个查询结果 或某个查询建议 你可以将交互标记为 与这个查询相关联 这样就可以了 用户现在可以获得成熟的搜索体验 能够流畅处理多个平台和语言区域 的多样化搜索内容 我们了解了如何向完全私密的 设备端搜索索引提供内容 如何检索结果和建议 以及如何不断提升 最相关的搜索结果 采用 Core Spotlight 能够很好地 帮助用户在你的 App 中查找内容 有了语义搜索 它变得前所未有的强大
如果想要进一步了解 其他类型的聚焦集成 请观看我们的其他讲座 包括如何利用 App Intents 如何使用 CoreData 免费获得 CoreSpotlight 提供 感谢观看 期待在聚焦里见到你
-
-
2:14 - Creating CSSearchableItem
// Creating searchable items for donation let item = CSSearchableItem(uniqueIdentifier: uniqueIdentifier, domainIdentifier: domainIdentifier, attributeSet: attributeSet)
-
2:28 - Creating CSSearchableAttributeSet
// Creating searchable content for donation let attributeSet = CSSearchableItemAttributeSet(contentType: UTType.text) attributeSet.contentType = UTType.text.identifier
-
2:40 - Searchable items with type
// Searchable items with text attributeSet.title attributeSet.textContent // Searchable items with media attributeSet.contentType attributeSet.contentURL // Searchable items with links attributeSet.contentURL attributeSet.relatedUniqueIdentifier
-
3:31 - Batch indexing with client state
// 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 } } }
-
3:56 - Avoid overwriting existing attributes
// Make it an update to avoid overwriting existing attributes item.isUpdate = true
-
7:19 - Configure a query
// Configure a query let queryContext = CSUserQueryContext() queryContext.fetchAttributes = ["title", "contentDescription"]
-
7:33 - Ranked results
// Ranked results queryContext.enableRankedResults = true queryContext.maxRankedResultCount = 2
-
7:47 - Suggestions
// Suggestions queryContext.maxSuggestionCount = 4
-
7:55 - Filter queries
// Filter queries queryContext.filterQueries = ["contentTypeTree=\"public.image\""]
-
8:23 - Query for searchable items and suggestions
// 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 } }
-
8:40 - Suggestions
// Suggestions suggestion.localizedAttributedSuggestion
-
8:56 - Preparing for queries
// Preparing for queries CSUserQuery.prepare CSUserQuery.prepareWithProtectionClasses
-
9:50 - Set the lastUsedDate
// 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
// 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)
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。