新功能:照片探索器 · 查找任何已添加到地图的旅行照片。

工程更新

Photo Explorer、Constellations和更快的Mapsake

两个雄心勃勃的照片功能提出了相同的问题:Mapsake 是否可以在不变得更慢的情况下执行更多工作? 一套新的模拟器和设备基准测试将答案转化为可测量的工程工作。

由...设计。 13 分钟阅读
Mapsake 照片探索器,带有过滤器、集合、地图和时间线控件,以及旅行照片结果。

一个功能发布和一个工程发布。

此更新引入了 Mapsake 的两个最具雄心的照片体验: 照片浏览, 使大型地图库可以被搜索,并且 星座, 发现遥远地点之间的视觉联系。

它还包括发布中不太明显的功能:一个永久的性能基准测试套件。该套件立即找到了最慢的共享路径,使修复成为可测量的,并为该应用程序提供了一种检测未来工作是否会使其变慢的方法。

结果不仅仅是更多的功能。 Mapsake 能够更快地将大型照片库转换为地点、查找附近的城市以及计划星空。

Photo Explorer搜索旅行记录,而不是相册。

Photo Explorer从Mapsake已经维护的映射照片的紧凑元数据开始。这包括位置、日期、来源、相机、笔记、海拔、速度、收藏夹、屏幕截图、编辑以及应用程序内部添加的组织。

索引存储在设备上。搜索可以是直接的(例如:日本、2024、iPhone、收藏夹),也可以用更自然的表达方式(例如:“去年来自意大利的精选照片”)。查询层将支持的语言转换为结构化过滤器集,而确定性词汇和拼写纠正提供可靠的备用方案。

搜索只是访问库的一种方式。 集合提供有用的分组;地图区域限制结果的地理范围;时间线按日期进行分组;保存的搜索和最近的搜索可以快速重复提问。 收藏夹、评分、标签、标签和备注存储在本地辅助文件中,因此整理照片不会更改或上传原始文件。

重要架构选择是每个工具都共享相同的索引快照。收藏、时间线、地图和文本搜索不会从头开始重建 82,000 照片的世界。

索引是派生的,而个人组织是持久的。

Photo Explorer需要两种类型的存储,它们的生命周期非常不同。诸如地点名称、拍摄年份、相机、海拔和来源之类的搜索字段可以从Mapsake现有的元数据中重建。收藏夹、私人笔记、评分、标签或颜色标签是由用户编写的,不能被视为可丢弃的缓存数据。

因此,Mapsake 将用户创建的组织存储在小的、可备份的附加文件中。更大的搜索索引位于缓存中,不包含任何图像字节,从备份中排除,并且可以在每次其模式更改时重新生成。重新扫描库或清除派生数据不会擦除某人组织时所付出的努力。

这种划分也使备份更加可靠。无损的 JSON 和 HTML 备份可以包含注释和组织,但它们不会悄悄地膨胀成照片档案。Apple Photos 的注释保留了最佳的稳定 iCloud 标识符,因此可以恢复的备份可以重新连接到另一个 Apple 设备上的本地副本;Immich 资产标识符已经在其源头稳定。

第一次完整的压力测试产生了约 12.4 MB 的压缩索引,用于 82,000 张照片。 在开发模拟器上进行完整的地理构建需要 2.61 秒,稍后从磁盘恢复需要 1.20 秒,生成集合需要 126 毫秒,而每日时间线模型需要 211 毫秒。 这些数字为该功能的每个部分设置了单独的预算,而不是将所有内容隐藏在一个通用的“搜索”指标后面。

Photo Explorer还会解释为什么某个项目匹配。结果可能表明它与京都、2024、iPhone相机、私人笔记或所选过滤器匹配。当查询将自然语言与几个精确控制相结合时,这行文字非常重要:用户永远不应该猜测搜索引擎的含义。

搜索语言是接口,而不是即兴发挥的许可。

每个受支持的查询最终都会成为一个经过验证的过滤器结构。直接路径可以识别地点、日期、来源、相机型号、笔记、收藏夹、评分、标签、海拔、速度、屏幕截图和编辑的照片。一个受限的拼写检查器可以修复意图单词和已知的索引词汇,但它不会重写任意的私人笔记。

