Skip to content

postgrespro/demodb

Repository files navigation

Генератор демобазы

Назначение

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

Программу также можно использовать как генератор нагрузки, например для демонстрации систем мониторинга или тренировки оптимизации запросов.

Установка

Подключитесь в psql к любой базе, кроме demo, убедитесь, что находитесь в каталоге репозитория, и выполните установку:

\! pwd
\i install

При необходимости смените текущий каталог командой \cd.

В ходе установки будет заново создана база данных demo. Если она существовала, то все данные в ней будут потеряны! В этой базе данных будут созданы две схемы: gen для объектов генератора и bookings для создаваемой демобазы.

Устанавливаются расширения btree_gist (для реализации темпорального ключа), earthdistance и cube (для расчета расстояний на сфере), а также dblink (для запуска параллельных процессов). Эти расширения входят в стандартный набор, но убедитесь, что они присутствуют в вашей установке PostgreSQL.

Быстрый старт

Генерация запускается процедурой generate, которой передаются начальное и конечное модельное время (которое будет фигурировать в таблицах демобазы). Например:

CALL generate( now(), now() + interval '1 year' );

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

Чтобы ускорить работу, можно запустить генерацию в нескольких параллельных процессах:

CALL generate( now(), now() + interval '1 year', 4 );

Работа в любом случае выполняется в параллельных процессах (даже если такой процесс один), поэтому команда CALL немедленно возвращает управление.

Быстро проверить состояние генерации можно запросом:

SELECT busy();

Истинное значение будет означать, что генерация еще в процессе.

Более полное представление о процессе можно получить, наблюдая за журналом сообщений генератора:

SELECT * FROM gen.log ORDER BY at DESC LIMIT 30 \watch 60

Разрыв соединения не завершает работу генератора. Прервать генерацию досрочно можно командой:

CALL abort();

После успешного окончания генерации полезно ознакомиться с получившимися характеристиками:

\i check.sql

Если все в порядке, полученную демобазу можно выгрузить в виде SQL-скрипта. Для этого в операционной системе выполните команду, находясь в каталоге репозитория:

./export.sh > `date +%Y%m%d`.sql

Генерацию можно продолжить с того момента, на котором она остановилась. Например, сгенерировать данные еще за три месяца:

CALL continue( now() + interval '1 year 3 month', 4 );

Настройка

Генерация настраивается рядом конфигурационных параметров. Доступ к значениям параметров должны иметь параллельные процессы, поэтому установка на уровне сеанса (SET) не сработает. Удобнее всего устанавливать параметры на уровне базы данных:

ALTER DATABASE demo SET gen.имя-параметра = значение;

(Внутренние настройки не вынесены на уровень пользователя, но присутствуют в исходном коде в виде immutable-функций; неудачные значения могут привести к ошибкам генерации или к неожиданным результатам. Часть настроек и вовсе никуда не вынесена и присутствует в коде только в виде констант.)

gen.connstr

Строка подключения к базе данных demo.

Значение по умолчанию dbname=demo, что соответствует подключению к локальному серверу. При необходимости укажите любые параметры, допускаемые libpq.

gen.airlines_name

Название авиакомпании. Появляется только в значении, возвращаемом функцией bookings.version.

Значение по умолчанию PostgresPro.

gen.airlines_code

Код авиакомпании. Используется как префикс номеров билетов bookings.tickets.ticket_no.

Значение по умолчанию PG.

gen.traffic_coeff

Коэффициент для пересчета относительного пассажиропотока gen.airports_data.traffic в количество бронирований из данного аэропорта в неделю.

gen.domestic_frac

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

Значение по умолчанию 0.9.

gen.roundtrip_frac

Доля бронирований, при которых билеты покупаются «туда и обратно». Это целевое значение; в реальности доля будет меньше из-за того, что обратные билеты не всегда доступны.

Значение по умолчанию 0.9.

gen.delay_frac

Доля задержанных рейсов.

Значение по умолчанию 0.05.

gen.cancel_frac

