Палантир. Часть 10. Полнотекстовый поиск.
#палантир@eshu_coding
В прошлом посте я демонстрировал, как работает полнотекстовый поиск в постгресе в зависимости от используемого словаря.
Словари имеют некоторые особенности. Дефолтный коряво отрезает окончания, не умеет в синонимы.
Тот, который я компилировал из исходников очень неплохо справляется с падежами и склонениями. Но при этом он бьёт имена собственные: человека по фамилии Медведев он превратит в медведя.
К тому же у него есть особенность: при попадании на разбор "слова" из 80 и более символов (что-то типа ахахахаха....) он пытается съесть 10^19 бит памяти, которых на сервере естественно нет. Ещё этот словарь крашит постгрес при попадании какого-нибудь экзотического символа, например иероглифа.
Проблемы больших слов и иероглифов я решил тупо регулярным выражением, которое вырезает некондицию из текста.
В итоге я не смог выбрать, что мне больше нравится - качественный поиск по обычным словам или возможность искать имена собственные - и оставил векторизироваться и индексироваться оба словаря.
Со временем надо будет дорабатывать словарь, расширяя функционал работы с падежами и склонениями на имена собственные.
Вообще, готовое решение для полностекстового поиска на русском языке есть встроенное в Postgres Pro, но он платный, лицензия около 200к рублей.
Впрочем, Yandex.Cloud предоставляет Postgrespro как сервис, примерно за 10 тыс рублей в месяц, потому лицензию покупать не обязательно, можно арендовать пробный сервер и поиграться с ним.
#палантир@eshu_coding
В прошлом посте я демонстрировал, как работает полнотекстовый поиск в постгресе в зависимости от используемого словаря.
Словари имеют некоторые особенности. Дефолтный коряво отрезает окончания, не умеет в синонимы.
Тот, который я компилировал из исходников очень неплохо справляется с падежами и склонениями. Но при этом он бьёт имена собственные: человека по фамилии Медведев он превратит в медведя.
К тому же у него есть особенность: при попадании на разбор "слова" из 80 и более символов (что-то типа ахахахаха....) он пытается съесть 10^19 бит памяти, которых на сервере естественно нет. Ещё этот словарь крашит постгрес при попадании какого-нибудь экзотического символа, например иероглифа.
Проблемы больших слов и иероглифов я решил тупо регулярным выражением, которое вырезает некондицию из текста.
В итоге я не смог выбрать, что мне больше нравится - качественный поиск по обычным словам или возможность искать имена собственные - и оставил векторизироваться и индексироваться оба словаря.
Со временем надо будет дорабатывать словарь, расширяя функционал работы с падежами и склонениями на имена собственные.
Вообще, готовое решение для полностекстового поиска на русском языке есть встроенное в Postgres Pro, но он платный, лицензия около 200к рублей.
Впрочем, Yandex.Cloud предоставляет Postgrespro как сервис, примерно за 10 тыс рублей в месяц, потому лицензию покупать не обязательно, можно арендовать пробный сервер и поиграться с ним.
Telegram
Эшу быдлокодит
Как разные словари для полнотекстового поиска в постгресе (для #палантир@eshu_coding) разбирают текст.
Структура таблицы:
1. Исходный текст
2. Текст, разобранный дефолтным парсером
3. Текст, разобранный парсером со словарем от OpenOffice
4. Текст, разобранный…
Структура таблицы:
1. Исходный текст
2. Текст, разобранный дефолтным парсером
3. Текст, разобранный парсером со словарем от OpenOffice
4. Текст, разобранный…
Палантир. Часть 11. Быстродействие поиска.
#палантир@eshu_coding
После запуска индексирования всего массива данных всплыла проблема быстродействия поиска: в тот момент в базе было около 600 млн сообщений (сейчас за 750) и поиск по ним работал, но мееедленно, минут 10-15 на запрос.
Перепробовал все варианты, которые предлагали на хабре, после чего совершенно случайно обнаружил у себя "небольшой" косяк.
Запросы проходят ту же процедуру очистки регулярными выражениями, что и тексты. Я поставил очистку прямо в запрос, не особо задумываясь, как было в примерах.
В ходе экспериментов я совершенно случайно обнаружил, что очистка над текстом запроса выполнялась для КАЖДОЙ проверяемой записи в БД отдельно.
Вынес очищенный текст запоса в отдельную переменную, которую стал использовать в поиске и случилась магия: поиск стал работать за десятки секунд.
После этого задействовал все трюки, которые вычитал на хабре, добившись скорости поиска в секунды.
Трюки состоят в следующем: поставить расширение, где добавлен особый индекс для полнотекстового поиска, результат запоса сортировать по "похожести" и возвращать верхнюю 1000 результатов.
В целом, получилось неплохо, через какое-то время запущу для подписчиков тестового бота. Проект, кстати, получил от уважаемого @ssleg название "Палантир", так и запишем:)
#палантир@eshu_coding
После запуска индексирования всего массива данных всплыла проблема быстродействия поиска: в тот момент в базе было около 600 млн сообщений (сейчас за 750) и поиск по ним работал, но мееедленно, минут 10-15 на запрос.
Перепробовал все варианты, которые предлагали на хабре, после чего совершенно случайно обнаружил у себя "небольшой" косяк.
Запросы проходят ту же процедуру очистки регулярными выражениями, что и тексты. Я поставил очистку прямо в запрос, не особо задумываясь, как было в примерах.
В ходе экспериментов я совершенно случайно обнаружил, что очистка над текстом запроса выполнялась для КАЖДОЙ проверяемой записи в БД отдельно.
Вынес очищенный текст запоса в отдельную переменную, которую стал использовать в поиске и случилась магия: поиск стал работать за десятки секунд.
После этого задействовал все трюки, которые вычитал на хабре, добившись скорости поиска в секунды.
Трюки состоят в следующем: поставить расширение, где добавлен особый индекс для полнотекстового поиска, результат запоса сортировать по "похожести" и возвращать верхнюю 1000 результатов.
В целом, получилось неплохо, через какое-то время запущу для подписчиков тестового бота. Проект, кстати, получил от уважаемого @ssleg название "Палантир", так и запишем:)
Telegram
Эшу быдлокодит
Прошу прощения за долгое молчание, было безумно много работы.
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …
Палантир. Часть 12. Юзер интерфейс.
#палантир@eshu_coding
Тестировать поиск через запросы, как напрямую в БД, так и отправляемые через Postman на API - это прекрасно, но удобно только для разработчика, т.е. меня.
Как только проект обрёл признаки MVP - появилась необходимость подключать к тестированию других людей, а стало быть пришлось заняться пользовательским интерфейсом.
Вариант с отдельным сайтом я пока отмел: с фронтендом я не знаком от слова совсем, хотя со временем было бы неплохо познакомиться, остановился на боте для телеграма.
Ботов я раньше писал, и часть, связанная с тем, чтобы сделать использование бота УДОБНЫМ, да ещё и без глюков, всегда была кошмаром.
В этот раз по началу все шло также: все было глючным и неудобным. Но в какой-то момент мне стукнуло в голову: а что если представить бота как конечный автомат?
Конечный автомат - абстракция, в которой нечто, взаимодействующее с внешним миром, представляется в виде черного ящика, имеющего ограниченный набор состояний, правил перехода между ними и реакций на внешние раздражители, зависящих от текущего состояния.
С этой абстракцией я познакомился после какого-то заваленного собеседования, подумал "что за дичь? Мне оно не упёрлось" (тогда я пилил ботов, бгг). И только сейчас, спустя 8 месяцев я осознал, зачем всё это.
Я быстренько выделил 5 основных состояний у бота, за вечер описал каждое из них, не пытаясь засунуть в голову ВСЕ варианты сочетаний раздражителей и реакций одновременно, и с ходу получил MVP, не без глюков конечно, но без фатальных проблем.
Кстати, очень удобным для реализации поиска, оказалось использование gRPC в качестве протокола общения. Бот посылает одиночный запрос, сервер в ответ начинает стрим и передаёт результаты по мере нахождения, а бот и соответственно отображает. Для пользователя это ещё сильнее увеличивает быстродействие: первый результат появляется практически сразу, а что находится потом - долетает отдельно.
Всё это можно сделать и на отдельных запросах, но такой вариант выглядит как-то изящнее. На очереди развитие бота: база данных, уровни доступа, кеширование результатов поиска, более удобный интерфейс.
#кодинг
#палантир@eshu_coding
Тестировать поиск через запросы, как напрямую в БД, так и отправляемые через Postman на API - это прекрасно, но удобно только для разработчика, т.е. меня.
Как только проект обрёл признаки MVP - появилась необходимость подключать к тестированию других людей, а стало быть пришлось заняться пользовательским интерфейсом.
Вариант с отдельным сайтом я пока отмел: с фронтендом я не знаком от слова совсем, хотя со временем было бы неплохо познакомиться, остановился на боте для телеграма.
Ботов я раньше писал, и часть, связанная с тем, чтобы сделать использование бота УДОБНЫМ, да ещё и без глюков, всегда была кошмаром.
В этот раз по началу все шло также: все было глючным и неудобным. Но в какой-то момент мне стукнуло в голову: а что если представить бота как конечный автомат?
Конечный автомат - абстракция, в которой нечто, взаимодействующее с внешним миром, представляется в виде черного ящика, имеющего ограниченный набор состояний, правил перехода между ними и реакций на внешние раздражители, зависящих от текущего состояния.
С этой абстракцией я познакомился после какого-то заваленного собеседования, подумал "что за дичь? Мне оно не упёрлось" (тогда я пилил ботов, бгг). И только сейчас, спустя 8 месяцев я осознал, зачем всё это.
Я быстренько выделил 5 основных состояний у бота, за вечер описал каждое из них, не пытаясь засунуть в голову ВСЕ варианты сочетаний раздражителей и реакций одновременно, и с ходу получил MVP, не без глюков конечно, но без фатальных проблем.
Кстати, очень удобным для реализации поиска, оказалось использование gRPC в качестве протокола общения. Бот посылает одиночный запрос, сервер в ответ начинает стрим и передаёт результаты по мере нахождения, а бот и соответственно отображает. Для пользователя это ещё сильнее увеличивает быстродействие: первый результат появляется практически сразу, а что находится потом - долетает отдельно.
Всё это можно сделать и на отдельных запросах, но такой вариант выглядит как-то изящнее. На очереди развитие бота: база данных, уровни доступа, кеширование результатов поиска, более удобный интерфейс.
#кодинг
Telegram
Эшу быдлокодит
Прошу прощения за долгое молчание, было безумно много работы.
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …
Палантир. Часть 13. Жизненный цикл приказов, эпизод черт знает какой.
#палантир@eshu_coding
Изначальная идея взаимодействия мастера и сборщиков заключалась в следующем:
Они ничего не знают о состояниях друг друга, сборщик просит приказ, мастер его выдает, если приказ подходит под возможности сборщика - он выполняется, если нет - возвращается назад.
После трех итераций и пары месяцев работы я пришел к выводу, что этот подход не годится. В какой-то момент подобное отношение к приказам приводило к тому, что сборщики начинали передавать туда-сюда невыполнимые приказы.
Решением стала полная перекройка логики. При работе клиент телеграма сохраняет "сессию" - данные для упрощения повторных логинов и повторных запросов к чатам и каналам, которые уже встречались аккаунту на просторах телеграма. В моем случае база централизовано хранится в отдельном сервере Postgres с помощью очень удобного инструмента, ссылку на который я обнаружил, читая документацию к telethon (да, я иногда это делаю:)).
У всех чатов и канало в базе добавилась колонка Finder, где содержится массив всех номеров телефонов сборщиков, "знакомых" с этим каналом. Сборщик, когда просит данные, "представляется" и сообщает, заблокированы ли у него тяжелые запросы.
Если может запрашивать новые чаты - мастер выдает приказ на запрос, если не может - выдается приказ подтянуть историю сообщений с одного из знакомых чатиков. В дополнение к трем очередям приказов: обычной, среднего и высокого приоритета, добавилось число очередей по количеству сборщиков.
У одного чата "Finder"-ов может быть много, хоть все сборщики сразу. Потому, во избежание размножения дублирующихся записей, пришлось распихивать приказы по всем соответствующим очередям одновременно и делать потокобезопасное поле-флаг, где отмечено состояние приказа. Если была попытка получить приказ, находящийся в состоянии отличном от "требуется исполнение" - приказ выбрасывается из очереди, а на его место забирается следующий.
#палантир@eshu_coding
Изначальная идея взаимодействия мастера и сборщиков заключалась в следующем:
Они ничего не знают о состояниях друг друга, сборщик просит приказ, мастер его выдает, если приказ подходит под возможности сборщика - он выполняется, если нет - возвращается назад.
После трех итераций и пары месяцев работы я пришел к выводу, что этот подход не годится. В какой-то момент подобное отношение к приказам приводило к тому, что сборщики начинали передавать туда-сюда невыполнимые приказы.
Решением стала полная перекройка логики. При работе клиент телеграма сохраняет "сессию" - данные для упрощения повторных логинов и повторных запросов к чатам и каналам, которые уже встречались аккаунту на просторах телеграма. В моем случае база централизовано хранится в отдельном сервере Postgres с помощью очень удобного инструмента, ссылку на который я обнаружил, читая документацию к telethon (да, я иногда это делаю:)).
У всех чатов и канало в базе добавилась колонка Finder, где содержится массив всех номеров телефонов сборщиков, "знакомых" с этим каналом. Сборщик, когда просит данные, "представляется" и сообщает, заблокированы ли у него тяжелые запросы.
Если может запрашивать новые чаты - мастер выдает приказ на запрос, если не может - выдается приказ подтянуть историю сообщений с одного из знакомых чатиков. В дополнение к трем очередям приказов: обычной, среднего и высокого приоритета, добавилось число очередей по количеству сборщиков.
У одного чата "Finder"-ов может быть много, хоть все сборщики сразу. Потому, во избежание размножения дублирующихся записей, пришлось распихивать приказы по всем соответствующим очередям одновременно и делать потокобезопасное поле-флаг, где отмечено состояние приказа. Если была попытка получить приказ, находящийся в состоянии отличном от "требуется исполнение" - приказ выбрасывается из очереди, а на его место забирается следующий.
Telegram
Эшу быдлокодит
Палантир. Часть 2. Жизненный цикл команд.
#палантир@eshu_coding
Как я уже упоминал, мой сборщик построен на микросервисной архитектуре: центральный сервер - master для хранения информации, находящийся над БД (postgresql) и slave-ы сборщики, в некотором количестве.…
#палантир@eshu_coding
Как я уже упоминал, мой сборщик построен на микросервисной архитектуре: центральный сервер - master для хранения информации, находящийся над БД (postgresql) и slave-ы сборщики, в некотором количестве.…
Эшу быдлокодит
Палантир. Часть 12. Юзер интерфейс. #палантир@eshu_coding Тестировать поиск через запросы, как напрямую в БД, так и отправляемые через Postman на API - это прекрасно, но удобно только для разработчика, т.е. меня. Как только проект обрёл признаки MVP - появилась…
К вопросу о конченных конечных автоматах.
Сегодня, обсуждали с коллегой - программистом по образованию - довольно сложную штуку: работу аснхронности (в разрезе многопоточности) в c#. Про неё написаны книги, огромное количество статей на хабре.
Объяснять суть своими словами (особенно импровизируя в разговоре, а не читая подготовленную лекцию) можно долго.
- Знаешь что такое конечный автомат?
- Да.
- Ну вот всё приложение в целом представляется средой выполнения чем-то похожим. А используемые await-ы - границы между состояниями . И вот оно по ним щелк-щелк, используя потоки из пула.
- Аааа, понятно!
Сегодня, обсуждали с коллегой - программистом по образованию - довольно сложную штуку: работу аснхронности (в разрезе многопоточности) в c#. Про неё написаны книги, огромное количество статей на хабре.
Объяснять суть своими словами (особенно импровизируя в разговоре, а не читая подготовленную лекцию) можно долго.
- Знаешь что такое конечный автомат?
- Да.
- Ну вот всё приложение в целом представляется средой выполнения чем-то похожим. А используемые await-ы - границы между состояниями . И вот оно по ним щелк-щелк, используя потоки из пула.
- Аааа, понятно!
Палантир. Часть 14. Дубли в базе. Боль и страдания.
#палантир@eshu_coding
Одной из первых проблем были дубли в данных: одно и то же сообщение засасывалось более одного раза.
В какой-то момент я принял решение просто наплевать на них: ну есть у меня 15% дублирующихся данных, да и черт с ними. Но тут случился эпик фейл.
Запись данных в БД существенно опережала индексацию сообщения в поиске. В какой-то момент механизм защиты от дублей дал сбой и в базу поперли дубли. Некоторые сообщения дублировались по 20 раз.
Я решил проиндексировать вообще все сообщения: загрузка опережала поисковую индексацию на 250 млн сообщений. Удалил индекс со столба с полнотекстовым данными, подождал примерно сутки и решил запускать индексацию (часа 3-4) по моим оценкам.
Через 4.5 часа создание индекса рухнуло с ошибкой "слишком много дублей". И вот я остался с почти терабайтной базой с морем дублей и без рабочего поиска.
Может быть сделать тупое построчное удаление? Добавить сервис, который будет построчно брать данные из основной таблицы, искать к ним дубли и удалять их. Посчитал - обработка займет от 15 до 20 лет.
Нагуглил запрос, который угробит все дубли в таблице. Запустил. Спустя 6 часов PostgreSQL съел 8 Гб оперативки, 10 Гб файла подкачки, после чего ушёл в Out Of Memory.
Попробовал тот же запрос на маленьком кусочке данных - получилось, что в сумме дубли будут чиститься пару недель.
В итоге я пришел к довольно топорному решению: сделать отдельную таблицу, в которую вошли ключи недублирубщихся данных. От дублей - только один, первый встретившийся ключ.
А дальше запрос, который удаляет из исходной таблицы все строки, id которых нет во вспомогательной. Молотило оно больше суток, но мусор почистило.
Итого, в базе осталось около 550 млн уникальных сообщений. Дублей было около 250 тысяч (в какой-то момент закачка обновлений сошла с ума и выкачивала вместо обновления всю историю чата повторно в течение двух недель).
Всего было записано в таблицу около 1 млрд сообщений, часть из которых была угроблена предыдущими попытками уничтожения дублей.
В этот раз жизнь заставила меня сделать следующий шажок в глубину баз данных: научиться пользоваться планировщиком запросов.
Итого на борьбу с дублями я потратил дней пять. И хорошо, что это - мой личный проект.
Мораль сей басни такова: всплыла проблема - решай сразу, а не жди когда она выстрелит под нагрузкой на работающем продукте.
#postgresql
#палантир@eshu_coding
Одной из первых проблем были дубли в данных: одно и то же сообщение засасывалось более одного раза.
В какой-то момент я принял решение просто наплевать на них: ну есть у меня 15% дублирующихся данных, да и черт с ними. Но тут случился эпик фейл.
Запись данных в БД существенно опережала индексацию сообщения в поиске. В какой-то момент механизм защиты от дублей дал сбой и в базу поперли дубли. Некоторые сообщения дублировались по 20 раз.
Я решил проиндексировать вообще все сообщения: загрузка опережала поисковую индексацию на 250 млн сообщений. Удалил индекс со столба с полнотекстовым данными, подождал примерно сутки и решил запускать индексацию (часа 3-4) по моим оценкам.
Через 4.5 часа создание индекса рухнуло с ошибкой "слишком много дублей". И вот я остался с почти терабайтной базой с морем дублей и без рабочего поиска.
Может быть сделать тупое построчное удаление? Добавить сервис, который будет построчно брать данные из основной таблицы, искать к ним дубли и удалять их. Посчитал - обработка займет от 15 до 20 лет.
Нагуглил запрос, который угробит все дубли в таблице. Запустил. Спустя 6 часов PostgreSQL съел 8 Гб оперативки, 10 Гб файла подкачки, после чего ушёл в Out Of Memory.
Попробовал тот же запрос на маленьком кусочке данных - получилось, что в сумме дубли будут чиститься пару недель.
В итоге я пришел к довольно топорному решению: сделать отдельную таблицу, в которую вошли ключи недублирубщихся данных. От дублей - только один, первый встретившийся ключ.
А дальше запрос, который удаляет из исходной таблицы все строки, id которых нет во вспомогательной. Молотило оно больше суток, но мусор почистило.
Итого, в базе осталось около 550 млн уникальных сообщений. Дублей было около 250 тысяч (в какой-то момент закачка обновлений сошла с ума и выкачивала вместо обновления всю историю чата повторно в течение двух недель).
Всего было записано в таблицу около 1 млрд сообщений, часть из которых была угроблена предыдущими попытками уничтожения дублей.
В этот раз жизнь заставила меня сделать следующий шажок в глубину баз данных: научиться пользоваться планировщиком запросов.
Итого на борьбу с дублями я потратил дней пять. И хорошо, что это - мой личный проект.
Мораль сей басни такова: всплыла проблема - решай сразу, а не жди когда она выстрелит под нагрузкой на работающем продукте.
#postgresql
Telegram
Эшу быдлокодит
Прошу прощения за долгое молчание, было безумно много работы.
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …
Наверное самое ценное в канале - когда более опытные программисты, наткнувшиеся на него, по прочитанному дают обратную связь - что и как можно было бы сделать лучше/оптимальнее.
Спасибо за обратную связь!
Спасибо за обратную связь!
Палантир. Часть 15. Окончательное решение вопроса дублей.
#палантир@eshu_coding
Несмотря на локальную победу над дублями, они продолжали потихоньку попадать в базу.
В далёкие времена, когда я проектировал базу данных, я собирался использовать составной primary key в таблице с сообщениями: временная метка сообщения, id чата и порядковый номер сообщения. Но что-то пошло не так. Стандартный способ защиты таблицы с помощью триггера "before insert" не годился на секционированной таблице.
Делать проверку внутри хранимой процедуры для записи оказалось медленно: проверка занимает около 10 мс, на каждое из примерно 1000 сообщений, прилетающих каждую секунду. База мигом захлёбывается.
В итоге я забил на дубли, к чему это привело можете судить по прошлым постам.
Спасибо доброму человеку @vekhden_speak, он подсказал решение, с помощью которого я окончательно поборол дубли. Как окалось, в самом insert-e можно предотвратить конфликт добавив предложение "on conflict on constraint messages_pkey do nothing".
За сутки вычистив базу от остатков дублей, я дописал хранимую процедуру для записи данных в БД, после чего перешёл к изначальной идее ключей. Вот теперь дубли изжиты окончательно.
#postgresql
#палантир@eshu_coding
Несмотря на локальную победу над дублями, они продолжали потихоньку попадать в базу.
В далёкие времена, когда я проектировал базу данных, я собирался использовать составной primary key в таблице с сообщениями: временная метка сообщения, id чата и порядковый номер сообщения. Но что-то пошло не так. Стандартный способ защиты таблицы с помощью триггера "before insert" не годился на секционированной таблице.
Делать проверку внутри хранимой процедуры для записи оказалось медленно: проверка занимает около 10 мс, на каждое из примерно 1000 сообщений, прилетающих каждую секунду. База мигом захлёбывается.
В итоге я забил на дубли, к чему это привело можете судить по прошлым постам.
Спасибо доброму человеку @vekhden_speak, он подсказал решение, с помощью которого я окончательно поборол дубли. Как окалось, в самом insert-e можно предотвратить конфликт добавив предложение "on conflict on constraint messages_pkey do nothing".
За сутки вычистив базу от остатков дублей, я дописал хранимую процедуру для записи данных в БД, после чего перешёл к изначальной идее ключей. Вот теперь дубли изжиты окончательно.
#postgresql
Telegram
Эшу быдлокодит
Прошу прощения за долгое молчание, было безумно много работы.
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …
Лучшая из угроз "роботы всех нас автоматизируют", которую я видел, звучит внушительно. Самый класс - в конце поста.
Telegram
Kedr to Earth | Земля, я Кедр
Учебный год у меня начался в четверг с занятия по истории инноваций в магистратуре Физтеха. Вечером того же дня я прочитал, что в США товарищи пролетарии, получив пособие от властей, больше не хотят трудиться за гроши продавцами и официантами, и дефицит занятости…
Палантир. Часть 16. Клиентская часть для пользователей.
#палантир@eshu_coding
Работа над сборщиком данных в телеграме подошла к финальной стадии:
доделал mvp (минимально жизнеспособный продукт) части для пользователей, на выходе получилось два типа ботов:
Поисковик по телеграму @palantir_search_bot
Сервис оповещений @space_observer_bot
Поисковик просто ищет по скачанной истории сообщений за выбранный интервал времени, выплевывая 1000 самых похожих на запрос результатов.
Сервис оповещений проверяет все входящие сообщения (не старше 6 часов), и если они совпадают с заранее введенным запросом - оповещает пользователей.
Пока что реализована только демо версия, которая отрабатывает по следующему запросу:
Оператор | означает "или", оператор <-> - объединение слов по бокам в фразу. За первый же день работы на небольшую группу бета-тестеров стало очевидно, что все поисковые запросы и оповещения нужно приправлять блокировкой порнухи, ставок на спорт, крипты, политоты и экстремизма, чтобы случайно не заработать себе статью.
Занятной получилась реализация сервиса оповещений. Анализ текста у меня происходит на уровне базы данных, с использованием словарей для полнотекстового поиска. При этом, из базы результат нужно как-то доносить до пользователя.
В итоге родилась идея: приправить основную таблицу триггером after insert, который будет пытаться вставить сообщение, если оно свежее 6 часов, в другую таблицу, получившую название spotter (наводчик).
На таблице spotter висит триггер, который делает select из таблицы queries (хранящей запросы), давая ответ: подходит под запрос или нет.
После этого вызывается функция pg_notify("test", "информация о сообщении"), которая передает информацию о сообщении всем, кто выполнил команду listen "test" и продолжает висеть на связи. В сообщении отправляется ссылка на сообщение и коротенькое превью из 200 первых символов.
Бот-слушатель соответственно рассылает сообщения подписантам.
Теперь для адекватной работы оповещалки (сокращения времени от опубликования до нахождения сообщения до 30-60 минут) нужно в очередной (в 8й) раз переделать менеджер команд сборщикам.
#postgresql
#палантир@eshu_coding
Работа над сборщиком данных в телеграме подошла к финальной стадии:
доделал mvp (минимально жизнеспособный продукт) части для пользователей, на выходе получилось два типа ботов:
Поисковик по телеграму @palantir_search_bot
Сервис оповещений @space_observer_bot
Поисковик просто ищет по скачанной истории сообщений за выбранный интервал времени, выплевывая 1000 самых похожих на запрос результатов.
Сервис оповещений проверяет все входящие сообщения (не старше 6 часов), и если они совпадают с заранее введенным запросом - оповещает пользователей.
Пока что реализована только демо версия, которая отрабатывает по следующему запросу:
'(илон <-> маск) | рогозин | космос | ракета | космическая <-> станция | астероид | галактика | солнечная <-> система | комета | марс | юпитер | сатурн | плутон |венера | солнечные <-> пятна | солнечный <-> ветер | байконур | роскосмос | space <-> x | spacex | орбита | космический <-> мусор | МКС | космонавт | астронавт'
Оператор | означает "или", оператор <-> - объединение слов по бокам в фразу. За первый же день работы на небольшую группу бета-тестеров стало очевидно, что все поисковые запросы и оповещения нужно приправлять блокировкой порнухи, ставок на спорт, крипты, политоты и экстремизма, чтобы случайно не заработать себе статью.
Занятной получилась реализация сервиса оповещений. Анализ текста у меня происходит на уровне базы данных, с использованием словарей для полнотекстового поиска. При этом, из базы результат нужно как-то доносить до пользователя.
В итоге родилась идея: приправить основную таблицу триггером after insert, который будет пытаться вставить сообщение, если оно свежее 6 часов, в другую таблицу, получившую название spotter (наводчик).
На таблице spotter висит триггер, который делает select из таблицы queries (хранящей запросы), давая ответ: подходит под запрос или нет.
После этого вызывается функция pg_notify("test", "информация о сообщении"), которая передает информацию о сообщении всем, кто выполнил команду listen "test" и продолжает висеть на связи. В сообщении отправляется ссылка на сообщение и коротенькое превью из 200 первых символов.
Бот-слушатель соответственно рассылает сообщения подписантам.
Теперь для адекватной работы оповещалки (сокращения времени от опубликования до нахождения сообщения до 30-60 минут) нужно в очередной (в 8й) раз переделать менеджер команд сборщикам.
#postgresql
Forwarded from Библиотека программиста | программирование, кодинг, разработка
Егор Рогов из Postgres Professional подробно и доступно рассказывает теорию и практику работы с PostgreSQL:
📌 Индексы
- Механизм индексирования
- Интерфейс метода доступа, классы и семейства операторов
- Hash
- B-tree
- GiST
- SP-GiST
- GIN
- RUM
- BRIN
- Bloom
📌 Изоляция и многоверсионность
- Изоляция, как ее понимают стандарт и PostgreSQL
- Слои, файлы, страницы — что творится на физическом уровне
- Версии строк, виртуальные и вложенные транзакции
- Снимки данных и видимость версий строк, горизонт событий
- Внутристраничная очистка и HOT-обновления
- Обычная очистка (vacuum)
- Автоматическая очистка (autovacuum)
- Переполнение счетчика транзакций и заморозка
📌 Журналирование
- Буферный кеш
- Журнал предзаписи — как устроен и как используется при восстановлении
- Контрольная точка и фоновая запись — зачем нужны и как настраиваются
- Настройка журнала — уровни и решаемые задачи, надежность и производительность.
📌 Блокировки:
- Блокировки отношений
- Блокировки строк
- Блокировки других объектов и предикатные блокировки
- Блокировки в оперативной памяти
📌 Запросы
- Этапы выполнения запросов
- Статистика
- Последовательное сканирование
- Индексное сканирование
- Соединение вложенным циклом, а также будет продолжение про соединение хешированием / слиянием и сортировку
А еще у Postgres Professional есть учебные курсы, которые доступны всем желающим.
📌 Индексы
- Механизм индексирования
- Интерфейс метода доступа, классы и семейства операторов
- Hash
- B-tree
- GiST
- SP-GiST
- GIN
- RUM
- BRIN
- Bloom
📌 Изоляция и многоверсионность
- Изоляция, как ее понимают стандарт и PostgreSQL
- Слои, файлы, страницы — что творится на физическом уровне
- Версии строк, виртуальные и вложенные транзакции
- Снимки данных и видимость версий строк, горизонт событий
- Внутристраничная очистка и HOT-обновления
- Обычная очистка (vacuum)
- Автоматическая очистка (autovacuum)
- Переполнение счетчика транзакций и заморозка
📌 Журналирование
- Буферный кеш
- Журнал предзаписи — как устроен и как используется при восстановлении
- Контрольная точка и фоновая запись — зачем нужны и как настраиваются
- Настройка журнала — уровни и решаемые задачи, надежность и производительность.
📌 Блокировки:
- Блокировки отношений
- Блокировки строк
- Блокировки других объектов и предикатные блокировки
- Блокировки в оперативной памяти
📌 Запросы
- Этапы выполнения запросов
- Статистика
- Последовательное сканирование
- Индексное сканирование
- Соединение вложенным циклом, а также будет продолжение про соединение хешированием / слиянием и сортировку
А еще у Postgres Professional есть учебные курсы, которые доступны всем желающим.
Postgres Professional
Компания Postgres Professional
Postgres Professional - российская компания, разработчик систем управления базами данных
Создавая базу знаний, описывающую реальность, какой id вы присвоили бы понятию "религия"?
Я нашёл это понятие под id 666, у добавившего всё хорошо с чувством юмора.
P.S. на другие интересные сочетания цифр ничего не нашлось.
Я нашёл это понятие под id 666, у добавившего всё хорошо с чувством юмора.
P.S. на другие интересные сочетания цифр ничего не нашлось.
Экспериментирую сейчас с MongoDB.
Установил, разрешил подключения из внешнего мира, сижу, отлаживаюсь.
И тут в монге появляется новая база данных с сообщением, что все мои данные архивированы, плоти биткоины за расшифровку.
Спасибо ребятам за указание на дыру в безопасности:
по умолчанию в монге доступно анонимное подключение, но только локально.
Разрешив подключение из внешнего мира я забыл вырубить возможность подключиться просто по 27017 порту, хорошо, что сейчас, а не на проде. Заодно и уползу на другой порт.
Установил, разрешил подключения из внешнего мира, сижу, отлаживаюсь.
И тут в монге появляется новая база данных с сообщением, что все мои данные архивированы, плоти биткоины за расшифровку.
Спасибо ребятам за указание на дыру в безопасности:
по умолчанию в монге доступно анонимное подключение, но только локально.
Разрешив подключение из внешнего мира я забыл вырубить возможность подключиться просто по 27017 порту, хорошо, что сейчас, а не на проде. Заодно и уползу на другой порт.
Forwarded from Kedr to Earth | Земля, я Кедр (✅ Yuri Ammosov)
Кажется, пора учредить премию "Безумный банщик", и собирать туда самые идиотские и нелепые причины, за что люди попадали в бан на фейсбуке.
Начну.
1) за преследование и оскорбление гравитации путём именования её собакой женского пола (пока что первое место, история произошла на днях с френдессой, у меня глаза как выпали на клавиатуру, так и лежат)
2) за употребление слова "хатифнатт" (пост удалили, выкатили предупреждение)
3) за употребление словосочетания "этрусский скот" в беседе об античной истории
4) за ироничное цитирование одного товарища (товарища оставили, мне выкатили предупреждение)
5) за фотографии статуй из Летнего сада
6) за фотографии маленьких детей на пляже - потому что детская порнография
7) за цитаты из классической литературы (не помню, какие, но довольно известные и вполне невинные)
8) за фразу "Резать, не дожидаясь перитонита"
9) за фото кильки в булке (порно)
10) за анонс лекции с изображением распятия из-за "демонстрации жестокости"
11) за "грузинских с--обак", хотя имелись в виду именно животные вида Canis lupus familiaris, обитающие в Грузии
12) за цитату статьи Даля о глаголе "майданить"
13) за скриншот антисемитского высказывания в свой адрес (автор скриншота забанен не был)
14) бан на неделю за публикацию перевода фразы, автоматически сделанного фейсбуком (и неверного, насколько я понимаю)
15) за фото своего кобеля, где чуть-чуть видны его яйца - порнография (видимо, на собаку мужского пола желательно надевать трусы перед тем, как сделать фото - прим. Улисса)
16) за слово а р * б в адрес лошади - разжигание
17) за комментарий о том, что мне не нравятся чёрные собаки - расизм. К комментарию, где я говорю, что белые собаки мне тоже не нравятся, у фб претензий нет.
18) за фото обычной морской черепахи. Потому что обнажёнка. Апелляцию не удовлетворили.
19) человека забанили на 30 дней за эпитет "жирненькая" по отношению к традесканции.
20) забанили бизнес-аккаунт магазина шмоток. На фото была куртка из коричневой кожи, обвинили в работорговле. Апелляцию не удовлетворили.
21) В группе томатоводов китайская хохлатая сожрала рассаду баклажанов. Ну народ ржал и обсуждал особенности лысых китайских с-бак. Фб забанил полгруппы вместе с админами
22) за поговорку "Россия родина слонов"
23) за комментарий о том, что автор не может ни одну нацию назвать тупой
24) за упоминание поэта начала 20 века, псевдоним которого состоял из имени Саша и наименования одного неполиткорректного цвета
25) за частое редактирование поста (чую, доиграюсь я сама с этим постом в итоге ^^)
https://facebook.com/story.php?story_fbid=10215431865910389&id=1849806973
Начну.
1) за преследование и оскорбление гравитации путём именования её собакой женского пола (пока что первое место, история произошла на днях с френдессой, у меня глаза как выпали на клавиатуру, так и лежат)
2) за употребление слова "хатифнатт" (пост удалили, выкатили предупреждение)
3) за употребление словосочетания "этрусский скот" в беседе об античной истории
4) за ироничное цитирование одного товарища (товарища оставили, мне выкатили предупреждение)
5) за фотографии статуй из Летнего сада
6) за фотографии маленьких детей на пляже - потому что детская порнография
7) за цитаты из классической литературы (не помню, какие, но довольно известные и вполне невинные)
8) за фразу "Резать, не дожидаясь перитонита"
9) за фото кильки в булке (порно)
10) за анонс лекции с изображением распятия из-за "демонстрации жестокости"
11) за "грузинских с--обак", хотя имелись в виду именно животные вида Canis lupus familiaris, обитающие в Грузии
12) за цитату статьи Даля о глаголе "майданить"
13) за скриншот антисемитского высказывания в свой адрес (автор скриншота забанен не был)
14) бан на неделю за публикацию перевода фразы, автоматически сделанного фейсбуком (и неверного, насколько я понимаю)
15) за фото своего кобеля, где чуть-чуть видны его яйца - порнография (видимо, на собаку мужского пола желательно надевать трусы перед тем, как сделать фото - прим. Улисса)
16) за слово а р * б в адрес лошади - разжигание
17) за комментарий о том, что мне не нравятся чёрные собаки - расизм. К комментарию, где я говорю, что белые собаки мне тоже не нравятся, у фб претензий нет.
18) за фото обычной морской черепахи. Потому что обнажёнка. Апелляцию не удовлетворили.
19) человека забанили на 30 дней за эпитет "жирненькая" по отношению к традесканции.
20) забанили бизнес-аккаунт магазина шмоток. На фото была куртка из коричневой кожи, обвинили в работорговле. Апелляцию не удовлетворили.
21) В группе томатоводов китайская хохлатая сожрала рассаду баклажанов. Ну народ ржал и обсуждал особенности лысых китайских с-бак. Фб забанил полгруппы вместе с админами
22) за поговорку "Россия родина слонов"
23) за комментарий о том, что автор не может ни одну нацию назвать тупой
24) за упоминание поэта начала 20 века, псевдоним которого состоял из имени Саша и наименования одного неполиткорректного цвета
25) за частое редактирование поста (чую, доиграюсь я сама с этим постом в итоге ^^)
https://facebook.com/story.php?story_fbid=10215431865910389&id=1849806973
Палантир. Часть 17. Оптимизация базы данных.
#палантир@eshu_coding
В ближайшее время я планирую запустить поисковик @palantir_search_bot в общее пользование. Пришло время нагрузочного тестирования. Для этого я изобразил отдельный проектик, который имитирует поискового бота.
Для формирования тестовых поисковых запросов я использовал следущий поход: набил штук 100 разных слов (поток сознания там получился занятный, от "фавызм" (именно в таком написании) до хурмы и дыни.
Из этих слов случайным образом формируется пул запросов.
Запрос отправляется на сервер, ожидается ответ. Сразу по получении ответа - посылается следущий запрос. И так в N потоков.
Запустил в 1 поток: всё отлично.
Запустил в 10 потоков: всё отлично, постгрес не замечает нагрузки.
Запустил в 30 потоков. Постгрес не замечает нагрузки. Проходит пара минут и всё виснет.
Полез смотреть на сервер - 8 Гб оперативки кончились, вместе с 10 Гб файла подкачки, все съел постгрес, у которого установлен размер кэша в 2 Гб. Но каждое отдельное подключение, через которое шел поток данных, отъелось и в итоге память кончилась.
Оставил на ночь - постгрес не отвис: память утекла.
Итого, корень зла оказался в том, что подключения к постгресу, когда живут долгое время, не освобождают съеденную оператианую память (или освобождают не всю).
#postgresql
#палантир@eshu_coding
В ближайшее время я планирую запустить поисковик @palantir_search_bot в общее пользование. Пришло время нагрузочного тестирования. Для этого я изобразил отдельный проектик, который имитирует поискового бота.
Для формирования тестовых поисковых запросов я использовал следущий поход: набил штук 100 разных слов (поток сознания там получился занятный, от "фавызм" (именно в таком написании) до хурмы и дыни.
Из этих слов случайным образом формируется пул запросов.
Запрос отправляется на сервер, ожидается ответ. Сразу по получении ответа - посылается следущий запрос. И так в N потоков.
Запустил в 1 поток: всё отлично.
Запустил в 10 потоков: всё отлично, постгрес не замечает нагрузки.
Запустил в 30 потоков. Постгрес не замечает нагрузки. Проходит пара минут и всё виснет.
Полез смотреть на сервер - 8 Гб оперативки кончились, вместе с 10 Гб файла подкачки, все съел постгрес, у которого установлен размер кэша в 2 Гб. Но каждое отдельное подключение, через которое шел поток данных, отъелось и в итоге память кончилась.
Оставил на ночь - постгрес не отвис: память утекла.
Итого, корень зла оказался в том, что подключения к постгресу, когда живут долгое время, не освобождают съеденную оператианую память (или освобождают не всю).
#postgresql
Палантир. Часть 18. Оптимизация базы данных.
#палантир@eshu_coding
Подключения к базе данных устанавливаются относительно продолжительное время, потому принято пользоваться ими длительное время. Мои боты, которых я писал летом 2020 висят на постоянных подключениях иногда по нескольку месяцев и проблем не было.
Но как через подключения потекли значительные объемы данных, проблемы резко возникли. А с учётом того, что в поисковике ожидается много пользователей, подключений используется тоже много (в среднем 200-300, с максимальным лимитом в 1500).
Проблему утечки памяти из прошлого поста я решил переработкой менеджера подключений. Некоторое время назад я написал класс, который ведёт учёт всех подключений к базе (чтобы не выйти за установленное максимальное число), держит несколько готовых подключений в горячем резерве и закрывает те, которые больше не нужны. Добавил к нему функцию закрытия подключений, которые живут и используются слишком долго и в которых мог накопиться мусор.
В принципе, в ConnectionString, строке, которой описывается подключение к PostgreSQL, есть группа параметров, отвечающих за тот самый пул подключений, который я сам наколхозил. И время жизни соединения там тоже можно задать. Но соединение там рвется только при неактивности в течение N секунд, а мне нужен костыль, ограничивающий время жизни вне зависимости от активности использования.
По хорошему, хранением соединений должна заниматься библиотека, с помощью которой я цепляюсь к базе данных - Npgsql. Но вот функции горячего резерва N подключений и безболезненного ограничения максимального числа в ней нет: мой менеджер подключений ждёт пока освободится слот, а Npgsql кидает исключение, что мне в этом проекте неудобно.
В итоге я пришел к следующим настройкам пула: 200 подключений в резерве, время жизни подключения 30 секунд, проверка и обслуживание пула раз в 3 секунды.
#csharp
#палантир@eshu_coding
Подключения к базе данных устанавливаются относительно продолжительное время, потому принято пользоваться ими длительное время. Мои боты, которых я писал летом 2020 висят на постоянных подключениях иногда по нескольку месяцев и проблем не было.
Но как через подключения потекли значительные объемы данных, проблемы резко возникли. А с учётом того, что в поисковике ожидается много пользователей, подключений используется тоже много (в среднем 200-300, с максимальным лимитом в 1500).
Проблему утечки памяти из прошлого поста я решил переработкой менеджера подключений. Некоторое время назад я написал класс, который ведёт учёт всех подключений к базе (чтобы не выйти за установленное максимальное число), держит несколько готовых подключений в горячем резерве и закрывает те, которые больше не нужны. Добавил к нему функцию закрытия подключений, которые живут и используются слишком долго и в которых мог накопиться мусор.
В принципе, в ConnectionString, строке, которой описывается подключение к PostgreSQL, есть группа параметров, отвечающих за тот самый пул подключений, который я сам наколхозил. И время жизни соединения там тоже можно задать. Но соединение там рвется только при неактивности в течение N секунд, а мне нужен костыль, ограничивающий время жизни вне зависимости от активности использования.
По хорошему, хранением соединений должна заниматься библиотека, с помощью которой я цепляюсь к базе данных - Npgsql. Но вот функции горячего резерва N подключений и безболезненного ограничения максимального числа в ней нет: мой менеджер подключений ждёт пока освободится слот, а Npgsql кидает исключение, что мне в этом проекте неудобно.
В итоге я пришел к следующим настройкам пула: 200 подключений в резерве, время жизни подключения 30 секунд, проверка и обслуживание пула раз в 3 секунды.
#csharp
Telegram
Эшу быдлокодит
Прошу прощения за долгое молчание, было безумно много работы.
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …
Палантир. Часть 19. Результаты нагрузочного тестирования.
#палантир@eshu_coding
В настоящий момент Master сервер,на котором осуществляется поиск, представляет собой следующее:
8 Гб оперативки, 4 ядра CPU, 1.5 Тб SSD диск. ОС - 18я серверная убунта, база данных - PostgreSQL 13.3. Объем базы - чуть больше 1 Тб, около 800 млн строк в основной таблице, по которой и осуществляется полнотекстовый поиск. Принцип формирования запросов я рассказывал выше.
После устранения утечки памяти (рассказывал выше) и оптимизации конфигурации Postgres по части памяти, сервис свободно держит 100 RPS (запросов в секунду).
В рамках экспериментов я выкручивал мощность машины до 16 ядер и 64 Гб оперативки. В таком сетапе удерживается нагрузка в 500-750 RPS.
Постгрес могёт однако.
#postgresql
#палантир@eshu_coding
В настоящий момент Master сервер,на котором осуществляется поиск, представляет собой следующее:
8 Гб оперативки, 4 ядра CPU, 1.5 Тб SSD диск. ОС - 18я серверная убунта, база данных - PostgreSQL 13.3. Объем базы - чуть больше 1 Тб, около 800 млн строк в основной таблице, по которой и осуществляется полнотекстовый поиск. Принцип формирования запросов я рассказывал выше.
После устранения утечки памяти (рассказывал выше) и оптимизации конфигурации Postgres по части памяти, сервис свободно держит 100 RPS (запросов в секунду).
В рамках экспериментов я выкручивал мощность машины до 16 ядер и 64 Гб оперативки. В таком сетапе удерживается нагрузка в 500-750 RPS.
Постгрес могёт однако.
#postgresql
Telegram
Эшу быдлокодит
Палантир. Часть 17. Оптимизация базы данных.
#палантир@eshu_coding
В ближайшее время я планирую запустить поисковик @palantir_search_bot в общее пользование. Пришло время нагрузочного тестирования. Для этого я изобразил отдельный проектик, который имитирует…
#палантир@eshu_coding
В ближайшее время я планирую запустить поисковик @palantir_search_bot в общее пользование. Пришло время нагрузочного тестирования. Для этого я изобразил отдельный проектик, который имитирует…
❤1
Палантир. Часть 20. Ускорение поиска.
#палантир@eshu_coding
Оценить результат вы можете в боте: @palantir_search_bot
В какой-то момент, читая про то, как работает постгрес по одной из ссылок в этом посте, я наткнулся на упоминание, что можно указать держать в оперативной памяти (кешировать) конкретную таблицу. Для этого используется расширение pg_prewarm.
Сначала я пропустил этот момент мимо: у меня база за терабайт, держать в оперативке её мягко говоря дорого.
А потом в какой-то момент мне стукнуло в голову решение: основная таблица - messages - у меня секционирована по месяцам.
Секционирование - разбиение одной большой таблицы на группу по-меньше. Для каждой из таблиц существует отдельный индекс, что позволяет существенно ускорить работу: работать со 100 индексами 10-ти гигабайтных таблиц быстрее, чем с одним монстроиндексом терабайтной таблицы.
Соответственно, таблица messages представляет собой около 200 таблиц вида messages_01_2021, messages_02_2021 и так далее, с 2014 по 2030 год.
Для того, чтобы поиск для пользователя выглядел мгновенным, я держу в оперативной памяти данные за последние 2 месяца, а остальное - пусть лежит на диске и используется по мере необходимости. Пользователь сразу получает хоть какой-то результат, а "хвост" долетит со временем.
Кроме загрузки таблиц в память я пробовал другой вариант - загнать в память только индексы, по которым идет поиск. Идея к сожалению себя не оправдала.
Также был доработан поисковый запрос на уровне c# - теперь он проводится в 3 этапа:
1. Запрос в последний месяц
2. Запрос в предпоследний месяц
3. Запрос во всю остальную базу, если нужно.
Результаты замеров скорости отклика на поиске глубиной в месяц:
1. Без кеширования - среднее время 200 мс, максимальное - 15 секунд
2. С закешированными индексами последних двух месяцев - среднее время 120 мс, максимальное - 6 секунд
3. С закешированными таблицами messages_10_2021 и messages_11_2021 - среднее время 80 мс, максимальное - 1.5 секунды
Под вариант "удобно использовать" подходит исключительно 3й, потому у сервера теперь 32 Гб оперативки (+3 тысячи к месячной плате)
#postgresql
#палантир@eshu_coding
Оценить результат вы можете в боте: @palantir_search_bot
В какой-то момент, читая про то, как работает постгрес по одной из ссылок в этом посте, я наткнулся на упоминание, что можно указать держать в оперативной памяти (кешировать) конкретную таблицу. Для этого используется расширение pg_prewarm.
Сначала я пропустил этот момент мимо: у меня база за терабайт, держать в оперативке её мягко говоря дорого.
А потом в какой-то момент мне стукнуло в голову решение: основная таблица - messages - у меня секционирована по месяцам.
Секционирование - разбиение одной большой таблицы на группу по-меньше. Для каждой из таблиц существует отдельный индекс, что позволяет существенно ускорить работу: работать со 100 индексами 10-ти гигабайтных таблиц быстрее, чем с одним монстроиндексом терабайтной таблицы.
Соответственно, таблица messages представляет собой около 200 таблиц вида messages_01_2021, messages_02_2021 и так далее, с 2014 по 2030 год.
Для того, чтобы поиск для пользователя выглядел мгновенным, я держу в оперативной памяти данные за последние 2 месяца, а остальное - пусть лежит на диске и используется по мере необходимости. Пользователь сразу получает хоть какой-то результат, а "хвост" долетит со временем.
Кроме загрузки таблиц в память я пробовал другой вариант - загнать в память только индексы, по которым идет поиск. Идея к сожалению себя не оправдала.
Также был доработан поисковый запрос на уровне c# - теперь он проводится в 3 этапа:
1. Запрос в последний месяц
2. Запрос в предпоследний месяц
3. Запрос во всю остальную базу, если нужно.
Результаты замеров скорости отклика на поиске глубиной в месяц:
1. Без кеширования - среднее время 200 мс, максимальное - 15 секунд
2. С закешированными индексами последних двух месяцев - среднее время 120 мс, максимальное - 6 секунд
3. С закешированными таблицами messages_10_2021 и messages_11_2021 - среднее время 80 мс, максимальное - 1.5 секунды
Под вариант "удобно использовать" подходит исключительно 3й, потому у сервера теперь 32 Гб оперативки (+3 тысячи к месячной плате)
#postgresql
Telegram
Эшу быдлокодит
Егор Рогов из Postgres Professional подробно и доступно рассказывает теорию и практику работы с PostgreSQL:
📌 Индексы
- Механизм индексирования
- Интерфейс метода доступа, классы и семейства операторов
- Hash
- B-tree
- GiST
- SP-GiST
- GIN
- RUM
- BRIN…
📌 Индексы
- Механизм индексирования
- Интерфейс метода доступа, классы и семейства операторов
- Hash
- B-tree
- GiST
- SP-GiST
- GIN
- RUM
- BRIN…
Палантир. Часть 21. Боты, рефакторинг.
#палантир@eshu_coding
Идея с Final State Machine оказалась удачной, но первая реализация естественно вышла комом. Как только появилось понимание архитектуры, которую я хочу видеть в ботах, я сел и провел глобальный рефакторинг, оставив только логику и некоторые удачные модули, а заодно сменил базу, с которой работают боты, на MongoDB. У них в нынешнем виде вся логика работы с базой сводится к двум операциям: вставить/прочитать информацию по известному id.
Выбор базы обусловлен следующими причинами:
1. Операции без сложной логики "вставить/прочитать" в ней работают ощутимо быстрее, чем в постгресе.
2. У монги достаточно агрессивный механизм кеширования, который удобен для логики работы бота: Монга как хомяк набивает оперативку "горячей" информацией до тех пор, пока не выйдет за установленный лимит или не съест всю память. Информации там не будет очень много (перерасход 1-2 Гб оперативки я даже не замечу), а вот дополнительная скорость доступа к данным о юзерах, активных в настоящий момент не повредит.
В целом, MongoDB мне понравилась, с третьего подхода. Теперь хотя бы понятно, где она в тему, и в чём лучше PostgreSQL: скорость работы на некоторых операциях и простота использования.
При этом, главная её особенность, я бы сказал киллер-фича - простота построения распределенного хранилища, которое просто расширять и администрировать, мной пока не используется.
#палантир@eshu_coding
Идея с Final State Machine оказалась удачной, но первая реализация естественно вышла комом. Как только появилось понимание архитектуры, которую я хочу видеть в ботах, я сел и провел глобальный рефакторинг, оставив только логику и некоторые удачные модули, а заодно сменил базу, с которой работают боты, на MongoDB. У них в нынешнем виде вся логика работы с базой сводится к двум операциям: вставить/прочитать информацию по известному id.
Выбор базы обусловлен следующими причинами:
1. Операции без сложной логики "вставить/прочитать" в ней работают ощутимо быстрее, чем в постгресе.
2. У монги достаточно агрессивный механизм кеширования, который удобен для логики работы бота: Монга как хомяк набивает оперативку "горячей" информацией до тех пор, пока не выйдет за установленный лимит или не съест всю память. Информации там не будет очень много (перерасход 1-2 Гб оперативки я даже не замечу), а вот дополнительная скорость доступа к данным о юзерах, активных в настоящий момент не повредит.
В целом, MongoDB мне понравилась, с третьего подхода. Теперь хотя бы понятно, где она в тему, и в чём лучше PostgreSQL: скорость работы на некоторых операциях и простота использования.
При этом, главная её особенность, я бы сказал киллер-фича - простота построения распределенного хранилища, которое просто расширять и администрировать, мной пока не используется.
Telegram
Эшу быдлокодит
Прошу прощения за долгое молчание, было безумно много работы.
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …
Палантир. Часть 22. Бот-агрегатор.
#палантир@eshu_coding
Ранее я описывал механизм работы "оповещалки" о происходящем в телеграме по ключевым словам: мной пишется запрос для полнотекстового поиска, который через каскад триггеров вызывает функцию pg_notify и сообщает внешним сервисам, что искомая фраза найдена.
Изначально этот функционал крутился в основной базе, на которой и так складирование всей информации и обслуживание поисковика. Чтобы разгрузить базу, я использовал следующий трюк: самодельную подписку на gRPC. Все желающие сообщений могут постучаться с запросом на сервер, после чего между ними и сервером повиснет gRPC канал, через который master-сервер потоком сливает все сообщения, только что пришедшие от сборщиков данных.
А на другом конце провода - практически полный клон master сервера, я его назвал NotificationProvider, с практически идентичной базой, в которой и происходит анализ. Но оповещение вылетает не в бота на прямую, а публикуется в брокер сообщений RabbitMQ, к которому уже цепляются боты - подписчики. RabbitMQ, NotificationProvider и PostgreSQL запущены с помощью Docker-compose и работают как единый организм.
Такой подход позволяет плодить ботов-агрегаторов в неограниченных количествах, хотя сейчас их всего 6 штук.
#палантир@eshu_coding
Ранее я описывал механизм работы "оповещалки" о происходящем в телеграме по ключевым словам: мной пишется запрос для полнотекстового поиска, который через каскад триггеров вызывает функцию pg_notify и сообщает внешним сервисам, что искомая фраза найдена.
Изначально этот функционал крутился в основной базе, на которой и так складирование всей информации и обслуживание поисковика. Чтобы разгрузить базу, я использовал следующий трюк: самодельную подписку на gRPC. Все желающие сообщений могут постучаться с запросом на сервер, после чего между ними и сервером повиснет gRPC канал, через который master-сервер потоком сливает все сообщения, только что пришедшие от сборщиков данных.
А на другом конце провода - практически полный клон master сервера, я его назвал NotificationProvider, с практически идентичной базой, в которой и происходит анализ. Но оповещение вылетает не в бота на прямую, а публикуется в брокер сообщений RabbitMQ, к которому уже цепляются боты - подписчики. RabbitMQ, NotificationProvider и PostgreSQL запущены с помощью Docker-compose и работают как единый организм.
Такой подход позволяет плодить ботов-агрегаторов в неограниченных количествах, хотя сейчас их всего 6 штук.
Telegram
Эшу быдлокодит
Прошу прощения за долгое молчание, было безумно много работы.
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …
Работа над диссертацией продолжается, но пока вяленько, планирую активизироваться на следующей неделе.
За прошедший месяц я реализовал и запустил новый проект: парсер текстов из телеграма, …