在支持 Apple 设备的本地 Foundation 模型上,输入的文本也可以解释为相同的受限结构。仅将查询和当前年份提供给该系统模型。照片像素、元数据索引、位置说明和个人组织永远不会提供。无效范围和未知值将被拒绝,并且确定性解析器仍然是备用方案。

界面显示解释,并提供返回原始单词的方法。这部分,巧妙之处只有在它仍然可以检查时才有用。“去年高于 3,000 米的照片”应该听起来像口语,但它仍然应该像一个精确的过滤器集。

Constellations 寻找跨越距离的重复。

“Then & Now” 询问是否有人返回到同一地点。 “Constellations” 提出几乎相反的问题:他们在相隔遥远的地方重复了哪些视觉想法?

设备的索引会从符合条件的旅行照片中提取一组紧凑的视觉信号和主题。规划器会寻找那些对一张图像来说是独特的特征,而不是普遍存在的特征,然后将候选对象连接到不同的目的地。门、海岸线、天际线、山脉的形状、颜色、季节和构图都可能成为主题的词汇。

这些线程被组织成一个三维天空。用户可以在其中漫游,打开一个星座,保留或放弃一个连接,并播放一个匹配剪辑电影,其中相关的照片从一个地方溶解到另一个地方。共享卡片和动态使用相同的保存的线程数据。

提取和规划工作在设备上完成。 Mapsake 不会将旅行库发送到图像分析服务。 后台批处理可以随着时间的推移加深索引,而无需在首次启动时等待整个库。

视觉索引旨在以低成本进行重新调整。

对于每个符合条件的参与者,Mapsake 会对一小张图像进行解码,并推导出几个信号:Vision 特征、原始分类器标签、紧凑的颜色调色板以及从位置、时间和太阳高度估算的亮度类别。 特征是一个小的数值描述,用于相似性比较;它不是图像的副本,也不能以这种方式显示。

索引存储原始分类器标识符,而不是立即将其替换为面向产品的动机。这种选择在实际库测试中发挥了作用。最初的动机列表包含听起来合理但实际上未包含在 Vision 支持的分类体系中的标签。由于原始标签仍然可用,因此重建“塔和桥梁”、“船和港口”等动机组是一个快速的评分过程,而不是再次扫描数千个原始文件。

索引的开始方式是从具有代表性的照片开始,而不是严格地从最新到最旧地读取整个库。照片被分组到近似的位置和日期,优先选择有用的静态图像,并在序列之间留出间隔。然后,规划器以循环方式浏览位置。这在早期阶段提供了广泛的地理覆盖范围,而后台批处理逐渐增加了深度。

第一次版本为每个位置选择一张照片。 来自实际设备的数据显示了缺陷:大多数位置仍然低于线程引擎使用的三个照片的最小值,因此仍然可以产生数千个索引资源,而没有候选者。 将每个轮次分块为三个代表性照片,可以使索引更快地变得有用,而不会增加其总预算。 这正是为什么合成测试和真实的、复杂的库都至关重要的原因。

提取器以序列批处理方式工作,以原子方式提交进度,在热压时暂停,并在低功耗模式下跳过后台提取。 首先尝试设备上已有的 Apple Photos 缩略图;仅在 iCloud 中的图像可以在稍后在允许网络连接时进行处理。 Immich 通过其现有的缩略图客户端使用相同的视觉流水线。

相似性本身并不能构成一个故事。

基于距离的功能可以找到两张视觉上相似的照片,但 Constellations 的目的是找到地点之间的联系,而不是检测重复项。候选照片必须位于相距至少 150 公里的地点。引擎还会考虑独特的图案、不寻常的光线、季节和重复的日历仪式,然后再建立联系。

“独特”是困难的部分。早期的评分模型奖励在两个地方都存在的特征。在开发库中,这导致数百个连接,主要与夜间和常见季节相关。这些特征在技术上是共享的,但并不令人惊讶。现在,引擎评估差异:当一个特征在两个地方都异常强烈,并且与用户的整个库相比时,该特征才重要。

这将问题从“两个地方都包含夜间照片吗?”更改为“这两个地方是否对于这个库来说,夜间照片异常多?” 常见的信号会融入背景,而重复的蓝色时段、门框、港口、冬季光线或重复的假期,可能会变得有意义。

