# 67.3.可扩展性

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

要让GIN访问方法发挥作用,只需实现几个用户定义的方法,这些方法定义树中键的行为以及键、索引项和可索引查询之间的关系。简而言之,GIN结合了可扩展性、通用性、代码重用和干净的接口。

GIN的运算符类必须提供两种方法:

Datum*extractValue(Datum itemValue、int32*nkeys、布尔**nullFlags)

返回给定要索引的项的palloc键数组。返回的密钥数必须存储到*肯基。如果任何键都可以为null,则也可以使用*肯基 布尔字段,将其地址存储在*空旗,并根据需要设置这些空标志。*空旗可以留下无效的(其初始值)如果所有键都非空。返回值可以是无效的如果该项不包含密钥。

数据*提取查询(数据查询,int32*nkeys,StrategyNumber n,布尔**pmatch,指针**extra_数据,布尔**nullFlags,int32*搜索模式)

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

搜索模式是一个输出参数,允许提取查询指定有关如何完成搜索的详细信息。如果*搜索模式被设定为GIN_SEARCH_MODE_DEFAULT(这是它在调用之前初始化的值),只有匹配至少一个返回键的项目才被认为是候选匹配。如果*搜索模式被设定为GIN_SEARCH_MODE_INCLUDE_EMPTY,那么除了包含至少一个匹配键的项目之外,根本不包含键的项目被认为是候选匹配。(例如,此模式对于实现 is-subset-of 运算符很有用。)如果*搜索模式设定为GIN_SEARCH_MODE_ALL,则索引中的所有非空项都被视为候选匹配项,无论它们是否匹配任何返回的键。(这种模式比其他两种选择慢得多,因为它基本上需要扫描整个索引,但可能需要正确实现极端情况。在大多数情况下需要这种模式的运算符可能不是 GIN 的好候选者运算符类。)用于设置此模式的符号定义在访问/gin.h.

匹配是支持部分匹配时使用的输出参数。要使用它,提取查询必须分配一个数组*nkeys 布尔s 并将其地址存储在*匹配.如果对应的键需要部分匹配,则数组的每个元素都应设置为 true,否则为 false。如果*匹配设定为空值然后 GIN 假定不需要部分匹配。变量初始化为空值在调用之前,因此不支持部分匹配的运算符类可以简单地忽略此参数。

额外数据是一个输出参数,允许提取查询将附加数据传递给持续的比较部分方法。要使用它,提取查询必须分配一个数组*nkeys指针并将其地址存储在*额外数据,然后将它想要的任何内容存储到各个指针中。变量初始化为空值在调用之前,因此不需要额外数据的运算符类可以简单地忽略此参数。如果*额外数据设置,整个数组被传递给持续的方法,以及适当的元素比较部分方法。

运算符类还必须提供一个函数来检查索引项是否与查询匹配。它有两种风格,一个布尔值持续的函数和三元三一致功能。三一致涵盖两者的功能,因此提供三一致一个人就足够了。但是,如果布尔变量的计算成本要低得多,那么同时提供两者可能是有利的。如果仅提供布尔变量,则某些依赖于在获取所有键之前反驳索引项的优化将被禁用。

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

如果索引项满足具有策略编号的查询运算符,则返回 truen(或者可能满足它,如果返回重新检查指示)。此函数不能直接访问索引项的值,因为 GIN 没有显式存储项。相反,可用的是关于从查询中提取的哪些键值出现在给定索引项中的知识。这查看数组有长度,这与之前返回的键数相同提取查询为了这询问基准。的每个元素查看如果索引项包含相应的查询键,则数组为真,即如果(检查[一世]== true) 的第 i 个键提取查询结果数组存在于索引项中。原本的询问数据通过的情况下持续的方法需要咨询它,所以也是查询键[]空标志[]先前返回的数组提取查询.额外数据是由返回的额外数据数组提取查询, 或者空值如果没有。

什么时候提取查询返回一个空键查询键[], 相应的查看[]如果索引项包含空键,则元素为真;也就是说,语义查看[].这持续的函数可以检查相应的空标志[]元素是否需要区分常规值匹配和空匹配。

成功时,*重新检查如果需要根据查询运算符重新检查堆元组,则应设置为 true,如果索引测试准确,则应设置为 false。即一个假的返回值保证堆元组不匹配查询;一个真正的返回值*重新检查设置为 false 保证堆元组匹配查询;和一个真正的返回值*重新检查设置为 true 意味着堆元组可能匹配查询,因此需要通过直接针对原始索引项评估查询运算符来获取和重新检查它。

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

三一致类似于持续的, 但不是布尔值查看向量,每个键有三个可能的值:GIN_TRUE,GIN_FALSEGIN_MAYBE.GIN_FALSEGIN_TRUE与常规布尔值具有相同的含义,而GIN_MAYBE意味着该密钥的存在是未知的。什么时候GIN_MAYBE值存在,函数应该只返回GIN_TRUE如果该项目肯定匹配索引项目是否包含相应的查询键。同样,该函数必须返回GIN_FALSE仅当项目肯定不匹配时,无论它是否包含GIN_MAYBE键。如果结果取决于GIN_MAYBE条目,即无法根据已知查询键确认或反驳匹配,该函数必须返回GIN_MAYBE.

当没有GIN_MAYBE中的值查看向量,一个GIN_MAYBE返回值相当于设置复查布尔值中的标志持续的功能。

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

int compare(基准a,基准b)

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

或者,如果操作符类不提供比较方法,GIN 将查找索引键数据类型的默认 btree 运算符类,并使用其比较功能。建议在仅用于一种数据类型的 GIN 运算符类中指定比较函数,因为查找 btree 运算符类需要几个周期。然而,多态 GIN 操作符类(例如数组操作) 通常不能指定单个比较函数。

GIN 的操作符类可以选择提供以下方法:

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

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

无效选项(local_relopts *reopts)

定义一组控制操作符类行为的用户可见参数。

选项函数被传递一个指向 a 的指针local_reoptsstruct,它需要填充一组操作符类特定的选项。可以使用其他支持功能访问这些选项PG_HAS_OPCLASS_OPTIONS()PG_GET_OPCLASS_OPTIONS()宏。

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

为了支持“部分匹配”查询,操作符类必须提供比较部分方法及其提取查询方法必须设置匹配遇到部分匹配查询时的参数。看第 67.4.2 节详情。

各种实际数据类型基准上述值因运营商类别而异。传递给的项目值提取值总是属于操作符类的输入类型,并且所有键值都必须属于该类的贮存类型。的类型询问参数传递给提取查询,持续的三一致是由策略编号标识的类成员运算符的右手输入类型。这不必与索引类型相同,只要可以从中提取正确类型的键值即可。但是,建议这三个支持函数的 SQL 声明使用 opclass 的索引数据类型询问参数,即使实际类型可能是其他类型,具体取决于运算符。