Telegram Web
Извиняюсь за долгое молчание, как-то не было ни интересных тем, ни желания что-то писать. Но тема появилась.

Столкнулся с необходимостью саггрегировать логи, хранящиеся в Opensearch, надо было взять уникальные сообщения об ошибках, по 1 шт. Логов после всех фильтров немного, десятки тысяч строк. Визуальный конструктор запросов не предложил ничего внятного, пошел в гугл - предлагает писать запросы в виде json-ов, как монга, но синтаксис естественно отличается.

С мыслью "вы наркоманы что-ли, ещё один оригинальный язык запросов?!" я отправился к нейронке, но она не помогла. Тогда я выгрузил результат как csv и нижеприведенным кодом на шарпе решил проблему.
var data = File.ReadAllLines("Книга1.csv")
.Select(line => line.Split(',')[2])
.Distinct()
.ToArray();

File.WriteAllLines("Книга2.csv", data);


Теперь печально задаюсь вопросом, почему каждая no-sql кочка изобретает свой язык запросов, а завозят ограниченную поддержку SQL для типовых ситуаций - далеко не все.
Тем по it пока не наблюдается: все занимательное что происходит у меня - под NDA. Подумал - может быть имеет смысл разбавить техническую муть моим основным увлечением - автотуризмом с рыбалкой? Фоточки, байки, всякое такое.
Anonymous Poll
58%
Да
25%
Нет
17%
Все равно
В последнюю неделю апреля и в первых числах мая мы с семьёй (жена, я и двое детей - 6 и 3.5 лет) отправились в отпуск на Селигер.

Наверное самым запоминающимся моментом была ночь с 30 апреля на 1 мая. Мы как раз съехали с турбазы и отправились пожить с палатками в лесу на берегу озера. Фотка сделана около 1:00, когда я вел маящегося животом младшего погреться у печки во второй палатке. На следующее утро мы поняли, что с двумя детьми жить в лесу в снегу пока рановато и через новогодний заснеженный лес (на видео) эвакуировались на турбазу.

#природа
This media is not supported in your browser
VIEW IN TELEGRAM
Ещё один занятный момент произошел когда мы остановились показать детям бобриную плотину на одном из ручьёв, который пересекала дорога, ведущая с турбазы. Из леса на водопой вышел кабанчик, спокойно попил и потрусил по своим делам дальше.

#природа
И завершу тему прошедшего отпуска небольшой подборкой фоточек с Селигера.

#природа
На выходных был на рыбалке на Рыбинском водохранилище, открывал летний водомоторный сезон.

В сумме я провел на воде около 16 часов, кидая спиннинг и исследуя место впадения речки Рени в Рыбинское водохранилище. Ехал я за щукой, но она не клевала, совсем: ни единой отметины зубов на приманках я не увидел. Клевал окунь, два (грамм по 300) оказались достаточно голодными, чтобы проглотить щучью приманку.

Несмотря на малое количество рыбы, поездка удалась: сильно прокачался в управлении лодкой, обкидал новый спиннинг, попал в ливень посреди залива, покупался.

#природа
Последние полтора года я работал в банке ПСБ, но пришло время расставаться. Был получен крайне интересный опыт, правда больше организационный: я увидел как может быть организована разработка в крупной организации с серьезным контролем качества и сохранности данных.

За полтора года пользования внутренними платформенными решениями и следования корпоративным стандартам кода я неслабо забыл базовые вещи, потому далее будет серия постов-шпаргалок по разным вопросам, которые могут встретиться на собеседованиях на сеньора-шарписта.

Основная цель - осознать и запомнить некоторые моменты, которые не держатся в голове, заодно получив материалы для освежения в памяти базы.

Далее подобные посты будут публиковаться под тегом #собес
И начну я серию постов к собеседованиям #собес с базовой базы: первых четырёх нормальных форм (НФ) реляционки. Вообще, я как-то больше по денормализации, потому попробую снабдить каждую из НФ короткими ремарками, как я её попирал.

Первая нормальная форма: в таблицах есть первичные ключи, отсутствуют дубли, к тому же нет составных данных, то есть не допускается хранение данных в одной записи в виде массива или просто утрамбованных в текстовый тип данных с разделителем. Про то, как я мучался с дублями в таблице в ~500Гб можно почитать тут. А еще у меня на одном из рабочих проектов был опыт, когда одно из хранимых мной полей могло быть long, long[], guid или objectId (монговский формат "уникального" id). Сохранение в виде строки не проходило по требованиям к объему базы, раскидывание по разным строкам - по требованиям к производительности. В итоге я изобразил свой бинарный формат и хранил тупо байтики.

Поясню: long - id сущности из другой системы, например - "инфаркт" (система была для медтеха). long[] - жесткая сцепка двух понятий, например - "инфаркт в анамнезе", что несет несколько другой смысл для принятия врачебных решений (делалась СППВР).

Вторая нормальная форма
. База пребывает в первой форме, а в дополнение - данные во всех столбцах зависят от первичного ключа целиком. Нарушал, сознательно, получилось удачно. Таблица, в которой хранятся логи того, что произошло с заказом. Ключ у таблицы составной, пусть будет id заказа + id изменения, уникальный в рамках данного заказа. Мне понадобилось иметь быстрый доступ к статусу заказа, ну я и стал его проставлять во всех записях, относящихся к заказу. В результате можно получить некоторый выигрыш в получении статуса: указываем id заказа, после чего первая встреченная нами запись гарантировано содержит нужную нам информацию. Вообще, это дикость и варварство, не надо так делать, но в том конкретном случае получилось отлично за счёт некоторых нюансов, про которые я когда-нибудь напишу отдельно.

Третья нормальная форма + нормальная форма Бойса-Кодда - база пребывает в первой и второй НФ, к тому же отсутствует один из любимых (в т.ч. мной) способов посрезать углы: вместо внешнего ключа, указывающего на таблицу-справочник, писать значение из несостоявшегося справочника прямо в основную таблицу. Встречал подобное десятки раз, обычно так сохраняют статусы, меняющиеся со временем или обвешивают записи системой тегов для группировки или фильтрации. И сам так делал и буду делать, если дозволяют принятые стандарты.

Для себя не вижу смысла разделять их между собой. С т.з. формального определения разница существенная, а вот стандартное нарушение едино.

Четвертая нормальная форма
- база пребывает во всех предшествующих нормальных формах, а в дополнение в таблицах отсутствуют данные, зависящие только от первичного ключа, но при этом не имеющие между собой логических связей. Этот принцип я нарушал множество раз и с особым цинизмом. Один из примеров - был у меня маленький проект, связанный с системой построения отчётов FastReports (я писал о ней). Мне нужно было решить проблему хранения файлов отчётов и информации о них: название, тег (идентификатор отчёта, по которому его запрашивает фронт), группа, сам файл макета отчёта, сериализованный в base64 (да, хранить такое в базе - дикость, но иногда приходится).

По хорошему, у меня должно было быть три или четыре таблицы, связанные внешними ключами, что-то вроде: reports_info, reports_tags, reports_groups, reports_base64_files. Но я все утрамбовал в одну таблицу, вынимая по тегу отчёт, имеющий самую свежую дату. Примитивно и сердито.

Из кучи просмотренного в интернете по нормальным формам, самой толковой оказалась информация на сайте ИТМО: первая и вторая, третья, четвертая.
2025/06/25 02:45:15
Back to Top
HTML Embed Code: