支持的版本:当前 (16) / 15 / 14 / 13 / 12
开发版本:devel
不支持的版本:11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2

70.3. 可扩展性 #

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

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

对于 GIN,操作符类必须提供两种方法

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

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

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

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

searchMode 是一个输出参数,它允许 extractQuery 指定有关如何执行搜索的详细信息。如果 *searchMode 设置为 GIN_SEARCH_MODE_DEFAULT(这是在调用之前对其进行初始化的值),则只考虑与至少一个返回的键匹配的项作为候选匹配项。如果 *searchMode 设置为 GIN_SEARCH_MODE_INCLUDE_EMPTY,则除了包含至少一个匹配键的项之外,还将不包含任何键的项视为候选匹配项。(例如,此模式对于实现 is-subset-of 运算符非常有用。)如果 *searchMode 设置为 GIN_SEARCH_MODE_ALL,则索引中的所有非 null 项都将被视为候选匹配项,无论它们是否与任何返回的键匹配。(此模式比其他两个选择要慢得多,因为它需要扫描整个索引,但正确实现特殊情况可能是必要的。在大多数情况下需要此模式的运算符可能不适合 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 数据,并且 extractQuery 之前返回的 queryKeys[]nullFlags[] 数组也是如此。 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_FALSE,无论它是否包含 GIN_MAYBE 键。如果结果取决于 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 的索引数据类型,即使实际类型可能根据操作符而有所不同。

提交更正

如果您在文档中看到任何不正确的内容,与您对特定功能的体验不符或需要进一步澄清,请使用 此表单 报告文档问题。