# 文档

在 Typesense 中索引的每条记录都称为一个 Document(文档)。

# 索引文档

要在指定集合中索引的文档必须符合该集合的模式定义

如果文档包含一个 string 类型的 id 字段,Typesense 将使用该字段作为文档的唯一标识符。否则,Typesense 会自动为文档分配一个标识符。由于这是一个特殊字段,id 字段不需要在集合模式中预先定义。

注意

id 不应包含空格或任何其他需要在 URL 中编码 (opens new window)的字符。

# 索引单个文档

当您需要在应用程序中响应用户操作来索引文档时,可以使用单文档创建端点。

如果需要一次性索引多个文档,我们强烈推荐使用批量导入文档端点,该端点针对批量导入进行了优化。 例如:如果您有100个文档,使用批量导入端点一次性索引将比逐个索引文档性能更高。

下面我们来看看如何向集合中添加一个新文档。

# 单文档更新或插入(Upsert)

如果文档 id 已存在,我们可以替换该文档;如果不存在相同 id 的文档,则会创建新文档。

如果需要批量更新或插入多个文档,强烈建议使用 批量导入文档 端点并设置 action=upsert,该接口针对批量操作进行了优化。 例如:如果有100个文档,使用导入端点一次性操作会比逐个文档 upsert 性能高得多。

示例响应

接口定义

POST ${TYPESENSE_HOST}/collections/:collection/documents

TIP

如果您的应用每秒写入次数超过10次,建议切换到使用批量导入API,该接口在处理高吞吐量写入时比单文档写入端点性能更高。 例如,通过10000次单独的API调用发送10000个文档,其CPU消耗和速度会比通过单次批量导入API调用发送这些文档慢一个数量级。

切换到批量导入的简单方法是让您的应用先将数据写入本地的缓冲表,而非直接写入Typesense。 然后设置一个定时任务(比如每隔5-10秒)从该表读取数据,并分批刷新到Typesense中。 更详细的指南请参阅Typesense中的高吞吐量写入

# 批量索引文档

您可以使用导入 API 批量索引多个文档。

当需要索引多个文档时,相比快速连续多次调用单文档创建端点,此端点的性能要高得多。

需要导入的文档应格式化为换行符分隔的 JSON 字符串,即 JSONLines (opens new window) 格式。这实际上是每行一个 JSON 对象,文档之间没有逗号分隔。例如,以下是 3 个文档以 JSONL 格式表示的示例:

{"id": "124", "company_name": "Stark Industries", "num_employees": 5215, "country": "US"}
{"id": "125", "company_name": "Future Technology", "num_employees": 1232, "country": "UK"}
{"id": "126", "company_name": "Random Corp.", "num_employees": 531, "country": "AU"}

如果您使用我们的客户端库,也可以直接传入文档数组,库会自动将其转换为 JSONL 格式。

在导入到 Typesense 之前,您还可以将 CSV 转换为 JSONL将 JSON 转换为 JSONL

# 操作模式(create、upsert、update 和 emplace)

除了批量创建文档外,您还可以使用 action 查询参数通过文档的 id 字段来更新文档。

create(默认) 创建新文档。如果已存在相同 id 的文档,则操作失败
upsert 创建新文档,如果已存在相同 id 的文档则更新现有文档。 需要发送完整文档。如需部分更新,请使用下面的 update 操作。
update 更新现有文档。如果给定 id 的文档不存在,则操作失败。您可以发送 仅包含需要更新字段的部分文档。
emplace 创建新文档,如果已存在相同 id 的文档则更新现有文档。 您可以发送完整文档或用于更新的部分文档。

现在让我们看看如何使用 create 模式导入一些文档。

定义

POST ${TYPESENSE_HOST}/collections/:collection/documents/import

示例响应

响应中的每一行表示请求体中每个文档的处理结果(顺序一致)。如果单个文档导入失败,不会影响其他文档。

