examples
Данный пример сработает на конфигурации из песочницы, описанной в предисловии, то есть создан спейс под названием tester с первичным числовым ключом. Функция в примере выполнит следующие действия:
- выбрать кортеж, значение ключа которого – 1000;
- вызвать ошибку, если кортеж уже существует и содержит 3 поля;
- вставить или заменить кортеж следующими значениями:
- field[1] = 1000
- field[2] = UUID
- field[3] = количество секунд с 1970-01-01;
- получить field[3] из замененного кортежа;
- отформатировать значение из field[3] в виде yyyy-mm-dd hh:mm:ss.ffff;
- Вернуть отформатированное значение. Функция использует функции 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, dlocal replaced_tuple, time_fieldlocal formatted_time_fieldlocal fiber = require('fiber')table_of_selected_tuples = box.space.tester:select{1000}if table_of_selected_tuples ~= nil thenif table_of_selected_tuples[1] ~= nil thenif #table_of_selected_tuples[1] == 3 thenbox.error({code=1, reason='This tuple already has 3 fields'})endendendreplaced_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 % 1d = string.sub(c, 3, 6)formatted_time_field = formatted_time_field .. '.' .. dreturn formatted_time_fieldend
Результат вызова функции:
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 endsearch_key = page[#page][1]iterator_string = "GT"return pageendend
Разработчикам, использующим paged_iter, необязательно знать, почему
она работает, следует лишь понимать, что вызвав функцию в цикле, можно
получать 10 кортежей за раз до тех пор, пока кортежи не кончатся.
В данном примере кортежи лишь выводятся по странице за раз. Но легко изменить функцию, например, путем передачи управления после каждой выборки или с помощью прерывания, если кортежи не будут соответствовать дополнительным критериям.
for page in paged_iter("X", 10) doprint("New Page. Number Of Tuples = " .. #page)for i = 1, #page, 1 doprint(page[i])endend
Этот вложенный модуль может использоваться для поиска в пространственных данных, если тип индекса – RTREE. Существуют операции для поиска прямоугольников (геометрические фигуры с 4 углами и 4 сторонами) и параллелепипедов (геометрические фигуры с количеством углов более 4 и количеством сторон более 4, которые иногда называются гиперпрямоугольниками). В данном руководстве используется термин прямоугольник-или-параллелепипед для всего класса объектов, который включает в себя прямоугольники и параллелепипеды. Примерами иллюстрируются только прямоугольники.
Прямоугольники описаны в соответствии с координатами по оси X (горизонтальной оси) и оси Y (вертикальной оси) на сетке произвольного размера. Ниже представлен рисунок четырех прямоугольников на сетке с 11 горизонтальными точками и 11 вертикальными точками:
X AXIS1 2 3 4 5 6 7 8 9 10 1112 #-------+ <-Прямоугольник №1Y AXIS 3 | |4 +-------#5 #-----------------------+ <-Прямоугольник №26 | |7 | #---+ | <-Прямоугольник №38 | | | |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](#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.