Доля отмененных рейсов.

Значение по умолчанию 0.005.

gen.exchange

Коэффициент пересчета минут полета в стоимость билета в предпочитаемой валюте. В зависимости от класса обслуживания применяется дополнительный повышающий коэффициент (функция get_price).

Значение по умолчанию 50.

gen.max_pass_per_booking

Максимальное количество пассажиров в одном бронировании.

Значение по умолчанию 5.

gen.min_transfer

Минимальное время в часах между пересадками. Уменьшение запаса на пересадку увеличивает количество рейсов, доступных для формирования маршрута, но и увеличивает шанс опоздать на стыковочный рейс при задержке предыдущего.

Значение по умолчанию 2.

gen.max_transfer

Максимальное время в часах между пересадками. Увеличение этого порога увеличивает количество рейсов, доступных для формирования маршрута, но где взять таких терпеливых пассажиров?

Значение по умолчанию 48.

gen.max_hops

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

Значение по умолчанию 4.

gen.log_severity

Приоритет сообщений, попадающих в журнал gen.log. Наиболее важные сообщения имеют приоритет 0.

Значение по умолчанию 0, что означает, что записываются только важные сообщения. Большее значение имеет смысл устанавливать только для отладки.

bookings.lang

Язык, на котором в демобазе будут выводиться названия моделей самолетов, стран, городов и аэропортов. Это значение будет устанавливаться при развертывании демобазы, но впоследствии может быть изменено. Поддерживаются русский (ru) и английский (en) языки.

Значение по умолчанию en.

Программный интерфейс

Ряд процедур и функций образуют API, с помощью которого пользователь взаимодействует с генератором.

generate

Подпрограмма generate начинает генерацию демобазы. Ее параметры:

  • start_date (timestamptz) — модельное время начала генерации;
  • end_date (timestamptz) — модельное время окончания генерации;
  • jobs (integer) — количество параллельных процессов (по умолчанию 1).

Пример вызова:

CALL generate(
    start_date => date_trunc( 'day', now() ),
    end_date   => date_trunc( 'day', now() + interval '1 year' ),
    jobs       => 4
);

continue

Подпрограмма continue продолжает генерацию демобазы после останова прошлого вызова generate или continue. Ее параметры:

  • end_date (timestamptz) — модельное время окончания генерации;
  • jobs (integer) — количество параллельных процессов (по умолчанию 1).

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

Пример вызова:

CALL continue(
    end_date   => date_trunc( 'day', now() + interval '2 years' ),
    jobs       => 4
);

busy

Функция busy возвращает текущее состояние генерации: true — работает, false — завершилась.

Пример вызова:

SELECT busy();

abort

Процедура abort досрочно прерывает генерацию. После прерывания можно начать генерацию заново с помощью generate, но вызов continue не гарантирует корректного продолжения.

Пример вызова:

CALL abort();

get_passenger_name

Функция get_passenger_name выдает случайное имя пассажира из указанной страны.

Параметр:

  • country (text) — код страны.

Справочники генератора содержат имена, записанные латиницей, для следующих стран: Россия (RU), Китай (CN), Индия (IN), США (US), Канада (CA), Япония (JP), Франция (FR), Германия (DE), Италия (IT), Великобритания (GB), Чили (CL), Швеция (SE), Непал (NP), Финляндия (FI), Новая Зеландия (NZ), Австрия (AT) и Чехия (CZ).

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

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

CALL calc_names_cume_dist(); -- необходимо выполнить один раз
SELECT get_passenger_name('NP') FROM generate_series(1,10);

Журнальная таблица

Генератор записывает сообщения в журнальную таблицу gen.log, которую можно исследовать после генерации или использовать в процессе генерации для мониторинга:

SELECT * FROM gen.log ORDER BY at DESC LIMIT 30 \watch 60

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

