Windows Azure изнутри

Улучшите исследование данных с помощью Azure Search

Bruno Terkaly

Исходный код можно скачать по ссылке

Продукты и технологии:

Microsoft Azure, Azure Search, Node.js

В статье рассматриваются:

  • конфигурирование режимов полнофункционального поиска в более крупных архитектурах;
  • подготовка полнотекстового поиска;
  • разработка клиентского интерфейса на основе Node.js для выполнения операций поиска.

Бруно Теркали Сферы применения исследования данных (data exploration), анализа в реальном времени и машинного обучения самые разнообразные. Компании создают интересные архитектуры, опираясь на множество программных пакетов с открытым исходном кодом. Azure Search — один из таких фрагментов более крупной архитектуры. Azure Search является новой мощной средой поиска для ваших веб-сайтов и приложений, даже если вы не эксперт в области поиска.

Azure Search — полностью управляемый облачный сервис, использующий простой REST API. Он поддерживает опережающие предложения при вводе букв (type-ahead suggestions), предлагаемые результаты, основанные на ближайших совпадениях, разноплановую навигацию и возможность регулировки используемых мощностей, исходя из текущих потребностей. Azure Search обеспечивает полнотекстовый поиск с весовыми значениями, расстановкой по степени важности (ranking) и пользовательские поведения при поиске на основе схемы, определенной комбинациями атрибутов полей. Данные немедленно индексируются, что сводит к минимуму задержки при поиске.

Потребность в эффективном поиске постоянно растет параллельно с появлением хранилищ данных огромных размеров. Только в Facebook пользователи тратят ежемесячно сотни миллиардов минут на поиск. Для эффективного поиска Wikipedia вам понадобилось бы проиндексировать 17 миллионов записей. Twitter объединяет более 600 миллионов пользователей, генерирующих более 50 000 твитов в день. Выполнение полнотекстового поиска в таких масштабах требует весьма творческих подходов. Индексирование и отслеживание всей этой информации явно не для слабонервных.

Многие компании, для которых поиск является неотъемлемой частью бизнеса, начинают работать с Azure G-Series Virtual Machines, имеющими 32 ядра, 448 Гб оперативной памяти и 6,5 Тб на твердотельных накопителях (SSD). Некоторые инженеры пишут собственный код на ассемблере и C, чтобы оптимизировать когерентность кеширования как данных, так и инструкций. Они используют кеши для сокращения времени простоя процессора в ожидании выполнения запроса к памяти и для уменьшения общего объема передаваемых данных. Одна из трудных задач в рамках этих колоссальных, многоядерных машин заключается в том, что за шину памяти конкурирует множество потоков. Прирост производительности от использования кешей уровней L2 и L3 на порядки существеннее. Все это важно, потому что быстрое получение больших объемов данных вашей системой полнотекстового поиска имеет критическое значение.

Корректно выполняемый полнотекстовый поиск

Azure Search предлагает много преимуществ. Он уменьшает сложность подготовки собственного поискового индекса (search index) и управления им. Это полностью управляемый сервис, который помогает вам избежать всех забот, связанных с возможностью повреждения индекса, доступностью сервиса, масштабированием и обновлениями сервиса. Одно из крупных преимуществ в том, что Azure Search поддерживает богатые, тонко-настраиваемые модели ранжирования (ranking models). Это позволяет связывать результаты поиска с бизнес-целями. Кроме того, обеспечивается многоязыковый поиск, коррекция грамматических ошибок и опережающие предложения при наборе букв. Если результаты поиска неудовлетворительны, Azure Search может предложить запросы на основе ближайших совпадений. Рекомендую изучить краткое учебное руководство по подготовке нового экземпляра Azure Search по ссылке bit.ly/1wYb8L8.

Это учебное руководство проведет вас по всем этапам, необходимым для того, чтобы приступить к работе и выполнить ряд обязательных операций на портале. Вы будете подготавливать Azure Search на Azure Management Portal (portal.azure.com), который требует двух вещей: URL, предоставляемого самим порталом, и API-KEY. URL представляет конечную точку в облаке, где выполняется ваш сервис Azure Search, с которым будет взаимодействовать клиентское приложение. API-KEY нужно тщательно защищать, поскольку он открывает полный доступ к вашему сервису. Более того, ни один клиент не сможет обратиться к сервису Azure Search без аутентификации по этому ключу.

