CloudKit — queryable 和 searchable

CloudKit Index 是用来优化 CloudKit 数据查询性能的机制,与数据库中的索引类似。索引能够提高在 CloudKit 数据库(比如 Public Database 或 Private Database)中查询特定字段或数据的效率,让你的查询请求(CKQuery)更快地执行。

在 CloudKit 中,索引是一种在服务器端的预定义搜索优化,开发者通过为特定字段设置索引,能让 CloudKit 在记录集合中高效检索匹配的数据。当你查询未索引的字段时,可能会遇到查询失败的情况。


CloudKit Index 的核心作用 #

  1. 提升查询效率
  • 索引会在 CloudKit 数据库中建立一个供查询字段快速访问的结构,从而显著减少查询时间。
  • 对于大量数据的筛选操作,索引尤为重要。
  1. 支持查询操作
  • 要对某个字段执行查询(例如:筛选特定值的记录),该字段必须被设置为索引。
  • 如果字段未索引,而你尝试在 CKQuery 中使用它进行条件查询,会导致查询失败。
  1. 支持排序
  • 如果你需要根据某个字段对结果排序(CKQuery.SortDescriptor),该字段也需要被设置为索引。
  1. 提升 Predicate 过滤效率
  • 在 CloudKit 中,CKQuery 的查询条件由 NSPredicate 表达式定义。索引字段能让筛选特定值、范围或者关系的条件计算更高效。

CloudKit 中的索引类型 #

CloudKit 提供两种索引类型,可以根据不同场景使用:

索引类型适用的字段类型用途
查询索引(Queryable Index)所有支持类型(字符串、整数、日期等)用于字段的筛选(Predicate 查询条件)。如果你需要过滤字段值,需设置为查询索引。
排序索引(Sortable Index)字符串、数字、日期等支持排序的类型用于字段的排序操作。例如根据日期字段从最新到最旧排序。

为什么需要索引? #

CloudKit 中的数据虽然存储在结构化的 CKRecord 中,但只有创建索引的字段能够被服务器搜索和排序。如果一个字段没有索引:

  1. 无法在查询中指定该字段作为条件(Predicate 会报错)。
  2. 数据性能会大大降低,因为在没有索引时,查询需要依赖表扫描的方式(CloudKit 不支持全表扫描操作)。

例如:

let predicate = NSPredicate(format: "title == %@", "Important Note")
let query = CKQuery(recordType: "Note", predicate: predicate)
  • 字段未设置索引(title 没有索引):查询将失败,因为 CloudKit 无法通过未索引字段完成筛选。
  • 字段已设置索引:执行非常快速,能够正确返回结果。

索引的创建 #

1. 定义索引字段 #

在 CloudKit 的管理 UI(CloudKit Dashboard)或者代码中,可以为 Record 的字段手动设置索引:

  1. 登录到 CloudKit Dashboard (通过 CloudKit Dashboard 管理)。
  2. 打开对应的 Record Type
  3. 给字段开启:

示例:

  • Queryable:表示此字段支持查询(在查询条件中使用)。
  • Sortable:表示此字段支持排序。
  • title(字符串类型):可同时设置为 QueryableSortable
  • creationDate(日期类型):通常设置为排序索引(支持排序记录从新到旧)。

2. 自动索引处理 #

CloudKit 将以下字段设置为默认索引字段(不需要手动设置):

  • recordName:记录的唯一标识符。
  • creationDate:记录的创建日期。
  • modificationDate:记录的最近修改日期。

如果你只依赖这些字段,开发时无需再额外配置。


索引字段的使用示例 #

1. 查询索引字段 #

如果想查询某个 title 字段包含 “CloudKit” 的记录:

let predicate = NSPredicate(format: "title CONTAINS %@", "CloudKit")
let query = CKQuery(recordType: "Note", predicate: predicate)

let database = CKContainer.default().publicCloudDatabase
database.perform(query, inZoneWith: nil) { results, error in
    if let records = results {
        print("Records found: \(records)")
    } else if let error = error {
        print("Query error: \(error.localizedDescription)")
    }
}
  • 这里 title 字段必须设置为 Queryable Index,否则查询 title 会失败。

2. 排序索引字段 #

如果需要按 creationDate 字段,从最近到最早排序结果:

let predicate = NSPredicate(value: true)  // 查询所有记录
let query = CKQuery(recordType: "Note", predicate: predicate)
query.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]

let database = CKContainer.default().privateCloudDatabase
database.perform(query, inZoneWith: nil) { results, error in
    if let records = results {
        print("Records sorted by creationDate: \(records)")
    } else if let error = error {
        print("Query error: \(error.localizedDescription)")
    }
}
  • 这里排序字段 creationDate 必须是 Sortable Index,否则排序会失败。

性能优化与注意事项 #

  1. 索引字段越多并不总是越好
  • 建立索引会增加 CloudKit 的存储成本(会影响查询性能),如果字段不会频繁用于查询或排序,则不要设置索引,避免不必要的开销。
  1. 仅考虑实际使用频率
  • 如果某个字段很少用作查询条件,没必要设置为索引字段。
  1. 多字段查询需索引所有字段
let predicate = NSPredicate(format: "title == %@ AND category == %@", "CloudKit", "Guide")
  • 如果查询需要多个字段作为过滤条件,那每个字段都必须设置为索引字段。
  1. 不要忘记重建索引
  • 如果后续增加字段,或者修改字段类型,可能需要重新生成索引。在 CloudKit Dashboard 中执行 Schema 更新。

总结 #

CloudKit Index 是用于优化查询性能和功能的必要机制,能够显著提升基于 CloudKit 的数据操作效率。在实际开发中:

  • Queryable Index 适合用于查询动作的字段。
  • Sortable Index 适合用于排序相关的字段。
  • 合理配置索引字段,既能提升查询性能,也能避免不必要的存储开销。

苹果官方文档关于索引的详细介绍可以参考:

queryable 和 searchable #

CloudKit 中,字段的 索引类型 (index type) 主要有以下两种:QueryableSearchable,它们是为特定字段定义的属性,用于优化数据库查询操作。虽然这两个索引类型都旨在提高查询效率,但它们的用途和工作机制有所不同。


索引类型概览 #

索引类型功能描述适用场景支持的字段类型
Queryable允许字段参与结构化查询(比如等值、范围查询)精确匹配、范围筛选、排序等场景。数字、字符串、布尔、日期等简单数据类型
Searchable允许字段支持全文搜索(适合未精确匹配的搜索,如关键字包含或前缀查询)文本内容的模糊搜索,比如查找含特定关键字的字段内容。只能应用于字符串字段 (String)

1. Queryable 索引 #

功能描述#

Queryable 索引是最常用的索引类型,适用于在结构化查询中作为条件的字段。索引字段支持以下功能:

  • 精确匹配查询 (equality comparison):

  • 例如 某个字段 == 某值

  • 范围查询 (range comparison):

  • 例如 某个字段 >= 某值值在某范围内

  • 排序 (sorting)。

如果你在 Predicate 中使用某字段作为查询条件 (如 field == "abc"),那么该字段必须设置为 Queryable 索引。


支持功能 #

  • 结构化查询 (精确匹配与范围查询)

  • 表达式语义:field == "value"field >= 10field BETWEEN {1, 100}

  • 按字段排序

  • 如果字段未设置为 Queryable,不能作为排序依据。


示例 #

应用场景:筛选数据 #

  • 目标:检索记录类型为 “Note” 的记录,找出字段 creationDate 在某个日期范围内的数据。
let predicate = NSPredicate(format: "creationDate >= %@ AND creationDate <= %@", startDate, endDate)
let query = CKQuery(recordType: "Note", predicate: predicate)

let database = CKContainer.default().publicCloudDatabase
database.perform(query, inZoneWith: nil) { records, error in
    if let records = records {
        print("Fetched records: \(records)")
    }
}
  • creationDate 必须设置为 Queryable 索引,否则会报错,因为范围查询需要索引支持。

