kdb+

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 16:17, 19 мая 2020.

kdb+
Kx logo.png
Создатели: Arthur Whitney
Разработчики: Kx Systems
Выпущена: 2003; 17 years ago (2003)
Написана на: q
Операционная система: Windows, macOS, Linux, Solaris
Платформа: IA-32, x86-64, SPARC (Scalable Processor ARChitecture)
Локализация: English
Тип ПО: Реляционная база данных временных рядов
Лицензия: Proprietary software
Веб-сайт code.kx.com

KDB+ — это колоночная база данных, ориентированная на очень большие объемы данных, упорядоченные определенным образом (в первую очередь по времени). Используется она, в первую очередь, в финансовых организациях – банках, инвестиционных фондах, страховых компаниях. Язык Q – это внутренний язык KDB+, позволяющий эффективно работать с этими данными. Идеология Q – это краткость и эффективность, понятность при этом приносится в жертву. Обосновывается это тем, что векторный язык в любом случае будет сложен для восприятия, а краткость и насыщенность записи позволяет увидеть на одном экране гораздо большую часть программы, что в итоге облегчает ее понимание.[Источник 1].

История

Компания KX была основана в 1993 году Артуром Уитни, который до этого работал в банке Морган Стэнли над языком A+, наследником APL — очень оригинальным и в свое время популярным языком в финансовом мире. Разумеется, в KX Артур продолжил в том же духе и создал векторно-функциональный язык K, руководствуясь идеями радикального минимализма. Программы на K выглядят как беспорядочный набор знаков препинания и специальных символов, смысл знаков и функций зависит от контекста, и каждая операция несет в себе намного больше смысла, чем это бывает в привычных языках программирования. За счет этого программа на K занимает минимум места — несколько строчек могут заменить страницы текста многословного языка типа Java — и является сверхконцентрированной реализацией алгоритма.[Источник 2].

Эту философию экстремальной эффективности при минимуме телодвижений Артур воплотил и в KDB+, которая появилась в 2003 году и есть ни что иное, как интерпретатор четвертой версии языка K. Поверх K добавлена более приятная взгляду пользователя версия K под названием Q. В Q также добавлена поддержка специфического диалекта SQL— QSQL, а в интерпретатор — поддержка таблиц, как системного типа данных, средств работы с таблицами в памяти и на диске и т.п.

Основные положения

С точки зрения пользователя KDB+ — это просто интерпретатор языка Q с поддержкой таблиц и похожих на SQL выражений в стиле LINQ из C#. Это важнейшее отличие KDB+ от других баз данных и главное ее конкурентное преимущество, которое часто упускают из вида. Это не база данных совместно со вспомогательным языком, а полноценный мощный язык программирования со встроенной поддержкой функций базы данных. Это различие играет определяющую роль в формировании преимуществ KDB+ относительно схожих бах данных.

Преимущества

Размер

По современным меркам KDB+ имеет просто микроскопический размер. Это в буквальном смысле один исполняемый файл размером меньше мегабайта и один небольшой текстовый файл с некоторыми системными функциями.

  • Такой размер позволяет KDB+ прекрасно себя чувствовать на любом железе — от микрокомпьютера Pi до серверов с терабайтами памяти. На функциональность это никак не влияет, более того стартует Q мгновенно, что позволяет его использовать в том числе как скриптовой язык.
  • При таком размере интерпретатор Q полностью помещается в кэш процессора, что ускоряет выполнение программ.
  • При таком размере исполняемого файла процесс Q занимает ничтожно мало места в памяти, можно запускать их сотнями. При этом при необходимости Q может оперировать и десятками-сотнями гигабайт памяти в рамках одного процесса.

Универсальность

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

С той же легкостью Q может быть in-memory базой данных. Добавление новых данных к таблицам в памяти происходит настолько быстро, что лимитирующим фактором являются запросы пользователей. Данные в таблицах хранятся по колонкам, а значит любая операция по колонке будет использовать кэш процессора на полную мощность. В добавление к этому в KX постарались реализовать все базовые операции типа арифметических через векторные инструкции процессора, максимизируя их скорость. Q может выполнять и задачи не свойственные базам данным — например, обрабатывать потоковые данные и вычислять в «реальном времени» (с задержкой от десятков миллисекунд до нескольких секунд в зависимости задачи) различные агрегирующие функции для финансовых инструментов для разных временных интервалов или строить модель влияния совершенной сделки на рынок и проводить ее профилирование практически сразу после ее совершения. В таких задачах чаще всего основную временную задержку вносит не Q, а необходимость синхронизации данных из разных источников. Высокая скорость достигается благодаря тому, что данные и функции, которые их обрабатывают, находятся в одном процессе, а обработка сводится к выполнению нескольких QSQL выражений и джойнов, которые не интерпретируются, а выполняются бинарным кодом.

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

Скорость

Хотя Q является интерпретируемым языком, это одновременно векторный язык. Это означает, что многие встроенные функции, в частности, арифметические, принимают аргументы любой формы — числа, вектора, матрицы, списки, а от программиста ожидается, что он будет реализовывать программу как операции над массивами. В таком языке, если вы складываете два вектора по миллиону элементов, уже не играет роли, что язык интерпретируемый, сложение будет производиться супероптимизированной бинарной функцией. Поскольку львиная доля времени в программах на Q уходит на операции с таблицами, использующими эти базовые векторизованные функции, то на выходе имеем весьма приличную скорость работы, позволяющую обрабатывать огромный объем данных даже в одном процессе. Это похоже на математические библиотеки в Python — хотя сам Python язык весьма небыстрый, в нем есть много прекрасных библиотек типа numpy, которые позволяют обрабатывать числовые данные со скоростью компилируемого языка (к слову, numpy идеологически близка к Q).

Помимо этого в KX весьма тщательно подошли к проектированию таблиц и оптимизации работы с ними. Во-первых, поддерживается несколько видов индексов, которые поддерживаются встроенными функциями и могут быть применены не только к колонкам таблиц, но и к любым векторам — группировка, сортировка, атрибут уникальности и специальная группировка для исторических баз. Индекс накладывается элементарно и автоматически корректируется при добавлении элементов в колонку/вектор. Индексы одинаково успешно могут накладываться на колонки таблиц как в памяти, так и на диске. При выполнении QSQL запроса индексы используются автоматически, если это возможно. Во-вторых, работа с историческими данными сделана через механизм отображения файлов ОС (memory map). Большие таблицы никогда не грузятся в память, вместо этого нужные колонки отображаются непосредственно в память и реально грузится только та их часть (тут помогают в том числе и индексы), которая необходима. Для программиста нет разницы, находятся данные в памяти или нет, механизм работы с mmap полностью скрыт в недрах Q.

KDB+ реляционная база данных, таблицы могут содержать произвольные данные, при этом порядок строк в таблице не меняется при добавлении новых элементов и может и должен использоваться при написании запросов. Эта особенность остро необходима для работы с временными рядами (данные с бирж, телеметрия, логи событий), потому что если данные отсортированы по времени, то пользователю не нужно применять никаких SQL трюков, чтобы найти в таблице первую или последнюю по времени строку или N строк, определить какая строка следует за N-й строкой и т.п. Еще больше упрощаются джойны таблиц.

Недостатки

Существенным недостатком KDB+/Q является высокий порог вхождения. Язык имеет странный синтаксис, некоторые функции сильно перегружены (value, например, имеет порядка 11 вариантов использования). Самое главное, он требует радикально другого подхода к написанию программ. В векторном языке необходимо все время мыслить в терминах преобразований массивов, все циклы реализовывать через несколько вариантов функций map/reduce (которые называются adverbs в Q), никогда не пытаться сэкономить, заменяя векторные операции атомарными. Например, для нахождения индекса N-го вхождения элемента в массив следует писать:

(where element=vector)[N]

хотя это выглядит жутко неэффективно по меркам C/Java (= создает булевый вектор, where возвращает индексы true элементов в нем). Но такая запись делает смысл выражения более понятным и вы используете быстрые векторные операции вместо медленных атомарных. Концептуальная разница между векторным языком и остальными сравнима с разницей между императивным и функциональным подходами к программированию, и к этому надо быть готовым.

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

Как плюс книга по Q — Q For Mortals доступна бесплатно на сайте компании, также там собрано много других полезных материалов.

Еще один большой минус — стоимость лицензии. Это десятки тысяч долларов в год за один CPU. Только большие фирмы могут позволить себе такие траты. В последнее время KX сделала лицензионную политику более гибкой и предоставляет возможность платить только за время использования или арендовать KDB+ в облаках Google и Amazon. Также KX предлагает для скачивания бесплатную версию для некоммерческих целей (32 битная версия или 64-битная по запросу).

Архитектура

Kdb+ - это высокопроизводительная база данных, разрабатываемая с самого начала для обработки огромных объемов данных. Она полностью [x86-64|64-разрядная]] и имеет встроенную многоядерную обработку и многопоточность. База данных включает свой собственный мощный язык запросов q, с помощью которого можно анализировать данные непосредственно из базы, не используя сторонних приложений.[Источник 3]

kdb+tick-это архитектура, которая позволяет записывать, обрабатывать и запрашивать данные в реальном времени, а также исторические данные.

На рисунке 1 представлена обобщенная схема типичной архитектуры Kdb+ / tick.

Рисунок 1 – обобщенная схема типичной архитектуры Kdb+ / tick
  • Каналы данных (Data Feeds) -это данные временных рядов, которые в основном предоставляются поставщиками каналов данных, такими как Reuters, Bloomberg или непосредственно с бирж.
  • Чтобы получить соответствующие данные, данные из канала данных анализируются обработчиком канала (feed handler).
  • После того, как данные будут проанализированы обработчиком каналов, они переходит на ticker-plant.
  • Чтобы восстановить данные после любого сбоя, ticker-plant сначала обновляет / сохраняет новые данные в файле журнала, а затем обновляет свои собственные таблицы.
  • После обновления внутренних таблиц и файлов журналов данные непрерывно публикуются в базу данных реального времени и отправляются всем связанным подписчикам, которые запросили данные.
  • В конце рабочего дня файл журнала удаляется, создается новый и база данных реального времени сохраняется в исторической базе данных. После того, как все данные сохраняются в исторической базе данных, база данных в реальном времени удаляет свои таблицы.

Компоненты архитектуры Kdb+ Tick

Канал данных (Data Feeds)

Каналы данных могут быть любыми рыночными или другими данными временных рядов. Рассматривайте каналы данных в качестве необработанных входных данных для обработчика каналов. Каналы могут быть непосредственно с биржи (live-streaming data), от поставщиков новостей/данных, таких как Thomson-Reuters, Bloomberg или любых других внешних агентств.

Обработчик каналов (Feed handler)

Обработчик каналов преобразует поток данных в формат, подходящий для записи в kdb+. Он подключен к каналу данных и извлекает и преобразует данные из специфичного для канала формата в сообщение Kdb+, которое публикуется в процессе Ticker Plant. Обычно обработчик каналов используется для выполнения следующих операций

  • Захват данных в соответствии с набором правил.
  • Переформатирование эти данные из одного формата в другой.
  • Нахождение новых значений.

Ticker Plant