Существуют лимиты и ограничения, о которых вы должны знать; они относятся к количеству индексов, максимальному числу полей на индекс, максимальному количеству документов и т. д. Одно из важных ограничений — никаких квот или лимитов с запросами не связывается. Количество запросов в секунду (queries-per-second, QPS) варьируется в зависимости от доступной полосы пропускания и конкуренции за системные ресурсы.

В случае бесплатного сервиса Azure Search вычислительные ресурсы и ресурсы хранилищ Azure, поддерживающие ваш сервис, являются общими для множества подписчиков, поэтому QPS для вашего решения будет варьироваться в зависимости от того, какие рабочие нагрузки выполняются параллельно с вашим сервисом. В случае выделенных сервисов (STANDARD SKU) все ресурсы выделяются клиенту и не являются общими.

Получив URL и API-KEY, вы готовы к использованию сервиса. Самый простой способ сделать это — применение Fiddler, так как он позволяет формировать собственные HTTP-запросы. (Бесплатную копию Fiddler можно получить по ссылке bit.ly/1jKA1UJ.) Azure Search использует простой HTTP, поэтому вставка и запрос данных с помощью Fiddler тривиальна (рис. 1). Далее в этой статье вы увидите, как использовать Node.js для взаимодействия с Azure Search.

Выполнение вставки в Azure Search с помощью Fiddler
Рис. 1. Выполнение вставки в Azure Search с помощью Fiddler

Fiddler can directly perform the REST- based insert into azure search Fiddler может напрямую выполнить вставку в Azure Search на основе REST
HTTP verb HTTP-команда
Fiddler Fiddler
URL URL
Request header Заголовок запроса
Request body Тело запроса

 

Как видите, вам нужно позаботиться о четырех вещах:

  • HTTP-команде;
  • URL;
  • заголовке запроса;
  • теле запроса

HTTP-команда (PUT, POST, GET или DELETE) сопоставляется с разными операциями. Например, PUT сопоставляется с определением схемы, а POST — со вставкой данных. URL доступен с Azure Portal и может изменяться в зависимости от параметров вашего запроса. API-KEY посылается в заголовке запроса. Тело запроса всегда является JSON-представлением схемы или вставляемых данных.

Azure Search может играть ключевую роль в более крупных архитектурах. Рис. 2 демонстрирует архитектуру, которая использует Azure Search. Начнем с важного уровня аутентификации, где у вас есть некоторые варианты. Например, вы можете задействовать Azure Active Directory Graph API, используя OAuth2 с Node.js. Что касается Node.js, то его можно использовать как прокси для URL конечной точки Azure Search, обеспечивающий некоторое структурирование и управление вашим сервисом.

Azure Search в более крупных архитектурах
Рис. 2. Azure Search в более крупных архитектурах

REST- Capable clients Клиенты, поддерживающие REST
iOS Apps Приложения iOS
Android Apps Приложения Android
Windows Apps Приложения Windows
JavaScript Apps Приложения JavaScript
Any HTTP client Любой HTTP-клиент
Azure Datacenter (One of 16 Global Datacenters) Информационный центр Azure (один из 16 глобальных информационных центров)
Authentication Аутентификация
Azure AD Azure AD
Active Directory Active Directory
Social Identity (Twitter, Facebook, etc.) Идентификация в социальных сетях (Twitter, Facebook и др.)
Auth Key from Azure Search Ключ аутентификации от Azure Search
Node.js Proxy Layer Уровень прокси Node.js
Data Layer Уровень данных
Hadoop/HDInsight Hadoop/HDInsight
PIG PIG
HIVE HIVE
Azure Storage Azure Storage
Blobs Storage Blobs Storage
Tweets Твиты
Blogs Блоги
XML XML
Azure Search Azure Search
Data Loaded into Azure Search Данные, загруженные в Azure Search
Social Networks Социальные сети
Twitter Twitter
Facebook Facebook
LinkedIn LinkedIn
Blogs (WordPress, etc.) Блоги (WordPress и др.)
Relational Data Store Реляционное хранилище данных
SQL Server SQL Server
MySQL MySQL
Online Retail/User-Generated Онлайновые данные, генерируемые сектором розничной торговли или пользователями
Tags, Descriptions, User Feedback, Recipes, News, Photo-Sharing Sites Теги, описания, отзывы пользователей, новости, сайты хостинга фотографий

 

