知识库

索引限制和解决方法

在本文中,我们将讨论索引提供程序及其存在的限制和变通方法。

Neo4j 中有两种索引类型:btree 和全文索引(full-text)。本文针对 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 字节。

Contains 和 Ends With 查询

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

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

要创建与默认提供程序不同的索引,最简单的方法是使用 db.createIndexdb.createUniquePropertyConstraintdb.createNodeKey 过程,您可以为这些过程提供索引提供程序名称。另一个选项是使用 dbms.index.default_schema_provider 配置默认索引提供程序。请注意,此配置选项需要重启才能生效。

键大小计算

本节介绍如何计算原生索引的键大小。

如键大小章节所述,使用 native-btree-1.0 索引提供程序时,键大小存在限制。本附录详细介绍了如何计算这些大小。

元素大小计算

了解如何计算单个值的大小对于计算结果键的总大小很有帮助。在某些情况下,条目大小会根据该条目是否在数组中而有所不同。

表 1. 元素大小
类型 elementSizeifSingle(单个元素大小) * elementSizeifInArray(数组内元素大小) **

Byte(字节)

3

1

Short(短整型)

4

2

Int(整型)

6

4

Long

10

8

浮点数

6

4

双精度浮点数

10

8

布尔值

2

1

Date

9

8

Time

13

12

LocalTime

9

8

DateTime

17

16

LocalDateTime

13

12

Duration

29

28

Period(周期)

29

28

Point (Cartesian)(笛卡尔坐标点)

28

24

Point (Cartesian 3D)(三维笛卡尔坐标点)

36

32

Point (WGS-84)(WGS-84 坐标点)

28

24

Point (WGS-84 3D)(三维 WGS-84 坐标点)

36

32

字符串

3 + utf8StringSize ***

2 + utf8StringSize ***

Array(数组)

不支持嵌套数组

* elementSizeifSingle 表示单个条目时的元素大小。

** elementSizeifInArray 表示作为数组一部分时的元素大小。

*** utf8StringSize 是以 UTF8 编码时的 String 大小(以字节为单位)。

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

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

    elementSizeArray = 4 + ( 数组长度 * elementSizeifInArray )

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

    elementSizeArray = 6 + ( 数组长度 * elementSizeifInArray )

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

    elementSizeArray = 3 + ( 数组长度 * 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 + ( 数组长度 * elementSizeifInArray ) = 4 + ( 20 * 4 ) = 84 字节

非复合索引

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

字符串

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

数组

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

1 + elementSizeArray =< 8167

这里 elementSizeArray 是从 元素大小 计算得出的数值。

通过反向计算,我们可以得出每种数据类型的确切数组长度限制

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

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

这些计算结果如下表所示

表 2. 每个数据类型的最大数组长度
数据类型 maxArrayLength(最大数组长度)

Byte(字节)

8163

Short(短整型)

4081

Int(整型)

2040

Long

1020

浮点数

2040

双精度浮点数

1020

布尔值

8164

字符串

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

Date

1020

Time

680

LocalTime

1020

DateTime

510

LocalDateTime

680

Duration

291

Period(周期)

291

Point (Cartesian)(笛卡尔坐标点)

340

Point (Cartesian 3D)(三维笛卡尔坐标点)

255

Point (WGS-84)(WGS-84 坐标点)

340

Point (WGS-84 3D)(三维 WGS-84 坐标点)

255

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

String 类型的属性是一个特例,因为它们的大小是动态的。下表根据某些字符串大小显示了数组中允许的最大数组元素数量

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

1

2721

10

680

100

80

1000

8

该表可用作参考点。例如:如果我们知道数组中的所有字符串均占用 100 字节或更少,那么长度为 80 或更小的数组肯定符合要求。

复合索引

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

  • 复合索引包含字符串

  • 复合索引包含数组

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

我们将复合索引的目标属性称为 槽(slot)。例如,: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 + ( 数组长度 * elementSizeifInArray ) = 4 + ( 250 * 4 ) = 1004

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

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

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

© . This site is unofficial and not affiliated with Neo4j, Inc.