Версия:

Вложенный модуль box.index

Вложенный модуль box.index

Общие сведения

Вложенный модуль box.index обеспечивает доступ к схемам индекса и ключам индекса в режиме только для чтения. Индексы хранятся в массиве box.space.имя-спейса.index в каждом спейсе. Они предоставляют API для упорядоченной итерации по кортежам. Этот API представляет собой прямую привязку к соответствующим методам объектов типа``box.index`` в движке базы данных.

Индекс

Ниже приведен перечень всех функций и элементов модуля box.index.

Имя Использование
index_object.unique Флаг, если индекс уникальный – true
index_object.type Тип индекса
index_object.parts Массив полей с ключами индекса
index_object:pairs() Подготовка к итерации
index_object:select() Выбор одного или более кортежей по индексу
index_object:get() Выбор кортежа по индексу
index_object:min() Поиск минимального значения в индексе
index_object:max() Поиск максимального значения в индексе
index_object:random() Поиск случайного значения в индексе
index_object:count() Подсчет кортежей с совпадающим значением ключа
index_object:update() Обновление кортежа
index_object:delete() Удаление кортежа по ключу
index_object:alter() Изменение индекса
index_object:drop() Удаление индекса
index_object:rename() Переименование индекса
index_object:bsize() Подсчет байтов для индекса
index_object:stat() Получение статистических данных по индексу
index_object:compact() Удаление неиспользуемого пространства индекса
index_object:user_defined() Любая функция / метод, которые хочет добавить любой пользователь
object index_object
index_object.unique

Если индекс уникальный – true, если индекс не уникален – false.

тип возвращаемого значения:
 boolean (логический)
index_object.type

Тип индекса: „TREE“ или „HASH“ или „BITSET“ или „RTREE“.

index_object.parts

Массив, описывающий поля индекса. Чтобы узнать больше о типах полей индекса, обращайтесь к этой таблице.

тип возвращаемого значения:
 таблица

Пример:

tarantool> box.space.tester.index.primary
            ---
            - unique: true
              parts:
              - type: unsigned
                is_nullable: false
                fieldno: 1
              id: 0
              space_id: 513
              name: primary
              type: TREE
            ...
index_object:pairs([key[, {iterator = iterator-type}]])

Поиск кортежа или набора кортежей по заданному индексу и итерация по одному кортежу за раз.

Параметр key (ключ) задает, что именно должно совпадать в индексе.

Примечание

key используется в поиске только первого совпадения. Не стоит ожидать, что все подобранные кортежи будут содержать этот ключ.

Параметр iterator (итератор) задает правило для совпадений и упорядочивания. Различные типы индексов поддерживают различные итераторы. Например, TREE-индекс поддерживает строгий порядок ключей и может вернуть все кортежи в порядке по возрастанию или по убыванию, начиная с указанного ключа. Однако другие типы индексов не поддерживают упорядочивание.

Чтобы понять логику возврата кортежей с помощью итератора, важно знать принципы работы подсистемы обработки транзакций в Tarantool’е. В итераторе Tarantool’а нет собственного постоянного вида просмотра. Наоборот, каждая процедура получает эксклюзивный доступ ко всем кортежам и спейсам до тех пор, пока не «переключится контекст», что может произойти по причине неявной передачи управления или в результате явного вызова функции fiber.yield. Когда поток выполнения возвращается к процедуре, передавшей управление, набор данных может уже значительно измениться. Итерация возобновляется после стадии передачи управления и не сохраняет вид просмотра, а продолжает работу с новым содержимым базы данных. В практическом задании «Индексированный поиск по шаблонам» демонстрируется один из способов одновременного использования итераторов и передачи управления.

For information about iterators“ internal structures see the «Lua Functional library» documentation.

Параметры:
  • index_object (index_object) – ссылка на объект.
  • key (scalar/table) – значение должно совпасть с индексным ключом, который может быть составным
  • iterator – как определено в таблицах ниже. По умолчанию используется итератор „EQ“
возвращается:

итератор, который может использовать в цикле for/end или с функцией totable()

Возможные ошибки:

  • спейс отсутствует; неправильный тип;
  • выбранный тип итерации не поддерживается для данного типа индекса;
  • ключ не поддерживается для данного типа итерации.

Факторы сложности Размер индекса, тип индекса; количество кортежей, к которым получен доступ.

Значение искомого ключа может представлять собой число (например, 1234), строку (например, 'abcd') или таблицу из чисел и строк (например, {1234, 'abcd'}). Каждая часть ключа будет сопоставляться с каждой частью ключа в индексе.

Найденные кортежи будут упорядочены по значению ключа в индексе или по хешу значения ключа, если тип индекса – „hash“. Если индекс не уникален, то дубликаты будут упорядочены во вторую очередь по первичному значению ключа. Порядок будет обратным, если тип итератора – „LT“, „LE“ или „REQ“.

Типы итераторов для TREE-индексов

Type Аргументы Описание
box.index.EQ или „EQ“ искомое значение Оператором сравнения будет „==“ (равно). Если ключ индекса равен искомому значению, получим совпадение. Найденные кортежи упорядочены по возрастанию по ключу индекса. Этот тип используется по умолчанию.
box.index.REQ или „REQ“ искомое значение Совпадения находятся таким же образом, что и для box.index.EQ. Разница только в том, что найденные кортежи упорядочены по ключу индекса по убыванию, а не по возрастанию.
box.index.GT или „GT“ искомое значение Оператором сравнения будет „>“ (больше чем). Если ключ индекса больше, чем искомое значение, получим совпадение. Найденные кортежи упорядочены по возрастанию по ключу индекса.
box.index.GE или „GE“ искомое значение Оператором сравнения будет „>=“ (больше или равен). Если ключ индекса больше искомого значения или равен ему, получим совпадение. Найденные кортежи упорядочены по возрастанию по ключу индекса.
box.index.ALL или „ALL“ искомое значение Как для box.index.GE.
box.index.LT или „LT“ искомое значение Оператором сравнения будет „<“ (меньше чем). Если ключ индекса меньше искомого значения, получим совпадение. Найденные кортежи упорядочены по убыванию по ключу индекса.
box.index.LE или „LE“ искомое значение Оператором сравнения будет „<=“ (меньше или равен). Если ключ индекса меньше искомого значения или равен ему, получим совпадение. Найденные кортежи упорядочены по убыванию по ключу индекса.

Неофициально можно сказать, что поиск с помощью TREE-индексов пользователи обычно считают интуитивно понятным при условии, что нет нулевых значений и отсутствующих частей. Формально же логика заключается в следующем. Ключ поиска состоит из нуля или более частей, например, {}, {1,2,3},{1,nil,3}. Ключ индекса состоит из одной или более частей, например, {1}, {1,2,3},{1,2,3}. Ключ поиска может содержать нулевое значение nil (но не msgpack.NULL, этот тип не будет правильным). Ключ индекса не может содержать nil или msgpack.NULL, хотя в последующих версиях правила работы Tarantool’а будут другие – поведение поиска с nil может измениться. Возможные итераторы: LT, LE, EQ, REQ, GE, GT. Считается, что ключ поиска соответствует ключу индекса, если следующие операторы, которые представляют собой псевдокод для операции сопоставления, возвращают TRUE.

If (number-of-search-key-parts > number-of-index-key-parts) return ERROR
If (number-of-search-key-parts == 0) return TRUE
for (i = 1; ; ++i)
{
  if (i > number-of-search-key-parts) OR (search-key-part[i] is nil)
  {
    if (iterator is LT or GT) return FALSE
    return TRUE
  }
  if (type of search-key-part[i] is not compatible with type of index-key-part[i])
  {
    return ERROR
  }
  if (search-key-part[i] == index-key-part[i])
  {
    continue
  }
  if (search-key-part[i] > index-key-part[i])
  {
    if (iterator is EQ or REQ or LE or LT) return FALSE
    return TRUE
  }
  if (search-key-part[i] < index-key-part[i])
  {
    if (iterator is EQ or REQ or GE or GT) return FALSE
    return TRUE
  }
}

Типы итераторов для HASH-индексов

Type Аргументы Описание
box.index.ALL нет Все ключи индекса являются совпадениями. Найденные кортежи упорядочены по возрастанию по хешу ключа индекса, который будет выглядеть случайным.
box.index.EQ или „EQ“ искомое значение Оператором сравнения будет „==“ (равный). Если ключ индекса равен искомому значению, получим совпадение. Количество найденных кортежей будет 0 или 1. Этот тип используется по умолчанию.
box.index.GT или „GT“ искомое значение Оператором сравнения будет „>“ (больше чем). Если хеш ключа индекса больше, чем хеш искомого значения, получим совпадение. Найденные кортежи упорядочены по возрастанию по хешу ключа индекса, который будет выглядеть случайным. При условии, что спейс не обновляется, можно получить все кортежи в спейсе, N кортежей за раз, используя {iterator=“GT“, limit=N} в каждом поиске и последнее найденное значение из предыдущего результата поиска в качестве начального значения для следующего поиска.

Типы итераторов для BITSET-индексов

Type Аргументы Описание
box.index.ALL или „ALL“ нет Все ключи индекса являются совпадениями. Найденные кортежи упорядочены по положению в спейсе.
box.index.EQ или „EQ“ значение bitset (битовое множество) Если ключ индекса равен искомому значению, получим совпадение. Найденные кортежи упорядочены по положению в спейсе. Этот тип используется по умолчанию.
box.index.BITS_ALL_SET значение bitset (битовое множество) Если все биты, которые равны 1 в битовом множестве, также равны 1 в ключе индекса, получим совпадение. Найденные кортежи упорядочены по положению в спейсе.
box.index.BITS_ANY_SET значение bitset (битовое множество) Если один из битов, которые равны 1 в битовом множестве, также равен 1 в ключе индекса, получим совпадение. Найденные кортежи упорядочены по положению в спейсе.
box.index.BITS_ALL_NOT_SET значение bitset (битовое множество) Если все биты, которые равны 1 в битовом множестве, равны 0 в ключе индекса, получим совпадение. Найденные кортежи упорядочены по положению в спейсе.

Типы итераторов для RTREE-индексов

Type Аргументы Описание
box.index.ALL или „ALL“ нет Все ключи являются совпадениями. Найденные кортежи упорядочены по положению в спейсе.
box.index.EQ или „EQ“ искомое значение Если все точки прямоугольника-или-параллелепипеда, определенные искомым значением, совпадают с точками прямоугольника-или-параллелепипеда, определенного ключом индекса, получим совпадение. Найденные кортежи упорядочены по положению в спейсе. «Прямоугольник-или-параллелепипед» означает «прямоугольник-или-параллелепипед, как описано в разделе о RTREE». Этот тип используется по умолчанию.
box.index.GT или „GT“ искомое значение Если все точки прямоугольника-или-параллелепипеда, определенные искомым значением, находятся в пределах прямоугольника-или-параллелепипеда, определенного ключом индекса, получим совпадение. Найденные кортежи упорядочены по положению в спейсе.
box.index.GE или „GE“ искомое значение Если все точки прямоугольника-или-параллелепипеда, определенные искомым значением, находятся в пределах прямоугольника-или-параллелепипеда, определенного ключом индекса, или рядом с ним, получим совпадение. Найденные кортежи упорядочены по положению в спейсе.
box.index.LT или „LT“ искомое значение Если все точки прямоугольника-или-параллелепипеда, определенные ключом индекса, находятся в пределах прямоугольника-или-параллелепипеда, определенного искомым значением, получим совпадение. Найденные кортежи упорядочены по положению в спейсе.
box.index.LE или „LE“ искомое значение Если все точки прямоугольника-или-параллелепипеда, определенные ключом индекса, находятся в пределах прямоугольника-или-параллелепипеда, определенного искомым значением, или рядом с ним, получим совпадение. Найденные кортежи упорядочены по положению в спейсе.
box.index.OVERLAPS или „OVERLAPS“ искомое значение Если некоторые точки прямоугольника-или-параллелепипеда, определенные искомым значением, находятся в пределах прямоугольника-или-параллелепипеда, определенного ключом индекса, получим совпадение. Найденные кортежи упорядочены по положению в спейсе.
box.index.NEIGHBOR или „NEIGHBOR“ искомое значение Если некоторые точки прямоугольника-или-параллелепипеда, определенные ключом, находятся в пределах, определенных ключом индекса, или рядом с ним, получим совпадение. Найденные кортежи упорядочены следующим образом: сначала ближайший сосед.

Первый пример pairs():

„TREE“-индекс, используемый по умолчанию, и функция pairs():

tarantool> s = box.schema.space.create('space17')
 ---
 ...
 tarantool> s:create_index('primary', {
          >   parts = {1, 'string', 2, 'string'}
          > })
 ---
 ...
 tarantool> s:insert{'C', 'C'}
 ---
 - ['C', 'C']
 ...
 tarantool> s:insert{'B', 'A'}
 ---
 - ['B', 'A']
 ...
 tarantool> s:insert{'C', '!'}
 ---
 - ['C', '!']
 ...
 tarantool> s:insert{'A', 'C'}
 ---
 - ['A', 'C']
 ...
 tarantool> function example()
          >   for _, tuple in
          >     s.index.primary:pairs(nil, {
          >         iterator = box.index.ALL}) do
          >       print(tuple)
          >   end
          > end
 ---
 ...
 tarantool> example()
 ['A', 'C']
 ['B', 'A']
 ['C', '!']
 ['C', 'C']
 ---
 ...
 tarantool> s:drop()
 ---
 ...

Второй пример pairs():

Данный код на Lua найдет все кортежи, значения первичного ключа в которых начинаются с „XY“. Рабочие предположения заключаются в следующем: есть однокомпонентный первичный TREE-индекс по первому полю, которое должно представлять собой строку. Цикл с итератором обеспечивает поиск кортежей, в которых первое значение больше или равно „XY“. Условный оператор в цикле служит для того, чтобы цикл останавливался, если первые две буквы не „XY“.

for _, tuple in
 box.space.t.index.primary:pairs("XY",{iterator = "GE"}) do
   if (string.sub(tuple[1], 1, 2) ~= "XY") then break end
   print(tuple)
 end

Третий пример pairs():

Данный код на Lua найдет все кортежи, значения первичного ключа которых равны или больше 1000 и меньше или равны 1999 (такой тип запроса иногда называют поиском по диапазону или поиском в заданных пределах). Рабочие предположения заключаются в следующем: есть однокомпонентный первичный TREE-индекс по первому полю, которое должно представлять собой число. Цикл с итератором обеспечивает поиск кортежей, в которых первое значение больше или равно 1000. Условный оператор в цикле служит для того, чтобы цикл останавливался, если первое значение больше 1999.

for _, tuple in
 box.space.t2.index.primary:pairs(1000,{iterator = "GE"}) do
   if (tuple[1] > 1999) then break end
   print(tuple)
 end
