суббота, 14 ноября 2015 г.

Знакомство с Elasticsearch

Знакомство с Elasticsearch

В этом уроке мы познакомим вас с Elasticsearch и рассмотрим как связать данный инструмент с PHP. Elasticsearch - это бесплатный поисковый сервер, работающий на основе Apache Lucene. Главное преимущество данного инструмента в том, что он предоставляет возможность осуществить быстрый и гибкий поиск. Так же нам доступен REST API, который позволяет создавать, удалять, изменять и получать данные.

Установка Elasticsearch

Для установки Elasticsearch нам потребуется Java. По умолчанию в Ubuntu её нет, так что сначала добавляем репозиторий.
1sudo add-apt-repository ppa:webupd8team/java
2sudo apt-get update
Теперь приступаем непосредственно к установке Java.
1sudo apt-get install oracle-java8-installer
Далее скачиваем Elasticsearch, используя wget.
1wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.5.2.tar.gz
На данный момент версия 1.5.2 является самой стабильной, поэтому мы будем использовать именно её. Если вам нужна какая-то другая версия, то архив релизов можно найти тут.
Затем распаковываем и запускаем установку.
1mkdir es
2tar -xf elasticsearch-1.5.2.tar.gz -C es
3cd es
4./bin/elasticsearch
Теперь после обращения к адресу http://localhost:9200 в адресной строке браузера, вы должны увидеть следующее:
01{
02  "status" : 200,
03  "name" : "Rumiko Fujikawa",
04  "cluster_name" : "elasticsearch",
05  "version" : {
06    "number" : "1.5.2",
07    "build_hash" : "62ff9868b4c8a0c45860bebb259e21980778ab1c",
08    "build_timestamp" : "2015-04-27T09:21:06Z",
09    "build_snapshot" : false,
10    "lucene_version" : "4.10.4"
11  },
12  "tagline" : "You Know, for Search"
13}

Использование Elasticsearch

Теперь можем начать наше взаимодействие с Elasticsearch. Для начала давайте установим PHP клиент для работы с Elasticsearch.
1composer require elasticsearch/elasticsearch
Затем создаём новый php файл, который будем использовать для примеров.
1<?php
2require 'vendor/autoload.php';
3
4$client = new Elasticsearch\Client();

Индексация документов

Индексация документов осуществляется вызовом метода index, который принимает массив аргументов. В нём должно быть три ключа: body, index и type. В ключе body будет располагаться массив с данными, которые нужно индексировать. В index следует указывать сегмент, где вы собираетесь индексировать данные (что-то типа название базы данных). В type следует указывать категорию документа (что-то типа названия таблицы). Вот пример:
01$params = array();
02$params['body']  = array(
03  'name' => 'Ash Ketchum',
04  'age' => 10,
05  'badges' => 8
06);
07
08$params['index'] = 'pokemon';
09$params['type']  = 'pokemon_trainer';
10
11$result = $client->index($params);
Если вывести $result, то результат будет такой:
1Array
2(
3    [_index] => pokemon
4    [_type] => pokemon_trainer
5    [_id] => AU1Bn51W5l_vSaLQKPOy
6    [_version] => 1
7    [created] => 1
8)
В приведённом примере мы не указали ID документа. В этом случае Elasticsearch автоматически присвоит уникальный ID. Это можно сделать и самим:
01$params = array();
02$params['body']  = array(
03  'name' => 'Brock',
04  'age' => 15,
05  'badges' => 0
06);
07
08$params['index'] = 'pokemon';
09$params['type']  = 'pokemon_trainer';
10$params['id'] = '1A-000';
11
12$result = $client->index($params);
Результат вывода переменной $result:
1Array
2(
3    [_index] => pokemon
4    [_type] => pokemon_trainer
5    [_id] => 1A-001
6    [_version] => 1
7    [created] => 1
8)
Для индексации документов мы можем использовать как простые массивы, так и вложенные:
01$params = array();
02$params['body']  = array(
03  'name' => 'Misty',
04  'age' => 13,
05  'badges' => 0,
06  'pokemon' => array(
07    'psyduck' => array(
08      'type' => 'water',
09      'moves' => array(
10        'Water Gun' => array(
11          'pp' => 25,
12          'power' => 40
13        )
14      )
15    )
16  )
17);
18
19$params['index'] = 'pokemon';
20$params['type']  = 'pokemon_trainer';
21$params['id'] = '1A-002';
22
23$result = $client->index($params);
Вложенность может быть какой угодно глубины (однако увлекаться этим не стоит).

