Что я узнал, строя Государство веганизма 🌱

К настоящему времени мы все знаем, что новости и СМИ формируют наши взгляды на обсуждаемые темы. Конечно, от человека к человеку все по-разному. Некоторые могут быть подвержены влиянию немного больше, чем другие, но всегда высказывается какое-то мнение.

Учитывая это, я подумал, что было бы действительно интересно наблюдать за постоянным развитием настроения, направленного на определенную тему или человека в СМИ.

Для меня веганство - интересная тема, тем более, что она часто упоминается в СМИ. Поскольку мнение СМИ меняет мнение людей, было бы интересно посмотреть, какие чувства они выражают.

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

Конечно, огромный процент проанализированных статей должен быть отнесен к категории «Нейтральных», если авторы хорошо справляются только с передачей информации, поэтому мы должны помнить об этом.

Я понял, что это была невероятная возможность приобрести новый набор инструментов, особенно когда я подумал о огромном количестве статей, публикуемых ежедневно.
Итак, я подумал о создании масштабируемой архитектуры - такой, которая была бы дешевой / бесплатной вначале, когда нет трафика и только несколько статей, но легко и бесконечно масштабируема при увеличении количества упоминаний или трафика. Я услышал зов облака.

Проектирование архитектуры

Планирование - это все, особенно когда мы хотим убедиться, что архитектура масштабируется с самого начала.

Начать с бумаги - это хорошо, потому что это позволяет вам быть очень грубым и быстрым в повторении.

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

Для меня процесс создания подходящей и, что еще более важно, разумной архитектуры был ключевым моментом, который я хотел улучшить в этом проекте. Различные компоненты казались довольно «простыми» для реализации и сборки, но создание правильной системы, правильного взаимодействия и хорошего, чистого конвейера данных было действительно интересной частью.

Вначале в моем дизайне были некоторые узкие места, которые в какой-то момент поставили всю мою систему на колени. В этой ситуации я подумал о том, чтобы просто добавить больше «масштабируемых» сервисов, таких как очереди, чтобы поставить в очередь нагрузку и позаботиться о ней.

Когда у меня наконец появился дизайн, который, как я догадывался, мог выдерживать тонны нагрузки и был динамически масштабируемым, это был беспорядок: слишком много сервисов, много накладных расходов и общая «грязная» структура.

Когда я посмотрел на архитектуру несколько дней спустя, я понял, что есть так много всего, что я могу оптимизировать с помощью нескольких изменений. Я начал убирать все очереди и подумал о замене реальных виртуальных машин компонентами FAAS.
После того сеанса у меня был гораздо более чистый и масштабируемый дизайн.

Думайте о структуре и технологиях, а не о реализациях

Это была одна из ошибок, которые я допустил в самом начале проекта. Я начал с того, что посмотрел, какие услуги может предложить IBM BlueMix, и продолжил. Какие из них я мог бы смешать вместе и использовать в своем дизайне, которые, казалось, работали вместе с триггерами, очередями и т. Д.?

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

Разделенный на несколько отдельных этапов, проект должен:

  • Каждый час (вначале, так как статей на данный момент было всего несколько - ›можно было делать каждую минуту или даже каждую секунду) получать новости с какого-нибудь NewsAPI и сохранять их.
  • Обработайте каждую статью, проанализируйте ее тональность и сохраните в базе данных для запроса.
  • При посещении веб-сайта получите данные о выбранном диапазоне и отобразите столбцы / статьи.

Итак, в итоге я получил триггер CloudWatch, который запускает лямбда-функцию каждый час. Эта функция получает данные новостей за последний час из NewsAPI. Затем он сохраняет каждую статью как отдельный файл JSON в корзину S3.

Эта корзина после ObjectPut запускает другую лямбда-функцию. Это загружает JSON из S3, создает «контекст» для появления частичного слова «веганский» и отправляет созданный контекст в анализ настроений AWS Comprehend. Как только функция получает информацию о настроении для текущей статьи, она записывает ее в таблицу DynamoDB.

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

Если вас интересует более подробное объяснение, перейдите к описанию отдельных компонентов.

Кто такой «единственный» облачный провайдер?