视觉候选者使用每个地点的多个代表性地点,而不是单个的“幸运组合”。 线程标识符由其位置和家庭派生,因此相同的连接在重新评分后会保留其身份。 保持、拒绝和查看状态在调整后仍然有效,因此即使引擎再次运行,已拒绝的线程也不会重新出现。

天空布局也是预先计算和确定的。地理位置用于生成节点,连接的地点相互吸引,并且一个小量的随机抖动可以防止完全重叠。实时界面可以在球形地理和完成的星座之间通过一个转换值进行动画处理;它不运行每个帧都消耗电池的物理模拟。

匹配剪辑电影使用 Vision 注意力显著性来将轻柔的相机运动放置在每个示例的重要部分周围。门溶解到另一个门,而不是简单地对齐两个图像中心。减少运动会消除漂移运动并缩短过渡时间,而居中裁剪始终是当无法使用显著性时,优雅的备用方法。

为什么现在要构建一个基准测试套件?

大型库的性能已经达到一个临界点,仅凭直觉是不够的。一个更改可能会使一个屏幕感觉更快,但同时可能会使导入、回忆或星座图变慢,因为它们都依赖于相同的地理和照片处理流程。

新的套件有两个通道:

  • 一个逻辑通道,对小型、中型和压力测试环境运行确定性功能引擎,包括基于开发期间可用最大的真实世界报告的82,000照片层。
  • UI 布局显示具有代表性的屏幕,而 Mapsake 自己的性能仪表记录操作时间、错误和内存。

基准测试使用发布优化,并启用了测试功能。调试版本有意排除,因为未优化的 Swift 会产生与已发布应用程序不相关的数字。模拟器和物理设备的测试结果也具有单独的基线,因此不同的硬件不会被视为相同的环境。

此套件涵盖地理信息系统、地图几何、导入、照片元数据、成就、Passport、Friends、备份、邮票、Constellations、回忆和照片浏览器。实时网络、相机质量、系统照片枚举以及 CloudKit 仍然是集成测试,因为假定这些输入是确定的会使结果不那么真实。

基准测试可能完全错误。

开发此应用程序套件比简单地使用秒表测量应用程序代码所需的时间更多。 在第一个测试环境中,使用普通的哈希函数来选择坐标;Swift 故意在进程之间随机化此哈希函数,这导致从一个运行到另一个运行,几何工作大约变化了 30%。 现在,测试环境使用固定的生成器,并且该套件在接受结果之前会验证生成的形状。

在一个早期的场景中,使用 import.merge 名称来衡量新条目的数量。其目的是安全地将更改合并到现有地图中。测试既快速又可重复,但测试的内容不正确。通过更正测试数据,在尝试任何优化之前,基本值已更改。

UI测量存在类似的问题。性能计数器从启动时开始累积,因此一个标签手势可能会继承启动动画的延迟,看起来比实际慢。现在,每个交互都会刷新其手势之前的快照,然后仅在该场景自身的上下文中执行工作。

记录运行环境、操作系统、硬件配置、构建版本和热状态。模拟结果永远不会优先于设备基准。非正常的热运行仍然是有用的诊断信息,但它们会被注释,而不是导致回归测试失败。回归测试必须同时超过相对阈值和小的绝对下限,以防止亚毫秒级的噪声被误判为紧急情况。

这些细节并非围绕基准的官僚程序。它们是使数字具有价值的原因。

准确性检查发现地图错误。

在第一个性能测试中,最重要的测试不是测量速度。它将优化后的照片到位置的推导与在边界密集坐标上故意简化的参考进行比较。

在优化引擎发生变化之前,该保护就失效了。位于重叠的行政区划内的照片(例如,柏林位于勃兰登堡内,首尔位于京畿道内,基辅市位于其周围的州内),可能根据字典的随机迭代顺序进行分配。相同的坐标在启动后可能会得到不同的结果。

参考引擎和生产引擎现在都会按多边形面积排列重叠的候选项,从而以确定性的方式选出最具体的行政区域。只有在 82,000 张测试照片上实现零差异,并且热路径与冷路径的结果一致后,才采用这些空间优化。

