Skip to main content
Version: nightly 🚧

文档

在 kumosearch 中,您索引的每条记录称为 文档

索引文档

要在给定索引表中建立索引的文档必须符合 索引表 的 schema

如果文档包含 string 类型的 id 字段,kumosearch 将使用该字段作为文档的标识符。否则,kumosearch 将为文档分配一个自动生成的标识符。由于 id 字短是一个特殊字段,它不需在索引表 schema 中定义。

注意

id 不应包含空格或其他需要 url 编码 的字符。

索引单个文档

如果需要为文档建立索引以响应用户操作,可以使用单文档创建端点。

如果需要一次性索引多个文档,建议使用 批量导入文档 端点,该端点针对批量导入进行了优化。例如:如果有 100 个文档,使用导入端点一次性索引它们的性能会优于逐个索引。

让我们看看如何将新文档添加到索引表中。

let document = {
'id': '124',
'company_name': 'Stark Industries',
'num_employees': 5215,
'country': 'USA'
}

client.collections('companies').documents().create(document)

更新插入单个文档

如果文档已存在,可以替换具有相同 id 的文档,或者如果不存在具有相同 id 的文档,则创建一个新文档。

如果需要一次性更新插入多个文档,建议使用带有 action=upsert批量导入文档 端点,该端点针对批量更新插入进行了优化。例如:如果有 100 个文档,使用导入端点一次性更新插入的性能优于逐个更新插入。

let document = {
'id': '124',
'company_name': 'Stark Industries',
'num_employees': 5215,
'country': 'USA'
}

client.collections('companies').documents().upsert(document)

响应示例

{
"id": "124",
"company_name": "Stark Industries",
"num_employees": 5215,
"country": "USA"
}

定义

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

索引多个文档

可以使用导入 API 批量索引多个文档。当索引多个文档时,此端点的性能要远高于多次调用 单个文档创建端点

要导入的文档需要格式化为换行符分隔的 JSON 字符串,也称为 JSONLines 格式。这本质上是每行一个 JSON 对象,文档之间没有逗号。例如,以下是一组以 JSONL 格式表示的 3 个文档。