Ниже перечислены основные типы сообщений и их значение.

  • Job N (connname=соединение): результат

    Запуск рабочего процесса номер N, используя соединение с именем соединение.

  • день: one day in время

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

  • New bookings: B (forceoneway F), nopath P, noseat S

    За день модельного времени было создано B бронирований. Из них F штук планировались как бронирования «туда и обратно» (с учетом значения параметра gen.roundtrip_frac), но из-за отсутствия нужных билетов бронь была сделана только в одну сторону. При этом P попыток создать бронирование полностью не удались из-за отсутствия подходящих рейсов, а S — из-за того, что на одном из выбранных рейсов не оказалось свободных мест.

  • Book-ref retries = R (F retries/booking)

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

    Чем дольше работает генератор, тем больше номеров будет занято и тем больше времени будет уходить на поиск свободного значения. Емкость номера бронирования составляет около 2 млрд значений; за один модельный год при настройках по умолчанию генерируется около 5 млн бронирований, поэтому на горизонте нескольких модельных лет эта причина не вызывает замедления.

  • New boarding passes: BP

    За день модельного времени было создано BP посадочных талонов.

  • Building routes, range период

    Выполняется перестроение маршрутов с периодом действия период. После этого сообщения идет перечисление новых маршрутов.

  • А1 -> A2: модель x N, traffic = P pass/week

    Построен маршрут из аэропорта А1 в аэропорт А2. Он выполняется самолетом модель N раз в неделю, предполагаемый пассажиропоток составляет P пассажиров в неделю.

  • Cannot choose an aircraft for А1 -> А2 (out of range?)

    Маршрут из аэропорта А1 в аэропорт А2 не удалось построить. Обычная причина состоит в том, что расстояние между аэропортами превышает дальность всех самолетов компании. Само по себе такое сообщение не является ошибкой, но может указывать на неудачно выбранный флот, если повторяется многократно.

  • Vacuum

    Выполнение очистки и анализа.

  • End date reached, exiting

    Рабочий процесс завершил свою работу.

Скрипт проверки

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

\i check.sql

Скрипт выполняет несколько запросов, описанных ниже.

Generation errors in log

Число, отличное от нуля, означает, что в процессе генерации произошли ошибки. Ошибки будут записаны в журнальную таблицу gen.log и будут начинаться со слова Error.

Generation stats

Запросы этой секции показывают количество сгенерированных бронирований, билетов, перелетов, рейсов и маршрутов.

Generation speed

Скорость генерации в событиях в секунду.

Рассчитанная скорость включает и время простоя между вызовами generate и continue.

Airplanes utilization

Первый запрос показывает среднюю заполненность салонов самолетов.

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

Третий запрос показывает список моделей самолетов и количество маршрутов, которые эта модель обслуживала. Учтите, что в разные периоды времени один и тот же маршрут может обслуживаться разными самолетами, поэтому выведенные числа не стоит складывать. Вердикт NOT USED означает, что модель не выполнила ни одного рейса — такую модель, скорее всего, стоит заменить. Вердикт WRONGLY USED свидетельствует об ошибке в алгоритме и не должен появляться.

Roundtrips to overall tickets

Отношение количества билетов «туда и обратно» к общему количеству билетов. Второе число показывает целевое значение (заданное параметром gen.roundtrip_frac). Реальное значение всегда будет меньше целевого из-за того, что не для каждого прямого билета удается купить обратный.

Passengers per booking

Вердикт ERROR: max_pass_per_bookings not satisfied говорит о том, что в бронированиях бывает более gen.max_pass_per_booking пассажиров и свидетельствует об ошибке в алгоритме.

Второй запрос показывает распределение бронирований по количеству пассажиров в них. Например, строка с npass, равным 2, и cnt, равным 100, говорит о том, что сто бронирований включают двух пассажиров.

Frequent flyers

Запрос показывает распределение пассажиров по количеству выполненных ими бронирований. Например, строка с nbook, равным 3, и cnt_pass, равным 1000, говорит о том, что тысяча пассажиров сделали по три бронирования.

Segments per ticket