通过等效性检查进行性能工程的这种安静优势在于,它可以发现正常的计时工作永远无法发现的正确性问题。

首次测量单位的更改。

初始的压力测试暴露了几个共享的瓶颈。第一个优化步骤增加了索引几何形状的命中测试、持久的地理单元缓存、记忆化的位置解析、共享照片快照以及增量 Atlas 注释更新。

在模拟器上,从 82,000 张照片的地图的冷启动时间从 34.5 秒到 8.0 秒.。在更改过滤器或打开“地点”后的常见路径保持不变。 2.8 秒. 10,000 照片级别上的星座规划功能下降了。 3.3 秒到 0.9 秒. 标签切换时间下降了 31%,Passport 页面器延迟下降了 47%。

下一个步骤将重复的 SQLite 纬度带扫描替换为延迟的、按纬度排序的最近城市索引以及有界记录缓存。在模拟器基准测试中,中等大小的最近城市批次从... 2.11 秒到 5.2 毫秒. 在物理 iPhone 上,相同的共享引擎功能下降了。 3.06 秒到 6.35 毫秒,,而基于压力的星座规划下降了。 5.60 秒到 65.9 毫秒.

这一步也加速了从 82,000 获取照片的时间,大约从 7.96 秒缩短到 ~ 秒。 1.00 秒 在模拟器中,有一个984毫秒的预热时间。 由于最近城市查找位于导入、Then & Now、地图生成和Constellations之下,而不是属于单个屏幕,因此性能得到了提升。

这些是受控的基准工作负载,而不是保证每个设备或库都会产生相同数量的结果。 它们的价值在于可比性:固定的配置、记录的热状态、已提交的结果以及可以标记有意义的回归的网关。

由于代码的可重用性提高,因此速度更快。

最重要的改进不是通过删除功能或添加加载指示器来实现的。而是通过停止重复的工作来实现的:

  • 区域几何形状现在会在进行昂贵的点测试之前缩小候选多边形。
  • 与构建相关的地理单元缓存会记住已解析的区域。
  • 查找最近城市的查询使用数字空间索引,而不是为每个坐标重新构建数据库排序。
  • 基于照片的界面共享一个不可变的过滤快照。
  • 地图销和旗帜通过标识符进行更新,而不是删除和重新创建所有内容。

Photo Explorer和Constellations都受益于它们构建在相同的底层技术之上。导入、Then & Now、数据地图和地点故事也是如此。

基准测试代码已从 App Store 归档中删除,但该代码仍然保留在存储库中:在对关键代码路径进行更改时,运行此套件,将其与正确的基线进行比较,并保留结果。现在,性能是该项目可以测试的内容,而不仅仅是希望能够注意到的内容。

这些数字还保留了未完成的工作。在物理设备 UI 的后续传递中,出现了严重的散热问题,并且仍然记录到标签周期内存峰值很大,并且在打开 Constellations 时几乎有一秒的延迟。这些读数是诊断性的,而不是干净的回归比较,但显示这些读数比宣布应用程序“完成”更有用。

这三个项目有什么共同之处。

Photo Explorer、Constellations和基准套件都始于相同的约束:大型旅行库应该在不离开设备或使应用程序的其他部分感觉更慢的情况下变得更有用。

Photo Explorer将已知的元数据转换为问题和集合。Constellations将代表性图像信号转换为视觉故事。基准套件使两者都符合共享的底层引擎。

此功能的工作在搜索结果、星空和匹配剪辑中可见。 工程工作主要体现在未发生的事情上:启动不会等待所有 82,000 照片的下载,过滤器不会创建同一数组的五个副本,并且快速空间索引不会默默地更改照片所属的城市。

这是我希望 Mapsake 中的性能工作朝着的方向发展。速度不是在雄心勃勃的想法之后进行的清理阶段。它是使这些想法保持安全的一个工具。

Mapsake 应用程序图标

Mapsake 的独立开发者,讲述了该应用程序背后的产品、地图、隐私和 Apple 平台工作。

创建您自己的旅行地图。

从您已经拥有的旅行历史开始。

Mapsake 免费,使用核心功能无需 Mapsake 帐户,并且支持的照片匹配功能都在您的设备上运行。

免费获取 Mapsake。