{"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 格式。

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

操作 (create, upsert, update & emplace)

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

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

让我们看看如何使用 create 创建一些文档。

let documents = [{
'id': '124',
'company_name': 'Stark Industries',
'num_employees': 5215,
'country': 'USA'
}]

// IMPORTANT: Be sure to increase connectionTimeoutSeconds to at least 5 minutes or more for imports,
// when instantiating the client

client.collections('companies').documents().import(documents, {action: 'create'})

定义

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

响应示例

{"success": true}
{"success": true}

响应的每一行指示请求正文中每个文档的结果(以相同的顺序)。如果单个文档导入失败,不会影响其他文档。

如果出现故障,响应行将包含相应的错误消息以及实际的文档内容。例如,第二个文档导入失败,响应如下:

{"success": true}
{"success": false, "error": "Bad JSON.", "document": "[bad doc]"}
NOTE

无论单个文档的导入结果如何,导入端点始终会返回 HTTP 200 OK 状态码。这是因为在部分情况下,可能有些文档导入成功,而另一些文档导入失败。为了避免在这些部分成功的场景中返回 HTTP 错误码,我们统一返回 HTTP 200 状态码。

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

返回导入文档的 id

如果您希望导入响应中返回所导入文档的 id,可以使用 return_id 参数。

# Makes the import response return the `id` field of imported documents in the response
curl -H "X-KUMOSEARCH-API-KEY: ${KUMOSEARCH_API_KEY}" -X POST --data-binary @documents.jsonl \
'http://localhost:8868/collections/companies/documents/import?return_id=true'
{"success": true, "id": "0"}
{"success": true, "id": "1"}
...

同样,使用 return_doc 参数将返回整个文档作为响应。

配置批量大小

默认情况下,kumosearch 一次将 40 个文档导入。每导入 40 个文档后,kumosearch 就会为搜索请求队列提供服务,然后再切换回导入。要增加此值,请使用 batch_size 参数。

请注意,此参数控制在单个导入 API 调用中发送的文档的服务器端批处理。增加此值可能会影响搜索性能,因此建议您不要更改默认值,除非确实需要。您还可以通过多个导入 API 调用(可能并行)发送文档来进行客户端批处理。

const documentsInJsonl = await fs.readFile("documents.jsonl");
client.collections('companies').documents().import(documentsInJsonl, {batch_size: 100});

注意:较大的批量大小将在导入过程中消耗较大的瞬时内存。

处理脏数据

dirty_values 参数决定了当字段的类型与先前自动推断的类型或索引表schema中的预定义类型不匹配时的处理方式。

此参数可以与任意文档写入 API 端点一起发送,适用于单个文档和多个文档。

操作
coerce_or_reject尝试将字段的值强制转换为先前推断的类型。如果强制失败,则直接拒绝写入并显示错误消息。
coerce_or_drop尝试将字段的值强制转换为先前推断的类型。如果强制失败,则删除特定字段并为文档的其余部分建立索引。
drop删除特定字段并对文档的其余部分建立索引。
reject彻底拒绝该文档。

默认行为

如果 schema 中定义了通配符 (.*) 字段或者schema 中包含任何带有正则表达式名称的字段(例如名为 .*_name 的字段),默认行为是 coerce_or_reject。否则,默认行为是 reject

dirty 数据索引文档

例如,我们可以使用 coerce_or_reject 行为将包含整数的 title 字段索引到之前被推断为 string 类型的文档中:

let document = {
'title': 1984,
'points': 100
}

client.collections('titles').documents().create(document, {
"dirty_values": "coerce_or_reject"
})

同样,我们可以将 dirty_values 参数用于 更新插入导入 操作。

将所有值索引为字符串

kumosearch 提供了一种通过使用 string* 字段类型将所有字段存储为字符串的便捷方法。将类型定义为 string* 允许 kumosearch 接受单值和多值/数组值。

例如,我们想要从多个设备获取数据,但希望将它们存储为字符串,这是由于每个设备都可以对同一字段名称使用不同的数据类型(例如,一个设备可以发送 record_id 作为整数,而另一个设备可以发送 record_id 作为字符串)。

为此,我们可以定义一个 schema,如下所示:

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

现在,kumosearch 会自动将任何单值/多值数据转换为相应的字符串。并在使用 dirty_values:"coerce_or_reject" 模式对数据进行索引时自动处理。

您可以在下面看到它们是如何转换的:

{
"record_id": 141414,
"values": [76.24, 88, 100.67]
}

导入 JSONL 文件

您可以导入 JSONL 文件,也可以将 kumosearch 导出操作 的输出直接导入到 导入端点,因为两者都使用 JSONL。

这是一个示例文件:

{"id": "1", "company_name": "Stark Industries", "num_employees": 5215, "country": "USA"}
{"id": "2", "company_name": "Orbit Inc.", "num_employees": 256, "country": "UK"}

您可以按照上述说明导入 documents.jsonl 文件。

const documentsInJsonl = await fs.readFile("documents.jsonl");
client.collections('companies').documents().import(documentsInJsonl, {action: 'create'});

导入 JSON 文件

如果您有 JSON 格式的文件,可以使用 jq 将其转换为 JSONL 格式:

jq -c '.[]' documents.json > documents.jsonl

获得 JSONL 文件后,您可以按照上述说明 导入文件。

导入 CSV 文件

如果您有带有列标题的 CSV 文件,可以使用 mlr 将其转换为 JSONL 格式:

mlr --icsv --ojsonl cat documents.csv > documents.jsonl

获得 JSONL 文件后,您可以按照上述说明 导入文件。

导入其他文件类型

kumosearch 主要存储 JSON 文档并针对快速搜索进行了优化。如果您可以从其他文件类型中提取数据并将其转换为结构化 JSON,则可以将其导入 kumosearch 进行搜索。

例如,您可以使用以下库将 DOCX 文件转换为 JSONApache Tika 是一个从 PDF、PPT、XLS 和 1000 多种不同文件格式中提取文本和元数据的库。

提取 JSON 后,您可以在 kumosearch 中对它们进行索引。

检索文档

使用 id 从索引表中获取单个文档。

client.collections('companies').documents('124').retrieve()

响应示例

{
"id": "124",
"company_name": "Stark Industries",
"num_employees": 5215,
"country": "USA"
}

定义

GET ${KUMOSEARCH_HOST}/collections/:collection/documents/:id

更新文档

kumosearch 允许您更新单个文档、多个文档或通过 filter_by 查询匹配的文档。

更新单个文档

我们可以使用 id 从索引表中更新单个文档。更新可以是部分的,如下所示:

let document = {
'company_name': 'Stark Industries',
'num_employees': 5500
}

client.collections('companies').documents('124').update(document)

响应示例

{
"company_name": "Stark Industries",
"num_employees": 5500
}

定义

PATCH ${KUMOSEARCH_HOST}/collections/:collection/documents/:id

更新多个文档

要更新多个文档,请使用带有 action=updateaction=upsertaction=emplace的批量导入端点。

通过查询更新

要更新与给定 filter_by 查询匹配的所有文档:

let document = {
'tag': 'large'
}

client.collections('companies').documents().update(document, {"filter_by": "num_employees:>1000"})

响应示例

{
"tag": "large"
}

定义

PATCH ${KUMOSEARCH_HOST}/collections/:collection/documents

删除文档

删除单个文档

使用 id 从索引表中删除单个文档。

client.collections('companies').documents('124').delete()

注意: 当给定 id 的文档不存在时,将返回错误。若要忽略此错误并将删除操作视为成功,可以发送 ignore_not_found=true 参数。

响应示例

{
"id": "124",
"company_name": "Stark Industries",
"num_employees": 5215,
"country": "USA"
}

定义

DELETE ${KUMOSEARCH_HOST}/collections/:collection/documents/:id

通过查询删除

您还可以删除一组匹配特定 filter_by 条件的文档:

client.collections('companies').documents().delete({'filter_by': 'num_employees:>100'})

使用 batch_size 参数控制一次应删除的文档数量。较大的值将加快删除速度,但会影响服务器上运行的其他操作的性能。

响应示例

{
"num_deleted": 24
}

定义

DELETE ${KUMOSEARCH_HOST}/collections/:collection/documents?filter_by=X&batch_size=N

tip

要按ID删除多个文档,可以使用 filter_by=id: [id1, id2, id3]

要删除索引表中的所有文档,可以使用与索引表中的所有文档匹配的过滤器。 例如,如果您的文档中有一个名为 popularityint32 字段,可以使用 filter_by=popularity:>0 删除所有文档。 或者,如果您的文档中有一个名为 in_stockbool 字段,可以使用 filter_by=in_stock:[true,false] 删除所有文档。

导出文档

以 JSONL 格式导出索引表中的文档。

client.collections('companies').documents().export()

响应示例

{"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"}

导出时,可以使用以下参数来控制导出的结果:

参数描述
filter_by将导出限制为满足 filter by 查询 的文档。
include_fields导出文档中应出现的字段列表。
exclude_fields导出文档中不应出现的字段列表。

定义

GET ${KUMOSEARCH_HOST}/collections/:collection/documents/export