Ticker Plant[1] является важнейшим компонентом архитектуры KDB+. Именно с помощью Ticker Plant база данных или непосредственно абоненты (клиенты) получают доступ к финансовым данным. Он работает в механизме публикации и подписки. Он выполняет следующие операции:

  • Получает данные от обработчика каналов.
  • Сразу же после того, как Ticker Plant получает данные, он сохраняет копию в виде файла журнала и обновляет его, как только Ticker Plant получает любое обновление, так что в случае любого сбоя, не модет быть никакой потери данных.
  • Клиенты (абонент в режиме реального времени) могут напрямую подписаться на Ticker Plant.
  • В конце каждого рабочего дня, т.е. после того, как база данных реального времени получает последнее сообщение, он сохраняет все сегодняшние данные в исторической базе данных и отправляет то же самое всем подписчикам, которые подписались на сегодняшние данные. Затем он сбрасывает все свои таблицы. Файл журнала также удаляется после того, как данные сохранятся в исторической базе данных или в другой непосредственно связанной базе данных реального времени.
  • В результате, Ticker Plant, база данных реального времени и историческая база данных работают в режиме 24/7.

Поскольку Ticker Plant является частью Kdb+, его таблицы могут быть запрошены с помощью q. Также важно, что все клиенты ticker-plant должны иметь доступ к базе данных только в качестве подписчиков.

База данных в реальном времени

База данных реального времени (rdb) хранит сегодняшние данные. Она напрямую соединена с Ticker Plant. Обычно она будет храниться в памяти в течение дня и записываться в историческую базу данных (hdb) в конце дня. Поскольку данные (rdb data) хранятся в памяти, обработка происходит чрезвычайно быстро.

Поскольку kdb+ рекомендует иметь размер ОЗУ, который в четыре или более раз превышает ожидаемый размер данных в день, запрос, выполняемый на rdb, очень быстр и обеспечивает превосходную производительность. Поскольку база данных реального времени содержит только сегодняшние данные, столбец даты (параметр) не требуется.

Например, у нас могут быть запросы следующие запросы к rdb:

select from trade where sym = `ibm

или

select from trade where sym = `ibm, price > 100

Историческая база

Если необходимо рассчитать оценки компании, нужно иметь доступ к ее историческим данным. Историческая база данных (hdb) содержит данные о транзакциях, совершенных в прошлом. Запись каждого нового дня будет добавлена в hdb в конце дня. Большие таблицы в hdb либо хранятся в разнесенном виде (каждый столбец хранится в своем собственном файле), либо они хранятся секционировано по временным данным. Кроме того, некоторые очень большие базы данных могут быть дополнительно секционированы с помощью файла par.txt .

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

Историческая база данных может также использоваться для целей внутренней и внешней отчетности, т.е. для аналитики. Например, предположим, что мы хотим получить торги компании IBM за определенный день из таблицы "trade". Необходимо написать запрос следующим образом:

thisday: 2014.10.12
select from trade where date = thisday, sym =`ibm

Примеры запросов

Создадим одну торговую таблицу и проверим результат разных табличных выражений:

q)trade:([]sym:5?`ibm`msft`hsbc`samsung;price:5?(303.00*3+1);size:5?(900*5);time:5?(.z.T-365))

q)trade

  sym        price   size   time
-----------------------------------------
 msft      743.8592  3162  02:32:17.036
 msft      641.7307  2917  01:44:56.936
 hsbc      838.2311  1492  00:25:23.210
 samsung   278.3498  1983  00:29:38.945
 ibm       838.6471  4006  07:24:26.842


Select

Синтаксис использования инструкции Select выглядит следующим образом:

select [columns] [by columns] from table [where clause]

Пример как использовать инструкцию Select:

q)/ select expression example

q)select sym,price,size by time from trade where size > 2000

    time      |  sym    price     size
------------- | -----------------------
 01:44:56.936 |  msft   641.7307  2917
 02:32:17.036 |  msft   743.8592  3162
 07:24:26.842 |  ibm    838.6471  4006

Insert

Синтаксис использования инструкции Insert выглядит следующим образом:

tablename insert (values)
Insert[`tablename; values]

Пример как использовать инструкцию Insert :

q)/ Insert expression example

