Трансформация project

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


Назначение трансформации project

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

Ключевая роль:

  • уменьшение объёма данных в дальнейшем конвейере
  • явное определение используемых атрибутов
  • упрощение последующих трансформаций и выражений
  • повышение читаемости и предсказуемости схемы данных

В отличие от calculate или aggregate, project не изменяет значения — только структуру объекта данных.


Базовая концепция работы

Каждый объект данных в Vega представляет собой набор ключ-значение. Например:

{
  "country": "Kazakhstan",
  "year": 2020,
  "value": 42,
  "unused_field": "noise"
}

После применения проекции:

{
  "country": "Kazakhstan",
  "value": 42
}

Поле year и unused_field удаляются на этапе трансформации.


Синтаксис в Vega

В Vega трансформация project задаётся внутри массива transform:

{
  "type": "project",
  "fields": ["country", "value"]
}

Полный фрагмент data:

{
  "data": [
    {
      "name": "table",
      "values": [
        {"country": "KZ", "year": 2020, "value": 10},
        {"country": "KZ", "year": 2021, "value": 15}
      ],
      "transform": [
        {
          "type": "project",
          "fields": ["country", "value"]
        }
      ]
    }
  ]
}

Особенности поведения

1. Полное удаление лишних полей

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

2. Порядок полей не гарантируется

Хотя логически порядок в fields может совпадать с итоговой структурой, движок не обязан сохранять порядок ключей в объектах JavaScript.

3. Отсутствие вычислений

project не может:

  • создавать новые поля
  • переименовывать существующие
  • выполнять выражения

Отличие от аналогичных трансформаций

project vs calculate

  • project — удаляет поля
  • calculate — добавляет или изменяет поля

Пример calculate:

{
  "type": "calculate",
  "expr": "datum.value * 2",
  "as": "double_value"
}

project vs filter

  • project не изменяет количество строк
  • filter изменяет количество строк

Использование в цепочках трансформаций

project часто применяется как подготовительный этап перед более тяжёлыми операциями:

"transform": [
  {
    "type": "project",
    "fields": ["country", "value"]
  },
  {
    "type": "filter",
    "expr": "datum.value > 10"
  },
  {
    "type": "calculate",
    "expr": "datum.value * 100",
    "as": "scaled"
  }
]

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


Роль в оптимизации пайплайна

Удаление лишних полей на раннем этапе:

  • уменьшает объём сериализации данных
  • ускоряет выполнение выражений (expr)
  • снижает стоимость вычислений в aggregate, window
  • уменьшает память на уровне runtime Vega

Особенно заметно при больших наборах данных (десятки и сотни тысяч строк).


Поведение при отсутствии полей

Если в fields указано поле, которого нет в данных:

{
  "type": "project",
  "fields": ["country", "missing_field"]
}

то:

  • существующее поле сохраняется
  • отсутствующее игнорируется
  • ошибка не генерируется

Это делает трансформацию устойчивой к неоднородным данным.


Работа с вложенными структурами

project не выполняет глубокую проекцию вложенных объектов. Для данных вида:

{
  "a": 1,
  "b": {
    "x": 10,
    "y": 20
  }
}

указание:

"fields": ["b"]

сохраняет объект b целиком. Выбор b.x невозможен без предварительной трансформации через выражения.


Взаимодействие с Vega-Lite

В Vega-Lite явного project как отдельной трансформации нет в пользовательском API, но аналогичная логика реализуется через:

  • transform
  • calculate
  • внутреннюю оптимизацию компилятора

При компиляции Vega-Lite в Vega может автоматически вставляться project, если:

  • исходная спецификация использует только часть полей
  • остальные поля не задействованы в визуализации

Использование в реальных сценариях

Подготовка данных для графика

Если визуализация использует только две переменные:

  • категория
  • значение

лишние поля исключаются:

{
  "type": "project",
  "fields": ["category", "value"]
}

Уменьшение нагрузки перед агрегацией

Перед aggregate:

{
  "type": "project",
  "fields": ["group", "amount"]
},
{
  "type": "aggregate",
  "groupby": ["group"],
  "ops": ["sum"],
  "fields": ["amount"],
  "as": ["total"]
}

Удаление ненужных колонок снижает сложность агрегации.


Ограничения трансформации

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

Эти ограничения делают project строго структурной операцией без логики.


Влияние на читаемость спецификации

Использование project делает конвейер данных более явным:

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

Комбинирование с другими трансформациями

Наиболее типичные связки:

  • project + filter — предварительная очистка
  • project + calculate — вычисление на ограниченном наборе полей
  • project + aggregate — минимизация данных перед группировкой
  • project + window — оптимизация оконных вычислений

Практическая модель поведения в пайплайне

Внутренне Vega трактует project как узел графа данных, который:

  1. получает поток объектов
  2. создает новый поток
  3. копирует только указанные ключи
  4. передает дальше без модификации значений

Это делает трансформацию детерминированной и без побочных эффектов.


Типичные ошибки при использовании

  • попытка использовать project для фильтрации строк
  • ожидание переименования полей
  • попытка обращения к вложенным свойствам через dot-нотацию в fields
  • использование как замены calculate

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