CloudKit Index 是用来优化 CloudKit 数据查询性能的机制,与数据库中的索引类似。索引能够提高在 CloudKit 数据库(比如 Public Database 或 Private Database)中查询特定字段或数据的效率,让你的查询请求(CKQuery
)更快地执行。
在 CloudKit 中,索引是一种在服务器端的预定义搜索优化,开发者通过为特定字段设置索引,能让 CloudKit 在记录集合中高效检索匹配的数据。当你查询未索引的字段时,可能会遇到查询失败的情况。
CloudKit Index 的核心作用 #
- 提升查询效率:
- 索引会在 CloudKit 数据库中建立一个供查询字段快速访问的结构,从而显著减少查询时间。
- 对于大量数据的筛选操作,索引尤为重要。
- 支持查询操作:
- 要对某个字段执行查询(例如:筛选特定值的记录),该字段必须被设置为索引。
- 如果字段未索引,而你尝试在
CKQuery
中使用它进行条件查询,会导致查询失败。
- 支持排序:
- 如果你需要根据某个字段对结果排序(
CKQuery.SortDescriptor
),该字段也需要被设置为索引。
- 提升 Predicate 过滤效率:
- 在 CloudKit 中,
CKQuery
的查询条件由NSPredicate
表达式定义。索引字段能让筛选特定值、范围或者关系的条件计算更高效。
CloudKit 中的索引类型 #
CloudKit 提供两种索引类型,可以根据不同场景使用:
索引类型 | 适用的字段类型 | 用途 |
查询索引(Queryable Index) | 所有支持类型(字符串、整数、日期等) | 用于字段的筛选(Predicate 查询条件)。如果你需要过滤字段值,需设置为查询索引。 |
排序索引(Sortable Index) | 字符串、数字、日期等支持排序的类型 | 用于字段的排序操作。例如根据日期字段从最新到最旧排序。 |
为什么需要索引? #
CloudKit 中的数据虽然存储在结构化的 CKRecord
中,但只有创建索引的字段能够被服务器搜索和排序。如果一个字段没有索引:
- 无法在查询中指定该字段作为条件(Predicate 会报错)。
- 数据性能会大大降低,因为在没有索引时,查询需要依赖表扫描的方式(CloudKit 不支持全表扫描操作)。
例如:
let predicate = NSPredicate(format: "title == %@", "Important Note")
let query = CKQuery(recordType: "Note", predicate: predicate)
- 字段未设置索引(
title
没有索引):查询将失败,因为 CloudKit 无法通过未索引字段完成筛选。 - 字段已设置索引:执行非常快速,能够正确返回结果。
索引的创建 #
1. 定义索引字段 #
在 CloudKit 的管理 UI(CloudKit Dashboard)或者代码中,可以为 Record 的字段手动设置索引:
- 登录到 CloudKit Dashboard (通过 CloudKit Dashboard 管理)。
- 打开对应的 Record Type。
- 给字段开启:
示例:
- Queryable:表示此字段支持查询(在查询条件中使用)。
- Sortable:表示此字段支持排序。
title
(字符串类型):可同时设置为 Queryable 和 Sortable。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,否则排序会失败。
性能优化与注意事项 #
- 索引字段越多并不总是越好:
- 建立索引会增加 CloudKit 的存储成本(会影响查询性能),如果字段不会频繁用于查询或排序,则不要设置索引,避免不必要的开销。
- 仅考虑实际使用频率:
- 如果某个字段很少用作查询条件,没必要设置为索引字段。
- 多字段查询需索引所有字段:
let predicate = NSPredicate(format: "title == %@ AND category == %@", "CloudKit", "Guide")
- 如果查询需要多个字段作为过滤条件,那每个字段都必须设置为索引字段。
- 不要忘记重建索引:
- 如果后续增加字段,或者修改字段类型,可能需要重新生成索引。在 CloudKit Dashboard 中执行 Schema 更新。
总结 #
CloudKit Index 是用于优化查询性能和功能的必要机制,能够显著提升基于 CloudKit 的数据操作效率。在实际开发中:
- Queryable Index 适合用于查询动作的字段。
- Sortable Index 适合用于排序相关的字段。
- 合理配置索引字段,既能提升查询性能,也能避免不必要的存储开销。
苹果官方文档关于索引的详细介绍可以参考:
queryable 和 searchable #
在 CloudKit 中,字段的 索引类型 (index type) 主要有以下两种:Queryable 和 Searchable,它们是为特定字段定义的属性,用于优化数据库查询操作。虽然这两个索引类型都旨在提高查询效率,但它们的用途和工作机制有所不同。
索引类型概览 #
索引类型 | 功能描述 | 适用场景 | 支持的字段类型 |
Queryable | 允许字段参与结构化查询(比如等值、范围查询) | 精确匹配、范围筛选、排序等场景。 | 数字、字符串、布尔、日期等简单数据类型 |
Searchable | 允许字段支持全文搜索(适合未精确匹配的搜索,如关键字包含或前缀查询) | 文本内容的模糊搜索,比如查找含特定关键字的字段内容。 | 只能应用于字符串字段 (String ) |
1. Queryable 索引 #
功能描述: #
Queryable 索引是最常用的索引类型,适用于在结构化查询中作为条件的字段。索引字段支持以下功能:
精确匹配查询 (equality comparison):
例如
某个字段 == 某值
。范围查询 (range comparison):
例如
某个字段 >= 某值
或值在某范围内
。排序 (sorting)。
如果你在 Predicate 中使用某字段作为查询条件 (如 field == "abc"
),那么该字段必须设置为 Queryable 索引。
支持功能 #
结构化查询 (精确匹配与范围查询):
表达式语义:
field == "value"
、field >= 10
、field 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):支持
true
或false
的值查询。 - 日期类型 (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 时 #
如果字段是字符串,可以同时设置 Queryable 和 Searchable:
Queryable:用于精确匹配,比如
field == "value"
。Searchable:用于模糊搜索,比如
field CONTAINS "keyword"
或field BEGINSWITH "prefix"
。CloudKit 会根据查询的具体需求,选择使用哪种索引提升性能。
索引使用注意事项 #
- 未索引字段的限制:
- 未索引的字段无法用作查询条件(
CKQuery
会报错)。 - 也无法用作排序字段,或用于
Predicate
进行过滤。
- 索引类型配置:
- 只能通过 CloudKit Dashboard 或者 Schema API 设置字段索引类型。
- 索引配置后不能直接更改字段类型,必要时需删除字段后重新创建。
- 存储开销与性能权衡:
- 索引会增加 CloudKit 存储开销,且过多的索引可能降低性能,需仅对必要字段设置索引。
总结 #
索引类型 | 功能 | 支持操作类型 | 适用场景 |
Queryable | 支持结构化查询(精确匹配、范围筛选)和排序 | == 、>= 、<= 、排序等操作 | 精确值筛选,数值或日期范围筛选,字段排序等 |
Searchable | 支持全文搜索(模糊匹配、前缀查询) | CONTAINS 、BEGINSWITH | 文本搜索、查找包含特定关键字的内容 |
根据字段的用途需求,合理选择字段的索引类型,可以提升查询性能并确保 CloudKit 查询能够顺利进行。