index_object:select(search-key, options)

Это может быть альтернативой для функции box.space…select(), которая проходит по определенному индексу и может использовать дополнительные параметры, которые определяют тип итератора и пределы (то есть максимальное количество возвращаемых кортежей) и смещение (то есть с какого кортежа в списке начинать).

Параметры:
  • index_object (index_object) – ссылка на объект.
  • key (scalar/table) – значения для сопоставления с ключом индекса
  • options (table/nil) – ни один, любой или все следующие параметры
  • options.iterator – тип итератора
  • options.limit (number) – максимальное количество кортежей
  • options.offset (number) – номер начального кортежа
возвращается:

кортеж или кортежи, которые совпадают со значениями поля.

тип возвращаемого значения:
 

массив кортежей

Пример:

-- Создать спейс под названием tester.
 tarantool> sp = box.schema.space.create('tester')
 -- Создать уникальный индекс 'primary'
 -- который не будет нужен для данного примера..
 tarantool> sp:create_index('primary', {parts = {1, 'unsigned' }})
 -- Создать неуникальный индекс 'secondary'
 -- по второму полю.
 tarantool> sp:create_index('secondary', {
          >   type = 'tree',
          >   unique = false,
          >   parts = {2, 'string'}
          > })
 -- Вставить три кортежа, значения в поле2 field[2]
 -- равны 'X', 'Y' и 'Z'.
 tarantool> sp:insert{1, 'X', 'Row with field[2]=X'}
 tarantool> sp:insert{2, 'Y', 'Row with field[2]=Y'}
 tarantool> sp:insert{3, 'Z', 'Row with field[2]=Z'}
 -- Выбрать все кортежи, где вторичные ключи
 -- больше, чем 'X'.`
 tarantool> sp.index.secondary:select({'X'}, {
          >   iterator = 'GT',
          >   limit = 1000
          > })

Результатом будет следующая таблица кортежа:

---
     - - [2, 'Y', 'Row with field[2]=Y']
       - [3, 'Z', 'Row with field[2]=Z']
     ...

Примечание

Параметр index.имя-индекса необязателен. Если он пропущен, то подразумевается первый индекс (первичный ключ). Таким образом, для примера выше, box.space.tester:select({1}, {iterator = 'GT'}) вернет две одинаковых строки по первичному индексу „primary“.

Примечание

Параметр типа итератора iterator = тип-итератора необязателен. Если он пропущен, то подразумевается, что iterator = 'EQ'.

Примечание

Параметр field-value [, значение поля ] необязателен. Если он пропущен, то каждый ключ в индексе будет считаться совпадением независимо от типа итератора. Таким образом, для примера выше, box.space.tester:select{} выберет каждый кортеж в спейсе tester по первому индексу (первичный ключ).

Примечание

box.space.space-name.index.index-name:select(...)[1]`. can be replaced by box.space.space-name.index.index-name:get(...). That is, get can be used as a convenient shorthand to get the first tuple in the tuple set that would be returned by select. However, if there is more than one tuple in the tuple set, then get throws an error.

Пример с индексом BITSET:

Следующий скрипт показывает создание BITSET-индекса и поиск по нему. Обратите внимание, что битовое множество BITSET не может быть уникальным, поэтому сначала создается первичный индекс. Обратите внимание, что битовые значения вводятся как шестнадцатеричные литералы для удобства чтения.

tarantool> s = box.schema.space.create('space_with_bitset')
 tarantool> s:create_index('primary_index', {
          >   parts = {1, 'string'},
          >   unique = true,
          >   type = 'TREE'
          > })
 tarantool> s:create_index('bitset_index', {
          >   parts = {2, 'unsigned'},
          >   unique = false,
          >   type = 'BITSET'
          > })
 tarantool> s:insert{'Tuple with bit value = 01', 0x01}
 tarantool> s:insert{'Tuple with bit value = 10', 0x02}
 tarantool> s:insert{'Tuple with bit value = 11', 0x03}
 tarantool> s.index.bitset_index:select(0x02, {
          >   iterator = box.index.EQ
          > })
 ---
 - - ['Tuple with bit value = 10', 2]
 ...
 tarantool> s.index.bitset_index:select(0x02, {
          >   iterator = box.index.BITS_ANY_SET
          > })
 ---
 - - ['Tuple with bit value = 10', 2]
   - ['Tuple with bit value = 11', 3]
 ...
 tarantool> s.index.bitset_index:select(0x02, {
          >   iterator = box.index.BITS_ALL_SET
          > })
 ---
 - - ['Tuple with bit value = 10', 2]
   - ['Tuple with bit value = 11', 3]
 ...
 tarantool> s.index.bitset_index:select(0x02, {
          >   iterator = box.index.BITS_ALL_NOT_SET
          > })
 ---
 - - ['Tuple with bit value = 01', 1]
 ...
index_object:get(key)

Поиск кортежа по заданному индексу, как описано выше.