Одна из замечательных особенностей Azure Search в том, что вы можете индексировать и вести поиск почти любых структурированных данных, кроме фотоснимков, изображений и видеозаписей. На рис. 2 перечислены некоторые потенциальные источники данных для Azure Search. Поскольку реляционные базы данных не слишком хорошо подходят для выполнения полнотекстового поиска, многие начинающие компании берут свои реляционные данные и экспортируют ключевые части в Azure Search. Это тоже дает выигрыш, так как снимает бремя полнотекстового поиска в реляционных базах данных.

Это не означает, что Azure Search является панацеей. Вам все равно нужно просеивать данные, используя такие технологии преобразования/сокращения (map/reduce), как Hadoop или HDInsight, чтобы применять алгоритмы машинного обучения вроде кластеризации, где текстовые документы группируются в тематически связанные.

Вообразите анализ твита и присваивания ему некоей оценки, определяющей степень его вероятной принадлежности к какой-то другой категории. Например, у вас могут быть категории Rants (для эмоционально выраженной критики) и Raves (для позитивных мнений). Для таких целей часто применяются алгоритмы линейной классификации. Azure Search не способен на это. Но представьте, что индексация документов в Azure Search основана на том, как вы классифицируете и анализируете данные.

Node.js

Теперь я переключусь на написание клиентского интерфейса Node.js, который я буду использовать как уровень прокси перед Azure Search.

  • Выполните начальную подготовку, упомянутую ранее в этой статье, чтобы Azure Search предоставлялся на портале. Вспомните, что вам потребуются URL и API-KEY.
  • Скачайте и установите исполняющую среду Node.js локально на своем компьютере для разработок. Вы найдете необходимое на странице nodejs.org/download. Я установил в папку c:\program files\nodejs. Рекомендуется добиться выполнения базового примера «hello world» в Node.js, прежде чем продолжать дальше.
  • Убедитесь, что Node Package Manager (NPM) корректно установлен и настроен. NPM позволяет устанавливать приложения Node.js (JavaScript), доступные в реестре NPM.
  • Установите пакет elasticsearch, который упрощает написание кода для взаимодействия с Azure Search.

Завершив эти этапы, вы готовы вернуться в командную строку, перейти в нужный вам каталог и приступить к написанию кода. Если вы сталкиваетесь с какими-то ошибками NPM, проверьте следующие переменные окружения, которые должны выглядеть так:

C:\node>set nodejs=C:\Program Files\nodejs\
C:\node>set node_path=C:\Program Files\nodejs\node_modules\*
C:\node>set npm=C:\Program Files\nodejs\

Создаем решение Node.js

Теперь вы готовы к разработке кода на основе Node.js, который будет выполняться в вашей локальной системе для демонстрации взаимодействия с Azure Search. Node.js облегчает вставку и запрос данных в Azure Search. Допустим, у вас есть Azure Search URL вида terkaly.search.windows.net. Вы должны были получить свой URL с Azure Management Portal. Кроме того, вам понадобится API-KEY, который в этом примере выглядит так: B7D12B8CA3D018EC09C754F95CA552D2.

Разрабатывать приложения Node.js на локальном компьютере можно более чем одним способом. Если вам нравится отладчик в Visual Studio, тогда вам стоит установить плагин Node.js Tools for Visual Studio (nodejstools.codeplex.com). Если вы предпочитаете командную строку, зайдите на Nodejs.org. После установки Node.js важно интегрировать NPM. Это позволяет устанавливать приложения Node.js, доступные в реестре NPM. Используемый здесь базовый пакет называется request.

