Задача звучала просто: посчитать, у скольких товаров в базе есть в составе хоть одна Е-добавка. Я думал, это работа на полчаса. Работа заняла вечер, и большая часть вечера ушла на одну букву. Читать далее
Уровень сложностиСредний
Время на прочтение3 мин
Охват и читатели10K
Кейс
Задача звучала просто: посчитать, у скольких товаров в базе в составе есть хоть одна Е-добавка. Я думал, это работа на полчаса. Работа заняла вечер, и большая часть вечера ушла на одну букву.
Наивная версияwhere ingredients_text ilike '%Е%'
Восемьдесят с чем-то тысяч совпадений. То есть почти всё. Потому что буква «е» встречается примерно в каждом русском слове, а ilike про регистр не спрашивает.
Ладно, ищем букву с цифрами.
where ingredients_text ~ 'Е[0-9]{3}'
Стало пятнадцать тысяч, и вот тут начинается интересное.
Грабля первая: их двеБуква «Е» в кодах добавок пишется и кириллицей, и латиницей. Производители используют обе, часто в одном составе: «Е330, E202, краситель Е160а». Глазом не отличить, для regexp это два разных символа.
Лечится в лоб — классом [EЕ], где первая латинская, вторая кириллическая. В коде это выглядит как опечатка, и каждый, кто лезет в репозиторий, первым делом порывается её «исправить». Я теперь пишу рядом комментарий капслоком.
«Е471», «Е 471», «Е-471», «Е — 471». Всё это встречается, всё это один эмульгатор. Добавляем \s?-?\s?.
Вот это самое подлое. Без границы Е[0-9]{3} радостно ловит хвосты артикулов, маркировок упаковки и всякого мусора, который затесался в поле состава: «…ТУ 9226-015-00419785». Внутри сидит идеальная «Е785», которой не существует в природе.
Поэтому слева нужен не-буквенно-цифровой символ или начало строки:
ingredients_text ~* '(^|[^0-9A-Za-zА-Яа-яЁё])[EЕ]\s?-?\s?[0-9]{3,4}'
{3,4} — потому что есть четырёхзначные, тот же Е1422, модифицированный крахмал. Он, кстати, в топе.
После этого цифра успокоилась и перестала прыгать между прогонами.
Что получилось87 055 товаров с распознанным составом. Е-добавка есть у 17 270 — 19,8%. Каждый пятый.
Я ждал больше. Сильно больше.
Разброс по категориям, если брать крайности:
вода 0,0% конфеты 46,7%
мука 0,9% жвачка 45,8%
чай 1,4% ветчина 44,2%
сок 1,8% колбаса 40,6%
крупы 5,4% сосиски 38,9%
Середина тоже любопытная: газировка — 19,9%, ровно среднее по базе, хотя я был уверен, что там сплошняком. Сыр — 30,6%, почти как кетчуп.
Топ по частоте: Е621 (2 872 товара), Е536, Е476, Е330, Е471. Е536 — это антислёживатель из пачки соли, Е330 — лимонная кислота. На восьмом месте Е300, то есть витамин C, 1 200 товаров.
А теперь то, из-за чего цифру нельзя брать в лобМой regexp ищет код. Он не ищет добавку.
Производитель имеет полное право написать «рибофлавин» вместо Е101 или «лецитин соевый» вместо Е322. Вещество то же, регламент тот же, в мою выборку оно не попадает. Никакого обмана, просто другой способ записи — и он, между прочим, честнее выглядит для покупателя при ровно том же содержимом пачки.
Так что 19,8% — это не «доля товаров с добавками». Это доля товаров, где добавка названа кодом. Нижняя граница. Настоящая цифра выше, а насколько — я не знаю, и любой, кто вам назовёт её точно, тоже не знает.
Отдельно веселит вывод: хочешь, чтобы твой товар в любом сканере состава выглядел чище — просто пиши словами. Полностью легально.
Бонус: как я считал длину составаВторым критерием мне нужно было число позиций в составе. Сделал очевидное:
cardinality(array_remove(string_to_array(
regexp_replace(btrim(ingredients_text), '[;]', ',', 'g'), ','), ''))
Точки с запятой в запятые, split, посчитать. Работает — ровно до первой скобки.
«Шоколад (сахар, какао тёртое, масло какао, лецитин)» — это одна позиция состава. Мой счётчик видит пять. И чем сложнее товар, тем сильнее он завышает: у печенья с начинкой скобки вложены в скобки.
Я это оставил как есть, потому что критерий у меня грубый — «больше пяти позиций или нет». Но если кто-то соберётся считать состав всерьёз, начинать надо с парсера скобок, а не с split(','). Я вас предупредил.
Половина работы с составами — это не аналитика, а археология: как именно на этой конкретной фабрике решили написать одну и ту же вещь. Две буквы Е, четыре способа поставить дефис, скобки без системы.
Зато когда цифра наконец сошлась, выяснилось, что «еда — сплошная химия» всё-таки преувеличение. Ну, если верить кодам. А словам верить сложнее.
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | От 12 часов к 30 минутам: как мы join’им миллиарды товарных движений в ClickHouse | 0 | 10.93 | 10-08-2026 |
| 2 | 3000 точек на карте грузились полсекунды. Ускорял не там, где думал | 0 | 10.75 | 21-08-2026 |
| 3 | pg_anon: как быстро обезличить базу 1С без промежуточной копии | 0 | 13.38 | 22-09-2026 |
| 4 | [Перевод] Структуры данных на практике. Глава 16: Фильтры Блума и вероятностные структуры данных | 0 | 7 | 28-06-2026 |
| 5 | Как уронить базу данных | 0 | 6.72 | 17-08-2026 |
| 6 | Когда контекстное окно кончается, а проект — нет | 5 | 7 | 23-06-2026 |
| 7 | ТОП-10 сайтов мебельных магазинов: лучшие UX-решения и приемы юзабилити | 0 | 13.23 | 27-05-2026 |
| 8 | Более 100 000 вакансий: полный анализ IT‑рынка России в 2026 году. Кто нас на самом деле нанимает? | 0 | 11.81 | 24-08-2026 |
| 9 | В Екатеринбурге число вакансий для сборщиков заказов в ритейле выросло вдвое | 0 | 13.96 | 10-08-2026 |