Прежде чем я узнал, что собираюсь использовать AWS, я опробовал двух других облачных провайдеров. Это очень простой и крайне субъективный взгляд на то, какого провайдера выбрать, но, возможно, это поможет другим «новичкам в облаке» сделать выбор.

Я начал с IBM Bluemix Cloud, перешел в Google Cloud и, наконец, перешел на AWS. Вот несколько «причин» моего выбора.

Многие из перечисленных здесь пунктов на самом деле говорят только о том, насколько хороша общая документация и сообщество, сколько проблем, с которыми я столкнулся, уже существовали, и на какие из них есть ответы на StackOverflow.

Документация и сообщества - ключ к успеху

Это особенно актуально для новичков и людей, которые никогда не работали с облачными технологиями. Документация и, что еще более важно, задокументированные и объясненные примеры были просто лучшими для AWS.

Конечно, вам не нужно соглашаться на одного поставщика. В моем случае я мог бы легко использовать инструменты NLU от Google, потому что, на мой взгляд, они приносили лучшие результаты. Я просто хотел сохранить всю мою систему на одной платформе, и я все еще могу изменить это позже, если захочу.

Стартовые пакеты всех провайдеров действительно хороши. Вы получите 300 долларов в Google Cloud, которые позволят вам делать множество вещей. Однако это также довольно опасно, поскольку с вас будет взиматься плата, если вы израсходуете сумму и забудете выключить и уничтожить все службы, что приведет к увеличению затрат.

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

Для меня Amazon был самым приятным, поскольку у них также есть бесплатный уровень, который позволит вам использовать почти все функции (некоторые только с самым маленьким экземпляром, таким как EC2.micro).

Как я уже упоминал, это очень однозначное и субъективное мнение о том, какой из них выбрать… Для меня AWS был самым простым и быстрым в освоении, не вкладывая слишком много времени заранее.

Компоненты

По сути, весь проект можно разделить на три основных компонента, которые требуют доработки.

Сбор статей, который состоит из почасового задания cron, лямбда-функции, которая вызывает NewsAPI, и корзины S3, в которой хранятся все статьи.

Часть Data Enrichment, которая загружает статью из S3, создает контекст и анализирует его с помощью Comprehend, а также DynamoDB, в котором хранятся расширенные данные для последующего использования во внешнем интерфейсе.

И Frontend, который отображается, когда пользователи запрашивают веб-страницу. Этот компонент состоит из графического пользовательского интерфейса, масштабируемой серверной службы, обслуживающей веб-страницу, и, опять же, DynamoDB.

Сборник статей

Первой и, вероятно, самой простой частью всего проекта был сбор всех статей и новостей, содержащих ключевое слово «веган». К счастью, существует масса API, которые предоставляют такую ​​услугу.

Один из них - NewsAPI.org.

С их API это очень просто и понятно. У них разные конечные точки. Один из них называется «все», который, как следует из названия, просто возвращает все статьи, содержащие заданное ключевое слово.

Используя здесь Node.js, это выглядит примерно так:

Знак + перед строкой запроса «веганский» просто означает, что слово должно появиться.

PageSize определяет, сколько статей будет возвращено по запросу. Вы определенно хотите следить за этим. Если, например, ваша система имеет чрезвычайно ограниченную память, имеет смысл выполнять больше запросов (использовать предоставленный курсор), чтобы не вызвать сбой экземпляра из-за слишком больших ответов.

Ответ от NewsAPI.org выглядит так. Если вы хотите увидеть больше примеров, зайдите на их веб-сайт, где представлено множество примеров.

Как видите, эти записи статей дают только самое общее представление о самой статье. Такие термины, как веганский, которые появляются в некотором контексте внутри статьи, но не являются ее основной темой, не представлены в заголовке или описании. Поэтому нам нужен компонент Data Enrichment, о котором мы поговорим чуть позже. Однако это именно тот тип данных JSON, который хранится в корзине S3 и готов к дальнейшей обработке.

Локальное использование API и его фактическое использование в облаке очень похожи.
Конечно, есть некоторые моменты, когда вы не хотите вставлять ключ API в фактический код, а вместо этого использовать переменные среды, но это все.

