Статьи

Интеграция Elasticsearch с Silex

В предыдущей статье я начал изучать интеграцию между Drupal 7 и движком Elasticsearch . Цель состояла в том, чтобы увидеть, как мы можем объединить эти технологии с открытым исходным кодом для достижения высокопроизводительного приложения, которое использует лучшее из обоих миров. Если вы только что присоединились к нам, вы должны проверить этот репозиторий, который содержит соответствующий код для этих статей.

esdrupalsilex

Теперь мы создадим небольшое приложение Silex, которое считывает данные прямо из Elasticsearch и возвращает их пользователю.

Приложение Silex

Silex – это отличный PHP-фреймворк, разработанный теми же людьми, которые стоят за проектом Symfony. На самом деле он использует в основном компоненты Symfony, но на более упрощенном уровне. Давайте посмотрим, как мы можем начать очень быстро с приложением Silex.

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

"silex/silex": "~1.2",

Или вы можете даже создать новый проект, используя симпатичный маленький скелет, предоставленный создателем:

 composer.phar create-project fabpot/silex-skeleton

Независимо от того, как настроен ваш проект, для доступа к Elasticsearch нам потребуется использовать его PHP SDK . Это должно быть добавлено в Composer:

 "elasticsearch/elasticsearch": "~1.0",

И если мы хотим использовать Twig для вывода данных, нам это тоже понадобится (если, конечно, еще нет):

 "symfony/twig-bridge": "~2.3"

Чтобы использовать SDK, мы можем представить его как сервис для Pimple , крошечного контейнера внедрения зависимостей Silex (гораздо проще, чем кажется). В зависимости от того, как настроен наш проект, мы можем сделать это в нескольких местах (см. Репозиторий для примера). Но в основном, после того, как мы создаем новое приложение Silex, мы можем добавить следующее:

 $app['elasticsearch'] = function() {
  return new Client(array());
};

Это создает новый сервис с именем elasticsearchClient И не забудьте, что нам нужно использовать этот класс вверху:

 use Elasticsearch\Client;

Теперь, где бы мы ни хотели, мы можем получить клиента Elasticsearch, просто ссылаясь на это свойство в объекте $app

 $client = $app['elasticsearch'];

Подключение к Elasticsearch

В предыдущей статье нам удалось получить данные нашего узла в индексе node Так, например, это вернет все типы узлов статьи:

 http://localhost:9200/node/article/_search

Мы также видели, как создать экземпляр клиента для нашего Elasticsearch SDK. Теперь пришло время использовать это как-то. Одним из способов является создание контроллера:

 <?php

namespace Controller;

use Silex\Application;
use Symfony\Component\HttpFoundation\Response;

class NodeController {

  /**
   * Shows a listing of nodes.
   *
   * @return \Symfony\Component\HttpFoundation\Response
   */
  public function index() {
    return new Response('Here there should be a listing of nodes...');
  }
  
  /**
   * Shows one node
   *
   * @param $nid
   * @param \Silex\Application $app
   * @return mixed
   */
  public function show($nid, Application $app) {
    $client = $app['elasticsearch'];
    $params = array(
      'index' => 'node',
      'body' => array(
        'query' => array(
          'match' => array(
            'nid' => $nid,
          ),
        ),
      )
    );
    
    $result = $client->search($params);
    if ($result && $result['hits']['total'] === 0) {
      $app->abort(404, sprintf('Node %s does not exist.', $nid));
    }
    
    if ($result['hits']['total'] === 1) {
      $node = $result['hits']['hits'];
      return $app['twig']->render('node.html.twig', array('node' => reset($node)));
    }
  }
}

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

Нам также нужно создать маршрут, который сопоставляется с этим контроллером. Опять же, есть несколько разных способов справиться с этим, но в моем примере у меня есть файл routes.phpsrc/index.php

 <?php

use Symfony\Component\HttpFoundation\Response;

/**
 * Error handler
 */
$app->error(function (\Exception $e, $code) {
  switch ($code) {
    case 404:
      $message = $e->getMessage();
      break;
    default:
      $message = 'We are sorry, but something went terribly wrong. ' . $e->getMessage();
  }

  return new Response($message);
});

/**
 * Route for /node
 */
