Обработка результатов матрицы

Матрица результатов в контексте сервисов расстояний и времени маршрутов формируется как двумерная структура, где каждая строка соответствует исходной точке, а каждый столбец — точке назначения. В рамках экосистемы Google и Google Maps Platform такие данные чаще всего поступают через Distance Matrix сервис и обрабатываются в клиентском JavaScript-коде для последующего отображения, фильтрации и аналитики.

Ключевая особенность структуры — вложенность объектов:

  • rows[] — массив исходных точек
  • elements[] — массив результатов для каждой пары origin → destination
  • status — состояние запроса на уровне элемента и строки

Каждый элемент матрицы представляет отдельный маршрутный расчёт, содержащий расстояние, длительность и дополнительные метрики.


Формат ответа матрицы и его логическая модель

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

Origin  Destination B C D
A A→B A→C A→D
B B→B B→C B→D

В реальном API эта структура разворачивается в JSON:

  • rows[i] соответствует origin[i]
  • rows[i].elements[j] соответствует destination[j]

Каждый element содержит:

  • distance.text и distance.value
  • duration.text и duration.value
  • status

Разбор структуры элемента результата

Каждый элемент матрицы имеет следующую структуру:

  • distance

    • value — расстояние в метрах
    • text — человекочитаемое представление
  • duration

    • value — время в секундах
    • text — форматированное время
  • duration_in_traffic (если включён трафик)

    • учитывает дорожную ситуацию
  • status

    • OK — маршрут найден
    • ZERO_RESULTS — маршрут отсутствует
    • NOT_FOUND — точки не распознаны
    • MAX_ROUTE_LENGTH_EXCEEDED — превышены ограничения

Итерация по матрице результатов

При обработке данных основной задачей становится корректная навигация по двум уровням вложенности:

for (let i = 0; i < response.rows.length; i++) {
  const row = response.rows[i];

  for (let j = 0; j < row.elements.length; j++) {
    const element = row.elements[j];

    if (element.status === "OK") {
      const distance = element.distance.value;
      const duration = element.duration.value;
    }
  }
}

Такая структура позволяет строить произвольные таблицы расстояний, графы маршрутов и системы выбора оптимального пути.


Нормализация данных для дальнейшей обработки

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

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

Пример преобразования:

function normalizeElement(element) {
  return {
    distanceKm: element.distance.value / 1000,
    durationMin: element.duration.value / 60,
    isAvailable: element.status === "OK"
  };
}

Результатом становится структура, пригодная для алгоритмов поиска и сравнения.


Построение двумерной таблицы расстояний

Для аналитических задач матрица преобразуется в плоскую таблицу:

const table = [];

response.rows.forEach((row, i) => {
  row.elements.forEach((el, j) => {
    table.push({
      originIndex: i,
      destinationIndex: j,
      distance: el.distance?.value ?? null,
      duration: el.duration?.value ?? null,
      status: el.status
    });
  });
});

Такая форма удобна для:

  • сортировки
  • фильтрации
  • экспорта в CSV
  • загрузки в базы данных

Обработка ошибок на уровне элементов

Особенность матричного API заключается в частичной деградации данных: даже при ошибке отдельных пар остальные элементы остаются валидными.

Типичная стратегия обработки:

  • игнорировать NOT_FOUND
  • логировать ZERO_RESULTS
  • повторять запрос для критических пар
  • помечать некорректные элементы как null
if (element.status !== "OK") {
  return null;
}

Агрегация результатов

На основе матрицы строятся агрегированные метрики:

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

Пример нахождения ближайшего пункта:

function findNearest(originIndex, rows) {
  let min = Infinity;
  let bestIndex = -1;

  rows[originIndex].elements.forEach((el, j) => {
    if (el.status === "OK" && el.distance.value < min) {
      min = el.distance.value;
      bestIndex = j;
    }
  });

  return bestIndex;
}

Оптимизация обработки больших матриц

При увеличении числа точек возрастает сложность: O(n × m). В рамках Google Maps Platform существуют ограничения на размер запросов, поэтому обработка больших наборов данных требует архитектурных решений:

  • разбиение входных данных на батчи
  • кэширование повторяющихся запросов
  • дедупликация origin/destination
  • параллельная обработка ответов

Сериализация и хранение результатов

Для последующего использования матрицы часто сериализуются:

const serialized = JSON.stringify(response);
localStorage.setItem("distanceMatrix", serialized);

В серверных системах данные могут сохраняться в:

  • Redis (для быстрых вычислений)
  • PostgreSQL (для аналитики)
  • BigQuery (для агрегированных отчётов)

Преобразование матрицы в графовую модель

Матрица расстояний естественно трансформируется в взвешенный граф:

  • вершины — точки маршрута
  • рёбра — расстояния или времена
  • веса — значения duration.value или distance.value
const graph = {};

rows.forEach((row, i) => {
  graph[i] = {};

  row.elements.forEach((el, j) => {
    if (el.status === "OK") {
      graph[i][j] = el.duration.value;
    }
  });
});

Такой подход используется в алгоритмах:

  • Дейкстры
  • Флойда–Уоршелла
  • A* поиска

Учет трафика в матричных вычислениях

При включении параметра traffic данные становятся динамическими:

  • значения зависят от времени запроса
  • возможны расхождения между запросами
  • требуется временное кэширование
const duration = element.duration_in_traffic?.value 
              ?? element.duration.value;

Построение пользовательских таблиц отображения

Матрица часто визуализируется в виде UI-таблиц:

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

Формирование структуры для интерфейса:

const uiMatrix = rows.map(row =>
  row.elements.map(el => ({
    value: el.distance?.text ?? "-",
    status: el.status
  }))
);

Фильтрация и отбор данных

При работе с большими наборами точек применяется фильтрация:

  • исключение недоступных маршрутов
  • ограничение максимального расстояния
  • отбор по времени
const filtered = table.filter(el =>
  el.status === "OK" && el.duration < 3600
);

Композиция нескольких матриц

В сложных системах данные могут объединяться:

  • несколько регионов
  • разные режимы транспорта
  • альтернативные временные окна

При этом требуется унификация:

  • одинаковый порядок origins/destinations
  • синхронизация индексов
  • согласование единиц измерения

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

Основные узкие места:

  • разбор JSON
  • вложенные циклы
  • хранение больших массивов

Оптимизации:

  • использование Typed Arrays для числовых данных
  • предвычисление индексов
  • потоковая обработка результатов
  • минимизация копирования объектов

Типизация структуры результата

При строгой архитектуре данные описываются интерфейсом:

interface MatrixElement {
  distance?: {
    text: string;
    value: number;
  };
  duration?: {
    text: string;
    value: number;
  };
  status: string;
}

interface MatrixRow {
  elements: MatrixElement[];
}

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