Запрос показывает распределение билетов по количеству перелетов в них. Например, строка с segments, равным 3, и cnt, равным 1000, говорит о том, что тысяча билетов включает три перелета.

Flight statuses

Количество рейсов в разных статусах.

Три статуса, в которых рейсов немного, независимо от размера базы, — это On Time (вылет по расписанию), Departed (вылетел и находится в воздухе) и Boarding (посадка пассажиров). Если таких рейсов нет, возможно стоит продолжить генерацию на несколько модельных часов, чтобы обеспечить разнообразие данных.

Flight durations

Вердикт ERROR: route and flight discrepancy в первом запросе говорит о рассогласовании данных о продолжительности полетов между таблицами routes и flights и свидетельствует об ошибке в алгоритме.

Второй запрос показывает минимальную, среднюю и максимальную продолжительность полетов — как запланированную, так и реальную.

Flight delays

Минимальная, средняя и максимальная задержка вылетов и прибытий.

Overbookings

Вердикт ERROR: overbooking говорит о том, что посадочных талонов выдано больше, чем мест в самолете, и свидетельствует об ошибке в алгоритме.

Cancelled flights fraction

Доля отмененных рейсов и целевое значение (параметр gen.cancel_frac). Должны совпадать с хорошей точностью.

Adjacency of segments

Вердикт ERROR: non-adjacent segments говорит о том, что аэропорт прибытия одного перелета не совпадает с аэропортом вылета следующего перелета из того же билета. Это свидетельствует об ошибке в алгоритме.

Routes validity ranges

Вердикт ERROR: validity ranges have holes говорит о наличии пропусков между периодами действия маршрутов. Это свидетельствует об ошибке в алгоритме.

Flights consistency with routes

Вердикт ERROR: absent flights говорит о том, что в таблице flights отсутствуют рейсы, которые должны быть согласно таблице routes.

Вердикт ERROR: excess flights говорит о том, что в таблице flights есть рейсы, не соответствующие расписанию в таблице routes.

Возможны оба сообщения одновременно (absent and excess flights). Любая ошибка свидетельствует об ошибке в алгоритме.

Timings

Вердикт первого запроса ERROR: flights timing discrepancy говорит о рассогласовании времен в информации о рейсе.

Вердикт второго запроса ERROR: boarding after takeoff говорит о том, что посадка пассажиров продолжалась после взлета.

Вердикт третьего запроса ERROR: booking after boarding говорит о том, что бронирование на рейс продолжалось после начала посадки пассажиров.

Любая ошибка в этой секции свидетельствует об ошибке в алгоритме.

Miss the flight

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

Первый запрос выводит фактическое количество пассажиров, опоздавших на рейс, а также количество некорректно зарегистрированных генератором опозданий и количество незарегистрированных генератором опозданий. Вердикт ERROR: incorrect missed flights свидетельствует об ошибке в алгоритме.

Вердикт второго запроса ERROR: boarding after miss говорит о том, что пассажир садился в самолет после опоздания и свидетельствует об ошибке в алгоритме.

Interlaced flights

Вердикт ERROR: interlaced flights говорит о том, что один и тот же пассажир совершал более одного путешествия одновременно. Это свидетельствует об ошибке в алгоритме.

Экспорт демобазы

Сгенерированную демобазу можно выгрузить в виде SQL-скрипта, аналогичного результату работы команды pg_dump. Находясь в каталоге репозитория выполните скрипт, перенаправляя его результат в файл, например:

./export.sh | gzip > `date +%Y%m%d`.sql.gz

Скрипту можно передать любые параметры подключения, принимаемые утилитой pg_dump.

В SQL-скрипт будут входить объекты схемы booking, включая определения функций bookings.now (значение конечной модельной даты, указанной при генерации) и bookings.version (версия сгенерированной демобазы). Также будут включены команды для установки параметров bookings.lang и search_path на уровне базы данных.

Внутреннее устройство

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

Все таблицы генератора располагаются в схеме gen. Они используются при генерации и хранят ее текущее состояние. Далее, если имя схемы не указано, предполагается схема gen.

Таблицы демобазы находятся в схеме bookings и описаны в документации по демобазе.

events

Очередь событий. Очередь обрабатывается процедурой process_queue, а отдельное событие - процедурой process_event.

Ниже перечислены типы событий.

INIT

Это «затравочное» событие, обработка которого (процедура do_init) приводит к инициализации состояния всех таблиц и вставке начального набора событий: BUILD ROUTES, BOOKING, VACUUM, MONITORING.

BUILD ROUTES

Событие перестройки маршрутов. При его обработке (процедура build_routes) создается случайный, но связный граф маршрутов. В маршрутной сети участвуют аэропорты, имеющие непустое значение traffic в таблице airports_data. Перелеты между несколькими аэропортами одного города никогда не создаются.

Добавляемые ребра графа записываются в таблицу directions. Вначале от каждого аэропорта, начиная с наименее загруженного, добавляются ребра к двум другим случайным аэропортам. Вероятность добавления ребра пропорциональна трафику аэропорта назначения и обратно пропорциональна расстоянию между аэропортами. При этом с вероятностью gen.domestic_frac выбирается аэропорт той же страны (при наличии в маршрутной сети хотя бы двух городов этой страны).

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

Новые маршруты переносятся из directions в таблицу bookings.routes с соответствующим интервалом действия validity. Самолет, обслуживающий маршрут, и количество рейсов в неделю подбираются исходя из прогнозируемого трафика между аэропортами (таблица week_traffic).

Первое событие BUILD ROUTES добавляется при обработке INIT и порождает расписание на месяц, начиная с даты начала генерации. Далее маршруты перестраиваются каждый месяц, для чего в конце обработки события в очередь вставляется следующее событие BUILD ROUTES. Также для каждого построенного маршрута добавляется событие FLIGHT, отмечающее начало бронирований на этот маршрут за месяц до его вступления в силу.

BOOKING

Событие бронирования из заданного аэропорта. При его обработке (процедура make_booking) совершается попытка бронирования путешествия в случайный аэропорт. Вероятность выбора целевого аэропорта пропорциональна его трафику и обратно пропорциональна расстоянию между аэропортами, а также учитывает параметр gen.domestic_frac (как и при создании расписания).

Маршрут до выбранного аэропорта определяется (функция get_path) с учетом следующих факторов:

  • предпочтению отдается маршруту с наименьшим количеством пересадок, причем их количество не должно превышать gen.max_hops;
  • рассматриваются рейсы, на которые в продаже есть билеты и осталось достаточно времени до отправления (еще не открыта регистрация на рейс);
  • между стыковочными рейсами должно быть как минимум gen.min_transfer часов (иначе велик риск пропустить рейс из-за возможной задержки) и не должно быть больше gen.max_transfer часов (иначе слишком долго ждать);
  • среди возможных маршрутов выбирается тот, чей первый перелет начинается раньше.

Количество пассажиров в бронировании определяется случайно с учетом параметра gen.max_pass_per_booking.

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

С вероятностью gen.roundtrip_frac выполняется также попытка забронировать полет в обратном направлении через случайный интервал времени (до месяца, в среднем — около недели). Маршрут обратного следования может не совпадать с исходным маршрутом. Неуспешная попытка не отменяет бронирования в прямом направлении.

В результате бронирования создается строка в таблице bookings.bookings, строки для каждого билета в bookins.tickets (по одной на каждого пассажира и направления следования), строки в таблице перелетов bookings.segments.

Следующее событие BOOKING для данного аэропорта-источника создается так, чтобы события образовывали пуассоновский поток с частотой, соответствующей пассажиропотоку аэропорта. В среднем в неделю будет генерироваться airports_data.traffic умноженное на значение параметра gen.traffic_coeff событий бронирования.

FLIGHT

Событие добавления рейса в расписание за месяц до отправления.

Обработчик (процедура open_booking) вставляет строку в таблицу bookings.flights для рейса, открывая возможность бронирования (статус Scheduled). С вероятностью gen.cancel_frac рейс отменяется (статус Cancelled). Отмена всегда происходит заранее: не бывает ситуаций, когда рейс отменяется уже после того, как на него куплены какие-либо билеты.

За день до отправления неотмененного рейса на него должна открыться регистрация, за это отвечает добавляемое событие REGISTRATION.

REGISTRATION

Событие открытия регистрации на рейс за день до отправления.

Обработчик (процедура registration) меняет статус рейса на On Time и определяет фактическое время начала регистрации (допустима небольшая задержка на несколько минут). С вероятностью gen.delay_frac рейс задерживается (статус Delayed) на время от часа до 12 часов.

Создает события регистрации CHECK-IN для каждого билета, проданного на данный рейс (регистрация заканчивается за 40 минут до отправления). Также создает событие начала посадки BOARDING на этот рейс.

CHECK-IN

Событие регистрации на рейс для конкретного билета.

Пассажир проходит регистрацию только один раз, на первый рейс в билете. Обработчик (процедура check_in) создает строки в таблице bookings.boarding_passes для посадочных талонов на каждый рейс в билете (мы считаем, что все рейсы в билете являются стыковочными).

BOARDING

Событие начала посадки на рейс за полчаса до вылета.

Обработчик (процедура boarding) меняет статус рейса на Boarding и создает события посадки GET IN для каждого билета, проданного на рейс. Посадка завершается в течение 20 минут.

Если посадка заканчивается до конца периода генерации, события GET IN не создаются, а вместо этого номер и время посадки проставляются в посадочных талонах (таблица bookings.boarding_passes) немедленно. Эта оптимизация позволяет существенно сократить количество событий и ускорить генерацию.

Также создает событие взлета TAKEOFF, определяя фактическое время вылета (допускается небольшая задержка на несколько минут).

GET IN

Событие посадки в самолет для конкретного билета.

Обработчик (процедура get_in) проставляет номер и время посадки в посадочном талоне (таблица bookings.boarding_passes).

TAKEOFF

Событие взлета.

Обработчик (процедура takeoff) меняет статус рейса на Departed и создает событие приземления LANDING, определяя фактическую продолжительность полета (возможно отклонение от плановой продолжительности на несколько процентов как в одну, так и в другую сторону).

LANDING

Событие приземления.

Обработчик (процедура landing) меняет статус рейса на Arrived. На этом рейс считается отработанным; новых событий не генерируется.

VACUUM

Событие очистки.

Обработка очереди событий происходит хотя и в разных транзакциях, но в одном операторе CALL. Из-за этого статистика изменения таблиц не передается сборщику статистики: автоочистка не имеет представления, что содержимое таблиц меняется, и не срабатывает.

Поэтому раз в неделю модельного времени очистка и анализ запускаются принудительно с помощью данного события (процедура vacuum). Запуск происходит в отдельном процессе с помощью расширения dblink.

MONITORING

Событие мониторинга.

Событие срабатывает раз в день модельного времени и заносит в журнальную таблицу log сведения о прошедшем дне (процедура monitoring).

event_history

В эту таблицу переносятся отработанные строки из events для возможности отладки.

airplanes_data

Данные о моделях самолетов. В таблицу bookings.airplanes_data переносятся все строки и все столбцы, за исключением столбца in_use, который определяет, надо ли назначать данную модель на рейсы.

seats

Данные о конфигурации салонов самолетов. Все данные переносятся без изменений в таблицу bookings.seats.

seats_remain

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

airports_data

Данные об аэропортах. В таблицу bookings.airports_data переносятся все строки и все столбцы, за исключением столбцов:

  • country_code — двухсимвольный код страны в соответствии с ISO 3166-1 alpha-2 (попадает в номер билета bookings.tickets.ticket_no);
  • traffic — относительный пассажиропоток авиакомпании в данном аэропорту (абсолютное количество попыток бронирований в неделю из данного аэропорта вычисляется умножением этой величины на значение параметра gen.traffic_coeff).

