В своем выступлении по API машинного обучения на Google I / O я показал демонстрацию Twitter в реальном времени. Демонстрация отображает поток твитов на определенную тему в реальном времени с частями речи и настроениями последнего твита, а также некоторыми агрегированными данными по всем твитам, просмотренным на данный момент:

В этом посте я подробно расскажу о демоверсии и дам вам обзор Natural Language API. Если вы хотите перейти к коду, перейдите в репозиторий GitHub (он находится в подкаталоге nl-firebase-twitter).

Как работает демо

На бэкэнде я написал сервер Node, который транслирует твиты с помощью API потоковой передачи Twitter. Он отправляет текст каждого твита в Natural Language API и записывает ответ NL API как в Firebase для нашей панели мониторинга в реальном времени, так и в BigQuery для анализа, когда мы закончим сбор данных. Архитектура выглядит примерно так:

Потоковая передача твитов в реальном времени

Давайте рассмотрим несколько фрагментов кода с каждого шага диаграммы, начиная с сервера Node. Используя пакет twitter npm, я создаю клиента со своими учетными данными API и транслирую твиты, содержащие несколько поисковых запросов:

const searchTerms = 'googleio,googlecloud,firebase';
client.stream('statuses/filter', {track: searchTerms, language: 'en'}, function(stream) {
  stream.on('data', function(event) {
    callNlApi(event);
  });
});

Когда я получаю новый твит, API возвращает данные для каждого твита, включая текст, пользователя, хэштеги, часовой пояс и т. Д.

Вызов API естественного языка

Имея текст твита, я готов вызвать NL API с помощью модуля npm request. Мой запрос JSON выглядит так:

{
  "document": {
    "type": "PLAIN_TEXT",
    "content": tweet.text
  },
  "features": {
    "extractSyntax": true,
    "extractEntities": true,
    "extractDocumentSentiment": true
  }
}

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

Сохранение данных NL в Firebase

Я объединяю данные, возвращаемые из Twitter API (текст твита и местоположение), с данными из NL API (синтаксис, сущности, тональность) и сохраняю их в объекте для записи в Firebase:

let tweetDataForFirebase = {
  id: tweet.id_str,
  text: tweet.text,
  user: tweet.user.screen_name,
  user_time_zone: tweet.user.time_zone,
  user_followers_count: tweet.user.followers_count,
  hashtags: tweet.entities.hashtags,
  tokens: body.tokens,
  score: body.documentSentiment.score,
  magnitude: body.documentSentiment.magnitude,
  entities: body.entities
}

Сохранить его в Firebase очень просто. Сначала нам нужно инициализировать модуль firebase-admin для нашего приложения для записи в нашу базу данных Firebase:

var admin = require("firebase-admin");
var serviceAccount = require("./service-acct.json");
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://your-firebase-project-id.firebaseio.com"
});

Затем мы создадим ссылку на путь в нашей базе данных, где мы хотим сохранить твит:

const db = admin.database();
const latestTweetRef = db.ref('latest');

Я буду хранить только полные данные JSON для последнего твита. Запись этого в Firebase - это всего лишь одна строка кода:

latestTweetRef.set(tweetDataForFirebase);

У меня есть слушатель на этом /latest пути, и всякий раз, когда добавляется новый твит, я проверяю прилагательные и хэштеги, подсчитываю их и веду общий счет каждого прилагательного и хэштега, обнаруженного в Firebase:

Сохранение данных NL в BigQuery

Мы будем записывать в BigQuery те же данные, что и в Firebase, но JSON.stringify() хэштеги, токены и объекты, поэтому они будут строками в нашей таблице BigQuery. С инициализированным BigQuery (документация о том, как это сделать здесь), мы можем записать данные твита в нашу таблицу:

table.insert(bqRow, function(error, insertErr, apiResp) {
  if (error) {
    console.log('err', error);
  } else {
     console.log('successfully added the row!');
  }
});

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

SELECT COUNT(*) as adj_count, adjective
FROM 
 JS(
 (SELECT tokens FROM [sara-bigquery:googlenext_17.tweets] ),
 tokens,
 "[{ name:'adjective', type: 'string'}]",
 "function(row, emit) { 
   try {
     x = JSON.parse(row.tokens);
     x.forEach(function(token) {
       if (token.partOfSpeech.tag === 'ADJ') {
         emit({ adjective: token.lemma.toLowerCase() });
       }
     });
   } catch (e) {}
 }" 
 )
GROUP BY adjective
ORDER BY adj_count DESC
LIMIT 100Visualizing tweet data in realtime

Визуализация данных твита в реальном времени

Помните, как наш сервер Node хранил данные для последнего твита, а также количество каждого хэштега и прилагательного в Firebase? Пора визуализировать эти данные на клиенте! Полный код находится здесь, я лишь выделю несколько ключевых моментов.

Сначала я прикрепляю слушателя к узлу /latest в моей базе данных Firebase, чтобы обновлять пользовательский интерфейс последнего твита всякий раз, когда приходит новый:

database.ref('latest').on('value', function(data) {
  let tweet = data.val();
  let currentScore = tweet.score;
  // Display the latest nouns, verbs, and adjectives in the UI
  // Update the currentScore scale to reflect latest tweet sentiment
});

Затем я прикрепляю слушателя к пути /tokens/ADJ в своей базе данных, чтобы обновить диаграмму прилагательных (диаграмма построена с использованием Chart.js):

adjRef.orderByValue().limitToLast(10).once('value', function(data) {
  let chartLabels = [];
  let chartData = [];
  data.forEach(function(token) {
    let word = token.key;
    chartLabels.push(word);
    chartData.push(token.val());
  });
  var ctx = document.getElementById("adjChart");
  // Create ChartJS chart here
});

Я делаю то же, что и выше, для пути /hashtags, чтобы создать аналогичную диаграмму. Вот и все!

Что такое API естественного языка?

Если вы зашли так далеко, вам может быть интересно: что это за NL API и что я могу с ним делать? NL API помогает понять значение текста с помощью одного вызова API. В частности, он предоставляет три метода:

  • Аннотировать синтаксис: получайте лингвистические данные о своем тексте, такие как части речи, деревья зависимостей (какие слова зависят друг от друга) и дополнительные данные морфологии. Это полезно для анализа того, как люди говорят на определенную тему.

Начните работу с NL API

Вот несколько ресурсов, чтобы начать использовать NL API:

Я хотел бы услышать, что вы думаете! Дайте мне знать в комментариях или найдите меня в Twitter @SRobTweets.