Привет, это снова Егор. И да - это снова статья про Фидонет. Так уж сложилось, что именно эта тематика оказался слишком уж популярным на моём Хабре, и неразрывно связана со мной, хотя я всячески пытался "сбежать" от данной тематики.
Однако я решил совместить приятное с полезным - рассказать про недавние мои поправки в NodehistJ, которые значительно ускорит индексацию диффов нодлистов сети Фидонет, а также значительно снизит потребление ОЗУ, за счёт одного из лучших вещей, которая есть в Spring Data JDBC - live streaming данных с СУБД без использования неэффективной пагинации. Данная технология позволяет быстро перебирать нодлисты за считанные минуты, и ускорить индексацию даже на слабых серверах, за счёт прямого перебора данных из СУБД, в live-режиме, без использования неэффективной пагинации, но с использованием самых обычного Java Streams.
Что нужно для этого
Для того, чтобы использовать данную технологию, необходимо создать в репозитории метод с кастомным запросом, и с типом Stream<T>. Вот пример:
@Query("""
SELECT * FROM nodelist_entry nl
JOIN node_entry n
ON nl.id = n.nodelist_entry_id
ORDER BY nodelist_year DESC, nodelist_name DESC
""")
Stream<NodelistEntry> findAllAsStreamWithSort();
А дальше просто обращаемся к этому методу, и работаем со Streams как обычно:
nodeListEntries
.gather(Gatherers.windowSliding(2))
.map(window -> processDiffBetweenNodelists(window.get(0), window.get(1)))
.flatMap(list -> list.stream())
.forEach(nodeHistoryEntryRepository::save);
Я использую .gather() для создания "скользящего окна", но оно появилось в LTS-версиях Java только с 25 ветки. Мне пришлось мигрировать из за этого NodehistJ на новую версию Java.
Зачем мы берём целый нодлист вместо того, чтобы брать конкретные записи с него?
Это позволяет уменьшить количество запросов к нодлисту, но при этом жертвуя небольшим количеством ОЗУ. Благо в памяти мы храним только 2 нодлиста, по сути, и даже нодлисты за 1996 год не так сильно сожрёт ОЗУ. Но если мы не будем их хранить, мы замедлим работу уже с СУБД, что тоже неприятно.
Зачем я всё заново индексирую?
Вы наверное заметили это в моём коде:
nodeHistoryEntryRepository.deleteAll();
Так вот - именно это и обеспечивает гарантию того, что нодлисты будут задиффованны в нужном порядке. Да, это требует кучу ресурсов - зато это самое надёжное и безопасное решение. Лишние полчаса индексации в одном из сервисов никому не помешает :)
Итоги
Java Streams и Spring Boot JDBC дополняет друг-друга, и позволяет ускорить индексацию всего нодлистового архива, даже при полной индексации.