directions

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

directions_connect

Используется для определения связности графа перелетов.

airports_to_prob

Хранит предварительно вычисленные накопленные вероятности полета из одного аэропорта в другой (не обязательно связанных прямым рейсом) и используется при составлении графа перелетов и для выбора аэропорта назначения при бронировании.

week_traffic

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

firstnames

Данные о популярности имен (given names) в разбивке по странам. Таблица позволяет разделить имена одной страны на группы, например, на мужские и женские для тех языков, в которых фамилия зависит от пола. При инициализации в столбец cume_dist заносится накопленная вероятность выбора данного имени.

lastnames

Данные о популярности фамилий (family names) в разбивке по странам. Таблица позволяет разделить фамилии одной страны на группы. При инициализации в столбец cume_dist заносится накопленная вероятность выбора данной фамилии.

passengers

Перечень уникальных пассажиров. Таблица используется генератором, чтобы гарантировать, что одному номеру документа passenger_id соответствует одно имя, а также что один пассажир не участвует в нескольких одновременных поездках. Информация из этой таблицы не переносится в демобазу, в которой нет отдельной сущности «пассажир».

missed_flights

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

stat_bookings

Статистика по бронированиям. Используется для мониторинга генерации.

stat_jobs

Статистика по параллельным процессам. В норме счетчики обработанных событий для каждого процесса должны быть примерно равны. Если счетчик какого-либо процесса не увеличивается во время генерации, следует искать сообщение об ошибке в журнале log.

stat_bookrefs

Статистика по количеству повторов, которые потребовались для генерации уникального номера бронирования book\_ref.

Вопросы и ответы

Как добавить перевод названий на новый язык?

В демобазе язык перевода выбирается параметром bookings.lang. Переводятся названия моделей самолетов (представление airplanes), а также названия аэропортов, городов и стран (представление airports). В настоящий момент имеются переводы на два языка: русский (значение параметра ru) и английский (en).

Чтобы добавить новый язык, необходимо добавить переводы в JSON-столбцы airplanes_data.model, airports_data.airport_name, airports_data.city и airports_data.country. Это непростая задача, поскольку в таблице аэропортов содержится около 5500 строк. Как минимум нужно перевести хотя бы строки с непустым значением пассажиропотока (traffic), участвующие в маршрутной сети.

Как изменить флот авиакомпании?

Желаемые модели самолетов и конфигурацию их салонов необходимо поместить в таблицы airplanes_data и seats. Все они будут перенесены в аналогичные bookings-таблицы. В рейсах будут участвовать только самолеты с признаком in_use.

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

Вместимость самолетов должна соответствовать планируемому пассажиропотоку: рейс выполняется минимум раз в неделю и максимум семь раз в неделю. Без должного разнообразия вместимостей все рейсы могут оказаться переполненными или недозаполненными.

Каков критерий выбора стран для демобазы?

Были выбраны страны ведущих разработчиков PostgreSQL (major contributors), а также несколько других стран, имеющих определенное отношение к PostgreSQL.

Вы можете добавить и другие страны (см. ниже).

Каков критерий выбора количества городов?

Количество городов в демобазе пропорционально квадрату суммы логарифмов площадей стран и численности их населения:

$$ 0,5 ( log( площадь, км^2 ) + log( население, млн ) - 5 )^2 $$

Вы можете сделать другой выбор (см. ниже).

Как изменить маршрутную сеть в пределах существующих стран и городов?

Установите непустое значение пассажиропотока traffic для желаемых аэропортов в таблице airports_data. Эти аэропорты и будут использоваться в маршрутах.

Как добавить новую страну?

При добавлении новой страны недостаточно просто выбрать аэропорты в таблице airports_data. Потребуется также определить справочники имен для новой страны.

В настоящее время справочники генератора содержат имена, записанные латиницей, для следующих стран: Россия (RU), Китай (CN), Индия (IN), США (US), Канада (CA), Япония (JP), Франция (FR), Германия (DE), Италия (IT), Великобритания (GB), Чили (CL), Швеция (SE), Непал (NP), Финляндия (FI), Новая Зеландия (NZ), Австрия (AT) и Чехия (CZ).

