Взаимодействие React и Elastic Search создание виджета поиска с автозаполнением полей


Содержание материала:

Начало работы с Elasticsearch

Что такое Elasticsearch?

Варианты использования Elasticsearch

Настройка и запуск

Простые примеры

Доступ к ElasticSearch в Python

Web Scraping и Elasticsearch

Полученный контент

Таким образом, это основная программа, которая может парсить данные. Так как нам нужны данные в формате JSON — мне пришлось дополнительно их преобразовать.

Создаем индексы

Окей, мы с вами получили нужные данные и теперь должны их где-то хранить. Самое первое, что нам нужно сделать, это создать индекс. Назовем его recipes. Тип (type) будет называться salads. Далее нам нужно создать мэппинг нашей структуры документа.

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

_es.ping() фактически пингует сервер и выводит в консоль True, если удалось совершить подключение. Мне потребовалось некоторое время, чтобы выяснить как поймать стек-трейс, в итоге выяснилось, что он просто регистрируется.

На верхнем скриншоте много чего происходит. Во-первых, мы передали конфигурационную переменную, которая отображает всю структуры документа. Мэппинг -это термин в Elasticsearch, обозначающий микроразметку. Подобно тому, как мы устанавливаем определенный тип данных поля в таблицах, мы делаем что-то похожее и здесь. Но чтобы лучше во всем этом разобраться — читайте официальную документацию. Все поля имеют тип text , но у calories тип integer .

Следующий шаг — удостовериться, что индекса вообще не существует и затем создать его. Параметр ignore = 400 можно удалить после проверки. Но в случае, если вы не проверили существование индекса, данный параметр может спровоцировать ошибку и перезаписать индекс. Это будет тоже самое, что перезаписать базу данных. Когда индекс будет успешно создан, вы можете убедиться в этом, посетив страницу http://localhost:9200/recipes/_mappings. Должно получиться примерно следующее сообщение:

Передавая dynamic:strict , мы заставляем Elasticsearch выполнять строгую проверку любого входящего документа. Здесь salads является типом document. Тип ( type) в Elasticsearch это ответ на таблицы в RDBMS.

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

Следующим шагом является хранение фактических данных или документов.

Запускаем и вот что мы увидим:

Знаете, почему это происходит? Так как мы не добавляли в наш мэппинг компонентов, ES решил не разрешать нам хранить документ, не содержащий, по сути, ничего. Если вы не назначите компоненты мэппингу — произойдет повреждение данных. Теперь давайте немного подправим наш мэппинг и посмотрим, что произойдет:

Мы добавили ingredients типу nested , а затем назначили тип данных внутреннему полю. В нашем случае это text .

Вложенный тип данных (nested) позволяет установить тип вложенных объектов JSON. Запустите снова и взгляните на результат:

Так как вы не передали _ >

Прежде чем двигаться дальше, отправим строку в поле calories и посмотрим, как развернутся события. Вспомним тот факт, что мы присвоили ему тип integer. Учитывая это, при индексировании он выдаст следующую ошибку:

TransportError(400, ‘mapper_parsing_exception’, ‘failed to parse [calories]’)

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

Запрос записей

Теперь, когда записи индексируются, пришло время их запросить, в соответствии с нашими потребностями. Я собираюсь создать функцию и назвать ее search() . Она будет выводить на экран результаты наших запросов:

Все предельно просто. Вы передаете индекс и критерии поиска в него. Попробуем задать несколько запросов:

В приведенном выше запросе вернутся все записи, в которых calories равны 102. В нашем случае вывод будет:

А что делать, если вы хотите получить записи, в которых calories больше, чем 20?

Вы также можете указать, какие столбцы или поля вам хотелось бы вернуть. Приведенный выше запрос вернет все записи, в которых calories больше, чем 20. Кроме того, он будет отображать поле title только под _source.

Заключение

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

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

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

Установка Elasticsearch

Для установки Elasticsearch нам потребуется Java. По умолчанию в Ubuntu её нет, так что сначала добавляем репозиторий.

Теперь приступаем непосредственно к установке Java.

Далее скачиваем Elasticsearch, используя wget .

На данный момент версия 1.5.2 является самой стабильной, поэтому мы будем использовать именно её. Если вам нужна какая-то другая версия, то архив релизов можно найти тут.

Затем распаковываем и запускаем установку.

Теперь после обращения к адресу http://localhost:9200 в адресной строке браузера, вы должны увидеть следующее:

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

Теперь можем начать наше взаимодействие с Elasticsearch. Для начала давайте установим PHP клиент для работы с Elasticsearch.

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

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

Индексация документов осуществляется вызовом метода index , который принимает массив аргументов. В нём должно быть три ключа: body , index и type . В ключе body будет располагаться массив с данными, которые нужно индексировать. В index следует указывать сегмент, где вы собираетесь индексировать данные (что-то типа название базы данных). В type следует указывать категорию документа (что-то типа названия таблицы). Вот пример:

Если вывести $result , то результат будет такой:

В приведённом примере мы не указали ID документа. В этом случае Elasticsearch автоматически присвоит уникальный ID. Это можно сделать и самим:

Результат вывода переменной $result :

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

Вложенность может быть какой угодно глубины (однако увлекаться этим не стоит).

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

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

Давайте начнём с метода get . Точно так же как метод index он принимает массив аргументов. В массиве должны быть ключи index , type и id документа, который вы хотите найти.

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

В массиве аргументов для метода search следует указать ключи index , type и body . В ключе body указываем критерии запроса. Вот как можно вернуть все документы, где возраст равен 15 .

Давайте разберём результат:

  • took – время выполнения запроса.
  • timed_out – возвращает true если время выполнения запроса прошло.
  • _shards – по умолчанию, Elasticsearch размещает данные по 5 шардам (сегментам). Если значение 5 будет в total и successful то каждый шард работает корректно.
  • hits содержит результат поиска.

Метод который мы продемонстрировали, позволяет осуществить поиск по глубине равной единице. Если мы хотим искать глубже, то нам следует воспользоваться bool запросами. Для этого указываем ключ bool в query . Теперь в поиске будут задействованы все поля, разделяя их знаком . .

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

Так же мы можем осуществлять запросы, используя массивы, указав ключ bool , а затем must , terms . В качестве значения указываем массив значений, который должен быть задействован в поиске. В данном примере ищем документы, где поле age равняется 10 и 15.

В данном способе можно применять только линейные массивы.

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

Теперь давайте посмотрим как можно осуществить поиск с применением фильтров. Для фильтрации нужно указать ключ filtered , а в качестве значения начальное и конечно число диапазона искомых значений. В данном случае мы будем искать по полю age , где значение больше или равно (gte) 11 и меньше или равно (lte) 20.

OR и AND

При работе с запросами в реляционных СУБД мы часто используем ключевые слова AND или OR . В Elasticsearch у нас тоже есть такая возможность: для этого просто указываем ключ and . Выберем все документы, где возраст age равен 10 и badge равен 8.

Если нужно осуществить поиск по одному из этих двух значений, то используйте ключ or .

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

Мы можем ограничить число результатов поиска, используя поле size . Пример:

Возвращает только один документ.

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

В реляционных СУБД есть возможность выбирать данные по различным сегментам, используя ключевые слова LIMIT и OFFSET . В Elasticsearch тоже есть аналоги: ключи size и from . from позволяет нам осуществить выборку с нужного нам “отступа”. Индексация документов начинается с нуля. Вот как мы можем получить вторую страницу результатов:

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

Для обновления данных в документе нам необходимо сначала его извлечь. Для этого указываем index , type и id документа в методе get . Текущие данные можно найти в сегменте _source . Для обновления данных, просто обращаемся к полям и задаём новые значения. Для сохранения результатов следует вызвать метод update.