Код на рис. 3 прямолинеен. Он делает то же самое, что описывается в учебном пособии по ссылке bit.ly/1Ilh6vB, — единственное отличие в том, что этот код реализован вами и Node.js использует пакет request. Данный код охватывает более универсальные случаи применения, такие как создание индекса, вставка данных и, конечно, выполнение запросов. Здесь есть ряд обратных вызовов, которые определяют схему, вставляют и запрашивают данные.

Рис. 3. Код на основе Node.js, который показывает, как создать индекс, вставить и запросить данные

var request = require('request');
//////////////////////////////////////////////////
// OPTIONS FOR HTTP PUT
// Цель: используется для создания индекса с именем hotels
//////////////////////////////////////////////////
var optionsPUT = {
  url: 'https://terkaly.search.windows.net/indexes/hotels?
    api-version=2014-07-31-Preview',
  method: 'PUT',
  json: true,
  headers: {
    'api-key': 'B7D12B8CA3D018EC09C754F95CA552D2',
    'Content-Type': 'application/json'
  },
  body: {
    "name": "hotels",
    "fields": [
      { "name": "hotelId", "type": "Edm.String", "key": true,
        "searchable": false },
      { "name": "baseRate", "type": "Edm.Double" },
      { "name": "description", "type": "Edm.String",
        "filterable": false, "sortable": false,
        "facetable": false, "suggestions": true },
      { "name": "hotelName", "type": "Edm.String",
        "suggestions": true },
      { "name": "category", "type": "Edm.String" },
      { "name": "tags", "type": "Collection(Edm.String)" },
      { "name": "parkingIncluded", "type": "Edm.Boolean" },
      { "name": "smokingAllowed", "type": "Edm.Boolean" },
      { "name": "lastRenovationDate", "type":
        "Edm.DateTimeOffset" },
      { "name": "rating", "type": "Edm.Int32" },
      { "name": "location", "type": "Edm.GeographyPoint" }
    ]
  }
};
//////////////////////////////////////////////////
// OPTIONS FOR HTTP POST
// Цель: используется для вставки данных
//////////////////////////////////////////////////
var optionsPOST = {
  url: 'https://terkaly.search.windows.net/indexes/hotels/docs/
    index?api-version=2014-07-31-Preview',
  method: 'POST',
  json: true,
  headers: {
    'api-key': 'B7D12B8CA3D018EC09C754F95CA552D2',
    'Content-Type': 'application/json'
  },
  body: {
    "value": [
    {
      "@search.action": "upload",
      "hotelId": "1",
      "baseRate": 199.0,
      "description": "Best hotel in town",
      "hotelName": "Fancy Stay",
      "category": "Luxury",
      "tags": ["pool", "view", "wifi", "concierge"],
      "parkingIncluded": false,
      "smokingAllowed": false,
      "lastRenovationDate": "2010-06-27T00:00:00Z",
      "rating": 5,
      "location": { "type": "Point", "coordinates":
      [-122.131577, 47.678581] }
    },
    {
      "@search.action": "upload",
      "hotelId": "2",
      "baseRate": 79.99,
      "description": "Cheapest hotel in town",
      "hotelName": "Roach Motel",
      "category": "Budget",
      "tags": ["motel", "budget"],
      "parkingIncluded": true,
      "smokingAllowed": true,
      "lastRenovationDate": "1982-04-28T00:00:00Z",
      "rating": 1,
      "location": { "type": "Point", "coordinates":
      [-122.131577, 49.678581] }
    },
    {
      "@search.action": "upload",
      "hotelId": "3",
      "baseRate": 279.99,
      "description": "Surprisingly expensive",
      "hotelName": "Dew Drop Inn",
      "category": "Bed and Breakfast",
      "tags": ["charming", "quaint"],
      "parkingIncluded": true,
      "smokingAllowed": false,
      "lastRenovationDate": null,
      "rating": 4,
      "location": { "type": "Point", "coordinates":
      [-122.33207, 47.60621] }
    },
    {
      "@search.action": "upload",
      "hotelId": "4",
      "baseRate": 220.00,
      "description": "This could be the one",
      "hotelName": "A Hotel for Everyone",
      "category": "Basic hotel",
      "tags": ["pool", "wifi"],
      "parkingIncluded": true,
      "smokingAllowed": false,
      "lastRenovationDate": null,
      "rating": 4,
      "location": { "type": "Point", "coordinates":
      [-122.12151, 47.67399] }
    }
    ]
  }
};
//////////////////////////////////////////////////
// OPTIONS FOR HTTP GET
// Цель: используется для выполнения запроса
//////////////////////////////////////////////////
var optionsGET = {
  url: 'https://terkaly.search.windows.net/indexes/hotels/
    docs?search=motel&facet=category&facet=rating,
    values:1|2|3|4|5&api-version=2014-07-31-Preview',
  method: 'GET',
  json: true,
  headers: {
    'api-key': 'B7D12B8CA3D018EC09C754F95CA552D2',
    'Content-Type': 'application/json'
  },
  body: {
  }
};
request(optionsPUT, callbackPUT);
//////////////////////////////////////////////////
// Цель: используется для создания индекса
// HTTP-команда: PUT
// Конечный результат: определяет индекс, используя поля,
// которые образуют определение индекса
//////////////////////////////////////////////////
function callbackPUT(error, response, body) {
  if (!error) {
    try {
      if (response.statusCode === 204) {
          console.log('***success in callbackPUT***');
          request(optionsPOST, callbackPOST);
      }
    } catch (error2) {
      console.log('***Error encountered***');
      console.log(error2);
    }
  } else {
    console.log('error');
    console.log(error);
  }
}
//////////////////////////////////////////////////
// Цель: используется для вставки данных
// Конечный результат: вставляет документ
//////////////////////////////////////////////////
function callbackPOST(error, response, body) {
  if (!error) {
    try {
      var result = response.request.response.statusCode;
      if (result === 200) {
          console.log('***success in callbackPOST***');
          console.log("The statusCode = " + result);
        // Выполняем запрос
        request(optionsGET, callbackGET);
      }
    } catch (error2) {
      console.log('***Error encountered***');
      console.log(error2);
    }
  } else {
    console.log('error');
    console.log(error);
  }
}
//////////////////////////////////////////////////
// Цель: используется для извлечения информации
// HTTP-команда: GET
// Конечный результат: запрос ищет "motel" и получает
// категории для рейтингов
//////////////////////////////////////////////////
function callbackGET(error, response, body) {
  if (!error) {
    try {
      var result = response.request.response.statusCode;
      if (result === 200) {
          result = body.value[0];
          console.log('description = ' + result.description);
          console.log('hotel name = ' + result.hotelName);
          console.log('hotel rate = ' + result.baseRate);
      }
      console.log('***success***');
    } catch (error2) {
      console.log('***Error encountered***');
      console.log(error2);
    }
  } else {
    console.log('error');
    console.log(error);
  }
}