Полное имя пассажира формируется из имени (given name) и фамилии (family name), поэтому в качестве исходных данных необходимо иметь список имен и фамилий и их относительную частоту. В качестве такого списка можно, например, использовать данные переписи населения. В простом случае, если по правилам языка страны фамилия не склоняется в зависимости от рода имени (как, например, в германских и романских языках, таких как английский или французский), таких исходных данных будет достаточно.

Имена необходимо добавить в таблицу firstname:

  • country — двухсимвольный код страны в соответствии с ISO 3166-1 alpha-2;
  • name — имя;
  • qty — целое число, отражающее популярность имени (например, зарегистрированное количество людей, носящих данное имя).

В столбец grp поместите значение -.

Фамилии добавляются в таблицу lastnames с той же структурой.

Чтобы проверить результат, можно выполнить такой запрос, где XX — код страны:

CALL calc_names_cume_dist(); -- рассчитывает накопленную вероятность
SELECT get_passenger_name('XX') FROM generate_series(1,10);

Для языков, в которых фамилии зависят от рода имени (например, славянские и балтийские языки, такие как русский), потребуется разделить все имена и все фамилии на мужские и женские с помощью столбца grp. В этот столбец можно поместить любое текстовое значение, но оно должно совпадать в обеих таблицах (например, можно использовать m и f).

Имена, относящиеся как к мужским, так и к женским, должны быть помещены в обе группы (возможно, с разной популярностью).

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

При генерации имени сначала из всех групп выбирается случайная фамилия, а затем выбирается случайное имя из той группы, к которой принадлежит фамилия. При этом полные имена, в которых имя (given name) и фамилия (family name) одинаковы, не выбираются.

Как добавить новый аэропорт?

Добавьте строку в таблицу airports_data. Для этого необходимо знать:

  • Код ИАТА;
  • Английское название аэропорта;
  • Английское название города;
  • Часовой пояс;
  • Координаты аэропорта (указываются в формате «долгота, широта»).

Полной актуальной базы аэропортов нет в свободном доступе. Существует несколько открытых проектов (OpenFlights, OurAirports, DataHub), но полнота и актуальность их информации под вопросом. Конкретный аэропорт можно проверить на официальном сайте ИАТА.

Название аэропорта и города необходимо перевести на русский язык (и другие языки, если они должны поддерживаться настройкой многоязычности bookings.lang).

Чтобы новая запись была согласована с существующими, стоит придерживаться некоторых правил.

В качестве города (city) выбирается город, который обслуживается этим аэропортом. Часто это ближайший к аэропорту крупный населенный пункт, а не тот пункт, в котором расположен аэропорт. Например, для IAR городом является Ярославль, а не село Туношна.

Официальное название аэропорта часто состоит из названия населенного пункта, в котором расположен аэропорт, посвящения какому-либо видному деятелю и других частей. Для краткости имя сокращается по следующим правилам:

  • Название города не повторяется в названии аэропорта (за исключением случаев, когда официальное название состоит только из названия города, например, AAC «El Arish»);
  • В качестве названия аэропорта используется либо название населенного пункта, где расположен аэропорт, либо имя человека, причем предпочтение отдается населенному пункту (например, SVO «Шереметьево имени А. С. Пушкина» сокращается до «Шереметьево»).
  • Если используется посвящение человеку, титулы и воинские звания отбрасываются (например, YAI «General Bernardo O'Higgins» сокращается до «Bernardo O'Higgins»);
  • Отбрасываются слова «международный», «региональный» и т. п. (например, ROA «Roanoke–Blacksburg Regional» сокращается до «Blacksburg», учитывая, что Roanoke — название города).
  • В русском языке промежуточные инициалы убираются (например, JFK «John F. Kennedy» переводится как «Джон Кеннеди»).

About

Demonstration Database

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published