典型支持字段类型 #

  • 字符串类型 (String):用户 ID、标签、标题等需要精确匹配的字段。
  • 数字类型 (Int / Double):数值查询和排序。
  • 布尔类型 (Bool):支持 truefalse 的值查询。
  • 日期类型 (Date):范围筛选,例如从某日期到某日期之间的记录。

2. Searchable 索引 #

功能描述#

Searchable 索引专为字符串字段设计,支持更高级的文本查询操作,类似于全文搜索,能够处理更复杂的条件匹配,例如:

  • 关键字包含(CONTAINS)。
  • 前缀搜索(BEGINSWITH)。
  • 不支持精确值匹配(这是 Queryable 的职责)。

当你需要检索一段长文本 是否包含某个关键字以某个关键字开头 时,字段应设置为 Searchable


支持功能 #

  • 模糊查询 (非精确匹配)

  • 比如 field CONTAINS "keyword"field BEGINSWITH "prefix"

  • 多语言文本检索

  • Searchable 索引的实现方式更适合搜索自然语言文本字段,例如文章内容或长段文本。


示例 #

应用场景:模糊搜索 #

  • 目标:寻找字段 title 包含关键字 "CloudKit" 的记录。
let predicate = NSPredicate(format: "title CONTAINS %@", "CloudKit")
let query = CKQuery(recordType: "Note", predicate: predicate)

let database = CKContainer.default().publicCloudDatabase
database.perform(query, inZoneWith: nil) { records, error in
    if let records = records {
        print("Fetched records containing 'CloudKit': \(records)")
    }
}
  • 这里字段 title 需要设置为 Searchable 索引,否则查询失败。

典型支持字段类型 #

  • 仅支持 字符串类型 (String)

  • 通常用于描述信息(如标题、摘要、文章正文)的字段。


Queryable 和 Searchable 的主要区别 #

  • 功能范围不同

  • Queryable 索引适合结构化查询,如精确匹配、范围筛选、排序等。

  • Searchable 索引适合全文搜索,针对字符串字段支持模糊匹配和前缀搜索。

  • 数据类型支持不同

  • Queryable 支持字符串、数字、布尔值、日期等多种数据类型。

  • Searchable 仅支持字符串字段

  • 实现方式不同

  • Queryable 用于字段值的直接比较(等值、范围等)。

  • Searchable 使用的是基于文本的全文搜索引擎。


当字段同时设置 Queryable 和 Searchable 时 #

  • 如果字段是字符串,可以同时设置 QueryableSearchable

  • Queryable:用于精确匹配,比如 field == "value"

  • Searchable:用于模糊搜索,比如 field CONTAINS "keyword"field BEGINSWITH "prefix"

  • CloudKit 会根据查询的具体需求,选择使用哪种索引提升性能。


索引使用注意事项 #

  1. 未索引字段的限制
  • 未索引的字段无法用作查询条件(CKQuery 会报错)。
  • 也无法用作排序字段,或用于 Predicate 进行过滤。
  1. 索引类型配置
  • 只能通过 CloudKit Dashboard 或者 Schema API 设置字段索引类型。
  • 索引配置后不能直接更改字段类型,必要时需删除字段后重新创建。
  1. 存储开销与性能权衡
  • 索引会增加 CloudKit 存储开销,且过多的索引可能降低性能,需仅对必要字段设置索引。

总结 #

索引类型功能支持操作类型适用场景
Queryable支持结构化查询(精确匹配、范围筛选)和排序==>=<=、排序等操作精确值筛选,数值或日期范围筛选,字段排序等
Searchable支持全文搜索(模糊匹配、前缀查询)CONTAINSBEGINSWITH文本搜索、查找包含特定关键字的内容

根据字段的用途需求,合理选择字段的索引类型,可以提升查询性能并确保 CloudKit 查询能够顺利进行。

本文共 3582 字,上次修改于 Jan 4, 2025