Последовательности
Тег <sequence> объявляет именованный столбец значений длиной в count карточек.
Думайте о нём как о готовом столбце, который существует ещё до начала рендера:
генератор заполняет все строки, а на каждой выходной
строке вы достаёте значение по имени — либо через
интерполяцию ${{Name}}, либо внутри условия if.
Это логическая модель, и всё на этой странице следует из неё. Лежит ли столбец в
памяти на самом деле — отдельный вопрос, на который движок отвечает за вас: движок по
умолчанию считает каждое значение по номеру строки, пока строка проходит мимо, и столбец
не держит вовсе, а mode="memory" и объектный API массив действительно строят. Значения
в обоих случаях одни и те же — см. Большие объёмы.
Последовательности живут в <env>, рядом с count и seed. Разметка строки (в
<block>) сама значений не генерирует — она только читает столбцы, которые ваши
последовательности уже произвели.
Примеры вывода ниже иллюстративные: они показывают форму результата и могут отличаться между версиями ядра.
- Aодна последовательность — одна колонка, заполняется сама по себе
- Bвторая последовательность, ничего не знающая о первой
- Cтретья
- Dодна строка: та же позиция, взятая из каждой колонки и собранная в строку вывода
Атрибуты
| Атрибут | Обязательный | Что делает |
|---|---|---|
name | да | Имя последовательности — по нему обращаются, например ${{City}} |
parent | нет | Ограничивает последовательность подмножеством строк. Синтаксис: Parent.Value |
comment | нет | Свободный комментарий; движком игнорируется |
Единственный обязательный вложенный тег — один или несколько
<gen>, которые и производят сами значения.
Простая последовательность
Используйте её, когда нужен один столбец, к которому можно обращаться по имени из
любого места разметки. Объявите его один раз в <env> и читайте через ${{City}}:
<tdc>
<env count="5" seed="demo">
<sequence name="City">
<gen type="text" value="Moscow,Berlin,Paris"/>
</sequence>
</env>
<block>
<line><data>${{City}}</data></line>
</block>
</tdc>
Berlin Moscow Paris Berlin Paris
По умолчанию значения выбираются из списка случайно, а
seed фиксирует, какие именно вам достанутся. Нужен строгий
порядок списка? Добавьте order="sequential" — см.
Маски и регистр.
«Простая» последовательность определяется тем, что у неё ровно один безымянный
<gen>. Доступ — ${{ИмяПоследовательности}}.
С процентами
Та же форма из одного столбца покрывает и взвешенный выбор. Дайте генератору
text список percent, и значения выйдут в точных
пропорциях:
<sequence name="Gender">
<gen type="text" value="Мужчина,Женщина" percent="60,40"/>
</sequence>
На count=100 это даёт ровно 60 Мужчина и 40 Женщина — percent задаёт точное
разбиение на весь прогон, а не вероятность на каждой строке. О том, как percent
соблюдается, см. Детерминизм и пропорции.
Мужчина 60 Женщина 40
Составная по значению
Когда нужна — когда одно значение собирается из нескольких: полное имя из имени,
пробела и фамилии. Оставь <gen> без имён и поставь между ними текст:
<sequence name="FullName">
<gen type="template" value="person.male.firstName"/>
<data> </data>
<gen type="template" value="person.lastName"/>
</sequence>
Robert Williams James Johnson John Smith
${{FullName}} — одно значение, поэтому оно попадает в карточку, в колонку CSV или
Parquet как есть: склеивать на выводе нечего.
Именованные и безымянные <gen> уживаются в одном теле. Безымянные собирают
собственное значение последовательности, именованный остаётся полем рядом — он
доступен как ${{Name.Field}} и в склейку не входит.
Составная последовательность
Используйте её, когда у одной «сущности» есть несколько связанных полей — имя,
фамилия, возраст, — которые логически идут вместе. Сгруппируйте их в одну
последовательность вместо трёх отдельных и дайте каждому <gen> атрибут name:
<sequence name="Person">
<gen name="FirstName" type="template" value="person.male.firstName"/>
<gen name="LastName" type="template" value="person.male.lastName"/>
<gen name="Age" type="number" value="18..60"/>
</sequence>
Обращайтесь к полям через точку:
<line><data>${{Person.FirstName}} ${{Person.LastName}}, возраст ${{Person.Age}}</data></line>
Демьян Кузьмин, возраст 39 Демьян Андреев, возраст 35 Эдуард Николаев, возраст 26
Константное поле
<data> с атрибутом name — это константное поле, и в отличие от генератора
с одним значением оно не тратит розыгрыш:
<sequence name="Row">
<gen name="id" type="increment" value="1"/>
<data name="source">import-2026</data>
</sequence>
${{Row.source}} во всех записях равно import-2026.
<gen type="text" value="import-2026"/>Он даёт то же значение и всё равно тратит по розыгрышу на строку, поэтому если
вставить его в готовый конфиг, сдвинутся все колонки, объявленные после.
Именованный <data> не тратит ничего — и это единственный способ добавить
константу в конфиг, которым уже кто-то пользуется.
Правила составных
<gen>сname— это поле; без имени — часть собственного значения последовательности (см. составную по значению выше). Тело, где все<gen>именованы, — составная по полям, и своего значения у неё нет.- Имена полей должны быть уникальными внутри последовательности (ошибка
TDC111на дубликате). - Все поля делят один и тот же фильтр
parent. Если родитель задан, каждое поле заполняется только на подходящих строках, а на остальных остаётся пустым. - Обращение к составной последовательности без указания поля —
${{Person}}— остаётся в тексте вывода как есть. Этот нетронутый плейсхолдер — подсказка, что вы имели в виду${{Person.FieldName}}.
Поля в условиях if
Точечный доступ работает и внутри условий, не только в ${{...}}:
<line if="Person.Age >= 18"><data>взрослый</data></line>
<line if="Person.Age < 18"><data>несовершеннолетний</data></line>
Условная последовательность
Используйте её, когда значение столбца зависит от другого столбца. Перечислите
несколько веток <gen if="…">; побеждает первая ветка, чьё условие истинно.
Безымянный <gen> (без if) работает как «иначе»:
<sequence name="Age">
<gen type="number" value="0..90"/>
</sequence>
<sequence name="AgeGroup">
<gen if="Age < 18" type="text" value="Ребёнок"/>
<gen if="Age < 65" type="text" value="Взрослый"/>
<gen type="text" value="Пенсионер"/>
</sequence>
Поскольку ветки проверяются сверху вниз, Age < 65 видит только те строки, которые
уже не прошли Age < 18, — то есть фактически означает «18–64». Доступ — по имени
последовательности, ${{AgeGroup}}:
14 Ребёнок 42 Взрослый 71 Пенсионер 9 Ребёнок 58 Взрослый
Условная последовательность — по-прежнему один столбец: вы читаете её как
${{AgeGroup}}, так же как простую. Несколько тегов <gen> только решают, какое
значение заполнит каждую строку.
Зависимые последовательности (parent)
Последовательность может зависеть от другой через parent="Parent.Value". Дочерняя
вычисляется только на строках, где совпадает родитель, а любые проценты внутри неё
считаются от этого подмножества, а не от всего count. В этом — сердце иерархической
модели TDC:
<sequence name="Gender">
<gen type="text" value="Мужчина,Женщина" percent="50,50"/>
</sequence>
<sequence name="MaleName" parent="Gender.Мужчина">
<gen type="template" value="person.male.firstName"/>
</sequence>
<sequence name="FemaleName" parent="Gender.Женщина">
<gen type="template" value="person.female.firstName"/>
</sequence>
MaleName материализуется только на строках, где Gender == Мужчина; на остальных он
пуст. Полный разбор — вложенные проценты, несколько уровней — в разделе
Иерархические зависимости.
Составная последовательность с parent
Составные и parent сочетаются напрямую. Здесь каждый пол получает свою
сгруппированную сущность, а мужское подмножество несёт дополнительное поле Rank:
<sequence name="Gender">
<gen type="text" value="Мужчина,Женщина" percent="50,50"/>
</sequence>
<sequence name="Male" parent="Gender.Мужчина">
<gen name="FirstName" type="template" value="person.male.firstName"/>
<gen name="LastName" type="template" value="person.male.lastName"/>
<gen name="Rank" type="text" value="Рядовой,Капитан" percent="70,30"/>
</sequence>
<sequence name="Female" parent="Gender.Женщина">
<gen name="FirstName" type="template" value="person.female.firstName"/>
<gen name="LastName" type="template" value="person.female.lastName"/>
</sequence>
<block>
<line if="Gender == Мужчина"><data>М: ${{Male.FirstName}} ${{Male.LastName}} (${{Male.Rank}})</data></line>
<line if="Gender == Женщина"><data>Ж: ${{Female.FirstName}} ${{Female.LastName}}</data></line>
</block>
Ж: Нина Полякова М: Кирилл Вишневский (Рядовой) Ж: Алла Егорова Ж: Инна Давыдова М: Матвей Соловьёв (Капитан) М: Олег Романов (Рядовой)
Что это гарантирует:
- Все три поля
Male.*материализуются только на мужских строках; на женских они пусты (и наоборот). Male.Rankразбивается как70% Рядовой, 30% Капитанвнутри мужского подмножества — проценты считаются от числа мужчин, а не от общегоcount.
Детерминизм и порядок полей
Поля составной последовательности материализуются в порядке объявления, и каждый
<gen> расходует ГПСЧ независимо. Отсюда одно следствие, которое
стоит запомнить:
Перестановка двух тегов <gen name="…"> меняет вывод при том же сиде. Первое поле
вычерпывает другой отрезок случайного потока, чем раньше, поэтому каждое поле после
него сдвигается.
<!-- Эти два дают РАЗНЫЕ значения при одном и том же сиде -->
<sequence name="Person">
<gen name="FirstName" type="template" value="person.male.firstName"/>
<gen name="Age" type="number" value="18..60"/>
</sequence>
<sequence name="Person">
<gen name="Age" type="number" value="18..60"/>
<gen name="FirstName" type="template" value="person.male.firstName"/>
</sequence>
Если вам нужен байт-в-байт воспроизводимый вывод между прогонами, зафиксируйте порядок полей один раз и не переставляйте генераторы после того, как выбрали сид. Подробнее о том, что сид гарантирует, а что нет: Детерминизм и пропорции.
Смежные источники значений
Рядом с <sequence> в <env> живут ещё два именованных источника, которые тоже
читаются через ${{Name}}:
<mix>— распределение по точным процентам, где каждая ветка может быть целым составным блоком из литералов и генераторов (а не одним значением).<switch>— детерминированная таблица соответствий «ключ → значение».
Когда вам нужен просто один столбец случайных или взвешенных значений, инструмент — это
<sequence>.
Дальше
- Генераторы — тег
<gen>, производящий значения последовательности. - Детерминизм и пропорции — как связаны
seed,countиpercent. - Иерархические зависимости — полная
модель
parent.