$app->get("/node", "Controller\\NodeController::index");

/**
 * Route /node/{nid} where {nid} is a node id
 */
$app->get("/node/{nid}", "Controller\\NodeController::show");

Так что же происходит в моем примере выше? Во-первых, я определил обработчик ошибок для приложения, чтобы я мог видеть перехваченные исключения и выводить их на экран. Не так уж и важно. Затем я определил два маршрута, которые отображаются на два моих метода контроллера, определенных ранее. Но для краткости я лишь продемонстрировал, что может делать предполагаемый метод show()

  • Получить клиент Elasticsearch
  • Создайте параметры запроса Elasticsearch (аналогично тому, что мы делали в среде Drupal)
  • Выполнить запрос
  • Проверьте результаты и, если узел был найден, визуализируйте его с помощью шаблона Twig и передайте ему данные узла.
  • Если результатов не найдено, прервите процесс с помощью 404, который вызывает наш обработчик ошибок для этого HTTP-кода, объявленного выше.

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

После создания экземпляра приложения Silex вы можете зарегистрировать провайдера:

 $app->register(new TwigServiceProvider());

Убедитесь, что вы используете класс вверху:

 use Silex\Provider\TwigServiceProvider;

И добавьте его как сервис с некоторой базовой конфигурацией:

 $app['twig'] = $app->share($app->extend('twig', function ($twig, $app) {
  return $twig;
}));
$app['twig.path'] = array(__DIR__.'/../templates');

Теперь вы можете создавать файлы шаблонов внутри папки templates/ Чтобы узнать больше о настройке приложения Silex, я рекомендую вам прочитать это введение в среду .

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

Внутри файла page.html.twig

 <!DOCTYPE html>
	<html>
	<head>
	    {% block head %}
	        <title>{% block title %}{% endblock %} - My Elasticsearch Site</title>
	    {% endblock %}
	</head>
	<body>
	<div id="content">{% block content %}{% endblock %}</div>
	</body>
	</html>

А внутри файла node.html.twig

 {% extends "page.html.twig" %}

{% block title %}{{ node._source.title }}{% endblock %}

{% block content %}

    <article>
        <h1>{{ node._source.title }}</h1>

        <div id="content">

            {% if node._source.field_image %}
                <div class="field-image">
                    {% for image in node._source.field_image %}
                        <img src="{{ image.url }}" alt="img.alt"/>
                    {% endfor %}
                </div>
            {% endif %}

            {% if node._source.body %}
                <div class="field-body">
                    {% for body in node._source.body %}
                        {{ body.value|striptags('<p><div><br><img><a>')|raw }}
                    {% endfor %}
                </div>
            {% endif %}
        </div>
    </article>


{% endblock %}

Это всего лишь некоторые базовые шаблоны для печати данных нашего узла в браузере (иначе это не так весело). У нас есть базовый файл и один, который расширяет его и выводит заголовок узла, изображения и основной текст на экран.

Кроме того, вы также можете вернуть JSON-ответ от вашего контроллера с помощью класса JsonResponse

 use Symfony\Component\HttpFoundation\JsonResponse;

А из вашего контроллера просто верните новый экземпляр со значениями, переданными ему:

 return new JsonResponse($node);

Вы можете легко создать такой API. Но сейчас это уже должно работать. При указании вашего браузера на http://localhost/node/5 С одной большой разницей: это намного намного быстрее. Здесь нет начальной загрузки, слоя тем, запросов к базе данных и т. Д. С другой стороны, у вас нет ничего полезного, кроме того, что вы создаете сами, используя компоненты Silex / Symfony. Это может быть хорошо или плохо в зависимости от типа проекта, над которым вы работаете. Но дело в том, что у вас есть возможность нарисовать некоторые линии для этой интеграции и решить ее степень.

Одним из концов спектра может быть создание всего вашего внешнего интерфейса с помощью Twig или даже Angular.js с Silex в качестве бэкэнда API. Другой – использовать Silex / Elasticsearch для одной страницы Drupal и использовать его только для лучшего поиска контента. Где-то посередине, вероятно, будет использоваться такое решение для всего раздела сайта Drupal, который посвящен взаимодействию с тяжелыми данными (например, видеомагазином или чем-то еще). Тебе решать.

Вывод

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