Значение поля _version будет увеличиваться каждый раз при вызове метода update (в том случае, если хоть одно поле было изменено).

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

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

Для удаление документа достаточно вызвать метод delete . В массиве аргументов следует указать поля index , type и id .

Заметка: если вытащить документ, используя метод get , а затем его удалить, то может возникнуть ошибка.

Вывод

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


Elasticsearch — это прекрасный способ добавить в ваше PHP приложение гибкий и быстрый поиск.

Данный урок подготовлен для вас командой сайта ruseller.com
Источник урока: http://www.sitepoint.com/introduction-to-elasticsearch-in-php/
Перевел: Станислав Протасевич
Урок создан: 21 Августа 2015
Просмотров: 27599
Правила перепечатки

5 последних уроков рубрики «PHP»

Фильтрация данных с помощью zend-filter

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

Контекстное экранирование с помощью zend-escaper

Обеспечение безопасности веб-сайта — это не только защита от SQL инъекций, но и протекция от межсайтового скриптинга (XSS), межсайтовой подделки запросов (CSRF) и от других видов атак. В частности, вам нужно очень осторожно подходить к формированию HTML, CSS и JavaScript кода.

Подключение Zend модулей к Expressive

Expressive 2 поддерживает возможность подключения других ZF компонент по специальной схеме. Не всем нравится данное решение. В этой статье мы расскажем как улучшили процесс подключение нескольких модулей.

Совет: отправка информации в Google Analytics через API

Предположим, что вам необходимо отправить какую-то информацию в Google Analytics из серверного скрипта. Как это сделать. Ответ в этой заметке.

Подборка PHP песочниц

Подборка из нескольких видов PHP песочниц. На некоторых вы в режиме online сможете потестить свой код, но есть так же решения, которые можно внедрить на свой сайт.

Elasticsearch и автокомплит

Пару недель назад мы начали изучать возможности, которые предоставляет поисковый движок Elasticsearch. Тогда мы познакомились с технологией suggest’ов, то есть подсказок в ответ на опечатки. Сегодня мы разберемся с родственным им понятием — автодополнением (autocomplete). Автокомплит подсказывает возможное продолжение строки по мере ее ввода пользователем. Без этой фичи трудно представить себе поисковую систему.

Задача

Если вы не знакомы с Elasticsearch, советую прочитать мой первый пост об этой технологии. В том же посте мы решили нашу первую задачу о предоставлении подсказок на примере датасета Jeopardy. Напомню, что это известная американская телевикторина на подобии Своей игры. Сегодня мы продолжим работать с этим набором данных, используя результаты, которых достигли в прошлый раз.

Продолжая идею сервиса для работы с вопросами Jeopardy, можно поставить себе новую задачу. Теперь благодаря suggest’ам пользователь может корректировать свои запросы в соответствии с существующими категориями. Следующим шагом станет добавление функциональности автодополнения, благодаря которому пользователь значительно ускорит ввод своего запроса.

Completion Suggester

Для реализации автокомплита в Elasticsearch в дополнение к опечаточным suggester’ам существует еще один — Completion Suggester. Он был добавлен для решения именно этой проблемы и имеет ряд преимуществ перед другими фичами системы:

  1. Главное условие в работе автодополнения — это скорость. Если варианты подсказок не успевают появляться до того, как пользователь закончит печатать, их смысл абсолютно пропадает. Для хранения и поиска подсказок такого типа, ES использует конечный преобразователь (FST). Он представим в виде направленного графа, где дугами являются буквы, а полный путь содержит искомое слово. Такая структура данных позволяет находить suggest’ы с огромной скоростью (с бенчмарками можно ознакомиться на официальном блоге Elasticsearch).
  2. При полнотекстовом поиске релевантность результатов определяется метрикой TF-IDF (то есть, совпадения, встретившиеся в меньшем числе документов, будут более приоритетны). Для автодополнения такой сценарий не подходит. Поэтому в completion suggester’е наиболее распространенные в индексе выражения будут более приоритетными в выдаче подсказок.
  3. Еще одна фича этого suggester’а заключается в возможности сопоставлять несколько возможных вариантов ввода одному документу. Благодаря этому подсказки, например, могут учитывать разный порядок слов.

Похоже, completion suggester делает именно то, что нам нужно. Теперь перейдем к решению нашей задачи.

Первая реализация

Для того, чтобы показать, какие данные будут использоваться для автодополнения, в Elasticsearch есть специальный тип — completion. Добавим в наш маппинг поле category_suggest с дефолтным анализатором:

Теперь при индексировании нам нужно класть в это поле данные, которые мы будем дополнять. При этом есть возможность индексировать в этом поле несколько вариантов и устанавливать для каждого свое значение weight, тем самым влияя на порядок результатов в выдаче.

Мы пойдем по простому пути и будем помещать в это поле ту же строку, что и в поле category. После индексации датасета сделаем тестовый поисковый запрос в поисках возможных продолжений строки musica (допустим, пользователя интересуют музыкальные категории). Для этого мы определяем новый suggest с именем completion-suggest, в котором указываем искомый текст, поле, по которому ведем поиск и количество результатов. Также будем использовать параметр _source, в котором отмечаются поля, которые будут предоставлены в ответе.

Ответ выглядит следующим образом (часть полей и результатов пропущена):

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

Неприятное обновление

Как вы видите по результатам предыдущего запроса, completion suggester не проводит дедупликацию подсказок и выводит столько повторяющихся результатов, в скольких документах он их встретил. Что интересно, в Elasticsearch версий 2.* это поведение отличалось и дедупликация проводилась. Создатели ES объясняют такие перемены тем, что они решили сделать completion suggester более документо-ориентированным.

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

Мы же воспользуемся более официальным способом обхода этой проблемы. Ребята из поддержки Elasticsearch предлагают использовать отдельный индекс со значениями для автокомплита и обрабатывать дубликаты самостоятельно в работе с такими сценариями как у нас. Кстати говоря, в новых версиях 6.x должна быть добавлена настройка с возможностью дедупликации.

Добавим уникальности

Создадим новый индекс autocomplete с очень простым маппингом:

Теперь при индексации в уникальный id документа будем также прописывать название категории, как следствие в индексе не будет дубликатов. Посмотрим на результаты запроса:

Топ-пост этого месяца:  Оптимизированная структура сайта WordPress общие принципы

На этот раз все результаты уникальны. Проверим их в действии. В моем небольшом примере также используются результаты прошлого поста и выводятся подсказки об опечатках. Для выбора подсказки от автодополнения в приложении используются клавиши с номером строки suggest’а.

У этого варианта есть достаточно серьезная проблема. Одним из преимуществ completion suggester’а озвучивалась подходящая релевантность, учитывающая число документов, содержащих строку запроса. Так как мы насильно создаем уникальные документы, все подсказки будут иметь одинаковую релевантность. Как итог, suggester предлагает результаты в алфавитном порядке (так как в роли ключа мы указали эти же названия категорий).

Раздадим веса

Настало время вспомнить, что у completion полей есть свойство weight. Так как мы хотим видеть среди подсказок наиболее часто встречающиеся в документах категории, будем обновлять вес необходимого поля, инкрементируя его, вместо перезаписи документа. Для этого при обработке каждого документа при индексировании будем использовать следующий запрос:

Директива upsert выполняется в случае, если документа с таким id нет, создавая его и устанавливая вес подсказки в значение 1. Иначе выполняется операция script, которая увеличивает вес на единицу. Посмотрим на окончательный вариант примера:

Заключение

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

Written on October 28th, 2020 by Alexey Kalina

Создание текстового поля с автозаполнением

