Redrock Postgres 搜索 英文
版本: 9.3 / 9.4 / 9.5 / 9.6 / 10 / 11 / 12 / 13 / 14 / 15 / 16

70.3. 可扩展性 #

GIN 接口具有很高的抽象级别,要求访问方法实现者仅实现所访问数据类型的语义。 GIN 层本身负责并发、日志记录和搜索树结构。

要让 GIN 访问方法工作,只需实现几个用户定义的方法,这些方法定义了树中键的行为以及键、索引项和可索引查询之间的关系。简而言之,GIN 将可扩展性与通用性、代码重用和清晰的界面结合在一起。

对于 GIN 的运算符类,必须提供两种方法

Datum *extractValue(Datum itemValue, int32 *nkeys, bool **nullFlags)

给定要编制索引的项,返回已分配的键数组。返回的键数必须存储到 *nkeys 中。如果任何键可以为空,还要分配一个 *nkeys bool 字段的数组,将其地址存储在 *nullFlags 中,并根据需要设置这些空标志。如果所有键都不为空,则可以将 *nullFlags 保留为 NULL(其初始值)。如果该项不包含任何键,则返回值可以为 NULL

Datum *extractQuery(Datum query, int32 *nkeys, StrategyNumber n, bool **pmatch, Pointer **extra_data, bool **nullFlags, int32 *searchMode)

给定要查询的值,返回已分配的键数组;也就是说,query 是可索引运算符右侧的值,其左侧是索引列。n 是运算符类中运算符的策略编号(请参阅 第 38.16.2 节)。通常,extractQuery 需要查阅 n 以确定 query 的数据类型以及它应使用的方法来提取键值。返回的键数必须存储到 *nkeys 中。如果任何键可以为空,还要分配一个 *nkeys bool 字段的数组,将其地址存储在 *nullFlags 中,并根据需要设置这些空标志。如果所有键都不为空,则可以将 *nullFlags 保留为 NULL(其初始值)。如果 query 不包含任何键,则返回值可以为 NULL

searchMode 是一个输出参数,允许 extractQuery 指定有关如何执行搜索的详细信息。如果 *searchMode 设置为 GIN_SEARCH_MODE_DEFAULT(这是调用前初始化的值),则仅将匹配至少一个返回键的项视为候选匹配项。如果 *searchMode 设置为 GIN_SEARCH_MODE_INCLUDE_EMPTY,则除了包含至少一个匹配键的项之外,还将不包含任何键的项视为候选匹配项。(例如,此模式对于实现子集运算符非常有用。)如果 *searchMode 设置为 GIN_SEARCH_MODE_ALL,则索引中的所有非空项都将视为候选匹配项,无论它们是否匹配任何返回的键。(此模式比其他两个选项慢得多,因为它需要扫描整个索引,但可能需要正确实现特殊情况。在大多数情况下需要此模式的运算符可能不适合 GIN 运算符类。)用于设置此模式的符号在 access/gin.h 中定义。

pmatch 是支持部分匹配时使用的输出参数。要使用它,extractQuery 必须分配一个包含 *nkeys bool 的数组,并将它的地址存储在 *pmatch 中。如果相应的键需要部分匹配,则应将数组的每个元素设置为 true,否则设置为 false。如果 *pmatch 设置为 NULL,则 GIN 假设不需要部分匹配。该变量在调用前初始化为 NULL,因此不支持部分匹配的运算符类可以忽略此参数。

extra_data 是一个输出参数,允许 extractQuery 将附加数据传递给 consistentcomparePartial 方法。要使用它,extractQuery 必须分配一个包含 *nkeys 指针的数组,并将它的地址存储在 *extra_data 中,然后将它想要的内容存储到各个指针中。该变量在调用前初始化为 NULL,因此不需要附加数据的运算符类可以忽略此参数。如果设置了 *extra_data,则整个数组将传递给 consistent 方法,并将适当的元素传递给 comparePartial 方法。

运算符类还必须提供一个函数来检查索引项是否与查询匹配。它有两种类型,布尔 consistent 函数和三元 triConsistent 函数。triConsistent 涵盖了这两个函数的功能,因此仅提供 triConsistent 就足够了。但是,如果布尔变量的计算成本明显更低,则提供两者是有利的。如果仅提供了布尔变量,则在获取所有键之前依赖于否定索引项的一些优化将被禁用。

bool consistent(bool check[], StrategyNumber n, Datum query, int32 nkeys, Pointer extra_data[], bool *recheck, Datum queryKeys[], bool nullFlags[])

如果一个索引项满足策略编号为 n 的查询运算符(如果返回重新检查指示,则可能满足),则返回 true。此函数无权直接访问索引项的值,因为 GIN 不会显式存储项。相反,可用的信息是关于从查询中提取的哪些键值出现在给定的索引项中。check 数组的长度为 nkeys,它与先前由 extractQuery 为此 query 数据返回的键数相同。如果索引项包含相应的查询键,则 check 数组的每个元素都为 true,即,如果 (check[i] == true),则 extractQuery 结果数组的第 i 个键存在于索引项中。如果 consistent 方法需要查阅,则会传入原始 query 数据,queryKeys[]nullFlags[] 数组也是如此,它们先前由 extractQuery 返回。extra_data 是由 extractQuery 返回的额外数据数组,如果没有,则为 NULL

extractQueryqueryKeys[] 中返回 null 键时,如果索引项包含 null 键,则相应的 check[] 元素为 true;也就是说,check[] 的语义类似于 IS NOT DISTINCT FROM。如果 consistent 函数需要区分常规值匹配和 null 匹配,则它可以检查相应的 nullFlags[] 元素。

如果成功,则如果需要根据查询运算符重新检查堆元组,则应将 *recheck 设置为 true,如果索引测试是精确的,则应将其设置为 false。也就是说,false 返回值保证堆元组与查询不匹配;将 *recheck 设置为 false 的 true 返回值保证堆元组与查询匹配;将 *recheck 设置为 true 的 true 返回值意味着堆元组可能与查询匹配,因此需要通过直接针对原始索引项评估查询运算符来获取并重新检查它。

GinTernaryValue triConsistent(GinTernaryValue check[], StrategyNumber n, Datum query, int32 nkeys, Pointer extra_data[], Datum queryKeys[], bool nullFlags[])

triConsistent 类似于 consistent,但 check 向量中的布尔值不同,每个键有三个可能的值:GIN_TRUEGIN_FALSEGIN_MAYBEGIN_FALSEGIN_TRUE 的含义与常规布尔值相同,而 GIN_MAYBE 表示不知道该键是否存在。当存在 GIN_MAYBE 值时,只有在索引项是否包含相应的查询键时,该函数才应返回 GIN_TRUE。同样,只有当该项肯定不匹配时,无论它是否包含 GIN_MAYBE 键,该函数才必须返回 GIN_FALSE。如果结果取决于 GIN_MAYBE 项,即无法根据已知的查询键确认或反驳匹配,则该函数必须返回 GIN_MAYBE

check 向量中没有 GIN_MAYBE 值时,GIN_MAYBE 返回值等效于在布尔 consistent 函数中设置 recheck 标志。

此外,GIN 必须有一种方法来对存储在索引中的键值进行排序。运算符类可以通过指定比较方法来定义排序顺序

int compare(Datum a, Datum b)

比较两个键(不是已编入索引的项!)并返回小于零、零或大于零的整数,表示第一个键小于、等于或大于第二个键。空键永远不会传递给此函数。

或者,如果运算符类不提供 compare 方法,GIN 将查找索引键数据类型的默认 btree 运算符类,并使用其比较函数。建议在仅针对一种数据类型的 GIN 运算符类中指定比较函数,因为查找 btree 运算符类需要花费几个周期。但是,多态 GIN 运算符类(例如 array_ops)通常无法指定单个比较函数。

用于 GIN 的运算符类可以选择提供以下方法

int comparePartial(Datum partial_key, Datum key, StrategyNumber n, Pointer extra_data)

将部分匹配查询键与索引键进行比较。返回一个整数,其符号表示结果:小于零表示索引键与查询不匹配,但索引扫描应继续;零表示索引键与查询匹配;大于零表示索引扫描应停止,因为不可能再有更多匹配项。提供了生成部分匹配查询的运算符的策略编号 n,以防需要其语义来确定何时结束扫描。此外,extra_dataextractQuery 生成的额外数据数组的相应元素,如果没有,则为 NULL。空键永远不会传递给此函数。

void options(local_relopts *relopts)

定义一组用户可见参数,用于控制运算符类行为。

options 函数传递给 local_relopts 结构的指针,该指针需要填充一组运算符类特定选项。可以使用 PG_HAS_OPCLASS_OPTIONS()PG_GET_OPCLASS_OPTIONS() 宏从其他支持函数访问这些选项。

由于索引值的关键提取和 GIN 中键的表示是灵活的,它们可能依赖于用户指定的参数。

为了支持 部分匹配 查询,运算符类必须提供 comparePartial 方法,并且其 extractQuery 方法必须在遇到部分匹配查询时设置 pmatch 参数。有关详细信息,请参见 第 70.4.2 节

上述各种 Datum 值的实际数据类型因运算符类而异。传递给 extractValue 的项值始终为运算符类的输入类型,并且所有键值都必须为类的 STORAGE 类型。传递给 extractQueryconsistenttriConsistentquery 参数的类型是策略编号标识的类成员运算符的右手输入类型。只要可以从中提取正确类型的键值,它不必与索引类型相同。但是,建议这些三个支持函数的 SQL 声明对 query 参数使用 opclass 的索引数据类型,即使实际类型可能根据运算符而有所不同。