Поиск по документам

Для поиска следует использовать метод get или search: get в случа, если вы знаете ID документа. Так же следует отметить, что данный метод возвращает только один документ. Для поиска набора результатов по различным критериям (по полям) следует использовать метод search().

Get

Давайте начнём с метода get. Точно так же как метод index он принимает массив аргументов. В массиве должны быть ключи index, type и id документа, который вы хотите найти.
1$params = array();
2$params['index'] = 'pokemon';
3$params['type'] = 'pokemon_trainer';
4$params['id'] = '1A-001';
5
6$result = $client->get($params);
Результат поиска:
01Array
02(
03    [_index] => pokemon
04    [_type] => pokemon_trainer
05    [_id] => 1A-001
06    [_version] => 1
07    [found] => 1
08    [_source] => Array
09        (
10            [name] => Brock
11            [age] => 15
12            [badges] => 0
13        )
14
15)

Поиск по определённым полям

В массиве аргументов для метода search следует указать ключи index, type и body. В ключе body указываем критерии запроса. Вот как можно вернуть все документы, где возраст равен 15.
1$params['index'] = 'pokemon';
2$params['type'] = 'pokemon_trainer';
3$params['body']['query']['match']['age'] = 15;
4
5$result = $client->search($params);
Результат:
01Array
02(
03    [took] => 177
04    [timed_out] =>
05    [_shards] => Array
06        (
07            [total] => 5
08            [successful] => 5
09            [failed] => 0
10        )
11
12    [hits] => Array
13        (
14            [total] => 1
15            [max_score] => 1
16            [hits] => Array
17                (
18                    [0] => Array
19                        (
20                            [_index] => pokemon
21                            [_type] => pokemon_trainer
22                            [_id] => 1A-001
23                            [_score] => 1
24                            [_source] => Array
25                                (
26                                    [name] => Brock
27                                    [age] => 15
28                                    [badges] => 0
29                                )
30
31                        )
32
33                )
34
35        )
36
37)
Давайте разберём результат:
  • took – время выполнения запроса.
  • timed_out – возвращает true если время выполнения запроса прошло.
  • _shards – по умолчанию, Elasticsearch размещает данные по 5 шардам (сегментам). Если значение 5 будет в total и successful то каждый шард работает корректно.
  • hits содержит результат поиска.
Метод который мы продемонстрировали, позволяет осуществить поиск по глубине равной единице. Если мы хотим искать глубже, то нам следует воспользоваться bool запросами. Для этого указываем ключ bool в query. Теперь в поиске будут задействованы все поля, разделяя их знаком . .
1$params['index'] = 'pokemon';
2$params['type']  = 'pokemon_trainer';
3$params['body']['query']['bool']['must'][]['match']['pokemon.psyduck.type'] = 'water';
4$result = $client->search($params);

Поиск массивами

Так же мы можем осуществлять запросы, используя массивы, указав ключ bool, а затем must, terms. В качестве значения указываем массив значений, который должен быть задействован в поиске. В данном примере ищем документы, где поле age равняется 10 и 15.
1$params['index'] = 'pokemon';
2$params['type']  = 'pokemon_trainer';
3
4$params['body']['query']['bool']['must']['terms']['age'] = array(10, 15);
В данном способе можно применять только линейные массивы.

Поиск по фильтрам

Теперь давайте посмотрим как можно осуществить поиск с применением фильтров. Для фильтрации нужно указать ключ filtered, а в качестве значения начальное и конечно число диапазона искомых значений. В данном случае мы будем искать по полю age, где значение больше или равно (gte) 11 и меньше или равно (lte) 20.
1$params['index'] = 'pokemon';
2$params['type']  = 'pokemon_trainer';
3$params['body']['query']['filtered']['filter']['range']['age']['gte'] = 11;
4$params['body']['query']['filtered']['filter']['range']['age']['lte'] = 20;
5$result = $client->search($params);

OR и AND

При работе с запросами в реляционных СУБД мы часто используем ключевые слова AND или OR. В Elasticsearch у нас тоже есть такая возможность: для этого просто указываем ключ and. Выберем все документы, где возраст age равен 10 и badge равен 8.
1$params['index'] = 'pokemon';
2$params['type']  = 'pokemon_trainer';
3
4$params['body']['query']['filtered']['filter']['and'][]['term']['age'] = 10;
5$params['body']['query']['filtered']['filter']['and'][]['term']['badges'] = 8;
6
7$result = $client->search($params);
Если нужно осуществить поиск по одному из этих двух значений, то используйте ключ or.
1$params['body']['query']['filtered']['filter']['or'][]['term']['age'] = 10;
2$params['body']['query']['filtered']['filter']['or'][]['term']['badges'] = 8;

Выбор определённого числа результатов

Мы можем ограничить число результатов поиска, используя поле size. Пример:
1$params['body']['query']['filtered']['filter']['and'][]['term']['age'] = 10;
2$params['body']['query']['filtered']['filter']['and'][]['term']['badges'] = 8;
3$params['size'] = 1;
Возвращает только один документ.

Постраничное разделение

В реляционных СУБД есть возможность выбирать данные по различным сегментам, используя ключевые слова LIMIT и OFFSET. В Elasticsearch тоже есть аналоги: ключи size и from. from позволяет нам осуществить выборку с нужного нам “отступа”. Индексация документов начинается с нуля. Вот как мы можем получить вторую страницу результатов:
1$params['index'] = 'pokemon';
2$params['type']  = 'pokemon_trainer';
3
4$params['size'] = 10;
5$params['from'] = 10; // <-- возврат второй страницы

Редактирование документа

Для обновления данных в документе нам необходимо сначала его извлечь. Для этого указываем index, type и id документа в методе get. Текущие данные можно найти в сегменте _source. Для обновления данных, просто обращаемся к полям и задаём новые значения. Для сохранения результатов следует вызвать метод update.
01$params = array();
02$params['index'] = 'pokemon';
03$params['type'] = 'pokemon_trainer';
04$params['id'] = '1A-001';
05$result = $client->get($params);
06
07
08$result['_source']['age'] = 21; //задаём полю новое значение
09
10//добавляем новое поле
11$result['_source']['pokemon'] = array(
12  'Onix' => array(
13    'type' => 'rock',
14    'moves' => array(
15      'Rock Slide' => array(
16        'power' => 100,
17        'pp' => 40
18      ),
19      'Earthquake' => array(
20        'power' => 200,
21        'pp' => 100
22      )
23    )
24  )
25);
26
27$params['body']['doc'] = $result['_source'];
28
29$result = $client->update($params);
Результат:
1Array
2(
3    [_index] => pokemon
4    [_type] => pokemon_trainer
5    [_id] => 1A-001
6    [_version] => 2
7)
Значение поля _version будет увеличиваться каждый раз при вызове метода update (в том случае, если хоть одно поле было изменено).
Вы можете подумать, что Elasticsearch сохраняет предыдущие версии документа, но это не так. Данный счётчик просто показывает количество обновлений документа.

Удаление документа

Для удаление документа достаточно вызвать метод delete. В массиве аргументов следует указать поля index, type и id.
1$params = array();
2$params['index'] = 'pokemon';
3$params['type'] = 'pokemon_trainer';
4$params['id'] = '1A-001';
5
6$result = $client->delete($params);
Результат:
1Array
2(
3    [found] => 1
4    [_index] => pokemon
5    [_type] => pokemon_trainer
6    [_id] => 1A-001
7    [_version] => 7
8)
Заметка: если вытащить документ, используя метод get, а затем его удалить, то может возникнуть ошибка.

Вывод

В этой статье мы рассмотрели как стартануть с Elasticsearch и PHP, используя официальный Elasticsearch клиент. Так же мы рассмотрели как осуществить индексацию документов, организовать поиск, постраничный вывод, обновление и удаление данных.
Elasticsearch - это прекрасный способ добавить в ваше PHP приложение гибкий и быстрый поиск.
Данный урок подготовлен для вас командой сайта ruseller.com

Отблагодарить можно через форму справа "Donate" ... )

To reward you via the form on the right "Donate" ... )

:)

Комментариев нет :

Отправить комментарий

друзья )

Сохраняйте и делитесь желаниями, и не забывайте о важных датах! парсинг центр