AWS имеет очень удобный графический интерфейс для настройки Lambda. Это действительно помогает вам понять структуру вашего компонента и визуализировать, какие службы и элементы к нему подключены.

В случае с первым компонентом у нас есть почасовой триггер CloudWatch на «входной» стороне и ведение журнала с помощью CloudWatch и S3 Bucket в качестве системы хранения на «выходной» стороне.

Итак, собрав все вместе, импортировав SDK Node.JS для AWS и протестировав весь скрипт локально, я наконец развернул его как функцию Lamdba.

Итоговый сценарий на самом деле довольно короткий и понятный:

В графическом интерфейсе есть несколько хороших функций тестирования, с помощью которых вы можете просто запустить свою функцию вручную.

Но ничего не вышло…

После нескольких секунд поиска в Google я нашел термин «Политики». Я слышал о них раньше, но никогда не читал о них и не пытался понять их по-настоящему.

По сути, они описывают, какой службе / пользователю / группе и что разрешено делать. Это был недостающий элемент: мне пришлось разрешить моей лямбда-функции что-то записать в S3. (Я не буду вдаваться в подробности здесь, но если вы хотите перейти к правилам, смело переходите к концу статьи.)

Политика в AWS - это простая конфигурация в стиле JSON, которая в случае моей функции сбора статей выглядела так:

Это конфигурация, которая описывает ранее упомянутую сторону функции «Вывод». В операторах мы видим, что он получает доступ к разным методам средств ведения журнала и S3.

Странная часть назначенного ресурса для корзины S3 заключается в том, что, если иное не указано в параметрах вашей корзины S3, вы должны предоставить корень и «все, что ниже» как два отдельных ресурса.

Приведенный выше пример позволяет лямбда-функции делать что угодно с корзиной S3, но это не то, как вы должны настраивать свою систему! Вашим компонентам должно быть разрешено делать только то, для чего они предназначены.

Как только это было введено, я наконец смог увидеть, как записи помещаются в мое ведро S3.

Специальные персонажи злы ...

Когда я попытался вернуть данные из корзины S3, я столкнулся с некоторыми проблемами. Он просто не дал бы мне файл JSON для созданного ключа.
Мне было трудно выяснить, что было не так, пока в какой-то момент я не понял, что по умолчанию AWS позволяет вести журнал для ваших сервисов.

Это было золото!

Когда я заглянул в журналы, проблема сразу бросилась в глаза: казалось, что ключ-значение, которое отправляется S3-Trigger, выполняет некоторую кодировку URL. Однако эта проблема была совершенно незаметна, если просто взглянуть на названия клавиш S3, где все отображалось правильно.

Решение этой проблемы было довольно простым. Я просто заменил каждый специальный символ тире, которое не заменяется каким-либо закодированным значением.

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

Обогащение данных

Поскольку теперь у нас есть все статьи как отдельные записи в нашей корзине S3, мы можем подумать об обогащении. Мы должны объединить несколько шагов, чтобы выполнить наш конвейер, который, если вспомнить, был следующим:

  • Получите запись из ведра S3.
  • Создайте контекст из реальной статьи в сочетании с названием и описанием.
  • Проанализируйте созданный контекст и пополните запись результатом.
  • Записываем обогащенную статью-запись в нашу таблицу DynamoDB.

Одна из действительно замечательных особенностей Promises в JavaScript заключается в том, что вы можете моделировать конвейеры точно так, как вы бы описали их в тексте. Если мы сравним код с объяснением, какие шаги будут предприняты, мы увидим сходство.

Если вы внимательно посмотрите на первую строку приведенного выше кода, вы увидите обработчик экспорта. Эта строка всегда предопределена в лямбда-функциях, чтобы знать, какой метод вызывать. Это означает, что ваш собственный код находится в фигурных скобках асинхронного блока.

Для части обогащения данных нам нужно еще несколько сервисов. Мы хотим иметь возможность отправлять и получать данные из анализа настроений Comprehends, записывать нашу окончательную запись в DynamoDB, а также вести журнал.

Вы заметили службу S3 на стороне «вывода»? Вот почему я всегда заключаю выходные данные в кавычки, даже если мы хотим только читать здесь данные. Он отображается справа. Я просто перечисляю все службы, с которыми взаимодействует наша функция.

