---
metadata:
  - name: generator
    content: Diplodoc Platform v5.50.4
alternate:
  - https://ydb.tech/docs/en/yql/reference/types/yson.md
  - https://ydb.tech/docs/ru/yql/reference/types/yson.md
sourcePath: ru/core/yql/reference/types/yson.md
---
> **Documentation Index:** Fetch the complete configuration index at https://ydb.tech/docs/ru/llms.txt

# Yson

В данном разделе собрана информация про YSON — JSON-подобный формат данных, разработанный в Яндексе.

{% note info %}

SQL-функции для работы с YSON описаны [здесь](https://ydb.tech/docs/ru/yql/reference/udf/list/yson.md)

{% endnote %}

## Введение {#intro}

К основным **отличиям YSON от JSON** относится:

1. Поддержка бинарного представления скалярных типов (чисел, строк и булевого типа);
2. [Атрибуты](#attributes): произвольный словарь, который можно установить дополнительно на литерал любого (даже скалярного) типа.

Кроме того существуют **синтаксические отличия**:

1. Вместо запятой в качестве разделителя используется точка с запятой;
2. В словарях ключ от значения отделяется не двоеточием, а знаком равенства: `=`;
3. Строковые литералы не обязательно всегда заключать в кавычки (только если иначе возникает неоднозначность при парсинге).

Имеется следующий набор **скалярных** типов:

1. [Строки](#string) (`string`);
2. [Знаковые](#int) и [беззнаковые](#uint) 64-битные целые числа (`int64` и `uint64` );
3. [Числа с плавающей точкой](#double) двойной точности (`double`);
4. [Булев](#boolean) (логический) тип (`boolean`);
5. [Специальный тип entity](#entity), имеющий всего один литерал (`#`).

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

Есть два **композитных** типа:

1. [Список](#list) (`list`);
2. [Словарь](#map) (`map`).

## Скалярные типы {#scalar_types}

### Строки {#string}

Токены строк бывают трех видов:

1. **Идентификаторы** задаются регулярным выражением `[A-Za-z_][A-Za-z0-9_.\-]*` (Первый символ - буква или нижнее подчеркивание, со второго символа могут быть дополнительно использованы цифры и символы `-`,`.`). Идентификатор задает строку с идентичным ему содержимым и используется в первую очередь для краткости (не нужно ставить кавычки).

   Примеры:

   - `abc123`;
   - `_`;
   - `a-b`.

2. **Текстовые строки** — [C-escaped](https://en.wikipedia.org/wiki/Escape_sequences_in_C) строки в двойных кавычках.

   Примеры:

   - `"abc123"`;
   - `""`;
   - `"quotation-mark: \", backslash: \\, tab: \t, unicode: \xEA"`.

3. **Бинарные строки**: `\x01 + length (protobuf sint32 wire format) + data (<length> bytes)`.

### Знаковые 64-битные целые числа (`int64`) {#int}

Два способа записи:

1. **Текстовый**: (`0`, `123`, `-123`, `+123`);
2. **Бинарный**: `\x02 + value (protobuf sint64 wire format)`.

### Беззнаковые 64-битные целые числа (`uint64`) {#uint}

Два способа записи:

1. **Текстовый**: (`10000000000000`, `123u`);
2. **Бинарный**: `\x06 + value (protobuf uint64 wire format)`.

### Числа с плавающей точкой (`double`) {#double}

Два способа записи:

1. **Текстовый**: (`0.0`, `-1.0`, `1e-9`, `1.5E+9`, `32E1`, `%inf`, `%-inf`, `%nan`);
2. **Бинарный**: `\x03 + protobuf double wire format`.

{% note warning %}

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

{% endnote %}

{% note warning %}

Значения `%inf`, `%-inf`, `%nan` не существуют в JSON, поэтому вызов `Yson::SerializeJson` с содержащим эти значения YSON приведет к ошибке

{% endnote %}

### Булевы литералы (`boolean`) {#boolean}

Два способа записи:

1. **Текстовый** (`%false`, `%true`);
2. **Бинарный** (`\x04`, `\x05`).

### Entity (`entity`) {#entity}

Entity представляет собой атомарное скалярное значение, не имеющее никакого собственного содержимого. Сценарии, в которых данный тип может быть полезен, разнообразны. Например, часто `entity` обозначает `null`. При этом `entity` может иметь аттрибуты

Лексически entity кодируется символом решетки: `#`.

### Выделенные литералы {#special_literals}

Специальные токены:

`;`, `=`, `#`, `[`, `]`, `{`, `}`, `<`, `>`, `)`, `/`, `@`, `!`, `+`, `^`, `:`, `,`, `~`.

Не все эти символы используются в YSON, некоторые используются в [YPath](#ypath).

## Композитные типы {#composite_types}

### Список (`list`) {#list}

Задается следующим образом: `[value; ...; value]`, где `value` — литералы произвольных скалярных или композитных типов.

Пример: `[1; "hello"; {a=1; b=2}]`.

### Словарь (`map`) {#map}

Задается следующим образом: `{key = value; ...; key = value}`. Здесь `*key*` — литералы строкового типа, а `value` — литералы произвольных скалярных или композитных типов.

Пример: `{a = "hello"; "38 parrots" = [38]}`.

### Атрибуты {#attributes}

На любой литерал в YSON можно установить **атрибуты**. Записывается это так: `<key = value; ...; key = value> value`. Внутри угловых скобок синтаксис аналогичен словарю. Например, `<a = 10; b = [7,7,8]>"some-string"` или `<"44" = 44>44`. Но чаще всего атрибуты можно встретить на литералах типа `entity`, например, `<id="aaad6921-b5704588-17990259-7b88bad3">#`.

## Грамматика {#grammar}

YSON-данные бывают трех типов:

  1. **Node** (одно дерево, в примере — `<tree>`)
  2. **ListFragment** (значения, разделенные `;`, в примере — `<list-fragment>`)
  3. **MapFragment** (пары ключ-значение, разделенные `;`, в примере — `<map-fragment>`)


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

```antlr
          <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 `;` на конце | Сокращенная запись ||
||

```yson
<a=b;>c
{a=b;}
1;2;3;
```

|

```yson
<a=b>c
{a=b}
1;2;3
```

 ||
|#


## Примеры {#examples}

- Map (Node)

```yson
{ performance = 1 ; precision = 0.78 ; recall = 0.21 }
```

- Map (Node)

```yson
{ cv-precision = [ 0.85 ; 0.24 ; 0.71 ; 0.70 ] }
```


- List (Node)

```yson
[ 1; 2; 3; 4; 5 ]
```


- String (Node)

```yson
foobar
```

```yson
"hello world"
```

- Int64 (Node) `42`

- Double (Node) `3.1415926`

- ListFragment

```yson
{ key = a; value = 0 };
{ key = b; value = 1 };
{ key = c; value = 2; unknown_value = [] }
```

- MapFragment

```yson
do = create; type = table; scheme = {}
```

- HomeDirectory (Node)

```yson
{ home = { sandello = { mytable = <type = table> # ; anothertable = <type = table> # } ; monster = { } } }
```

## YPATH {#ypath}

В данном разделе собрана информация про YPath — язык, описывающий пути к объектам в YSON.

YPath представляет собой язык описания путей, которые идентифицирует объекты в YSON. Язык позволяет обращаться к узлам и указывать аннотации, которые могут быть полезны при совершении операций над узлами, такими как запись и чтение свойств.

Например:

- `/0-25-3ec012f-406daf5c/@type` — путь к атрибуту `type` объекта с идентификатором `0-25-3ec012f-406daf5c`;

Существует несколько разновидностей YPath. В самом простом случае YPath представляет собой строку, кодирующую путь.

### Лексика {#simple_ypath_lexis}

Строка, кодирующая простой YPath, разбивается на следующие **токены**:

1. **Специальные символы**: прямой слеш (`/`), "собака" (`@`), амперсанд (`&`), звездочка (`*`);
2. **Литералы**: максимальная непустая последовательность неспециальных символов. В литералах разрешен escaping вида `\<escape-sequence>`, где в качестве `<escape-sequence>` может выступать один из символов `\`, `/`, `@`, `&`, `*`, `[`, `{`, а также выражение вида `x<hex1><hex2>`, где `<hex1>` и `<hex2>` — шестнадцатеричные цифры.

### Синтаксис и семантика {#simple_ypath_syntax}

Структурно YPath имеет вид `/<relative-path>`. `<relative-path>` разбирается последовательно слева направо, в результате чего возникают шаги перемещения по дереву следующих видов:

- **Переход к потомку**: последовательность из токена `/` и литерала.
  Данный тип шагов применим к словарям и спискам. В случае словаря литерал должен содержать имя потомка. Пример: `/child` — переход к потомку с именем `child`.
  В случае списка литерал должен содержать целое число в десятичной системе счисления — номер потомка. Потомки в списке нумеруются с нуля. Разрешены также отрицательные номера, которые нумеруют потомков с конца списка. Примеры: `/1` — переход ко второму потомку в списке, `/-1` — переход к последнему потомку в списке;
- **Переход к атрибуту**: последовательность из токенов `/@` и литерала.
  Данный тип шагов применим в любой точке пути и означает переход к атрибуту с данными именем. Пример: `/@attr` — переход к атрибуту с именем `attr`.

{% note info %}

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

{% endnote %}

### Примеры {#simple_ypath_examples}

```yql
$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 ||
||

```json
{
  "0-25-3ec012f-406daf5c": {
    "a": {
      "$attributes": {
        "why": "I can just do it"
      },
      "$value": 1
    },
    "b": 2
  }
}
```

| `"I can just do it"` ||
|#


```yql
$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 ||
||

```json
{
    "a": "z",
    "x": "y"
}
```

|

```json
{
    "it_is_string": true
}
```

|

```json
true
```

|

```json
{
    "abc": 123,
    "def": 456
}
```

|

```json
{
    "abc": 234,
    "entity0123": null,
    "xyz": 789
}
```

|

```json
{
    "$attributes": {
        "here_you_can_store": "something"
    },
    "$value": null
}
```

|

```json
null
```

|

```json
{
    "$attributes": {
        "a": "z",
        "x": "y"
    },
    "$value": [
        {
            "abc": 123,
            "def": 456
        },
        {
            "abc": 234,
            "entity0123": null,
            "xyz": 789
        }
    ]
}
```

|

```json
{
    "a": {
        "$attributes": {
            "a": "z",
            "x": "y"
        },
        "$value": [
            {
                "abc": 123,
                "def": 456
            },
            {
                "abc": 234,
                "xyz": 789
            }
        ]
    },
    "b": {
        "38 parrots": [
            38
        ],
        "str": {
            "$attributes": {
                "it_is_string": true
            },
            "$value": "hello"
        }
    }
}
```

||
|#