q)`trade insert (`hsbc`apple;302.0 730.40;3020 3012;09:30:17.00409:15:00.000)
5 6

q)trade

   sym    price     size    time
------------------------------------------
  msft    743.8592  3162   02:32:17.036
  msft    641.7307  2917   01:44:56.936
  hsbc    838.2311  1492   00:25:23.210
 samsung  278.3498  1983   00:29:38.945
  ibm     838.6471  4006   07:24:26.842
  hsbc    302       3020   09:30:17.004
  apple   730.4     3012   09:15:00.000

q)/Insert another value

q)insert[`trade;(`samsung;302.0; 3333;10:30:00.000]
']

q)insert[`trade;(`samsung;302.0; 3333;10:30:00.000)]
,7

q)trade

   sym     price   size     time
----------------------------------------
  msft   743.8592  3162  02:32:17.036
  msft   641.7307  2917  01:44:56.936
  hsbc   838.2311  1492  00:25:23.210
 samsung 278.3498  1983  00:29:38.945
  ibm    838.6471  4006  07:24:26.842
  hsbc   302       3020  09:30:17.004
  apple  730.4     3012  09:15:00.000
 samsung 302       3333  10:30:00.000

Delete

Синтаксис использования инструкции Delete выглядит следующим образом :

delete columns from table
delete from table where clause

Пример как использовать инструкцию Delete:

q)/Delete expression example

q)delete price from trade

   sym   size       time
-------------------------------
  msft   3162   02:32:17.036
  msft   2917   01:44:56.936
  hsbc   1492   00:25:23.210
 samsung 1983   00:29:38.945
  ibm    4006   07:24:26.842
  hsbc   3020   09:30:17.004
  apple  3012   09:15:00.000
 samsung 3333   10:30:00.000

q)delete from trade where price > 3000

   sym     price     size       time
-------------------------------------------
  msft    743.8592   3162    02:32:17.036
  msft    641.7307   2917    01:44:56.936
  hsbc    838.2311   1492    00:25:23.210
 samsung  278.3498   1983    00:29:38.945
  ibm     838.6471   4006    07:24:26.842
  hsbc    302        3020    09:30:17.004
  apple   730.4      3012    09:15:00.000
 samsung  302        3333    10:30:00.000

q)delete from trade where price > 500

  sym     price     size     time
-----------------------------------------
 samsung  278.3498  1983  00:29:38.945
  hsbc    302       3020  09:30:17.004
 samsung  302       3333  10:30:00.000

Update

Синтаксис использования инструкции Update выглядит следующим образом :

update column: newValue from table where .

Используется следующий синтаксис для обновления формата / типа данных столбца с помощью функции cast:

update column:newValue from `table where 

Пример как использовать инструкцию Update :

q)/Update expression example

q)update size:9000 from trade where price > 600

  sym     price      size     time
------------------------------------------
  msft    743.8592   9000   02:32:17.036
  msft    641.7307   9000   01:44:56.936
  hsbc    838.2311   9000   00:25:23.210
 samsung  278.3498   1983   00:29:38.945
  ibm     838.6471   9000   07:24:26.842
  hsbc    302        3020   09:30:17.004
  apple   730.4      9000   09:15:00.000
 samsung  302        3333   10:30:00.000

q)/Update the datatype of a column using the cast function

q)meta trade

   c  |  t f a
----- | --------
  sym |  s
 price|  f
 size |  j
 time |  t

q)update size:`float$size from trade

  sym     price     size      time
------------------------------------------
  msft    743.8592  3162    02:32:17.036
  msft    641.7307  2917    01:44:56.936
  hsbc    838.2311  1492    00:25:23.210
 samsung  278.3498  1983    00:29:38.945
  ibm     838.6471  4006    07:24:26.842
  hsbc    302       3020    09:30:17.004
  apple   730.4     3012    09:15:00.000
 samsung  302       3333    10:30:00.000

q)/ Above statement will not update the size column datatype permanently

q)meta trade

   c   |  t f a
------ | --------
  sym  |   s
 price |   f
 size  |   j
 time  |   t

q)/to make changes in the trade table permanently, we have do

q)update size:`float$size from `trade
`trade

