Yson
В данном разделе собрана информация про YSON — JSON-подобный формат данных, разработанный в Яндексе.
Примечание
SQL-функции для работы с YSON описаны здесь
Введение
К основным отличиям YSON от JSON относится:
- Поддержка бинарного представления скалярных типов (чисел, строк и булевого типа);
- Атрибуты: произвольный словарь, который можно установить дополнительно на литерал любого (даже скалярного) типа.
Кроме того существуют синтаксические отличия:
- Вместо запятой в качестве разделителя используется точка с запятой;
- В словарях ключ от значения отделяется не двоеточием, а знаком равенства:
=
; - Строковые литералы не обязательно всегда заключать в кавычки (только если иначе возникает неоднозначность при парсинге).
Имеется следующий набор скалярных типов:
- Строки (
string
); - Знаковые и беззнаковые 64-битные целые числа (
int64
иuint64
); - Числа с плавающей точкой двойной точности (
double
); - Булев (логический) тип (
boolean
); - Специальный тип entity, имеющий всего один литерал (
#
).
Скалярные типы обычно имеют как текстовое, так и бинарное представление.
Есть два композитных типа:
Скалярные типы
Строки
Токены строк бывают трех видов:
-
Идентификаторы задаются регулярным выражением
[A-Za-z_][A-Za-z0-9_.\-]*
(Первый символ - буква или нижнее подчеркивание, со второго символа могут быть дополнительно использованы цифры и символы-
,.
). Идентификатор задает строку с идентичным ему содержимым и используется в первую очередь для краткости (не нужно ставить кавычки).Примеры:
abc123
;_
;a-b
.
-
Текстовые строки — C-escaped строки в двойных кавычках.
Примеры:
"abc123"
;""
;"quotation-mark: \", backslash: \\, tab: \t, unicode: \xEA"
.
-
Бинарные строки:
\x01 + length (protobuf sint32 wire format) + data (<length> bytes)
.
int64
)
Знаковые 64-битные целые числа (Два способа записи:
- Текстовый: (
0
,123
,-123
,+123
); - Бинарный:
\x02 + value (protobuf sint64 wire format)
.
uint64
)
Беззнаковые 64-битные целые числа (Два способа записи:
- Текстовый: (
10000000000000
,123u
); - Бинарный:
\x06 + value (protobuf uint64 wire format)
.
double
)
Числа с плавающей точкой (Два способа записи:
- Текстовый: (
0.0
,-1.0
,1e-9
,1.5E+9
,32E1
,%inf
,%-inf
,%nan
); - Бинарный:
\x03 + protobuf double wire format
.
Важно
Текстовое представление чисел с плавающей точкой включает в себя округление, которое может привести к тому, что при обратном парсинге значение окажется иным. В случае, если вам важна точность, следует использовать бинарное представление.
Важно
Значения %inf
, %-inf
, %nan
не существуют в JSON, поэтому вызов Yson::SerializeJson
с содержащим эти значения YSON приведет к ошибке
boolean
)
Булевы литералы (Два способа записи:
- Текстовый (
%false
,%true
); - Бинарный (
\x04
,\x05
).
entity
)
Entity (Entity представляет собой атомарное скалярное значение, не имеющее никакого собственного содержимого. Сценарии, в которых данный тип может быть полезен, разнообразны. Например, часто entity
обозначает null
. При этом entity
может иметь аттрибуты
Лексически entity кодируется символом решетки: #
.
Выделенные литералы
Специальные токены:
;
, =
, #
, [
, ]
, {
, }
, <
, >
, )
, /
, @
, !
, +
, ^
, :
, ,
, ~
.
Не все эти символы используются в YSON, некоторые используются в YPath.
Композитные типы
list
)
Список (Задается следующим образом: [value; ...; value]
, где value
— литералы произвольных скалярных или композитных типов.
Пример: [1; "hello"; {a=1; b=2}]
.
map
)
Словарь (Задается следующим образом: {key = value; ...; key = value}
. Здесь *key*
— литералы строкового типа, а value
— литералы произвольных скалярных или композитных типов.
Пример: {a = "hello"; "38 parrots" = [38]}
.
Атрибуты
На любой литерал в YSON можно установить атрибуты. Записывается это так: <key = value; ...; key = value> value
. Внутри угловых скобок синтаксис аналогичен словарю. Например, <a = 10; b = [7,7,8]>"some-string"
или <"44" = 44>44
. Но чаще всего атрибуты можно встретить на литералах типа entity
, например, <id="aaad6921-b5704588-17990259-7b88bad3">#
.
Грамматика
YSON-данные бывают трех типов:
- Node (одно дерево, в примере —
<tree>
) - ListFragment (значения, разделенные
;
, в примере —<list-fragment>
) - MapFragment (пары ключ-значение, разделенные
;
, в примере —<map-fragment>
)
Грамматика (определяется с точностью до пробельных символов, которые могут быть в произвольном количестве добавлены и удалены между токенами):
<tree> = [ <attributes> ], <object>;
<object> = <scalar> | <map> | <list> | <entity>;
<scalar> = <string> | <int64> | <uint64> | <double> | <boolean>;
<list> = "[", <list-fragment>, "]";
<map> = "{", <map-fragment>, "}";
<entity> = "#";
<attributes> = "<", <map-fragment>, ">";
<list-fragment> = { <list-item>, ";" }, [ <list-item> ];
<list-item> = <tree>;
<map-fragment> = { <key-value-pair>, ";" }, [ <key-value-pair> ];
<key-value-pair> = <string>, "=", <tree>; % Key cannot be empty
Символ ;
после последнего элемента внутри <list-fragment>
и <map-fragment>
может быть опущен. Следующие конструкции следует считать валидными при чтении:
C |
Сокращенная запись |
|
|
Примеры
- Map (Node)
{ performance = 1 ; precision = 0.78 ; recall = 0.21 }
- Map (Node)
{ cv-precision = [ 0.85 ; 0.24 ; 0.71 ; 0.70 ] }
- List (Node)
[ 1; 2; 3; 4; 5 ]
- String (Node)
foobar
"hello world"
-
Int64 (Node)
42
-
Double (Node)
3.1415926
-
ListFragment
{ key = a; value = 0 };
{ key = b; value = 1 };
{ key = c; value = 2; unknown_value = [] }
- MapFragment
do = create; type = table; scheme = {}
- HomeDirectory (Node)
{ home = { sandello = { mytable = <type = table> # ; anothertable = <type = table> # } ; monster = { } } }
YPATH
В данном разделе собрана информация про YPath — язык, описывающий пути к объектам в YSON.
YPath представляет собой язык описания путей, которые идентифицирует объекты в YSON. Язык позволяет обращаться к узлам и указывать аннотации, которые могут быть полезны при совершении операций над узлами, такими как запись и чтение свойств.
Например:
/0-25-3ec012f-406daf5c/@type
— путь к атрибутуtype
объекта с идентификатором0-25-3ec012f-406daf5c
;
Существует несколько разновидностей YPath. В самом простом случае YPath представляет собой строку, кодирующую путь.
Лексика
Строка, кодирующая простой YPath, разбивается на следующие токены:
- Специальные символы: прямой слеш (
/
), "собака" (@
), амперсанд (&
), звездочка (*
); - Литералы: максимальная непустая последовательность неспециальных символов. В литералах разрешен escaping вида
\<escape-sequence>
, где в качестве<escape-sequence>
может выступать один из символов\
,/
,@
,&
,*
,[
,{
, а также выражение видаx<hex1><hex2>
, где<hex1>
и<hex2>
— шестнадцатеричные цифры.
Синтаксис и семантика
Структурно YPath имеет вид /<relative-path>
. <relative-path>
разбирается последовательно слева направо, в результате чего возникают шаги перемещения по дереву следующих видов:
- Переход к потомку: последовательность из токена
/
и литерала.
Данный тип шагов применим к словарям и спискам. В случае словаря литерал должен содержать имя потомка. Пример:/child
— переход к потомку с именемchild
.
В случае списка литерал должен содержать целое число в десятичной системе счисления — номер потомка. Потомки в списке нумеруются с нуля. Разрешены также отрицательные номера, которые нумеруют потомков с конца списка. Примеры:/1
— переход ко второму потомку в списке,/-1
— переход к последнему потомку в списке; - Переход к атрибуту: последовательность из токенов
/@
и литерала.
Данный тип шагов применим в любой точке пути и означает переход к атрибуту с данными именем. Пример:/@attr
— переход к атрибуту с именемattr
.
Примечание
В YPath относительные пути начинаются со слешей. Тем самым, слеш служит не разделителем (как в случае файловых систем), а полноправным членом команды перемещения по дереву. В частности, для склейки двух YPath достаточно обычной конкатенации строк. Это свойство может показаться необычным, но во многих местах оно удобно, и к нему достаточно легко привыкнуть.
Примеры
$data = Yson(@@{"0-25-3ec012f-406daf5c" = {a=<why="I can just do it">1;b=2}}@@);
SELECT Yson::SerializeJson($data), Yson::SerializeJson(Yson::YPath($data, "/0-25-3ec012f-406daf5c/a/@/why"));
Результат:
column0 |
column1 |
|
|
$data = Yson(@@{
a = <a=z;x=y>[
{abc=123; def=456};
{abc=234; xyz=789; entity0123 = #};
];
b = {str = <it_is_string=%true>"hello"; "38 parrots" = [38]};
entity0 = <here_you_can_store=something>#;
}
@@);
SELECT Yson::ConvertToStringDict(Yson::YPath($data, "/a/@")) AS attrs_root,
Yson::SerializeJson(Yson::YPath($data, "/b/str/@")) AS attrs_b_str,
Yson::SerializeJson(Yson::YPath($data, "/b/str/@/it_is_string")) AS attr_exact,
Yson::SerializeJson(Yson::YPath($data, "/a/0")) as array_index0,
Yson::SerializeJson(Yson::YPath($data, "/a/-1")) as array_last,
Yson::SerializeJson(Yson::YPath($data, "/entity0")) as entity,
Yson::SerializeJson(Yson::YPath($data, "/a/#entity0123/abc")) as entity1,
Yson::SerializeJson(Yson::YPath($data, "/a")) AS whole_a,
Yson::SerializeJson($data) AS whole_data;
Результат:
attrs_root |
attrs_b_str |
attr_exact |
array_index0 |
array_last |
entity |
entity1 |
whole_a |
whole_data |
|
|
|
|
|
|
|
|
|