索引限制和解决方法
在本文中,我们将讨论索引提供程序及其存在的限制和变通方法。
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 索引提供程序及其对原生索引的支持情况
| 索引提供程序 | 原生索引支持的值类型 |
|---|---|
|
所有类型均为原生支持 |
|
单属性字符串使用 Lucene,其余使用原生支持 |
键大小限制
native-btree-1.0 索引提供程序的键大小限制为 8167 字节。此限制的表现形式取决于键包含的是单个字符串、单个数组还是多个值(即键是否属于复合索引)。
如果事务中一个或多个更改达到了键大小限制,则该事务将在提交任何更改之前失败。如果在索引填充过程中达到限制,则生成的索引将处于失败状态,因此无法用于任何查询。
请参阅下文了解如何计算原生索引的键大小。
如果键不符合此限制,最合适的方法通常是使用全文索引。如果不是这种情况,lucene+native-3.0 的键大小限制为 32766 字节。
Contains 和 Ends With 查询
native-btree-1.0 索引提供程序对 ENDS WITH 和 CONTAINS 查询的支持有限。这些查询无法像使用 STARTS WITH、= 和 <> 的查询那样进行优化搜索。相反,索引结果将通过索引扫描流进行过滤。
对于单属性字符串,可以使用 lucene+native-3.0 代替,它完全支持 ENDS WITH 和 CONTAINS。
要创建与默认提供程序不同的索引,最简单的方法是使用 db.createIndex、db.createUniquePropertyConstraint 或 db.createNodeKey 过程,您可以为这些过程提供索引提供程序名称。另一个选项是使用 dbms.index.default_schema_provider 配置默认索引提供程序。请注意,此配置选项需要重启才能生效。
键大小计算
本节介绍如何计算原生索引的键大小。
如键大小章节所述,使用 native-btree-1.0 索引提供程序时,键大小存在限制。本附录详细介绍了如何计算这些大小。
元素大小计算
了解如何计算单个值的大小对于计算结果键的总大小很有帮助。在某些情况下,条目大小会根据该条目是否在数组中而有所不同。
| 类型 | 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 |
|
36 |
32 |
|
28 |
24 |
|
36 |
32 |
|
|
|
|
† |
不支持嵌套数组 |
* elementSizeifSingle 表示单个条目时的元素大小。
** elementSizeifInArray 表示作为数组一部分时的元素大小。
*** utf8StringSize 是以 UTF8 编码时的 String 大小(以字节为单位)。
† elementSizeArray 是数组元素的大小,使用以下公式计算
-
如果数组的数据类型是数值数据类型
elementSizeArray = 4 + ( 数组长度 * elementSizeifInArray ) -
如果数组的数据类型是几何数据类型
elementSizeArray = 6 + ( 数组长度 * elementSizeifInArray ) -
如果数组的数据类型是非数值类型
elementSizeArray = 3 + ( 数组长度 * elementSizeifInArray )
|
UTF8 字符串编码
值得注意的是,字母、数字和某些符号等常见字符每个占用一个字节。非拉丁字符每个字符可能占用超过一个字节。因此,例如,包含 100 个字符或更少的字符串,如果包含多字节字符,其长度可能会超过 100 字节。 更具体地说,字符串的有效字节长度是指以 UTF8 编码时的长度。 |
考虑字符串 His name was Måns Lööv。
该字符串有 19 个字符,每个字符占用 1 字节。此外,有 3 个字符每个占用 2 字节,总计增加 6 字节。因此,以 UTF8 编码时的 String 大小(utf8StringSize)为 25 字节。
如果此字符串是原生索引的一部分,我们得到
elementSize = 2 + utf8StringSize = 2 + 25 = 27 字节
考虑数组 [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 )(针对非数值类型)。
这些计算结果如下表所示
| 数据类型 | maxArrayLength(最大数组长度) |
|---|---|
|
8163 |
|
4081 |
|
2040 |
|
1020 |
|
2040 |
|
1020 |
|
8164 |
|
参见 最大数组长度,字符串示例 |
|
1020 |
|
680 |
|
1020 |
|
510 |
|
680 |
|
291 |
|
291 |
|
340 |
|
255 |
|
340 |
|
255 |
请注意,在大多数情况下,Cypher 处理数字时会使用 Long 或 Double。
String 类型的属性是一个特例,因为它们的大小是动态的。下表根据某些字符串大小显示了数组中允许的最大数组元素数量
| 字符串大小 | 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。
考虑一个包含五个字符串的复合索引,每个字符串最多可占用 500 字节。
使用上面的等式,我们得到
sum( elementSize ) = 5 * ( 3 + 500 ) = 2515 < 8167
我们的复合索引完全在边界内。
考虑一个包含 10 个 Float 类型数组的复合索引,每个数组长度为 250。
首先我们计算每个数组元素的大小
elementSizeArray = 4 + ( 数组长度 * elementSizeifInArray ) = 4 + ( 250 * 4 ) = 1004
然后我们计算复合索引的大小
sum( elementSizeArray ) = 10 * 1004 = 10040 > 8167
此索引键将超出原生索引的键大小限制。
此页面有帮助吗?