q)meta trade

   c   |  t f a
------ | --------
  sym  |   s
 price |   f
 size  |   f
 time  |   t

Интеграция с Python

Чтобы упростить работу с KDB+ для людей, не знакомых с технологией, KX создали библиотеки для тесной интеграции с Python в рамках одного процесса. Можно как вызывать любую python-функцию из Q, так и наоборот — вызывать любую Q функцию из Python (в частности QSQL выражения). Библиотеки конвертируют при необходимости (ради эффективности не всегда) данные из формата одного языка в формат другого. В итоге Q и Python живут в таком тесном симбиозе, что границы между ними стираются. В результате программист, с одной стороны, имеет полный доступ к многочисленным полезным библиотекам Python, с другой стороны, он получает интегрированную в Python быструю базу для работы с большими данными, что особенно полезно тем, кто занимается машинным обучением или моделированием.

Пример:

>>> from pyq import q
>>> from datetime import date

>>> q()
q)trade:([]date:();sym:();qty:())
q)\

>>> q.insert('trade', (date(2006,10,6), 'IBM', 200))
k(',0')
>>> q.insert('trade', (date(2006,10,6), 'MSFT', 100))
k(',1')

>>> q.trade.show()
date       sym  qty
-------------------
2006.10.06 IBM  200
2006.10.06 MSFT 100

Пример написания функции:

q)f:{[s;d]select from trade where sym=s,date=d}

>>> x = q.f('IBM', date(2006,10,6))
>>> x.show()
date       sym qty
------------------
2006.10.06 IBM 200

Конкуренты

Существует довольно много специализированных баз, построенных на похожих принципах — колоночные, in-memory, ориентированные на очень большие объемы данных. Проблема в том, что это именно специализированные базы данных. Яркий пример — Clickhouse. У этой базы данных очень похожий на KDB+ принцип хранения данных на диске и строения индекса, некоторые запросы она выполняет быстрее KDB+, хотя и не существенно. Но даже как база данных Clickhouse является более специализированной чем KDB+ — web аналитика vs произвольные временные ряды (это различие очень важно — из-за него, например, в Clickhouse нет возможности использовать упорядоченность записей). Но, главное, у Clickhouse нет универсальности KDB+, языка, который позволил бы обрабатывать данные непосредственно в базе, а не грузить их предварительно в отдельное приложение, строить произвольные SQL выражения, применять произвольные функции в запросе, создавать процессы не связанные с исполнением функций исторической базы. Поэтому сложно сравнивать KDB+ с другими базами, они могут быть лучше в отдельных сценариях использования или просто лучше, если речь идет о задачах классических баз данных, но мне неизвестен другой столь же эффективный и универсальный инструмент для обработки временных данных.

Примечания

Источники

  1. Возможности языка Q и KDB+ на примере сервиса реального времени. URL: https://habr.com/ru/company/dbtc/blog/470596/ (дата обращения: 14.05.2020)
  2. База данных KDB+: от финансов до «Формулы 1». URL: https://habr.com/ru/company/dbtc/blog/446412/ (дата обращения: 06.05.2020)
  3. KDB+ Architecture. URL: https://www.wisdomjobs.com/e-university/kdb-tutorial-2037/kdb-plus-architecture-23898.html (дата обращения: 06.05.2020)

Ссылки/Литература

  • Книга по q [Электронный ресурс]: Q for Mortals .An introduction to q programming / Дата обращения: 06.05.2020. Режим доступа: https://code.kx.com/q4m3/
  • Статьи на тему применений KDB+/Q от сотрудников kx [Электронный ресурс]: Technical white papers / Дата обращения: 06.05.2020. Режим доступа: https://code.kx.com/v2/wp/