数据类型
了解 Meilisearch 如何处理不同的数据类型:字符串、数值、布尔值、数组和对象。
本文解释了 Meilisearch 如何处理数据集中不同类型的数据。
此处描述的行为仅涉及 Meilisearch 的内部处理流程,有助于理解分词器的工作原理。对于与 Meilisearch 内部机制无关的大部分实际用途,文档字段保持不变。
字符串(String)
字符串是 Meilisearch 中索引数据的主要类型。它用于创建可搜索的内容。字符串的处理流程如下所述。
字符串分词是将字符串拆分为单独术语列表的过程,这些术语被称为词元(tokens)。
字符串被传递给分词器,然后被分解为独立的字符串词元。一个词元就是一个单词。
分词过程
分词依靠两个主要流程来识别单词并将其分离为词元:分隔符和字典。
分隔符
分隔符是用于标识词语边界的字符。例如,在使用拉丁字母的语言中,词语通常由空白字符分隔。而在日语中,词语边界更多通过其他方式表示,比如在词尾添加助词如 に 和 で。
Meilisearch 中有两种分隔符:软分隔符和硬分隔符。硬分隔符表示重要的上下文切换,例如新句子或段落的开始。软分隔符仅用于分隔词语,不表示主题的重大变化。
以下列举了一些拉丁字母语言中最常见的分隔符:
- 软分隔符(距离值:1):空白字符、引号、
'-' | '_' | '\'' | ':' | '/' | '\\' | '@' | '"' | '+' | '~' | '=' | '^' | '*' | '#' - 硬分隔符(距离值:8):
'.' | ';' | ',' | '!' | '?' | '(' | ')' | '[' | ']' | '{' | '}'| '|'
如需了解更多分隔符(包括西里尔字母和泰语等其他书写系统中使用的分隔符),请查阅完整列表。
词典
在分词过程中,词典是将一组字符视为单个术语的列表。词典对于日语等语言的词语识别特别有用,因为这些语言的词语并不总是由分隔符标记。
Meilisearch 为其官方支持的语言提供了多个通用词典。当处理包含大量领域特定术语的文档(如法律文件或学术论文)时,提供自定义词典可能会提高搜索结果的相关性。
距离
距离在判断文档相关性时起着关键作用,因为其中一个排名规则是邻近度规则。邻近度规则会根据匹配查询词之间的距离从小到大对结果进行排序。因此,两个被软空格分隔的词语距离更近,被认为更相关于两个被硬空格分隔的词语。
在分词处理完成后,每个词语都会被索引并存储到对应索引的全局字典中。
示例
为了演示字符串如何通过空格分割,假设你有以下输入字符串:
在上面的例子中,Bruce 和 Willis 之间的距离为 1。Vin 和 Diesel 之间的距离同样为 1。然而,Willis 和 Vin 之间的距离为 8。同样的计算适用于 Bruce 和 Diesel(10)、Bruce 和 Vin(9)以及 Willis 和 Diesel(9)。
再看另一个例子。给定两个文档:
当查询 Bruce Willis 时,文档 002 会首先返回,文档 001 会排在第二位。这是因为在文档 002 中,Bruce 和 Willis 之间的邻近距离为 2,而在文档 001 中,由于点号 . 是硬空格,Bruce 和 Willis 之间的距离为 8。
数值类型
数值类型(integer、float)会被转换为人类可读的十进制数字字符串表示形式。数值类型在被转换为字符串后可以被搜索。
您可以添加自定义排序规则,为文档中包含数值的特定属性创建升序或降序排序规则。
您还可以创建筛选器。关系运算符 >、>=、<、<= 和 TO 仅适用于数值类型。
布尔类型
布尔值(true 或 false)会被接收并转换为小写的人类可读文本(true 和 false)。布尔值在被转换为字符串后可以被搜索。
null 类型
null 类型可以被推送到 Meilisearch 中,但它不会被纳入索引考虑范围。
数组类型
数组是一个有序的值列表。这些值可以是任何类型:数字、字符串、布尔值、对象,甚至是其他数组。
Meilisearch 会将数组展平并将其连接成字符串。非字符串值会按照本文前面章节所述的方式进行转换。
示例
以下输入:
将被处理为所有元素都处于同一层级:
当上述数组被展平后,它将按照字符串示例中描述的方式进行解析。
对象类型
当文档字段包含对象时,Meilisearch 会将其扁平化处理,将对象的键和值提升到文档的根层级。
需要注意的是,这里展示的扁平化对象是内部处理过程的中间快照。实际搜索时,返回的文档会保持原始结构。
以下示例中,patient_name 键包含一个对象:
在索引过程中,Meilisearch 使用点表示法消除嵌套字段:
通过点表示法,无论嵌套层级多深,扁平化嵌套对象时都不会丢失任何信息。
假设上述示例文档还包含一个额外的 address 对象,其中包含家庭和工作地址(它们本身也是对象)。扁平化处理后,文档将如下所示:
Meilisearch 的内部扁平化过程还会处理对象数组中的嵌套。这种情况下,值会按键分组。考虑以下文档:
扁平化处理后,文档将变为:
当文档中的所有对象都被扁平化后,Meilisearch 会继续按照前面章节描述的方式处理文档。例如,数组会被进一步扁平化,数字和布尔值会被转换为字符串。
嵌套文档查询与子文档
Meilisearch 没有子文档的概念,也无法执行嵌套文档查询。在前面的例子中,当扁平化处理 appointments 数组时,预约日期与医生之间的关联关系丢失了:
这可能导致搜索时出现意外行为。以下数据集展示了两位患者及其各自的预约记录:
以下查询会返回患者 0 和 1:
Meilisearch 无法仅返回在 2022-01-01 与 Jester Lavorre 有预约的患者。相反,它会返回与 Jester Lavorre 有过预约的患者,以及在 2022-01-01 有过预约的患者。
解决此限制的最佳方法是重新格式化数据。上面的例子可以通过在 appointmentsMerged 字段中合并预约数据来修复,从而保持预约与医生之间的关联关系:
可能的分词问题
即使分词行为完全符合预期,在某些情况下仍可能导致不符合直觉的结果,例如:
对于上述两个字符串,句点 . 将被视为硬空格。
10,3 会被拆分成两个字符串——10 和 3——而不是被处理为数字类型。