知识库

索引限制和解决方法

本文讨论索引提供者及其限制和解决方法。

Neo4j 中有两种索引类型:btree 和全文索引。本文针对 btree 索引,在 4.0 之前称为模式索引。这是通过 Cypher 创建索引或索引支持约束时获得的普通索引。

查询
CREATE INDEX "My index" FOR (p:Person) ON (p.name)

所有索引都由索引提供者支持。全文索引由 fulltext-1.0 支持,btree 索引由 native-btree-1.0(默认)或 lucene+native-3.0 支持。

下表列出了可用的 btree 索引提供者及其对原生索引的支持

索引提供者 支持原生索引的值类型

native-btree-1.0

所有类型均为原生

lucene+native-3.0

单属性字符串为 Lucene,其余为原生

键大小限制

native-btree-1.0 索引提供者具有 8167 字节的键大小限制。根据键是否保存单个字符串、单个数组或多个值(即键是否在复合索引中),此限制以不同的方式表现出来。

如果事务达到一个或多个更改的键大小限制,则该事务将在提交任何更改之前失败。如果在索引填充期间达到限制,则生成的索引将处于失败状态,因此不可用于任何查询。

有关如何计算原生索引的键大小的详细信息,请参见下文。

如果键不适合此限制,则很可能全文索引更适合用例,如果不是,则 lucene+native-3.0 的键大小限制为 32766 字节。

包含和以…结尾的查询

native-btree-1.0 索引提供者对 ENDS WITHCONTAINS 查询的支持有限。这些查询无法像使用 STARTS WITH=<> 的查询那样进行优化搜索。相反,索引结果将是带有过滤的索引扫描的流。

对于单属性字符串,可以使用 lucene+native-3.0 代替,它完全支持 ENDS WITHCONSTAINS

要使用与默认值不同的提供者创建索引,最简单的方法是使用 db.createIndexdb.createUniquePropertyConstraintdb.createNodeKey 过程,您可以向其中提供索引提供者名称。另一种选择是使用 dbms.index.default_schema_provider 配置默认索引提供者。请注意,此配置选项需要重新启动才能生效。

键大小计算

本部分描述了如何计算原生索引的键大小。

如键大小部分所述,在使用 native-btree-1.0 索引提供者时,键大小存在限制。本附录详细描述了如何计算大小。

元素大小计算

在计算结果键的总大小时,了解如何计算单个值的大小非常有用。在某些情况下,这些条目大小会因条目是否在数组中而异。

表 1. 元素大小
类型 elementSizeifSingle * elementSizeifInArray **

字节

3

1

短整型

4

2

整型

6

4

长整型

10

8

浮点型

6

4

双精度型

10

8

布尔型

2

1

日期

9

8

时间

13

12

本地时间

9

8

日期时间

17

16

本地日期时间

13

12

持续时间

29

28

周期

29

28

点(笛卡尔坐标系)

28

24

点(笛卡尔坐标系 3D)

36

32

点(WGS-84)

28

24

点(WGS-84 3D)

36

32

字符串

3 + utf8StringSize ***

2 + utf8StringSize ***

数组

不支持嵌套数组

* elementSizeifSingle 表示如果是一个单个条目,则条目的大小。

** elementSizeifInArray 表示如果是一个条目的一部分,则条目的大小。

*** utf8StringSize 是使用 UTF8 编码的String 的字节大小。

elementSizeArray 是数组元素的大小,使用以下公式计算

  • 如果数组的数据类型是数值数据类型

    elementSizeArray = 4 + ( arrayLength * elementSizeifInArray )

  • 如果数组的数据类型是几何数据类型

    elementSizeArray = 6 + ( arrayLength * elementSizeifInArray )

  • 如果数组的数据类型是非数值类型

    elementSizeArray = 3 + ( arrayLength * elementSizeifInArray )

使用 UTF8 编码字符串

值得注意的是,常见的字符(如字母、数字和一些符号)会转换为每个字符一个字节。非拉丁字符可能占用多个字节。因此,例如,如果包含多字节字符,则包含 100 个字符或更少字符的字符串可能大于 100 字节。

更具体地说,字符串的相关字节长度是在使用UTF8 编码时。

示例 1. 计算字符串在索引中使用时的长度