如果出现失败情况,响应行会包含相应的错误信息以及实际的文档内容。例如,以下响应中第二个文档导入失败:

注意

无论单个文档的导入结果如何,导入端点始终会返回 HTTP 200 OK 状态码。

这是因为可能存在部分文档导入成功而其他文档失败的情况,我们不希望在这种部分成功场景下返回 HTTP 错误码。 为了保持一致性,我们在所有情况下都返回 HTTP 200。

因此请务必检查 API 响应中是否存在 {success: false, ...} 记录,以确认是否有文档导入失败。

# 返回导入文档的 id

如果你希望导入响应中包含已导入文档的 id,可以使用 return_id 参数。


# 使导入响应返回被导入文档的 `id` 字段
curl -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" -X POST --data-binary @documents.jsonl \
'http://localhost:8108/collections/companies/documents/import?return_id=true'
{"success": true, "id": "0"}
{"success": true, "id": "1"}
...

同样地,使用 return_doc 参数将会在响应中返回整个文档内容。

# 配置批量大小

默认情况下,Typesense 会每次批量导入 40 个文档 - 每导入 40 个文档后,Typesense 会先处理搜索请求队列,然后再切换回导入模式。 要调整这个值,可以使用 batch_size 参数。

请注意,这个参数控制的是服务端对单个导入 API 调用中文档的批处理大小。 增加这个值可能会影响搜索性能,因此除非确实需要,否则不建议修改默认值。 你也可以通过多次调用导入 API(可以并行发送)来实现客户端批处理。

注意:较大的批量导入会消耗更多的临时内存。

# 处理脏数据

dirty_values 参数决定了当某个字段的索引数据类型与之前推断的类型或集合模式中预定义的类型不匹配时,Typesense 应该采取的措施。

该参数可以随任何文档写入 API 端点一起发送,适用于单文档和多文档操作。

行为
coerce_or_reject 尝试将字段值强制转换为先前推断的类型。如果强制转换失败,则直接拒绝写入并返回错误信息。
coerce_or_drop 尝试将字段值强制转换为先前推断的类型。如果强制转换失败,则丢弃该特定字段并索引文档的其余部分。
drop 直接丢弃该特定字段并索引文档的其余部分。
reject 直接拒绝整个文档。

默认行为

如果模式中定义了通配符 (.*) 字段 模式中包含任何带有正则表达式的字段名(例如名为 .*_name 的字段),则默认行为是 coerce_or_reject。否则,默认行为是 reject(这确保了与旧版 Typesense 的向后兼容性)。

# 索引包含脏数据的文档

现在让我们尝试索引一个 title 字段包含整数的文档。假设该字段之前被推断为 string 类型。这里我们将使用 coerce_or_reject 处理行为:

同样地,我们也可以在更新文档upsert单条文档批量导入文档操作中使用 dirty_values 参数。

# 将所有值索引为字符串

Typesense 提供了一种便捷方式,通过使用 string* 字段类型将所有字段存储为字符串。

将类型定义为 string* 允许 Typesense 同时接受单值和多值/数组值。

假设我们需要从多个设备摄取数据,但希望将它们存储为字符串,因为不同设备可能对相同字段名使用不同的数据类型(例如,一个设备可能将 record_id 作为整数发送,而另一个设备可能将 record_id 作为字符串发送)。

为此,我们可以定义如下模式:

{
  "name": "device_data",
  "fields": [
    {"name": ".*", "type": "string*" }
  ]
}

现在,当数据以 dirty_values: "coerce_or_reject" 模式索引时,Typesense 会自动将任何单值/多值数据转换为相应的字符串表示形式。

您可以在下方看到它们将如何被转换:

# 导入 JSONL 文件

你可以导入 JSONL 文件,也可以直接将 Typesense 导出操作 的输出作为导入内容,通过 导入端点 进行导入,因为两者都使用 JSONL 格式。

以下是一个示例文件:

你可以像这样导入上面的 documents.jsonl 文件。