Параметры:
  • index_object (index_object) – ссылка на объект.
  • key (scalar/table) – значения для сопоставления с ключом индекса
возвращается:

кортеж, в котором поля ключа в индексе равны переданным значениям ключа.

тип возвращаемого значения:
 

кортеж

Возможные ошибки:

  • отсутствие такого индекса;
  • неправильный тип;
  • больше одного кортежа подходят.

Факторы сложности: Размер индекса, тип индекса. См. также space_object:get().

Пример:

tarantool> box.space.tester.index.primary:get(2)
     ---
     - [2, 'Music']
     ...
index_object:min([key])

Поиск минимального значения в указанном индексе.

Параметры:
  • index_object (index_object) – ссылка на объект.
  • key (scalar/table) – значения для сопоставления с ключом индекса
возвращается:

кортеж для первого ключа в индексе. Если указано необязательное значение ключа key, будет выведен первый ключ, который больше или равен значению ключа key. Начиная с версии Tarantool’а 2.0 index_object:min(значение key) не вернет ничего, если значение key не равно значению в индексе.

тип возвращаемого значения:
 

кортеж

Возможные ошибки: тип индекса не „TREE“.

Факторы сложности: Размер индекса, тип индекса.

Пример:

tarantool> box.space.tester.index.primary:min()
     ---
     - ['Alpha!', 55, 'This is the first tuple!']
     ...
index_object:max([key])

Поиск максимального значения в указанном индексе.

Параметры:
  • index_object (index_object) – ссылка на объект.
  • key (scalar/table) – значения для сопоставления с ключом индекса
возвращается:

кортеж для последнего ключа в индексе. Если указано необязательное значение ключа key, будет выведен последний ключ, который меньше или равен значению ключа key. Начиная с версии Tarantool’а 2.0 index_object:max(значение key) не вернет ничего, если значение key не равно значению в индексе.

тип возвращаемого значения:
 

кортеж

Возможные ошибки: тип индекса не „TREE“.

Факторы сложности: Размер индекса, тип индекса.

Пример:

tarantool> box.space.tester.index.primary:max()
     ---
     - ['Gamma!', 55, 'This is the third tuple!']
     ...
index_object:random(seed)

Поиск случайного значения в заданном индексе. Данный метод используется, когда важно получить представление о распределении данных в индексе без необходимости проходить по всему набору данных.

Параметры:
  • index_object (index_object) – ссылка на объект.
  • seed (number) – произвольное неотрицательное целое число
возвращается:

кортеж для случайного ключа в индексе.

тип возвращаемого значения:
 

кортеж

Факторы сложности: Размер индекса, тип индекса.

Примечание про движок базы данных: vinyl не поддерживает random().

Пример:

tarantool> box.space.tester.index.secondary:random(1)
     ---
     - ['Beta!', 66, 'This is the second tuple!']
     ...
index_object:count([key][, iterator])

Итерация по индексу с подсчетом количества кортежей, которые соответствуют паре ключ-значение.

Параметры:
  • index_object (index_object) – ссылка на объект.
  • key (scalar/table) – значения для сопоставления с ключом индекса
  • iterator – метод сопоставления
возвращается:

the number of matching tuples.

тип возвращаемого значения:
 

число

Пример:

tarantool> box.space.tester.index.primary:count(999)
 ---
 - 0
 ...
 tarantool> box.space.tester.index.primary:count('Alpha!', { iterator = 'LE' })
 ---
 - 1
 ...
index_object:update(key, {{operator, field_no, value}, ...})

Обновление кортежа.

То же, что и box.space…update(), но поиск ключа происходит в этом индексе, вместо первичного. Данный индекс должен быть уникальным.

