Документация по PostgreSQL 9.4.1 | |||
---|---|---|---|
Пред. | Уровень выше | Глава 58. Индексы GIN | След. |
58.3. Расширяемость
Интерфейс GIN характеризуется высоким уровнем абстракции и таким образом требует от разработчика метода доступа реализовать только смысловое наполнение обрабатываемого типа данных. Уровень GIN берёт на себя заботу о параллельном доступе, поддержке журнала и поиске в структуре дерева.
Всё, что нужно, чтобы получить работающий метод доступа GIN — это реализовать несколько пользовательских методов, определяющих поведение ключей в дереве и отношения между ключами, индексируемыми объектами и поддерживаемыми запросами. Словом, GIN сочетает расширяемость с универсальностью, повторным использованием кода и аккуратным интерфейсом.
Класс операторов должен предоставить GIN следующие три метода:
int compare(Datum a, Datum b)
Сравнивает два ключа (не индексированные объекты!) и возвращает целое меньше нуля, ноль или целое больше нуля, показывающее, что первый ключ меньше, равен или больше второго. Ключи NULL никогда не передаются этой функции.
Datum *extractValue(Datum itemValue, int32 *nkeys, bool **nullFlags)
Возвращает массив ключей (выделенный через palloc) для индексируемого объекта. Число возвращаемых ключей должно записываться в *nkeys. Если какой-либо из ключей может быть NULL, нужно так же выделить через palloc массив из *nkeys полей bool, записать его адрес в *nullFlags и установить эти флаги NULL как требуется. В *nullFlags можно оставить значение NULL (это начальное значение), если все ключи отличны от NULL. Эта функция может возвратить NULL, если объект не содержит ключей.
Datum *extractQuery(Datum query, int32 *nkeys, StrategyNumber n, bool **pmatch, Pointer **extra_data, bool **nullFlags, int32 *searchMode)
Возвращает массив ключей (выделенный через palloc) для запрашиваемого значения; то есть, в query поступает значение, находящееся по правую сторону индексируемого оператора, по левую сторону которого указана индексируемая колонка. Аргумент n задаёт номер стратегии оператора в классе операторов (см. Подраздел 35.14.2). Часто функция
extractQuery
должна проанализировать n, чтобы определить тип данных аргумента query и выбрать метод для извлечения значений ключей. Число возвращаемых ключей должно быть записано в *nkeys. Если какие-либо ключи могут быть NULL, нужно так же выделить через palloc массив из *nkeys полей bool, сохранить его адрес в *nullFlags, и установить эти флаги NULL как требуется. В *nullFlags можно оставить значение NULL (это начальное значение), если все ключи отличны от NULL. Эта функция может возвратить NULL, если query не содержит ключей.Выходной аргумент searchMode позволяет функции
extractQuery
выбрать режим, в котором должен выполняться поиск. Если *searchMode имеет значение GIN_SEARCH_MODE_DEFAULT (это значение устанавливается перед вызовом), подходящими кандидатами считаются только те объекты, которые соответствуют минимум одному из возвращённых ключей. Если в *searchMode установлено значение GIN_SEARCH_MODE_INCLUDE_EMPTY, то в дополнение к объектам с минимум одним совпадением ключа, подходящими кандидатами будут считаться и объекты, вообще не содержащие ключей. (Этот режим полезен для реализации, например, операторов A-является-подмножеством-B.) Если в *searchMode установлено значение GIN_SEARCH_MODE_ALL, подходящими кандидатами считаются все отличные от NULL объекты в индексе, независимо от того, встречаются ли в них возвращаемые ключи. (Этот режим намного медленнее двух других, так как он по сути требует сканирования всего индекса, но он может быть необходим для корректной обработки крайних случаев. Оператор, который выбирает этот режим в большинстве ситуаций, скорее всего не подходит для реализации в классе операторов GIN.) Символы для этих значений режима определены в access/gin.h.Выходной аргумент pmatch используется, когда поддерживается частичное соответствие. Чтобы использовать его,
extractQuery
должна выделить массив из *nkeys булевских элементов и сохранить его адрес в *pmatch. Элемент этого массива должен содержать TRUE, если соответствующий ключ требует частичного соответствия, и FALSE в противном случае. Если переменная *pmatch содержит NULL, GIN полагает, что частичное соответствие не требуется. В эту переменную записывается NULL перед вызовом, так что этот аргумент можно просто игнорировать в классах операторов, не поддерживающих частичное соответствие.Выходной аргумент extra_data позволяет функции
extractQuery
передать дополнительные данные методамconsistent
иcomparePartial
. Чтобы использовать его,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[])
Возвращает TRUE, если индексированный объект удовлетворяет оператору запроса с номером стратегии n (или потенциально удовлетворяет, когда возвращается указание перепроверки). Эта функция не имеет прямого доступа к значению индексированного объекта, так как GIN не хранит сами объекты. Вместо этого, она знает о значениях ключей, извлечённых из запроса и встречающихся в данном индексированном объекте. Массив check имеет длину nkeys, что равняется числу ключей, ранее возвращённых функцией
extractQuery
для данного значения query. Элемент массива check равняется TRUE, если индексированный объект содержит соответствующий ключ запроса; то есть, если (check[i] == TRUE), то i-ый ключ в массиве результатаextractQuery
присутствует в индексированном объекте. Исходное значение query передаётся на случай, если оно потребуется методуconsistent
; с той же целью ему передаются массивы queryKeys[] и nullFlags[], ранее возвращённые функциейextractQuery
. В аргументе extra_data передаётся массив дополнительных данных, возвращённый функциейextractQuery
, или NULL, если дополнительных данных нет.Когда
extractQuery
возвращает ключ NULL в queryKeys[], соответствующий элемент check[] содержит TRUE, если индексированный объект содержит ключ NULL; то есть можно считать, что элементы check[] отражают условие IS NOT DISTINCT FROM. Функцияconsistent
может проверить соответствующий элемент nullFlags[], если ей нужно различать соответствие с обычным значением и соответствие с NULL.В случае успеха в *recheck нужно записать TRUE, если кортеж данных нужно перепроверить с оператором запроса, либо FALSE, если проверка по индексу была точной. То есть результат FALSE гарантирует, что кортеж данных не соответствует запросу; результат TRUE со значением *recheck, равным FALSE, гарантирует, что кортеж данных соответствует запросу; а результат TRUE со значением *recheck, равным TRUE, означает, что кортеж данных может соответствовать запросу, поэтому его нужно выбрать и перепроверить, применив оператор запроса непосредственно к исходному индексированному элементу.
GinTernaryValue triConsistent(GinTernaryValue check[], StrategyNumber n, Datum query, int32 nkeys, Pointer extra_data[], Datum queryKeys[], bool nullFlags[])
Функция
triConsistent
подобнаconsistent
, но вместо булевского массива check[], ей передаются три варианта сравнений для каждого ключа: GIN_TRUE, GIN_FALSE и GIN_MAYBE. GIN_FALSE и GIN_TRUE имеют обычное булевское значение. GIN_MAYBE означает, что присутствие этого ключа неизвестно. Когда в check[] есть элементы GIN_MAYBE, эта функция должна возвращать GIN_TRUE, только если объект удовлетворяет запросу независимо от того, содержит ли индекс соответствующие ключи запроса. Подобным образом, функция должна возвращать GIN_FALSE, только если объект не удовлетворяет запросу независимо от того, содержит ли он ключи GIN_MAYBE. Если результат зависит от элементов GIN_MAYBE, то есть соответствие нельзя утверждать или отрицать в зависимости от известных ключей запроса, функция должна вернуть GIN_MAYBE.Когда в массиве check нет элементов GIN_MAYBE, возвращаемое значение GIN_MAYBE равнозначно установленному флагу recheck в булевской функции
consistent
.
Дополнительно класс операторов может предоставить GIN следующий метод:
int comparePartial(Datum partial_key, Datum key, StrategyNumber n, Pointer extra_data)
Сравнивает ключ запроса с частичным соответствием с ключом индекса. Возвращает целое число, знак которого отражает результат сравнения: отрицательное число означает, что ключ индекса не соответствует запросу, но нужно продолжать сканирование индекса; ноль означает, что ключ индекса соответствует запросу; положительное число означает, что сканирование индекса нужно прекратить, так как других соответствий не будет. Функции передаётся номер стратегии n оператора, сформировавшего запрос частичного соответствия, на случай, если нужно знать его смысл, чтобы определить, когда прекращать сканирование. Кроме того, ей передаётся extra_data — соответствующий элемент массива дополнительных данных, сформированного функцией
extractQuery
, либо NULL, если дополнительных данных нет. Значения NULL этой функции никогда не передаются.
Для поддержки проверок на "частичное соответствие" класс операторов должен предоставить метод comparePartial
, а метод extractQuery
должен устанавливать параметр pmatch, когда встречается запрос на частичное соответствие. За подробностями обратитесь к Подразделу 58.4.2.
Фактические типы данных различных значений Datum, упоминаемых выше, зависят от класса операторов. Значения объектов, передаваемые в extractValue
, всегда имеют входной тип класса операторов, а все значения ключей должны быть типа, заданного параметром STORAGE для класса. Типом аргумента query, передаваемого функциям extractQuery
, consistent
и triConsistent
будет тот тип, что указан в качестве типа правого операнда оператора-члена класса, определяемого по номеру стратегии. Это не обязательно должен быть тип объекта, достаточно лишь, чтобы из него можно было извлечь значения ключей, имеющие нужный тип.
Пред. | Начало | След. |
Встроенные классы операторов | Уровень выше | Реализация |