Политика выглядит сравнимой с политикой компонента сбора статей. У него просто есть еще несколько ресурсов и правил, которые определяют отношения между Lambda и другими сервисами.

Несмотря на то, что Google Cloud, на мой взгляд, имеет «лучшие» компоненты NLU, Мне просто нравится простота и унифицированный API сервисов AWS. Если вы использовали один из них, вы думаете, что знаете торговый центр. Например, вот как получить запись из S3 и как работает определение настроения в Node.js:

Вероятно, одной из самых интересных задач компонента Data Enrichment Component было создание «контекста» слова «веган» в статье.

Напоминаем, что нам нужен этот контекст, так как во многих статьях упоминается только слово «веган», а тема «веганство» не рассматривается.

Итак, как нам извлекать части из текста? Я выбрал регулярные выражения. Они невероятно удобны в использовании, и вы можете использовать игровые площадки, такие как Regex101, чтобы поэкспериментировать и найти правильное регулярное выражение для вашего случая использования.

Задача заключалась в том, чтобы придумать регулярное выражение, которое могло бы найти предложения, содержащие слово «веганский». Почему-то было сложнее, чем я ожидал, сделать обобщение для целых текстовых отрывков, в которых также были разрывы строк и так далее.

Окончательное регулярное выражение выглядит так:

Проблема заключалась в том, что для длинных текстов это не работало из-за проблем с тайм-аутом. Решение в этом случае было довольно «простым»… Я просто сканировал текст и разбивал его по разрывам строк, что упростило обработку для модуля RegEx.

В конце концов, все контекстное «создание» представляло собой смесь разделения текста, фильтрации отрывков, содержащих слово веганский, извлечения подходящего предложения из этого отрывка и его повторного соединения, чтобы оно может использоваться в анализе настроений.

Также название и описание могут иметь значение, поэтому я добавил их в контекст, если они содержат слово «веганский».

Когда был готов весь код для различных шагов, я подумал, что могу приступить к созданию интерфейса. Но что-то было не так. Некоторые записи просто не отображались в моей таблице DynamoDB…

Пустые строки в DynamoDB - тоже зло

Проверяя состояние моей уже работающей системы, я понял, что некоторые статьи вообще не будут преобразованы в запись таблицы DynamoDB.

После проверки журналов я обнаружил это исключение, которое меня совершенно сбило с толку ...

Честно говоря, это было действительно странное поведение, поскольку, как было сказано в обсуждении, семантика и использование пустой строки полностью отличаются от семантики значения Null.

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

В моем случае это было действительно просто. Я просто перебрал весь объект JSON и проверил, есть ли пустая строка или нет. Если было, я просто заменил значение на ноль. Вот и все, работает как шарм и не вызывает никаких проблем. (Мне нужно было проверить, есть ли у него значение в интерфейсе, поскольку получение длины нулевого значения вызывает ошибку).

Внешний интерфейс

Последней частью было создание внешнего интерфейса и его развертывание, чтобы люди могли посетить страницу и увидеть StateOfVeganism.

Конечно, я думал о том, стоит ли мне использовать одну из этих причудливых интерфейсных фреймворков, таких как Angular, React или Vue.js… Но, что ж, я выбрал абсолютно старую школу, простой HTML, CSS и JavaScript.

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

В конце концов, так оно и оказалось. Вы можете заглянуть на эту страницу. Я думал о том, чтобы сделать его живым на stateOfVeganism.com, но мы посмотрим…

Обязательно обратите внимание на забавную третью статью из статей, которые были классифицированы как «Негативные»;)

Мне нужно было подумать о развертывании внешнего интерфейса на одном из сервисов AWS. Я определенно хотел воспользоваться сервисом, который уже включал эластичное масштабирование, поэтому мне пришлось выбирать между Elastic Container Service или Elastic Beanstalk (фактические экземпляры EC2).

В конце концов, я выбрал Beanstalk, так как мне очень понравился простой подход и невероятно простое развертывание. По сути, вы можете сравнить его с Heroku по способу настройки.