考虑字符串 His name was Måns Lööv

此字符串有 19 个字符,每个字符占用 1 个字节。此外,还有 3 个字符,每个字符占用 2 个字节,总共增加 6 个字节。因此,使用 UTF8 编码的String 的字节大小(即 utf8StringSize)为 25 个字节。

如果此字符串是原生索引的一部分,则我们得到

elementSize = 2 + utf8StringSize = 2 + 25 = 27 个字节

示例 2. 计算数组在索引中使用时的长度

考虑数组 [19, 84, 20, 11, 54, 9, 59, 76, 82, 27, 9, 35, 56, 80, 65, 95, 16, 91, 61, 11]。

此数组有 20 个Int 类型的元素。由于它们在数组中,因此我们需要使用 elementSizeifInArray,对于 Int 来说是 4

应用数值数据类型数组的公式,我们得到

elementSizeArray = 4 + ( arrayLength * elementSizeifInArray ) = 4 + ( 20 * 4 ) = 84 个字节

非复合索引

非复合索引违反大小限制的唯一方法是值是长字符串或大型数组。

字符串

非复合索引中的字符串具有 8164 字节的键大小限制。

数组

非复合索引中的数组使用以下公式

1 + elementSizeArray =< 8167

这里 elementSizeArray 是从元素大小 计算得到的数字。

如果我们倒着数,我们可以得到每种数据类型的精确数组长度限制

  • maxArrayLength = FLOOR( ( 8167 - 4 ) / elementSizeifInArray ) 对于数值类型。

  • maxArrayLength = FLOOR( ( 8167 - 4 ) / elementSizeifInArray ) 对于非数值类型。

这些计算得出了以下表格

表 2. 每种数据类型的最大数组长度
数据类型 maxArrayLength

字节

8163

短整型

4081

整型

2040

长整型

1020

浮点型

2040

双精度型

1020

布尔型

8164

字符串

请参见字符串的最大数组长度示例

日期

1020

时间

680

本地时间

1020

日期时间

510

本地日期时间

680

持续时间

291

周期

291

点(笛卡尔坐标系)

340

点(笛卡尔坐标系 3D)

255

点(WGS-84)

340

点(WGS-84 3D)

255

请注意,在大多数情况下,Cypher 会在处理数字时使用 LongDouble

类型为 String 的属性是一个特殊情况,因为它们是动态大小的。下表显示了数组中数组元素的最大数量,基于特定字符串大小

表 3. 字符串的最大数组长度示例
字符串大小 maxArrayLength

1

2721

10

680

100

80

1000

8

此表格可以用作参考点。例如:如果我们知道数组中的所有字符串都占用 100 字节或更少,则长度为 80 或更低的数组一定会适合。

复合索引

此限制仅在满足以下一个或多个条件时适用

  • 复合索引包含字符串

  • 复合索引包含数组

  • 复合索引针对许多不同的属性(>50 个)

我们称复合索引的目标属性为插槽。例如,对 :Person(firstName, surName, age) 的索引有三个属性,因此有三个插槽。

在索引中,每个插槽都由一个元素填充。为了计算索引的大小,我们必须知道索引中每个元素的大小,即elementSize,如前几部分所述。

可以使用以下等式验证特定复合索引条目是否在范围内

sum( elementSize ) =< 8167

在这里,sum( elementSize ) 是所有复合键元素大小的总和,如 [index-configuration-limitations-element-size-calculations]elementSizeifSingle 所定义。

示例 3. 包含字符串的复合索引的大小

考虑一个包含五个字符串的复合索引,每个字符串最多可以占用 500 字节。

使用上面的公式,我们得到

sum( elementSize ) = 5 * ( 3 + 500 ) = 2515 < 8167

我们的复合索引完全在限制范围内。

示例 4. 包含数组的索引的大小

考虑一个包含 10 个类型为 Float 的数组的复合索引,每个数组的长度为 250。

首先我们计算每个数组元素的大小

elementSizeArray = 4 + ( arrayLength * elementSizeifInArray ) = 4 + ( 250 * 4 ) = 1004

然后我们计算复合索引的大小

sum( elementSizeArray ) = 10 * 1004 = 10040 > 8167

此索引键将超过原生索引的键大小限制。