Цепочка обратных вызовов тоже довольно проста. Она начинается с простой GET, затем переходит к PUT, POST и второй GET (с запросом). Это демонстрирует базовые операции, используемые с Azure Search. Сначала создается схема для документов, которые вы будете потом добавлять. Схема определяется HTTP-командой PUT. Затем с помощью POST вставляются данные. Наконец, для запроса данных применяется GET.

Заключение

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


Bruno Terkaly -  ведущий инженер программного обеспечения в Microsoft. Его основная цель — обеспечить разработку лидирующих в отрасли приложений и сервисов, способных работать на любых устройствах. Отвечает за развитие главных возможностей облачных и мобильных технологий на территории США и за ее пределами. Помогает партнерам в выводе их приложений на рынок, обеспечивая руководство при проектировании архитектур и глубокие технические знания на этапах оценки, разработки и развертывания приложений, создаваемых независимыми поставщиками ПО (ISV). Кроме того, тесно взаимодействует с группами облачных и мобильных технологий, организуя обратную связь и влияя на их дорожные карты.

Выражаю благодарность за рецензирование статьи экспертам Microsoft Лиэму Кэвэну (Liam Cavanagh), Саймону Гуревичу (Simon Gurevich), Говинду Канши (Govind Kanshi), Раджу Кришнану (Raj Krishnan), Венугоралу Латчупатуле (Venugopal Latchupatula), Юджину Швецу (Eugene Shvets).