Параметры:
  • index_object (index_object) – ссылка на объект.
  • key (scalar/table) – значения для сопоставления с ключом индекса
  • operator (string) – тип операции, представленный строкой
  • field_no (number) – к какому полю применяется операция. Номер поля может быть отрицательным, что означает, что позиция рассчитывается с конца кортежа. (#кортеж + отрицательный номер поля + 1)
  • value (lua_value) – какое значение применяется
возвращается:

обновленный кортеж.

тип возвращаемого значения:
 

кортеж

index_object:delete(key)

Удаление кортежа по ключу.

То же, что и box.space…delete(), но поиск ключа происходит в этом индексе, вместо первичного. Данный индекс должен быть уникальным.

Параметры:
  • index_object (index_object) – ссылка на объект.
  • key (scalar/table) – значения для сопоставления с ключом индекса
возвращается:

удаленный кортеж.

тип возвращаемого значения:
 

кортеж

Примечание про движок базы данных: vinyl вернет nil, а не удаленный кортеж.

index_object:alter({options})

Alter an index. It is legal in some circumstances to change one or more of the index characteristics, for example its type, its sequence options, its parts, and whether it is unique, Usually this causes rebuilding of the space, except for the simple case where a part’s is_nullable flag is changed from false to true.

Параметры:
возвращается:

nil

Возможные ошибки:

  • индекс не существует,
  • the primary-key index cannot be changed to {unique = false}.

Note re storage engine: vinyl does not support alter() of a primary-key index unless the space is empty.

Пример:

tarantool> box.space.space55.index.primary:alter({type = 'HASH'})
     ---
     ...

     tarantool> box.space.vinyl_space.index.i:alter({page_size=4096})
     ---
     ...
index_object:drop()

Удаление индекса. Побочный эффект удаления первичного индекса – все кортежи удалятся.

Параметры:
возвращается:

nil.

Возможные ошибки:

  • индекс не существует,
  • первичный индекс невозможно удалить, если существует вторичный индекс.

Пример:

tarantool> box.space.space55.index.primary:drop()
     ---
     ...
index_object:rename(index-name)

Переименование индекса.

Параметры:
возвращается:

nil

Возможные ошибки: index_object не существует.

Пример:

tarantool> box.space.space55.index.primary:rename('secondary')
     ---
     ...

Факторы сложности: Размер индекса, тип индекса, количество кортежей, к которым получен доступ.

index_object:bsize()

Возврат общего количества байтов, занятых индексом.

Параметры:
возвращается:

количество байтов

тип возвращаемого значения:
 

число

index_object:stat()

Получение статистики о предпринятых действиях, которые влияют на индекс.

Используется с движком базы данных vinyl.

Подробные данные в выводе index_object:stat():

  • index_object:stat().latency содержит отметки времени в процентах;
  • index_object:stat().bytes – общее количество байтов;
  • index_object:stat().disk.rows – примерное количество кортежей в каждом диапазоне;
  • index_object:stat().disk.statement содержит количество вставок, обновлений, обновлений и вставок, удалений (inserts|updates|upserts|deletes);
  • index_object:stat().disk.compaction – counts of compactions and their amounts;
  • index_object:stat().disk.dump содержит количество дампов и их объем;
  • index_object:stat().disk.iterator.bloom содержит количество совпадений и несовпадений по фильтрами Блума;
  • index_object:stat().disk.pages содержит размер в страницах;
  • index_object:stat().disk.last_level – size of data in the last LSM tree level;
  • index_object:stat().cache.evict – number of evictions from the cache;
  • index_object:stat().range_size – maximum number of bytes in a range;
  • index_object:stat().dumps_per_compaction – average number of dumps required to trigger major compaction in any range of the LSM tree.

С помощью box.stat.vinyl() можно получить сводную статистику по индексу.

Параметры:
возвращается:

статистические данные

тип возвращаемого значения:
 

таблица

index_object:compact()

Remove unused index space. For the memtx storage engine this method does nothing; index_object:compact() is only for the vinyl storage engine. For example, with vinyl, if a tuple is deleted, the space is not immediately reclaimed. There is a scheduler for reclaiming space automatically based on factors such as lsm shape and amplification as discussed in the section Storing data with vinyl, so calling index_object:compact() manually is not always necessary.

возвращается:nil (Tarantool возвращает нулевое значение сразу же, не ожидая завершения слияния)
index_object:user_defined()

Пользователи могут сами определять любые желаемые функции и связывать их с индексами: фактически они могут создавать собственные методы для работы с индексом. Это можно сделать так:

  1. создать Lua-функцию,
  2. добавить имя функции в заданную глобальную переменную с типом «таблица» (table),
  3. впоследствии в любое время, пока работает сервер, вызвать функцию с помощью объект_индекса:имя-функции([параметры]).

Есть три заданные глобальные переменные:

  • Метод, добавленный в box_schema.index_mt, будет доступен для всех индексов.
  • Метод, добавленный в box_schema.memtx_index_mt, будет доступен для всех индексов в memtx’е.
  • Метод, добавленный в box_schema.vinyl_index_mt, будет доступен для всех индексов в vinyl’е.

Можно также сделать задаваемый пользователем метод доступным только для одного индекса путем вызова getmetatable(объект_индекса) и последующего добавления имени функции в метатаблицу.

Параметры:

Пример:

-- Доступный для любого индекса спейса memtx, без параметров.
 -- После таких запросов значение глобальной переменной global_variable будет 6.
 box.schema.space.create('t', {engine='memtx'})
 box.space.t:create_index('i')
 global_variable = 5
 function f() global_variable = global_variable + 1 end
 box.schema.memtx_index_mt.counter = f
 box.space.t.index.i:counter()

Пример:

-- Доступный только для индекса box.space.t.index.i, 1 параметр.
-- После таких запросов значение X будет 1005.
box.schema.space.create('t', {engine='memtx', id = 1000})
box.space.t:create_index('i')
X = 0
i = box.space.t.index.i
function f(i_arg, param) X = X + param + i_arg.space_id end
box.schema.memtx_index_mt.counter = f
meta = getmetatable(i)
meta.counter = f
i:counter(5)

Пример использования функций box

Данный пример сработает на конфигурации из песочницы, описанной в предисловии, то есть создан спейс под названием tester с первичным числовым ключом. Функция в примере выполнит следующие действия:

  • выбрать кортеж, значение ключа в котором равно 1000;
  • raise an error if the tuple already exists and already has 3 fields;
  • вставить или заменить кортеж следующими данными:
    • поле [1] = 1000
    • поле [2] = UUID
    • поле [3] = количество секунд с 01.01.1970;
  • получить поле [3] из того, что заменили;
  • преобразовать значение из поля [3] в формат yyyy-mm-dd hh:mm:ss.ffff (год-месяц-день час:минута:секунда.десятитысячные доли секунды);
  • вернуть преобразованное значение.

Данная функция использует функции box в Tarantool’е: box.space…select, box.space…replace, fiber.time, uuid.str. Данная функция использует Lua-функции os.date() и string.sub().

function example()
   local a, b, c, table_of_selected_tuples, d
   local replaced_tuple, time_field
   local formatted_time_field
   local fiber = require('fiber')
   table_of_selected_tuples = box.space.tester:select{1000}
   if table_of_selected_tuples ~= nil then
     if table_of_selected_tuples[1] ~= nil then
       if #table_of_selected_tuples[1] == 3 then
         box.error({code=1, reason='This tuple already has 3 fields'})
       end
     end
   end
   replaced_tuple = box.space.tester:replace
     {1000,  require('uuid').str(), tostring(fiber.time())}
   time_field = tonumber(replaced_tuple[3])
   formatted_time_field = os.date("%Y-%m-%d %H:%M:%S", time_field)
   c = time_field % 1
   d = string.sub(c, 3, 6)
   formatted_time_field = formatted_time_field .. '.' .. d
   return formatted_time_field
 end

… А вот что происходит, когда вызывается функция:

tarantool> box.space.tester:delete(1000)
 ---
 - [1000, '264ee2da03634f24972be76c43808254', '1391037015.6809']
 ...
 tarantool> example(1000)
 ---
 - 2014-01-29 16:11:51.1582
 ...
 tarantool> example(1000)
 ---
 - error: 'This tuple already has 3 fields'
 ...

Пример с заданным пользователем итератором

Здесь приведен пример того, как создать свой собственный итератор. Функция paged_iter представляет собой «функцию с итератором», что поймут только разработчики, которые ознакомились с разделом руководства по Lua Итераторы и замыкания. Она делает постраничную выборку, то есть возвращает 10 кортежей одновременно из таблицы под названием «t», первичный ключ которой определен с помощью create_index('primary',{parts={1,'string'}}).

function paged_iter(search_key, tuples_per_page)
   local iterator_string = "GE"
   return function ()
   local page = box.space.t.index[0]:select(search_key,
     {iterator = iterator_string, limit=tuples_per_page})
   if #page == 0 then return nil end
   search_key = page[#page][1]
   iterator_string = "GT"
   return page
   end
 end

Разработчикам, использующим paged_iter, необязательно знать, почему она работает, следует лишь понимать, что вызвав функцию в цикле, можно получать 10 кортежей за раз до тех пор, пока кортежи не кончатся.

В данном примере кортежи лишь выводятся по странице за раз. Но легко изменить функцию, например, путем передачи управления после каждой выборки или с помощью прерывания, если кортежи не будут соответствовать дополнительным критериям.

for page in paged_iter("X", 10) do
   print("New Page. Number Of Tuples = " .. #page)
   for i = 1, #page, 1 do
     print(page[i])
   end
 end

Вложенный модуль box.index с типом индекса RTREE для поиска в пространственных данных

Вложенный модуль box.index может использоваться для поиска в пространственных данных, если тип индекса – RTREE. Существуют операции для поиска прямоугольников (геометрические фигуры с 4 углами и 4 сторонами) и параллелепипедов (геометрические фигуры с количеством углов более 4 и количеством сторон более 4, которые иногда называются гиперпрямоугольниками). В данном руководстве используется термин прямоугольник-или-параллелепипед для всего класса объектов, который включает в себя прямоугольники и параллелепипеды. Примерами иллюстрируются только прямоугольники.

Прямоугольники описаны в соответствии с координатами по оси X (горизонтальной оси) и оси Y (вертикальной оси) на сетке произвольного размера. Ниже представлен рисунок четырех прямоугольников на сетке с 11 горизонтальными точками и 11 вертикальными точками:

      X AXIS
           1   2   3   4   5   6   7   8   9   10  11
        1
        2  #-------+                                           <-Прямоугольник №1
Y AXIS  3  |       |
        4  +-------#
        5          #-----------------------+                   <-Прямоугольник №2
        6          |                       |
        7          |   #---+               |                   <-Прямоугольник №3
        8          |   |   |               |
        9          |   +---#               |
        10         +-----------------------#
        11                                     #               <-Прямоугольник №4

Прямоугольники определяются в соответствии со следующей схемой: {верхняя левая координата по оси X, верхняя левая координата по оси Y, нижняя правая координата по оси X, нижняя правая координата по оси Y} – или коротко: {x1,y1,x2,y2}. Таким образом, на рисунке … Прямоугольник № 1 начинается в точке 1 по оси X и точке 2 по оси Y, а заканчивается в точке 3 по оси X и точке 4 по оси Y, поэтому его координаты будут следующие: {1,2,3,4}. Координаты Прямоугольника № 2: {3,5,9,10}. Координаты Прямоугольника № 3: {4,7,5,9}. И наконец, координаты Прямоугольника № 4: {10,11,10,11}. Прямоугольник № 4, на самом деле, является точкой, поскольку у него нулевая ширина и нулевая высота, так что его можно описать всего двумя числами: {10,11}.

Некоторые отношения между прямоугольниками могут быть описаны так: «Прямоугольник №1 является ближайшим соседом Прямоугольника №2», а «Прямоугольник №3 полностью находится внутри Прямоугольника №2».

Сейчас создадим спейс и добавим RTREE-индекс.

tarantool> s = box.schema.space.create('rectangles')
     tarantool> i = s:create_index('primary', {
              >   type = 'HASH',
              >   parts = {1, 'unsigned'}
              > })
     tarantool> r = s:create_index('rtree', {
              >   type = 'RTREE',
              >   unique = false,
              >   parts = {2, 'ARRAY'}
              > })

Поле №1 не имеет значения, мы создаем его лишь потому, что необходим первичный индекс. (RTREE-индексы не могут быть уникальными, поэтому не могут быть первичными индексами.) Второе поле должно быть массивом («array»), что означает, что его значения должны представлять собой точки {x,y} или прямоугольники {x1,y1,x2,y2}. Заполним таблицу, вставив два кортежа с координатами Прямоугольника №2 и Прямоугольника №4.

tarantool> s:insert{1, {3, 5, 9, 10}}
     tarantool> s:insert{2, {10, 11}}

Затем, после описания типов RTREE-итераторов (RTREE iterator types), можно произвести поиск прямоугольников с помощью данных запросов:

tarantool> r:select({10, 11, 10, 11}, {iterator = 'EQ'})
 ---
 - - [2, [10, 11]]
 ...
 tarantool> r:select({4, 7, 5, 9}, {iterator = 'GT'})
 ---
 - - [1, [3, 5, 9, 10]]
 ...
 tarantool> r:select({1, 2, 3, 4}, {iterator = 'NEIGHBOR'})
 ---
 - - [1, [3, 5, 9, 10]]
   - [2, [10, 11]]
 ...

Запрос №1 возвращает 1 кортеж, потому что точка {10,11} представляет собой то же, что и прямоугольник {10,11,10,11} («Прямоугольник №4» на рисунке). Запрос № 2 возвращает 1 кортеж, потому что прямоугольник {4,7,5,9}, который был «Прямоугольником №3» на рисунке находится полностью внутри {3,5,9,10}, что представляет собой Прямоугольник № 2. Запрос № 3 возвращает 2 кортежа, потому что итератор NEIGHBOR (сосед) всегда возвращает все кортежи, а первым найденным кортежем будет {3,5,9,10} («Прямоугольник №2» на рисунке), потому что он является ближайшим соседом {1,2,3,4} («Прямоугольник №1» на рисунке).

Теперь создадим спейс и индекс для кубоидов, которые представляют собой прямоугольники-или-параллелепипеды, у которых 6 углов и 6 сторон.

tarantool> s = box.schema.space.create('R')
     tarantool> i = s:create_index('primary', {parts = {1, 'unsigned'}})
     tarantool> r = s:create_index('S', {
              >   type = 'RTREE',
              >   unique = false,
              >   dimension = 3,
              >   parts = {2, 'ARRAY'}
              > })

Здесь задается дополнительный параметр``dimension=3``. По умолчанию, измерений 2, поэтому не было необходимости указывать данный параметр в примерах для прямоугольника. Максимальное количество измерений – 20. Что касается вставки и выборки, здесь будет 6 координат. Например:

tarantool> s:insert{1, {0, 3, 0, 3, 0, 3}}
     tarantool> r:select({1, 2, 1, 2, 1, 2}, {iterator = box.index.GT})

Теперь создадим спейс и индекс для пространственных объектов с метрикой расстояния городских кварталов (метрика Манхэттена), которые представляют собой прямоугольники-или-параллелепипеды; соседи для них рассчитываются иным образом.

tarantool> s = box.schema.space.create('R')
     tarantool> i = s:create_index('primary', {parts = {1, 'unsigned'}})
     tarantool> r = s:create_index('S', {
              >   type = 'RTREE',
              >   unique = false,
              >   distance = 'manhattan',
              >   parts = {2, 'ARRAY'}
              > })

Здесь задается дополнительный параметр distance='manhattan'. По умолчанию, расстояние измеряется по Евклидовой метрике, что лучше всего подходит для измерений по прямой линии. Другой способ расчета расстояния по метрике Манхэттена („manhattan“), который больше подходит, если необходимо следовать линиям сетки, а не по прямой.

tarantool> s:insert{1, {0, 3, 0, 3}}
     tarantool> r:select({1, 2, 1, 2}, {iterator = box.index.NEIGHBOR})

Другие примеры поиска в пространственных данных см. по ссылке R tree index quick start and usage.