IPv4 та IPv6 адреси в ClickHouse
ClickHouse надає великий набір функцій для роботи з IP-адресами, що дозволяє зберігати і обробляти мережеві дані прямо в базі, без необхідності вивантажувати їх у зовнішні скрипти.
IPv4 та IPv6 в одній колонці
Якщо IPv4 і IPv6 зберігаються в різних колонках — ніяких проблем не виникає: кожна група функцій працює з “своїм” типом даних.
Але в реальних завданнях (наприклад, при зберіганні логів nginx) часто потрібно розміщувати IPv4 і IPv6 в одній колонці. У цьому випадку зазвичай використовують тип IPv6, куди IPv4 записуються у вигляді IPv4-mapped адрес::ffff:x.x.x.x). Тут і з'являється нюанс: функції для IPv4 і IPv6 відрізняються, і виклик потрібної функції доводиться вибирати за умовою.
Як позбутися префікса ::ffff: у IPv4-адресах
При зберіганні IPv4 в колонці типу IPv6 вони автоматичні отримують префікс ::ffff:. Якщо потрібно вивести «чистий» IPv4-адресу, необхідно або перетворити її в тип IPv4, або прибрати префікс рядковими функціями. Тому в запитах зазвичай додають умову, що визначає тип адреси:
SELECT
if(
startsWith(toString(ip), '::ffff:'),
toString(toIPv4(ip)),
toString(ip)
)
FROM nginx_log;Виклик функцій для обробки IP-адрес
ClickHouse використовує сувору типізацію, схожу з C++. Тому при роботі з IP необхідно явно вказувати перетворення.
Наприклад, функція IPv4CIDRToRange застосовується тільки до даних типу IPv4. Якщо дані зберігаються у вигляді IPv6, але фактично є IPv4-mapped адресами, їх спочатку потрібно привести до IPv4:
SELECT
if(
startsWith(toString(ip), '::ffff:'),
toString(IPv4CIDRToRange(toIPv4(ip), netbits).1),
toString(IPv6CIDRToRange(ip, netbits).1)
) AS network
FROM ngnx_log;Формат даних, що повертаються
Функції IPv4CIDRToRange і IPv6CIDRToRange повертають tuple — масив із заздалегідь визначеними типами. Щоб отримати конкретний елемент, використовується точкова нотація:
IPv6CIDRToRange(ip, netbits).1(Наприклад .1 — це перший елемент масиву).
Проблема з різними типами і приведення до рядка
Важливо враховувати, що типи всередині повернутих масивів відрізняються: IPv6CIDRToRange повертає IPv6, а IPv4CIDRToRange — IPv4. Якщо спробувати об'єднати їх без приведення типів, ClickHouse видасть помилку:
Code: 386. DB::Exception: There is no supertype for types IPv6, IPv4 because some of them are numbers and some of them are notЩоб уникнути помилки, необхідно привести значення до єдиного типу — зазвичай до рядкового:
toString(...)Так можна коректно об'єднати результати обох функцій в одному запиті.