Ранее в этой главе мы узнали, как можно использовать Ajax и JSON для отправки запросов на сервер и получения данных. Кроме создания запросов Ajax вручную, можно также использовать клиентские библиотеки элементов управления и jQuery-плагины, которые позволяют абстрагироваться от стандартного кода для работы с запросами Ajax.

jQuery UI (http://jQueryui.com) является одним из таких наборов плагинов. Он построен на ядре jQuery и предоставляет несколько клиентских виджетов пользовательского интерфейса, в том числе «Аккордеон», автозаполнение, кнопки, календарь, диалоговое окно, индикатор выполнения, слайдер и вкладки.

В этом примере мы рассмотрим, как можно использовать плагин Autocomplete для создания списка городов с возможностью поиска, которая похожа на функциональность Google suggest, как на рисунке 7-10.

Рисунок 7-10: Google предлагает варианты, когда вы набираете текст

Создание CitiesController

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

Листинг 7-22: CitiesController

Строка 6: Создает хранилище

CitiesController создает экземпляр CityRepository в своем конструкторе. Это хранилище содержит единственный метод, Find , который принимает элемент поиска и находит все города, названия которых начинаются с указанного элемента. Внутренняя реализация CityRepository не важна для данного примера, но если вы следите за образцами кода для этой главы, вы увидите, что она загружает данные о городах из CSV файла.

Сам класс City представлен в следующем листинге.

Листинг 7-23: Создание класса City

Объект City представляет собой очень простой POCO (Plain Old CLR Object) — он просто определяет три перезаписываемых свойства (числовой идентификатор, название города и государства, в котором он находится) и одно свойство только для чтения, которое создает удобное для пользователя отображаемое имя.

Действие Index демонстрирует представление, показанное в следующем листинге.

Листинг 7-24: Страница с автозаполнением

Строки 1-6: Ссылка на скрипты JQuery

Строки 7-10: Ссылка на стили JQuery UI

Строка 12: Обработчик готового дерева DOM

Строка 13: Создаем URL поиска

Строки 14-19: Добавляем сценарий автозаполения

Строка 30: Контейнер для результатов

Как и в предыдущих примерах, нам необходим jQuery. Если вы не изменяли макет, ссылки на эти сценарии уже включены.

Затем мы добавляем ссылку на стили jQuery UI, которые также включены в шаблон проекта по умолчанию. Опять же, если вы не изменяли макет, они у вас уже есть.

Далее следует блок скрипта, который запускается по окончании загрузки страницы. В первую очередь мы создаем в нем переменную autoCompleteUrl , которая содержит URL-адрес действия Find контроллера CitiesController (который мы еще не создали). Это адрес, который будет запрашиваться каждый раз, когда пользователь вводит символ в поле поиска. Мы затем находим любое текстовое поле на странице с ID city и вызываем плагин Autocomplete на этом элементе. Ему сообщаем адрес, по которому он должен искать данные (в нашем случае autoCompleteUrl ), минимальное число символов, которое должно быть введено перед поиском (в нашем случае 2) и функцию обратного вызова, которая должна запускаться после того, как пользователь выбрал результат поиска. Для простоты, мы просто выводим на экран окно alert с названием выбранного города. Наконец, мы определяем текстовое поле, которое позволит пользователю выполнять поиск.

Если мы сейчас запустим страницу, на ней будет отображаться текстовое поле. Однако так как мы еще не создали действие Find , она будет выдавать ошибку, как показано на рисунке 7-11.

Рисунок 7-11: Текстовое поле с автозаполнением отправляет запрос Ajax, когда пользователь вводит поисковый запрос

Когда элемент поиска введен в поле, плагин Autocomplete отправляет запрос Ajax на сервер. В данном случае, он адресован к действию Find и передает ему элемент поиска в виде строкового параметра запроса под названием term . Плагин Autocomplete ожидает, что этот URL вернет массив объектов JSON со следующими свойствами: id , label (ярлык, который будет отображаться в результатах поиска) и value (значение, которое будет вставлено в текстовое поле при нажатии).

На данный момент это вызывает ошибку 404, потому что у нас еще нет действия Find . Давайте создадим его.

Листинг 7-25: Реализация действия Find

Строка 3: Поиск города

Строки 4-10: Создаем проекцию результатов

Строки 11-12: Преобразуем данные в JSON

Здесь мы сначала осуществляем поиск всех городов, имена которых начинаются с указанного символа. Затем мы используем LINQ-запрос «в памяти», чтобы сделать проекцию полученных объектов City в коллекцию анонимных типов, которая соответствует структуре JSON и которую ожидает плагин Autocomplete (свойства id , label и value ). Наконец мы преобразовываем эти результаты в формат JSON путем вызова метода Json . Как и в примере из листинга 7-13, мы должны явно разрешить передачу данных в формате JSON на запрос GET с помощью поведения AllowGet .

Наконец, когда вы повторно запустите страницу и введете поисковый запрос, вы увидите полученные с сервера результаты, как показано на рисунке 7-12.

Рисунок 7-12: Отображение результатов поиска

Вы также можете наблюдать получение данных JSON с сервера, отслеживая запросы Ajax с помощью Firebug, как показано на рисунке 7-13.

Рисунок 7-13: Получение данных JSON с сервера в ответ на поисковый запрос

Конечная страница позволяет нам выполнить поиск города, введя первые буквы его названия; сервер выполнит поиск и создаст соответствующий объект JSON. Плагин Autocomplete обработает результат и автоматически создаст раскрывающийся список, причем нам не нужно будет писать код для анализа результатов. Наконец, если мы выберем пункт в раскрывающемся списке, свойство value объекта JSON будет вставлено в текстовое поле.

Как сформировать запрос к различным API в React


Через fetch формирую запрос к API, как достать Json ответа из Promise

Или подскажите как правильно формировать запросы в React?

1 ответ 1

Вы можете сделать так

Возможно но не обязательно, что вам понадобятся прописывать method и headers

В реакт лучше всего использовать fetch в Redux. Не сохраняйте fetch в переменную, что бы получить данные от запроса. fetch возвращает промис узнайте больше о промисах https://learn.javascript.ru/promise .

В реакт без redux вы можете делать например так

Всё ещё ищете ответ? Посмотрите другие вопросы с метками javascript json reactjs или задайте свой вопрос.

Похожие

Подписаться на ленту

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

дизайн сайта / логотип © 2020 Stack Exchange Inc; пользовательское содержимое попадает под действие лицензии cc by-sa 4.0 с указанием ссылки на источник. rev 2020.11.7.35374

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

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

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

Системные требования Elasticsearch

Во-первых, надо обратить внимание на системные требования. В официальной документации заявлено, что программа будет идеально работать на машине с 64 Гб оперативной памяти, а минимальный объём — 8 Гб. И это понятно, потому что платформа работает на Java. Но это для производственных масштабов.

От себя же могу сказать, что с обработкой 1 млрд строк данных Elasticsearch неплохо справляется и на машине с 2 Гб, не так быстро как хотелось бы, но там, где MySQL задумывалась на несколько минут, Elasticsearch выдаёт результат почти мгновенно. Однако для машин с небольшим количеством ОЗУ нужна дополнительная настройка.

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

Установка Elasticsearch в Ubuntu

Elasticsearch — это оболочка для библиотеки Lucene, которая написана на Java. А поэтому для установки платформы вам необходимо установить Java. Разработчики рекомендуют использовать Java 8 версии 1.8.0_131 или выше. Мы будем рассматривать установку на примере Ubuntu. Установим OpenJDK:

sudo apt install openjdk-8-jre

Смотрим версию Java:

Если у вас уже установлена другая версия, то этот шаг можно пропустить. Затем добавляем репозиторий Elasticsearch:

wget -qO — https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add —

sudo apt-get install apt-transport-https
echo «deb https://artifacts.elastic.co/packages/6.x/apt stable main» | sudo tee -a /etc/apt/sources.list.d/elastic-6.x.list

И установка ElasticSearch:

sudo apt-get update && sudo apt-get install elasticsearch

В rpm дистрибутивах достаточно просто скачать и установить rpm пакет.

Настройка Elasticsearch

После завершения установки Elasticsearch нужно запустить и добавить в автозагрузку его службу, для этого выполните:

sudo systemctl start elasticsearch
sudo systemctl enable elasticsearch

Для машин с небольшим количеством ОЗУ нужно ограничить количество памяти, потребляемой программой. Для этого откройте файл /etc/elasticsearch/jvm.options и измените значение опций -Xms и -Xmx на то количество памяти, которое вы хотите, чтобы программа использовала. Например:

Теперь нужно перезапустить сервис:

sudo systemctl restart elasticsearch

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

1. Просмотр версии Elasticsearch

Для общения с Elasticsearch используется RESTful API или, если говорить простым языком, обыкновенные HTTP-запросы. И работать с ним мы можем прямо из браузера. Но делать этого не будем, а будем использовать Linux-утилиту curl. Для просмотра информации о сервисе достаточно обратиться по адресу localhost:9200:

curl -XGET http://localhost:9200

Опция -X задаёт протокол, который мы используем. В этой статье мы используем не только GET, но и POST, PUT, DELETE и другие. Если вы только что перезапустили сервис и получаете ошибку «http://localhost:9200 — conection refused», то ничего страшного — система загружается, надо подождать несколько минут.

Если будете пытаться ей помешать, можете потерять уже проиндексированные данные. Просто убедитесь, что сервис уже запущен (active) командой:

sudo systemctl status elasticsearch

Когда платформа загрузиться, вы получите такой ответ:

2. Список индексов Elasticsearch

Точно так же, как MySQL может иметь несколько баз данных, Elastic может иметь несколько индексов. У каждого из них может быть несколько отдельных таблиц (type), каждая из которых будет содержать документы (doc), которые можно сравнить с записями в таблице MySQL.

Чтобы посмотреть текущий список индексов, используйте команду _cat:

Общий синтаксис использования глобальных команд такой:

curl ‘localhost:9200/ _команда / имя ? параметр1 & параметр2 ‘

  • _команда — обычно начинается с подчеркивания и указывает основное действие, которое надо сделать;
  • имя — параметр команды, указывает, над чем нужно выполнить действие, или уточняет, что надо делать;
  • параметр1 — дополнительные параметры, которые влияют на отображение, форматирование, точность вывода и так далее;

Например, команда _cat также может отобразить общее «здоровье» индексов (health) или список активных узлов (nodes). Параметр v включает более подробный вывод, а pretty сообщает, что надо форматировать вывод в формате json (чтобы было красиво).

3. Индексация данных

Вообще, вам не обязательно создавать индекс. Вы можете просто начать записывать в него данные, как будто бы он и таблица уже существует. Программа создаст всё автоматически. Для записи данных используется команда _index. Вот только однострочной команды curl нам будет уже недостаточно, надо добавить ещ сами данные в формате json, поэтому создадим небольшой скрипт:

#!/bin/bash
curl -XPUT ‘http://localhost:9200/app/data?pretty ‘ -H ‘Content-Type: application/json’ -d ‘
<
«name»:»Ivan»,
«age» :»18″,
«degree» : «90»,
>’

Здесь я записываю данные: индекс app, таблицу data. Так как они не существуют, система их создаст. Как видите, сами данные нам нужно передать в формате json. Передаём заголовок с помощью опции -H, будем отсылать json, а потом с помощью -d передаём сами данные. Данные представляют из себя четыре(точно?, а то я просто вижу 3) поля:

  • name — имя;
  • age — возраст;
  • degree — оценка.

Нам следует ещё остановиться на синтаксисе формата json:

<
«имя_поля» : «значение_поля» ,
«имя_поля1» : «значение_поля» ,
«имя_поля2» : <
«имя_поля3» : «значение поля»,
«имя_поля4» : [ «значение1», «значение2» ]
>
>

Если вы знакомы с JavaScript, то уже знаете этот формат. Если нет, то ничего страшного, сейчас разберёмся. Данные представляются в виде пар имя: значение. И имя поля, и его значение нужно брать в кавычки и разделять их двоеточием. Каждая пара отделяется от следующей с помощью ?ЭТО ЧТО ЗА ЗВЕРЬ ТАКОЙ? комы& . Но если пар больше нет, то кома не ставится. Причём каждое поле может иметь в качестве значения либо текст, либо ещё один набор полей, заключённый в фигурные скобки <>. Если нужно перечислить два элемента без названия поля, надо использовать не фигурные скобки, а квадратные [] (массив), как в поле4. Для удобства форматирования используйте пробелы, табуляции Elasticsearch не понимает.

Теперь сохраняем скрипт и запускаем:

Если всё прошло успешно, то вы увидите такое сообщение:

Это значит, что документ добавлен в индекс. Теперь вы можете снова посмотреть список индексов.

4. Информация об индексе

Мы знаем список созданных индексов, но как посмотреть список типов (таблиц) в индексе и как узнать, какие и каких типов поля созданы в индексе? Для этого можно использовать команду _mapping. Но перед тем, как мы перейдём к ней, надо вернуться к синтаксису. Команды могут применяться как к глобально, так и для отдельного индекса или для отдельного типа. Синтаксис будет выглядеть так:

curl ‘localhost:9200/ индекс / тип / _команда / имя ? параметр1 & параметр2 ‘

Чтобы посмотреть все индексы и их поля, можно применить команду глобально:

Или только для индекса app:

Только для типа data индекса app:

В результате программа вернула нам ответ, в котором показан индекс app, в нём есть тип data, а дальше в поле properties перечислены все поля, которые есть в этом типе: age, degree и name. Каждое поле имеет свои параметры.

5. Информация о поле и мультиполя

Каждое поле описывается таким списком параметров:

«age» : <
«type» : «text» ,
«fields» : <
«keyword» : <
«type» : «keyword» ,
«ignore_above» : 256
>
>
>

Параметр type — указывает тип поля. В данном случае программа решила, что это текст, хотя это число. Дальше интереснее, у нас есть ещё параметр fields. Он задаёт так называемые подполя или мультиполя. Поскольку Elasticsearch — это инструмент поиска текста, то для обработки текста используются анализаторы, нормализаторы и токенизаторы, которые могут приводить слова к корневой форме, переводить текст в нижний регистр, разбивать текст на отдельные слова или фразы. Вс` это нужно для поиска и по умолчанию применяется к каждому текстовому полю.

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

Таким образом, если вы захотите проверить точное вхождение, то нужно обращаться именно к полю age.keyword а не к age. Или же отключить анализатор для age. Анализаторы выходят за рамки этой статьи, но именно эта информация нам ещё понадобится дальше.

6. Удаление индекса

Чтобы удалить индекс, достаточно использовать вместо GET протокол DELTE и передать имя индекса:

curl -XDELETE ‘http://localhost:9200/app?pretty’

Теперь индекс удалён. Создадим ещё один такой же вручную.

7. Ручное создание индекса

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

Топ-пост этого месяца:  Чаты в объявлениях Яндекс.Директ как добавить онлайн-консультант

curl -XPUT ‘http://localhost:9200/app?pretty ‘ -H ‘Content-Type: application/json’ -d ‘
<
«mappings» : <
«data» : <
«properties» : <
«age» : <
«type» : «integer»
>,
«degree» : <
«type» : «integer»
>,
«name» : <
«type» : «text»,
«fields» : <
«keyword» : <
«type» : «keyword»,
«ignore_above» : 256
>
>
>
>
>
>
>’

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


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

5. Массовая индексация данных

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

В файле находятся данные в формате json, которые надо проиндексировать. Это можно сделать с помощью команды _bluck:

curl -H ‘Content-Type: application/x-ndjson’ -XPOST ‘localhost:9200/shakespeare/doc/_bulk?pretty’ —data-binary @shakespeare_6.0.json

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

6. Поиск по индексу

Для поиска или, другими словами, выборки данных в Elasticsearch используется команда _search. Если вызвать команду без параметров, то будут обрабатываться все документы. Но выведены будут только первые 10, потому что это ограничение по умолчанию:

curl -XGET ‘http://localhost:9200/shakespeare/doc/_search?pretty’

Здесь мы выбрали первые десять документов из индекса shakespeare и таблицы doc. Чтобы выбрать больше, передайте параметр size со значением, например 10000:

curl -XGET ‘http://localhost:9200/shakespeare/doc/_search?size=10000&pretty’

Самый простой пример поиска — передать поисковый запрос в параметре q. При этом поиск Elasticsearch будет выполняться во всех полях индекса. Например, найдём все, что касается Эдгара (EDGAR):

curl -XGET ‘http://localhost:9200/shakespeare/doc/_search?q=EDGAR&pretty ‘

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

  • term — точное совпадение искомой строки со строкой в индексе или термом;
  • match — все слова должны входить в строку, в любом порядке;
  • match_phrase — вся фраза должна входить в строку;
  • query_string — все слова входят в строку в любом порядке, можно искать по нескольким полям, используя регулярные выражения;

Синтаксис term такой:

» query » <
» term » <
» имя_поля «: » что искать «
>
>

Например, найдем записи, где говорит Эдгар с помощью term:

#!/bin/bash
curl -XGET ‘http://localhost:9200/shakespeare/doc/_search?pretty ‘ -H ‘Content-Type: application/json’ -d ‘
<
«query» : <
«term» : <
«speaker.keyword» : «EDGAR»
>
>
>’

Мы нашли десять реплик, которые должен сказать Эдгар. Дальше испытаем неточный поиск с помощью match. Синтаксис такой же, поэтому я его приводить не буду. Найдём предложения, которые содержат слова of love:

#!/bin/bash
curl -XGET ‘http://localhost:9200/shakespeare/doc/_search?pretty ‘ -H ‘Content-Type: application/json’ -d ‘
<
«query» : <
«match» : <
«text_entry» : «love of»
>
>
>’

С query_string и match_phrase разберётесь сами, если будет нужно.

8. Операторы AND и OR для поиска

Если вы хотите сделать выборку по нескольким полям и использовать для этого операторы AND и OR, то вам понадобится конструкция bool. Синтаксис её такой:

«query» : <
«bool» : <
«must» : [
< "поле1" : "условие" >,
< "поле2" : "условие" >,
],
«filter» : <>,
«must_not» : <>
«should» : <>
>
>

Обратите внимание на синтаксис. Поскольку у нас два элемента подряд, мы используем массив []. Но так как дальше нам снова нужно создавать пары ключ:значение, то в массиве открываются фигурные скобки. Конструкция bool объединяет в себе несколько параметров:

  • must — все условия должны вернуть true;
  • must_not — все условия должны вернуть false;
  • should — одно из условий должно вернуть true;
  • filter — то же самое что и match, но не влияет на оценку релевантности.

Например, отберём все записи, где Helen говорит про любовь:

#!/bin/bash
curl -XGET ‘http://localhost:9200/shakespeare/doc/_search?pretty ‘ -H ‘Content-Type: application/json’ -d ‘
<
«query» : <
«bool» : <
«must»: [
<"match" : <
«text_entry» : «love»
>>,
<"match": <
«speaker»: «helen»
>>
]
>
>
>’

Как видите, найдено только два результата.

9. Группировка

И последнее, о чём мы сегодня поговорим, — группировка записей в Еlasticsearch и суммирование значений по ним. Это аналог запроса GOUP BY в MySQL. Группировка выполняется с помощью конструкции aggregations или aggs. Синтаксис её такой:

«aggregations» : <
«название» : <
«тип_группировки» : <
параметры
>,
дочерние_группировки
>
>

Разберём по порядку:

  • название — указываем произвольное название для данных, используется при выводе;
  • тип_группировки — функция группировки, которая будет использоваться, например terms, sum, avg, count и так далее;
  • параметры — поля, которые будем группировать и другие дополнительные параметры;
  • дочерние группировки — в каждую группировку можно вложить ещё одну или несколько других таких же группировок, что делает этот инструмент очень мощным.

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

#!/bin/bash
curl -XGET ‘http://localhost:9200/shakespeare/doc/_search?pretty&size=10000 ‘ -H ‘Content-Type: application/json’ -d ‘
<
«aggs» : <
«replics» : <
«terms»: <
«field»: «speaker.keyword»
>
>
>
>’

В результате запроса Еlasticsearch получим:

Сначала пойдут все найденные документы, а затем в разделе aggregations мы увидим наши значения. Для каждого имени есть doc_count, в котором содержится количество вхождений этого слова. Чтобы продемонстрировать работу вложенных группировок, давайте найдём сумму и среднее значение поля line_number для каждого участника:

#!/bin/bash
curl -XGET ‘http://localhost:9200/shakespeare/doc/_search?pretty&size=10000 ‘ -H ‘Content-Type: application/json’ -d ‘
<
«aggs» : <
«replics» : <
«terms»: <
«field»: «speaker.keyword»
>,
«aggs» : <
«total_number»: <
«sum»: <"field": "line_id">
>,
«avg_number»: <
«avg»: <"field": "line_id">
>
>
>
>
>’

В сумме у нас очень большие числа, поэтому они отображаются в экспоненциальном формате. А вот в среднем значении всё вполне понятно.

<
«key» : «DUKE VINCENTIO»,
«doc_count» : 909,
«total_number» : <
«value» : 5.4732683E7
>,
«avg_number» : <
«value» : 60211.97249724973
>
>

Тут key — имя персонажа, total_number.value — сумма поля, avg_number.value — среднее значение поля.

Выводы

Пожалуй это всё, статья и так очень сильно затянулась. Но и этого материала будет вполне достаточно, чтобы начать использование Elasticsearch в своих проектах. Понятно, что вы не будете там пользоваться curl, у программы есть библиотеки для различных языков программирования, в том числе и для php. Если вы нашили ошибки или неточности в описании работы Еlasticsearch, поправьте меня в комментариях!

Нет похожих записей

Оцените статью:

Об авторе

Основатель и администратор сайта losst.ru, увлекаюсь открытым программным обеспечением и операционной системой Linux. В качестве основной ОС сейчас использую Ubuntu. Кроме Linux интересуюсь всем, что связано с информационными технологиями и современной наукой.

10 комментариев

Админ! Низкий поклон тебе! Наконец-то! Наконец-то я дождался этого дня, когда (надеюсь) Лосст перешёл на новый уровень контента. Или, как нынче говорят — годнота подъехала!
Давайте побольше статей для недолбо@бов, да и последние тоже пусть читают и развиваются, прокачивая свои скиллы в Линуксе и мозг в целом. Давно пора заканчивать с этими «Установка Minecraft» и прочие, аналогичные виндузятникам начала 00-х «Как установить и пропатчить фотошоп на виндоус икспи»..
Сайт такой бешеный потенциал в себе несёт. Он же вполне может стать топом сегмента, что в наше время в любой отрасли очень и очень сложно в виду переизбытка и занятости. А здесь — такой старт. И ведь сколько проектов из-за неправильного контента канули в лету — Убунтовод, Пингвинукс и тд. Мне кажется, если Вы писали ерунду ранее в целях СЕО и привлечения ЦА — то сейчас нужно бить именно в уникальность, наращивая уровень знаний. К примеру — вместо обзоров со скриншотиками однотипных и, будем честны, никому не нужных дистрибутивов — можно сделать уклон в Gentoo или отечественную гордость Calculate Linux, пояснив, что каждый, кто хочет в кратчайшие сроки понять суть Линукса — просто-таки обязан попробовать эти дистры. Я сам не гентушник, отнюдь. Но да, в своё время именно для этого её себе и ставил. А что касательно Calculate — ну да, гордость берёт за то, что наши такой вклад несут, да и сам дистр крайне дружелюбен. Потом можно рассмотреть LFS, серверные оси, создание портабельных дистров под свои нужды. Если нужен именно СЕО-хайп — то лучше бить в кастомизацию популярных дистрибутивов. Да-да, именно путём БолдженОС и Дениса Попова, но называя вещи своими именами — просто залезая вглубь дистрибутива, кастомизируя его, с целью популяризировать Линукс, заинтересовать и поднять уровень среднестатистического пользователя. Ну и всякие DE обозревать. Особенно не стандартные, к примеру https://www.enlightenment.org/ — которая развивается с 1996-го года и, как по мне — весьма футуристично обогнала все DE на несколько десятилетий. Опять же — я ей не пользуюсь, но считаю, что такое нужно знать и пробовать для себя.
Попробую заинтересовать авторов статей, да и всех желающих, у кого есть немного свободного времени и желание в кратчайшие сроки прокачать скиллы до неслабого уровня, заиметь кастомизированный, анонимный и безопасный (что крайне важно в наше время) дистрибутив:
Есть такая штука, как Liberte Linux. В своём роде — весьма уникальный и нужный портабельный дистр с мимимальными размерами и требованиями к железу. При этом анонимность, приватность и безопасность в целом — максимализирована. Автор его забросил, но я бы так не сказал. Читая его комменты на Опеннет — он прямо сказал, что свою задачу выполнил. И я с ним согласен. Этот Максим Краммерер создал уникальный в своём роде дистрибутив, который в два счёта компиллируется, масштабируется и допиливается под свои нужды. Это во многом превосходит легендарный LFS и в тоже время не требует таких знаний по порогу вхождения, как LFS, т.к. с Lieberte может разобраться каждый.
Надеюсь, хоть кого-то заинтересовал;)
Успехов всем и участникам проекта — в первую очередь.
С уважением.

Вода вода вода
Зачем писать как работает json?!
And и or если в примере только and

must — and, should — or.

Хорошая статья. Длина — только плюс.
Тем, кому не нравятся — читайте про так как МС установить.

Можно ли cvs формат загрузить в еластик?

Спасибо за прекрасные примеры!
Хочется увидеть продолжение, желательно такое-же длинное, с большим количеством примеров.
Можно про анализаторы, можно про плагины, можно про более сложный поиск в elasticsearch-e.
В Интернете очень мало статьей по “Упругому поиску”. Как один из вариантов обучения – это читать unit-тесты автора elastica. Elatica – это php клиент Для elasticsearch https://github.com/ruflin/Elastica/tree/master/test

Спасибо! Материал действительно оказался очень полезным! В закладки.

Подскажите, если не зашло, как удалить elasticsearch с сервера? какой командой?

yum remove elasticsearch, а затем вручную удалите репозиторий /etc/yum.repos.d/elasticsearch.repo и удалите папку с индексами: /var/lib/elasticsearch

Большое спасибо. Уже месяц читаю ваш сайт, добавил в закладки, много полезного.

Учимся работать с Elasticsearch

Содержание статьи

Несмотря на то что XXI век принес в наши дома (не во все, но всё же) гигабитные каналы связи и котиков на YouTube в разрешении 4K и 60 FPS, основой Сети, самой массовой его частью, все еще остаются текстовые данные. Рефераты и курсовые работы, технические драмы на Хабре и Stack Overflow, сидящий занозой в . Роскомнадзора Луркмор — все это текст, все это слова. А поскольку каталогизация в реальном мире очевидно хромает, то без хорошего полнотекстового поиска никуда.

Основных поисковых брендов на данный момент существует несколько: это Solr, Sphinx, Elasticsearch. Но сегодня мы поговорим только о последнем. Elasticsearch — это на самом деле не вполне самостоятельный поиск. Это, скорее, красивая обертка над библиотекой Apache Lucene (на нем же строится Solr). Но не стоит воспринимать слово «обертка» в негативном ключе. Lucene сам по себе вообще мало на что годен. Это все-таки не полноценный сервис, а просто библиотека для построения поисковых систем. Все, что она может, — только индексировать и искать. А API для ввода данных, для поисковых запросов, кластеризация и прочее — это все отдается на откуп «обертке».

Что нам дает Elasticsearch?

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

На самом деле оно даже работает. В хипстерском стиле «чувак, вот тебе три команды — пользуйся ими и, пожалуйста, не задумывайся, какой ад происходит внутри». И часто это прокатывает. Новые ноды подключаются буквально парой строчек в конфиге, почти как у Redis. Главное, мастеры со слейвами не путать, а то он возьмет и молча потрет все данные :). При выпадении каких-либо серверов из кластера, если правильно были распределены реплики данных, корректно настроенное приложение продолжит поиск, как будто ничего не произошло. После того как сервер поднимется, он сам вернется в кластер и подтянет последние изменения в данных.

Мультиарендность (англ. multitenancy) — возможность организовать несколько различных поисковых систем в рамках одного объекта Elasticsearch. Причем организовать их можно абсолютно динамически. Очень интересная особенность, которая в отдельных случаях становится определяющей при выборе поисковой системы. На первый взгляд может показаться, что необходимости в этой особенности нет. Классические системы поиска типа Sphinx обычно индексируют какую-то одну базу с определенным кругом данных. Это форумы, интернет-магазины, чаты, различные каталоги. Все те места, где поиск для всех посетителей должен быть идентичным. Но на самом деле довольно часто возникают ситуации, когда систем поиска должно быть больше одной. Это либо мультиязычные системы, либо системы, где есть определенное количество пользователей, которым нужно предоставлять возможность поиска по их персональным данным.

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

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

Отсутствие схемы (schema-free) — Elasticsearch позволяет загружать в него обычный JSON-объект, а далее он уже сам все проиндексирует, добавит в базу поиска. Позволяет не заморачиваться слишком сильно над структурой данных при быстром прототипировании.

RESTful api — Elasticsearch практически полностью управляется по HTTP с помощью запросов в формате JSON.

Краткий словарик начинающего гуманитария

  • Стемминг — это нахождение основы слова для заданного исходного слова. Основа необязательно совпадает с морфологическим корнем слова.
  • Лемматизация — приведение слова к нормальной (словарной) форме. Для существительных это именительный падеж и единственное число.
  • Корпус — в лингвистике корпусом называется совокупность текстов, собранных в соответствии с определенными принципами, размеченных по определенному стандарту и обеспеченных специализированной поисковой системой. Это может быть и разделение по стилям и жанрам, разделение по эпохе написания, по форме написания.
  • Параллельный корпус — это один или более текстов на двух языках, сопоставленные между собой парами, когда в каждой паре оба предложения несут один и тот же смысл.
  • Стоп-слова, или шумовые слова, — предлоги, суффиксы, междометия, цифры, частицы и подобное. Общие шумовые слова всегда исключаются из поискового запроса (кроме поиска по строгому соответствию поисковой фразы), также они игнорируются при построении инвертированного индекса.
  • N-грамма — последовательность из n элементов. С семантической точки зрения это может быть последовательность звуков, слогов, слов или букв.

Установка и использование

Установить Elasticsearch проще простого. Есть готовые репозитории и для RHEL/Centos, и для Debian. Можно отдельно установить из тарбола.

Хакер #196. Все о Docker

И вся дальнейшая работа с ним происходит посредством HTTP-запросов в JSON-формате. Давай, к примеру, создадим новый индекс и забьем в него какие-нибудь тестовые данные. Я взял отсюда англо-русский параллельный корпус, собранный из данных OpenSubtitles.org. Формат TMX достаточно простой, описывать его отдельно не стану. Напишу небольшой парсер на Python, который бы разбирал файл и заливал данные в новый индекс:

На VPS’ке с четырьмя гигами памяти во флопсе заливка четырех с половиной миллионов документов (чуть больше 900 Мб данных в текстовом формате) занимает примерно полтора часа. В целом очень даже неплохо. Теперь накидаем небольшой скриптик для удобного поиска:

И проверяем, что у нас получилось:

Первая колонка — вес полученного значения, остальные две — найденные результаты. А теперь ищем по-русски:

Как видишь, неплохо ищет уже прямо из коробки, для какого-нибудь блога или небольшого форума вполне подойдет. А если качество выдачи покажется недостаточно высоким (а к такой мысли рано или поздно приходят почти все), то Elasticsearch предоставляет большое количество возможностей для дальнейшего тюнинга анализаторов и поисковых алгоритмов.

Анализаторы

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

  • символьной фильтрации;
  • токенизации;
  • фильтрации полученных токенов.

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

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

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

Что делает этот анализатор:

  1. Убирает HTML-теги из исходного текста с помощью символьного фильтра html_strip.
  2. Делит текст на слова и убирает пунктуацию с помощью токенизатора standart.
  3. Переводит все токены в нижний регистр.
  4. Убирает токены, находящиеся в списке стоп-слов.
  5. Проводит стемминг оставшихся токенов с помощью фильтра snowball.

И смотри, как это выглядит на живом примере. Возьмем предложение «Мама мыла раму, пока собака доедала сосиску» и разберем его по пунктам (рис. «Мама мыла-мыла. »).

Детальнее о предоставляемых вместе с Elasticsearch анализаторах и фильтрах можно прочитать в официальной документации. Здесь описывать не возьмусь, так как деталей там очень много.

Нечеткий поиск

Обработка естественных языков — это работа с постоянными неточностями. По большей части поисковые движки пытаются анализировать грамматические структуры различных языков, осваивать определенные паттерны, характерные для того или иного языка. Но поисковая система постоянно сталкивается с запросами, выходящими за рамки устоявшихся правил орфографии и морфологии. Чаще всего это либо опечатки, либо банальная безграмотность. Самый простой пример нечеткого поиска — это знаменитое «Возможно, Вы имели в виду. » в Гугле. Когда человек ищет «пгода вИ кутске», а ему показывают погоду в Иркутске.

Основой нечеткого поиска является расстояние Дамерау — Левенштейна — количество операций вставки/удаления/замены/транспозиции для того, чтобы одна строка совпала с другой. Например, для превращения «пгода вИ кутске» в «погода в Иркутске» такое расстояние было бы равно трем — две вставки и одна замена.

Расстояние Дамерау — Левенштейна — это модификация классической формулы Левенштейна, в которой изначально отсутствовала операция транспозиции (перестановки двух соседних символов). Elasticsearch поддерживает возможность использования в нечетком поиске обоих вариантов, по умолчанию включено использование расстояния Дамерау — Левенштейна.

При работе с нечетким поиском также не стоит забывать и о том, как Elasticsearch (да и любой другой поисковый движок в принципе) работает изнутри. Все данные, загружаемые в индекс, сперва проходят обработку анализатором, лемматизацию, стемминг. В индекс уже складываются только «обрывки» исходных данных, содержащие максимум смысла при минимуме знакового объема. И уже по этим самым обрывкам впоследствии проводится поиск, что при использовании нечеткого поиска может давать довольно курьезные результаты.

Например, при использовании анализатора snowball во время нечеткого поиска по слову running оно после прохода через стемминг превратится в run, но при этом по нему не найдется слово runninga, так как для совпадения с ним нужно больше двух правок. Поэтому для повышения качества работы нечеткого поиска лучше использовать самый простой стеммер и отказаться от поиска по синонимам.

Elasticsearch поддерживает несколько различных способов нечеткого поиска:

  • match query + fuzziness option. Добавление параметра нечеткости к обычному запросу на совпадение. Анализирует текст запроса перед поиском;
  • fuzzy query. Нечеткий запрос. Лучше избегать его использования. Больше похож на поиск по стеммам. Анализ текста запроса перед поиском не производится;
  • fuzzy_like_this/fuzzy_like_this_field. Запрос, аналогичный запросу more_like_this, но поддерживающий нечеткость. Также поддерживает возможность анализа весов для лучшего ранжирования результатов поиска;
  • suggesters. Предположения — это не совсем тип запроса, скорее другая операция, работающая изнутри на нечетких запросах. Может использоваться как совместно с обычными запросами, так и самостоятельно.

CJK — это три буквы боли западных систем полнотекстового поиска и людей, которые хотят ими воспользоваться. CJK — это сокращение для Chinese, Japanese, Korean. Три основных восточных языка, составляющих совокупно почти 10% современного интернета. Они отличаются от привычных западных языков практически всем — и письменностью, и морфологией, и синтаксисом. Все это, понятно, вызывает некоторые проблемы при разработке различных систем обработки естественных языков, в том числе и поисковых систем.

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

Для поисковой системы все предложение на китайском остается одной целой единицей, по которым проводится поиск. Например, предложение «Мэри и я гуляем по Пекину» выглядит вот так:

Девять символов без пробелов, 18 байт в UTF-8. В нормальной вселенной это прокатило бы за одно слово, но не тут. Если стратегически расставить пробелы в нужных местах, то предложение станет выглядеть вот так:

Шесть слов. С этим уже можно было бы работать. Вот только пробелы в китайском никто не использует. Можно пытаться разделять предложения на слова в автоматическом режиме (уже даже существует пара готовых решений), но и тут тебя будут ожидать неприятности. Некоторые слоги, стоящие в предложении рядом, могут, в зависимости от того, как их разделить пробелами, складываться в разные слова и резко менять смысл предложения. Возьмем для примера предложение 我想到纽约:

Как видишь, на автоматизированное членение лучше не полагаться. Как тогда быть? Тут нам поможет поиск по N-граммам. Предложение делится на куски по два-три знака:

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

Безопасность

У Elasticsearch нет никакой встроенной системы авторизации и ограничения прав доступа. После установки он по умолчанию вешается на порт 9200 на все доступные интерфейсы, что делает возможным не только полностью увести у тебя все, что находится в поисковой базе, но и, чисто теоретически, через обнаруженную дыру залезть в систему и там начудить. До версии 1.2 такая возможность была доступна прямо из коробки (см. CVE-2014-3120) и напрягаться не было вообще никакой нужды. В 1.2 по умолчанию выполнение скриптов в поисковых запросах отключено, но пока что и это не спасает.

Совсем недавно мы наблюдали ботнет на эластиках версий в том числе и 1.4 и выше. Судя по всему, использовалась уязвимость CVE-2015-1427. В версии 1.4.3 ее вроде как закрыли, но, сам понимаешь, полагаться на удачу в таких делах не вариант (на самом деле да, пока писалась эта статья, свежепоставленный эластик версии 1.5.0 на тестовых виртуалках у меня успели поломать уже на второй день :)). Вешай сервис только на локальные IP, все необходимые подключения извне ограничивай только доверенными адресами, фильтруй поисковые запросы, своевременно обновляйся. Спасение утопающих — дело рук самих утопающих.

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

  • type — тип хранилища, куда они будут складываться. Из коробки есть только файловая система. С помощью дополнительных плагинов можно реализовать заливку на AWS S3, HDFS и Azure Cloud;
  • location — куда сохранять новые бэкапы;
  • compress — сжимать ли бэкапы. Толку не очень много, так как по факту сжимает только метаинформацию, а файлы данных остаются несжатыми. По умолчанию включено.

После того как создан репозиторий, можно начать бэкапиться:

Такой запрос создает бэкап с названием snapshot_1 в репозитории my_backup.

Восстановить данные можно следующим образом:

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

Эпилог

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

Автозаполнение полей на js или живой поиск по БД

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

Для создания скрипта автозаполнения нам понадобится подключить библиотеку jQuery и UI (в моем примере она уже немного устарела, поэтому можете обновить).

Итак, чтобы сделать автозаполнение input поля пропишите код:

Теперь если вы будете вводить «scr» (слово script), то появятся первые 3 результата. При клике на один из них, подставится его текстовое значение в value input-а. Заметьте, что поиск идет сразу по всему полю.

Как вы уже догадались:
availableTags — массив результатов поиска для подстановки
source — источник для поиска (сюда и подставляем массив)

Чтобы ограничить минимальное число символов, чтобы поиск начал работать поставьте параметр: minLength: 3

Также для работы вам могут пригодиться следующие события:

open: function(event, ui) <> //действие в момент поиска (когда набирается текст)
select: function(event, ui) <> //действие когда элемент выбран и его название вписывается в input
close: function(event, ui) <> //действие когда поиск закрывается (ul список результатов)
ui.item.value — результат выбранного пользователем поиска

Поиск с автозаполнением прямо из БД

Чтобы организовать поиск по БД, в source вы можете поставить php файл, в котором берутся данные (в запрос можно добавлять GET), например: source: ‘poisk.php?adres=1’

Содержание файла poisk.php может быть следующим:

Как вы видите здесь введен лимит на вывод найденных значений до 20. Строка поиска передается в $_GET[‘term’] , а вывод результата идет в JSON формате. Только поставьте защиту для безопасного ввода/вывода из БД.

How To Build A Movie Search App With React and ElasticSearch

In this post, we will use React and Elasticsearch to build a MovieSearch app. I know you like React, and watching movies, but what is this Elasticsearch thing I’m talking about. Don’t worry. This blog post will give you a kickstart into understanding the basics of Elasticsearch — What is it? Why should you care about it? And, how can you use it with React to build powerful apps painlessly.

You should try out the Live Demo of our final app here to see what we will be building. I will wait for you!

What is Elasticsearch and why should you care about it?

Now, let’s understand the role of Elasticsearch in helping us build the above UI. Elasticsearch is a super fast, open-source, full-text search engine. It allows you to store, search, and analyze big volumes of data quickly (we are talking milliseconds here). It is generally used as the underlying engine/technology that powers applications that have complex search features and requirements. You can read more about it here.

With Elasticsearch, you can build a fast search utilizing its powerful Query DSL. However, setting up Elasticsearch correctly requires a lot of work. For instance, the data mapping, analyzers and tokenizers need to be set correctly or you may not receive accurate search results back. Besides, the more filters that get applied along with the search query, the more complex the resulting search query becomes.

We, at Appbase, have built some open-source tools to help you do all these things with the matter of some clicks.

  • Tool to add data into Elasticsearch — Importer
  • Tool to view Elasticsearch data like an excel sheet — Data Browser
  • Tool to generate relevant Elasticsearch queries easily — Query Builder
  • Tool to build UI components with an Elasticsearch backend — Reactive Search (we will be using this to build our MovieSearch app’s UI).

In this blog post, with the help of some of these toolings, we will utilize the strengths of Elasticsearch with React to build powerful apps.

How to use Elasticsearch with React?

We will be using ReactiveSearch open-source library to build the MovieSearch app in in this post. It offers a range of highly customizable rich UI components that can connect with any Elasticsearch server and provide you with a good default queries for all generic use-cases (think E-commerce, Aggregators, Events et al) bundled into these components. ReactiveSearch will help us to build UI widgets for filters and search related UI elements.

Работа с jQuery UI и визуальными элементами

jQuery UI и Autocomplete

Кроме стандартных элементов html мы можем использовать более богатые по функциональности и графической визуализации элементы, которые, как правило, реализуются в виде дополнительных плагинов на javascript и css. Наиболее популярным плагином является библиотека jQuery UI. Эта библиотека содержит набор виджетов, как accordion, autocomplete, button, datepicker, dialog, progressbar, slider и ряд других.

Для работы с jQuery UI необходимо прежде всего подключить библиотеку. Если в проектах для предыдущих версий MVC файлы jquery ui подключались по умолчанию, то в MVC 5 нам надо самим добавлять все необходимые файлы в проект. Для этого воспользуемся пакетным менеджером NuGet:

Необходимый пакет называется jQuery UI (Combined Library). Также нужно учитывать, что данная библиотека зависит от главной библиотеки jQuery, которая также должна быть установлена.

После установки в проект в каталог Content/themes/base будет добавлен ряд файлов css jquery ui, а в папку Scripts — ее скрипт в полной и минимизированной версии.

Теперь чтобы использовать библиотеку, нам надо в представлении подключить ее основной файл стилей all.css , иначе плагин просто не будет работать, а также скрипт

Рассмотрим действие jQuery UI на примере виджета Autocomplete, который реализует функциональность автозаполнения.

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

Затем изменим стандартный контроллер HomeController следующим образом:

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

Теперь изменим представление Index.cshtml, определив в нем элемент ввода, для которого и будет производиться автозаполнение:

Итак, чтобы подключить автозаполнение, мы добавляем к элементу ввода атрибут HTML5 data-autocomplete-source . Этот атрибут указывает на источник данных. В данном случае источником данных будет действие AutocompleteSearch в контроллере Home.

В методе извлекаются все объекты списка, и по ним формируется новый анонимный объект — модель компьютера. Итоговый массив новых объектов отправляется обратно клиенту в формате JSON. Причем каждый из создаваемых анонимных объектов должен иметь свойство label или свойство value (как в нашем случае), либо оба этих свойства. Свойство label применяется для отображения текста пользователю. При выборе пользователем определенного элемента в списке объектов виджет помещает value выделенного элемента в элемент ввода на странице. Если либо свойство label, либо value не указано, виджет будет использовать значение одного указанного свойства как для value, так и для label.

В конце представления определен скрипт, который вызывает функцию autocomplete для элемента заполнения:

Функция each вызывает для каждого найденного по селектору элемента функцию, указанную в параметре. В этой функции вызывается метод плагина autocomplete для каждого элемента. Параметр, передаваемый в метод autocomplete , представляет собой объект, в котором определено одно свойство — свойство source . Но можно установить и большее количество свойств, например, задержку после нажатия клавиши или минимальное количество символов, необходимое для срабатывания автозаполнения и отправки запрос к источнику данных.

В итоге при обращении к источнику данных (в данном случае — к действию AutocompleteSearch контроллера Home) плагин передает текущее значение элемента ввода в качестве параметра term в строке запроса, а обратно клиенту отсылается массив объектов в формате JSON, которые на клиенте преобразуются в форму для отображения:

Топ-пост этого месяца:  Как заработать менеджером по интернет-рекламе и где искать работу начинающему специалисту
Добавить комментарий