Боковое примечание: у меня были некоторые проблемы с моей группой автоматического масштабирования, которой не разрешили развертывать экземпляры EC2, потому что я использую уровень бесплатного пользования на AWS. Но после нескольких писем с поддержкой AWS все сразу заработало.

Я только что развернул серверное приложение Node.js Express, которое обслуживает мой интерфейс на каждом пути.

Эта настройка по умолчанию предоставляет index.html, который находится в «общедоступной» папке, и это именно то, что я хотел.

Конечно, это самая простая установка. Для большинства приложений это не рекомендуемый способ, поскольку вам каким-то образом необходимо предоставить учетные данные для доступа к таблице DynamoDB. Было бы лучше выполнить рендеринг на стороне сервера и сохранить учетные данные в переменных среды, чтобы никто не мог получить к ним доступ.

Играть круто и развертывать ключи AWS во внешнем интерфейсе

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

Я также ограничил количество запросов, которые могут быть выполнены, чтобы учетные данные «перестали работать» после превышения бесплатного ежемесячного лимита, на всякий случай.

Но не стесняйтесь просматривать данные и немного поэкспериментировать, если вам интересно. Только не переусердствуйте, так как API в какой-то момент перестанет предоставлять данные интерфейсу.

Политики, политики?… Политики!

Когда я начал работать с облачными технологиями, я понял, что должен быть способ разрешить / ограничить доступ к отдельным компонентам и создавать отношения. Здесь и вступает в силу политика. Они также помогают управлять доступом, предоставляя инструменты, необходимые для предоставления разрешений определенным пользователям и группам. В какой-то момент вы, вероятно, столкнетесь с этой темой, поэтому имеет смысл немного почитать об этом.

В AWS существует два основных типа политик. Оба являются простыми конфигурационными файлами в стиле JSON. Однако один из них назначается самому ресурсу, например S3, а другой назначается ролям, пользователям или группам.

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

Итак, в чем на самом деле разница? Это может стать яснее, если мы сравним примеры обоих типов политик.

Политика слева - это IAM-Policy (или Identity-Based). Правильный вариант - это политика, основанная на ресурсах.

Если мы начнем сравнивать их построчно, мы не увидим никакой разницы, пока не дойдем до первого оператора, который определяет некоторые правила, относящиеся к некоторому сервису. В данном случае это S3.

В Resource-Policy мы видим атрибут, который называется «Principal», который отсутствует в IAM-Policy. В контексте политики ресурсов это описывает сущности, которые «назначены» этому правилу. В приведенном выше примере это будут пользователи, Алиса и root.

С другой стороны, чтобы достичь того же результата с помощью политик IAM, нам пришлось бы назначить политику слева нашим существующим пользователям, Алисе и root.

В зависимости от вашего варианта использования может иметь смысл использовать один или другой. Это также вопрос того, каков ваш «стиль», условности или ваше рабочее место.

Что дальше?

StateOfVeganism уже в прямом эфире. Однако это не значит, что улучшать нечего. Одна вещь, над которой мне определенно нужно поработать, - это, например, то, что рецепты из Pinterest не относятся к категории позитивных, а скорее как нейтральные. Но базовая функциональность работает как положено. Конвейер данных работает нормально, и если что-то пойдет не так, у меня будет хорошее ведение журнала с уже включенным CloudWatch.

Было здорово по-настоящему продумать и построить такую ​​систему. Ставить под сомнение мои решения было очень полезно для оптимизации всей архитектуры.

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

Я хотел бы услышать о ваших проектах и ​​о том, что вы создаете. Протяни руку и расскажи мне о них.

Спасибо за чтение. Не забудьте подписаться на меня на YouTube и отметить StateOfVeganism на GitHub.

Не забудьте нажать кнопку хлопка и подписаться на меня в Twitter, GitHub, Youtube и Facebook, чтобы следить за мной в моем путешествии.

Я всегда ищу новые возможности.
Так что пожалуйста, не стесняйтесь обращаться ко мне. Я хотел бы с вами связаться.

Кроме того, в настоящее время я планирую пройти полугодовую стажировку в Сингапуре, начиная с марта 2019 года. Я хотел бы встретиться с как можно большим количеством из вас. Если вы живете в Сингапуре, свяжитесь с нами. Хотел бы поболтать за кофе или обедом.