be_a_dancer
@be_a_dancer
Backend/Fullstack Developer

Как извлечь named tuple / json / map со значениями различного типа из подзапроса в clickhouse?

Всем привет. Вопрос довольно сложный. У нас есть задача оптимизировать несколько запросов к базе, так как по очереди они выполняются более 10 секунд. Лучшим способом является объединить их в один. Для этого, надо результаты подзапросов сложить в массив json-подобных структур - пар ключ -> значение, причем значение может и должно быть разными типами.
Пример запроса.

SELECT 123456 as productId,
       ordersHistory # <- это должен быть результат вида [{'date': '2022-11-10', 'orders': 4}], сейчас он выглядит как  [('2022-11-10', 4)]
FROM products
GLOBAL LEFT JOIN (
   SELECT groupArray(tuple(date, orders)) ordersHistory,
          123456 as productId,
   FROM (
      SELECT date, orders
      FROM orders
      WHERE productId = 123456 AND date BETWEEN '2022-10-10' AND '2022-11-10'
   )
   GROUP BY productId
) orders ON products.productId = orders.productId


Я уже пытался использовать кастинг к json-у, как в виде output-формата, так и в виде ::JSON. Первый невозможен в подзапросах, второй требует либо named tuple (который непонятно как создавать в виде результата подзапроса), либо обычный plain tuple, что не работает в моем случае. Пробовал тайпкастинг к map-е, но ей нужно зафиксированный тип значения, а у меня там могут быть и строки, и числа, и флоаты.
  • Вопрос задан
  • 342 просмотра
Решения вопроса 1
be_a_dancer
@be_a_dancer Автор вопроса
Backend/Fullstack Developer
Проблему решил следующим образом: у нас на входе есть

tuple(date, orders) AS start.

Если мы хотим из него получить JSON, то нам нужно назвать его поля.

cast(tuple(date, orders), Tuple(date Date, orders UInt64)) AS namedTuple


Далее, преобразуем именованный кортеж в JSON объект.

namedTuple::JSON as jsonedTuple

Мы не можем сразу использовать JSON в groupArray - будет ошибка. Поэтому воспользуемся "хаком". Найдем супертип, который "кушает" и JSON и groupArray -> строка.

toString(jsonedTuple) as stringifiedJson

И вот в эту секунду мы можем сгрупировать наши JSON-строки.

groupArray(stringifiedJSON)

Итоговый код:
SELECT groupArray(toString(cast(tuple(date, orders), Tuple(date Date, orders UInt64))::JSON))


Решение выглядит грязновато. Но это единственное решение, которое я нашел для обхода этой проблемы.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы