Система есть, но работаем руками
Мы не сможем назвать заказчика, который пришел к нам с задачей, потому что связаны NDA. Давайте договоримся, что заказчиком стал отдел службы безопасности и аналитики «крупной госорганизации».
Около двух лет назад отдел безопасности в этой организации проверял кандидатов при трудоустройстве руками: гуглили ФИО, изучали данные из открытых баз ведомств, министерств, искали по соцсетям и окольными путями проверяли возможные связи кандидатов со штатными сотрудниками. Но эту структуру не назвать компанией ретроградов. Приложение для автоматизированной проверки и обработки больших данных у заказчика было, но оно не помогало, потому что:
- у него был сложный и античеловечный интерфейс: аналитики только и делали, что заполняли бесконечные поля даже в простейших задачах;
- не было возможности искать данные в открытых источниках автоматически;
- внутри было много фич, которые не работали;
- систему поддерживал один разработчик, который сопротивлялся всем нововведениям. У программистов такое, к сожалению, случается: любишь и не можешь отпустить, поэтому отказываешься от всех доработок.
То есть система как-то работала, но что с ней, что без нее, было тяжело. Однажды заказчик понял, что так жить больше нельзя. Организация попробовала найти исполнителей, которые осилят разработку big data системы и смогут сделать аналог приложения с новыми фичами.
Аккуратный старт
Заказчик долго искал разработчиков, которые смогут реализовать задуманное. Тех, кто работает с big data, в России не так-то много. До нас это пытался сделать фрилансер, кооператив фрилансеров и маленькая веб-студия. Но каждый из исполнителей не справлялся с чем-то своим.
Заказчик хотел:
- работающее big data приложение;
- сокращение человекочасов на работу благодаря этому приложению, которое сможет эффективно обрабатывать большие данные;
- упростить поиск связей между кандидатами и сотрудниками (по закону о госслужбе подобных конфликтов интересов быть не должно, это официальное препятствие для трудоустройства).
Когда тестовый контракт заключили с нами, мы предложили есть слона по кусочкам и начать с прототипа. С одной стороны, это удобно для заказчика (он видит, за что платит и что получится в итоге), с другой стороны это комфортно для нас — практически на старте проекта мы проверяем, на что способны, пойдет ли этот проект. Мы делаем так не во всех проектах. Только в тех, где есть не распространенные фичи, с которыми мы не сталкивались. В этом проекте ими были графы — системы связей между персонами.
Прототип прошел двухстороннюю проверку, и дальше мы действовали по привычному сценарию:
- Оценили дизайн.
- Сделали его.
- За счет дизайна оценили разработку.
- Разработали приложение.
- Взяли работу системы на поддержку.
Я вела проект, вместе со мной над ним работали UI/UX дизайнер, 4 программиста, QA специалисты.
Стэк — React + Ruby on Rails, потому что в нем есть отточенная система работы с базами данных, а у нас тут разработка big data и проект для создания досье на людей. Работы с базами много, очень много. Кроме этого, были готовые библиотеки для Apache Solr, платформы для полнотекстового поиска, которую мы решили использовать, готовые библиотеки для NEO4J (это графовая система для управления базами данных), воркеры и комфортная работа с фоновыми процессами.
Рельсовый ActiveModel это очень мощный инструмент работы с базой данных, а его реализация ActiveRecord — настоящий швейцарский нож от мира ORM. В работе мы использовали жадные и ленивые загрузки, валидации, скоупы, префиксы, наследования, коллбэки и прочие плюшки.
Придумали для системы кодовое название — Большой Брат. В прототипе у нас получилось сделать killer feature за счет дыры в безопасности ВКонтакте. И эта фича убедила заказчика, что искать исполнителей для разработки big data приложения больше не нужно 🙂
Прототип и дыры в безопасности ВК
Начали с Excel-таблиц. У заказчика таблицы были и до нас, только заполняли они их вручную. Создавали документ, вносили данные о человеке, добавляли номер паспорта, гуглили ИНН, по нему находили штрафы и долги и все это вносили в таблицу.
В прототип мы подключили Xneo и еще несколько сервисов. Так информация автоматически складывалась в Excel. После полноценной разработки работает так: аналитик добавляет данные в таблицу → система собирает ответы от сервисов → таблица обогащается новыми данными.
Пока мы работали над этой задачей, нашли дыру в системе безопасности ВКонтакте. За счет нее мы могли находить профиль человека в ВК только по номеру телефона.
В открытом API ВК такой возможности нет, мы делали это через приватный API, прокси и имитацию активности реального пользователя в мобильном приложении. Это работало так: ВКонтакте запрашивал доступ к номерам телефонов из контактной книги, чтобы быстро найти друзей. Вот тут то мы и нашли лазейку.
Мы этим воспользовались: записываем номера как будто в свои контакты и смотрим, какие аккаунты на них зарегистрированы. Для нашего прототипа это было Killer feature. Для заказчика это стало демонстрацией возможностей приложения (ого, оно еще вот так может) и показателем наших способностей. Компании, которые пытались собрать прототип до нас, с этой задачей не справлялись.
ВК, конечно, в итоге обнаружил лазейку и все прикрыл. Это произошло уже после старта основного проекта, в котором брали информацию только из открытых баз данных. Наша шалость не удалась.
Референсов нет, пожеланий — тоже
Референсов для дизайна у нас не было вообще. Антиреференсов — тоже. В плане дизайна мы вступали в этот проект как в темный лес без подробностей. Задача звучала так: “хотим сервис, с которым наша служба безопасности будет отлавливать нежелательных людей на рабочих местах и препятствовать кумовству”. Заказчик рассказал, что хочет видеть в системе. На этом пожелания к дизайну закончились.
Мы начали погружаться в проект и разработку big data. Да, на это уходит много времени на старте, зато потом гораздо проще проектировать. Главный дизайнер часами проходил пользовательские сценарии: искал знакомых и незнакомых людей в интернете через открытые источники, базы данных налоговой, ГИБДД, геотеги на фотографиях. Пытался с помощью этих источников понять, где люди живут, работают, отдыхают. Сегодня это не так уж и сложно, потому что люди выкладывают о себе практически все.
На разработку интуитивно понятного интерфейса для big data системы ушло немало сил
Такой ресерч помог понять, что на старте у нашего пользователя точно будет какая-то информация: номер паспорта, СНИЛС, номер телефона. Их можно забить вручную. Так у нас появилась форма создания досье. Блоки в досье старались группировать по смыслам. У заказчика особо не было предложений по дизайну, но были директивные правки “нам будет удобнее, если это поле будет здесь”. С такими правками мы не спорим, потому что удобство пользователя на первом месте, а в этом случае заказчик и пользователь — одно лицо.
Когда доделали основную часть, приступили к визуализации графов. Это оказалось самым сложным из-за ограничений библиотеки D3: мы не могли изобретать новое, только кастомизировать то, что дает библиотека. Было непросто, но мы справились.
В системе есть два вида графов: обычные и древовидные. Обычные строятся с ограничением в 6 прыжков через вершины, древовидные — через полный обход
Ваша жизнь в наших руках
Круг возможностей приложения как в самых лучших антиутопиях. Это сборник фич, о которых мы думаем: такое вряд ли возможно, мои данные в безопасности. Например, для досье на нового человека достаточно номера телефона. Система получит его и начнет собирать информацию из всех подключенных источников. Это:
- CROINFORM: доступ к ЕГРЮЛ, ЕГРН, ФНС, ФССП и др. интернет-ресурсов;
- Xneo помогает найти открытые данные аккаунтов из социальных сетей, объявления на АВИТО, ЦИАН, С2С-маркетплейсов. Он поможет узнать о владении транспортом;
- Открытое API Вконтакте;
- Avinfobot: объявления о продаже транспортного средства на drom.ru или avito.ru, информация об оплате чеков за парковку;
- EGRUL bot: регистрация в качестве ИП;
- MNP bot: оператор связи, регион, в котором подключена сим-карта;
- ФСИН: поиск по базе лиц в розыске;
- МВД: проверка паспорта;
- ГИБДД: проверка на наличие штрафов, их статусов, проверка данных по автомобилю;
- Reestr Zalogov: реестр уведомлений о залоге имущества;
- KonturFocus: сервис из 26 источников данных, через который мы искали контрагентов, аффилированности компаний и получали данные по ИНН (предпринимательская деятельность, участие в ЮЛ).
Или у нового человека есть друг: вводим номер нового человека и номер друга, система показывает все ваши одновременные активности (когда вы парковались в одном и том же месте, ходили в одну школу или жили на одной улице). Это как раз нужно для отслеживания возможных связей кандидатов с сотрудниками.
Аналитик или безопасник может создавать досье на человека и получать визуализированные связи между персонами, выгружать данные в Excel-таблицах. Досье автоматически обновляются, поэтому, если в вашей жизни что-то изменилось, в компании узнают об этом.
Что делать, если источники — кто в лес, а кто по дрова
Интегрироваться с таким количеством источников непросто. Хорошо, если у кого-то был полноценный API, но вот некоторых пришлось брать хитростью. Например, смотреть, какой запрос отсылает фронтенд сервиса и пытаться его повторить.
Сервисы периодически еще и отваливались, некоторые меняли свой API. Поэтому за стабильностью всех и вся приходилось постоянно следить. Кроме того, мы перегибали палку с обращениями к сервису (их было слишком много, и мы превышали лимит), поэтому система могла выдавать ошибки. В этом случае, например, половина списка могла быть обработана, а половина — не найдена. Чтобы работало без ошибок, запрограммировали паузу: система обработает одного человека → отдаст → подождет определенное кол-во времени в зависимости от сервиса → начнет обработку следующего. И так до конца очереди, которую задал аналитик.
Но ладно бы все заканчивалось на интеграции. Ее недостаточно: данные нужно не только находить, но и корректно записывать. При этом все ведут учет по-разному: у одного сервиса дата в формате день/месяц/год, у другого день.месяц.год или вообще — день-месяц-год. Человеку ничего, а у системы — взрыв мозга, поэтому нужно было адаптировать парсеры под каждый сервис отдельно.
Чтобы полечить эту проблему, нужно было нормализовывать данные. Для этого подключили систему управления базами данных MongoDB. Теперь все работало так: получили информацию → положили ее в Mongo (читайте: захламили базу сырыми данными) → нормализовали → сохранили чистые данные в PostgreSQL (читайте: прибрались и сделали по красоте). Так все отображалось корректно, и разный формат получаемых данных от внешних сервисов перестал быть проблемой для нашей системы.
Битва титанов
Мы никогда не работали с графами (диаграммы, которые строят связь между сотрудниками), поэтому на проекте это стало для нас самым интересным. Мы решили делать их с помощью библиотеки D3 — ее часто используют для гистограмм, древ, динамических графов. Главный профит — максимальный уровень абстракции, то есть много инструментов, с которыми можно делать что угодно.
С D3 не все так просто. Если абстрагироваться от сложных терминов, то она дает тебе набор инструментов. Допустим, это молоток, гвозди и доски. Что построишь ты — крутой дом или сельский туалет — зависит только от тебя.
Но вот мы повосхищались библиотекой, перешли к внедрению в нашу разработку, и тут нам стало больно. Ее нужно было встроить в React, который сам управляет структурой документа. Но и у D3 есть собственные принципы построения. Получалось, что две сущности, которые нужно было вложить одну в другую, конфликтовали хотели независимости. Нужно было что-то попроще, заточенное конкретно под React.
Нашли несколько библиотек, но в них не было нужного нам набора возможностей. От неизбежности вернулись к D3 и сели разбираться в документации. Дополнили своими силами пробелы в D3 и продолжили работу.
Сколько в России улиц Ленина 5?
Если D3 нужна для графов во фронтенде, в бэкенде мы решили использовать графовую систему управления базами данных Neo4j. Она отлично подходит для построения связей между людьми и визуализации больших данных (а это заказчику и нужно было).
Разработка big data системы — это сложно, но интересно
В этой системе главная “вершина” — человек. К нему уже крепятся остальные вершины: место работы, жительства и так далее. Но вот в чем беда: допустим, человек, на которого мы составляем досье, живет на Ленина, 5. Сколько в России таких адресов? Да практически в каждом городе есть улица Ленина. Какой в этом случае будет связь? Некорректной: просто куча точек, в которых невозможно разобраться. Система просто не понимала бы, где точка пересечения.
Но мы подозревали, что в базах данных это как-нибудь да классифицируется. И оказались правы: в базе ФИАС у каждого объекта есть свой уникальный ID. Иными словами: сколько в России улиц Ленина,5, столько уникальных ID. За счет этих ID мы решили проблему вершин в связях. В Neo4j вершина будет корректной, а в следующий раз, когда в систему начнут заносить новую персону, Neo4j свяжет их между собой, если связь есть.
Поиск учебных заведений Вконтакте: сначала выбираем страну, потом город, потом уже вводим номер
Со школам история та же. Чтобы у каждой был уникальный айдишник, и система не ломалась, решили использовать открытый API vk.com — система у них ведёт от общего к частному. Благодаря такому подходу система всегда знает, какая из сотни школ ей нужна.
Оптимизируй это и вот это еще
Мы доделали построение связей между сотрудниками и кандидатами и связи между досье. А теперь представим, что мы — аналитики заказчика и отправили запрос на построение связи сразу по сотне людей и по всем параметрам. Сколько будем сидеть? Минут 10? Мы поняли, что это нужно оптимизировать.
Сначала попытались добавить оперативной памяти. Neo4j захлебывалась под весом запросов и наше big data приложение начинало тормозить. Мы увеличили дефолтные лимиты системы до максимума, и запретили “мусорщику” сервера Puma убивать тяжелые процессы. По умолчанию он прерывал конвертацию больших графов, потому что они съедали много памяти. Так мы избавились от отклоненных запросов, но захотели пойти дальше.
Мы начали копаться в объектах, которые нам отдавал Neo4j, и нашли узкое место. Дело в том, что для работы NEO4J нужен определенный набор данных: флаги, айдишники, параметры, куча повторений, дублей… Но для построения графов используется далеко не все. Мы сделали так, чтобы на конвертация в json отправлялось только то, что нужно. Производительность поднялась на 20%.
Но и на этом мы не остановились. Придумали использовать кэш и вынесли построение графов в фон. Оно занимает столько же времени, но пользователь может запускать несколько потоков одновременно, а результаты забирать из кэша позже.
Для создания форм использовали библиотеку FinalForm. Она предоставляет большое количество параметров, которые помогают отслеживать состояние всей формы и отдельных полей. Чтобы оптимизировать динамичную форму и упростить поиск информации, разбили все поля на функциональные группы: поля, обязательные для создания досье, и те, что заполняются системой во время проверки персоны
Формы — это отдельная история. Главная проблема была в количестве данных, которые система получала от сторонних сервисов. Начали с минимальной версии, но чем дальше — тем сложнее. По мере разработки приложения заказчик находил новые источники данных, форма с полями разрослась до нереальных размеров. Так мы столкнулись с необходимостью оптимизировать длинный список полей.
Чтобы решить проблему бесконечного скролла, разбили все поля на функциональные группы и передизайнили макет — теперь все данные объединены в смысловые группы
Поисковая система
Еще одна фича, которая требовала продуманного решения — поиск по тексту. Проблема была все та же — огромное количество досье и массивных связей между людьми. У заказчика видения формата поиска не было, поэтому мы подключили платформу Solr для поиска по досье на свое усмотрение.
Использовали Apache Solr, потому что было необходимо работать с полнотекстовым поиском и группировкой результатов выдачи. Опыт разработки предыдущих проектов показал, что с этими задачами Solr справляется лучше всего.
Но сложность не в поиске, а в выдаче. Прикрутили параметры поиска, и пришлось повозиться с индексацией, потому что каждый параметр должен индексироваться по-своему. Например, есть у нас фамилия. Мы можем искать совпадение:
- точное.
- с первой буквы.
- по вхождению.
Если нужно искать по автомобильному VIN-у, то поиск начинается с первой цифры, если VIN вводится полностью — по точному совпадению. Мы смотрели, какие данные могут отдаваться по какому параметру и думали, как будем индексировать конкретно их.
Сделали так: пользователь вводит, например “ЖАР”→ система показывает совпадения по ФИО, компании → пользователь выбирает нужный параметр и продолжает поиск там. Получилось удобно.
Похоже на поиск в DNS: если в поисковой строке пользователь пишет “RTX”, система предлагает ему сузить поиск и продолжить в конкретном разделе — здесь, например, это “видеокарты” или “системные блоки”
Ещё добавили Edge N-grammы для живых предположений. Допустим, в конце мы хотим найти слово “холодок”, но пока вбиваем его, получаем десятки предложений для “х”, “хо”, “хол” и так далее.
Сначала заказчик принял это, а потом видение появилось. Ему нужен был сквозной поиск как в Google: вбиваешь фамилию/слово/запрос → получаешь все совпадения. Мы потратили кучу времени на поиск по параметрам и на переделки. Добавили общий поиск: пользователь вводит запрос, ему, как в Google, выпадает его запрос и предложения (возможно, вы искали: фамилию, адрес прописки и т.д.). Пользователь соглашается на предложение или нет, тогда запускается поиск по всему. Но поиск по параметрам все равно оставили.
Чемпионы разработки в тяжелом весе
Работа над таким проектом интересна сама по себе, а остроты добавляет работа с заказчиком — госструктурой. На каждый созвон к нам подключались 5-7 человек с серьезными лицами, вопросами, и в костюмах. Каждый, конечно, со своим видением проекта. Стратегические решения и утверждения принимали от еще более серьезных людей.
При этом мы работали по фиксированной цене (это же тендер), а фичи в скоуп только добавлялись с космической скоростью. Если это были небольшие доработки, мы делали бесплатно. Если доработки покрупнее, тратили 3-4 часа на созвоны, чтобы объяснить, почему это в скоуп не войдет.
При этом мы работали из одной крайности в другую: фичи либо сыпались как из рога изобилия, либо у заказчика не было четких запросов к следующему спринту. Незагруженные задачами разработчики уходили в другие проекты. Когда у заказчика видение появлялось, разработчиков приходилось возвращать. Вы наверняка слышали, что многозадачность — миф и вообще вредная штука, вот и здесь от этого никому хорошо не было.
Но проект дошел до конца, сотрудники уже тестируют новую систему, а мы кладем в портфолио удачный опыт работы с “заказчиком-тяжеловесом”.
Среди госструктур обработку big data внедряют, чтобы оптимизировать работу с данными. Визуализация больших данных — один из самых частых запросов, который приходит от клиентов. Для нас проект стал опытом работы с новыми инструментами разработки big data — теперь нас никаким проектом не напугаешь.
Big Data, разработка и опыт работы с серьезными людьми
“Проект ещё находится на стадии разработки, система уже используется сотрудниками. Приложение помогло оптимизировать работу сотрудников — теперь рабочие задачи выполняются почти в 20 раз быстрее. Мы смогли вывести эффективность сотрудников на новый уровень”, — комментирует заказчик.
Коллапс с кучей строк из 1C превратился в удобный интерфейс для работы с big data
Сейчас приложение умеет создавать досье и строить связи. С одной стороны, мы справились с новым инструментом: разобрались в графах и смогли научить приложение строить связи.
С другой стороны, мы сделали красивый и аккуратный инструмент как будто по ТЗ Оруэлла, Замятина и Хаксли одновременно. Теперь мы можем рассказывать на дружеских посиделках, что Большой Брат действительно существует — такая вот работа с big data в России.
Ищите компанию, которая работает с большими данными? Напишите нам — мы знаем, как разрабатывать приложения для обработки и визуализации больших данных.