53.2. 可扩展性 #
GIN 接口具有很高的抽象层次,访问方法实现者只需实现所访问数据类型的语义。GIN 层本身会处理并发、日志记录以及树结构的搜索。
要让一个 GIN 访问方法工作起来,只需实现四个(或五个)用户定义的方法,它们定义了树中键的行为,以及键、被索引值和可索引查询之间的关系。简言之,GIN 将可扩展性与通用性、代码复用以及清晰的接口结合了起来。
GIN 操作符类必须提供四个方法:
int compare(Datum a, Datum b)比较键(不是被索引的值!)并返回一个小于零、等于零或大于零的整数,用以表示第一个键是小于、等于还是大于第二个键。
Datum *extractValue(Datum inputValue, int32 *nkeys)给定一个要被索引的值,返回一个键数组。返回键的数量必须存入
*nkeys。Datum *extractQuery(Datum query, int32 *nkeys, StrategyNumber n, bool **pmatch, Pointer **extra_data)给定一个待查询的值,返回一个键数组;也就是说,
query是一个可索引操作符右侧的值,而该操作符左侧是被索引列。n是该操作符在操作符类中的策略号(见第 35.14.2 节)。通常,extractQuery需要查看n,以确定query的数据类型,以及需要提取的键值。返回键的数量必须存入*nkeys。如果查询不包含任何键,则extractQuery应根据操作符的语义向*nkeys存入 0 或 -1。0 表示每个值都匹配query,应执行全索引扫描(但参见第 53.5 节)。-1 表示没有任何值能匹配query,因此可以完全跳过索引扫描。pmatch是一个在支持部分匹配时使用的输出参数。要使用它,extractQuery必须分配一个包含*nkeys个布尔值的数组,并将其地址存入*pmatch。若相应键需要部分匹配,则数组对应元素应设置为 TRUE,否则设置为 FALSE。如果*pmatch被设置为 NULL,那么 GIN 认为不需要部分匹配。该变量在调用前会初始化为 NULL,因此不支持部分匹配的操作符类可以直接忽略此参数。extra_data是一个输出参数,用于让extractQuery向consistent和comparePartial方法传递额外数据。要使用它,extractQuery必须分配一个包含*nkeys个指针的数组,并将其地址存入*extra_data,然后把所需内容存入各个指针。该变量在调用前会初始化为 NULL,因此不需要额外数据的操作符类可以直接忽略此参数。如果设置了*extra_data,则整个数组会传给consistent方法,而对应元素会传给comparePartial方法。bool consistent(bool check[], StrategyNumber n, Datum query, int32 nkeys, Pointer extra_data[], bool *recheck)如果被索引值满足带有策略号
n的查询操作符(或者在返回了 recheck 指示的情况下可能满足),则返回 TRUE。check数组的长度为nkeys,它与extractQuery此前为此query值返回的键数量相同。如果被索引值包含相应的查询键,则check数组的对应元素为 TRUE,也就是说,如果 (check[i] == TRUE),则extractQuery结果数组的第 i 个键出现在被索引值中。原始的query值(不是提取出的键数组!)也会被传入,以防consistent方法需要查看它。extra_data是extractQuery返回的额外数据数组,如果没有则为 NULL。成功时,如果堆元组需要针对查询操作符重新检查,应把*recheck设为 TRUE;如果索引测试是精确的,则设为 FALSE。
另外,GIN 的操作符类还可以提供第五个方法:
int comparePartial(Datum partial_key, Datum key, StrategyNumber n, Pointer extra_data)将部分匹配查询与一个索引键进行比较。返回一个整型值,其符号表示结果:小于零表示索引键不匹配该查询,但索引扫描应继续;零表示索引键确实匹配该查询;大于零表示索引扫描应停止,因为不可能再有更多匹配。生成该部分匹配查询的操作符的策略号
n会被提供,以防需要依据其语义确定何时结束扫描。另外,extra_data是extractQuery所建额外数据数组中的对应元素,如果没有则为 NULL。
要支持“部分匹配”查询,操作符类必须提供 comparePartial 方法,并且其 extractQuery 方法在遇到部分匹配查询时必须设置
pmatch 参数。详见第 53.3.2 节。