ElasticSearch: От нуля до героя за 12 команд

Начать работу с ElasticSearch относительно просто. Но по мере того, как наши сценарии использования становились все более специфичными, мы обнаружили, что документации не хватает. В этой шпаргалке мы рассмотрим 12 команд: от настройки индекса ES до выполнения расширенных запросов ES для поддержки сложных (но распространенных) сценариев использования.

Эти 12 команд работают, если выполнять их последовательно. Я объясню каждую из них, но лучше всего попробовать выполнить их самостоятельно.

Этот пост является частью более обширной серии статей по ElasticSearch, которая будет опубликована в ближайшие недели:

  • Шпаргалка по ElasticSearch, необходимая для начала работы с ES — вы здесь
  • Использование DynamoDB + ElasticSearch для рабочих нагрузок — скоро будет здесь
  • И как создать потоки DynamoDB для асинхронной синхронизации изменений данных из DynamoDB в ES — скоро будет.
Содержание
  1. 0 | Предварительные условия
  2. A | Настройка индекса
  3. [1] Убедитесь, что кластер ES доступен
  4. [2] Создать индекс
  5. [3] Создание отображения для индекса
  6. [4] Показать отображение индекса
  7. B | Операции с данными с нашим индексом ES
  8. [5] Создание данных для индекса
  9. [6] Отображение всех данных
  10. [7] Точный поиск с идентификатором товара
  11. [8] Нечеткий поиск с названиями
  12. [9] Сортировка по ценам
  13. [10] Поиск всех продуктов «пиво», которые ПУБЛИКУЮТСЯ и есть в наличии. Сортировка от самых дешевых до самых дорогих
  14. [11] Поиск всех продуктов, имеющих хотя бы 1 из следующих тегов [‘poultry, ‘kampai’, ‘best-seller’], которые опубликованы и есть на складе. Отсортировано от самых дешевых до самых дорогих
  15. [12] Поиск всех продуктов, имеющих хотя бы 1 из следующих тегов [‘poultry, ‘kampai’, ‘best-seller’] и находящихся на складе. Цена должна быть только от 0 до 300. Отсортировано от самых дешевых до самых дорогих
  16. Заключение
  17. А как насчет вас? Есть ли другой синтаксис ElasticSearch, который вы хотите изучить?

0 | Предварительные условия

Установите Elasticsearch с помощью этого официального руководства по ES. А затем включите сервер ES на localhost:9200.

Для облегчения тестирования обязательно установите платформу API, например Postman.

A | Настройка индекса

В ElasticSearch мы храним наши данные в индексах (аналогично таблицам в базе данных MySQL). Мы заполняем индексы документами (подобно строкам). Мы создадим и настроим ваш первый индекс в следующих командах.

[1] Убедитесь, что кластер ES доступен

GET localhost:9200
Войдите в полноэкранный режим Выйти из полноэкранного режима

Сначала убедитесь, что ваш локальный сервер ES находится в сети, и у вас открыт Postman. Создайте новый GET-запрос, направленный на localhost:9200. Вы должны увидеть что-то вроде этого:

[2] Создать индекс

PUT localhost:9200/mynewindex
Войти в полноэкранный режим Выход из полноэкранного режима

Теперь давайте создадим наш первый индекс. Индексы хранят наши данные. Это эквивалентно созданию таблицы в реляционных базах данных.

[3] Создание отображения для индекса

Индекс, который мы только что создали, не имеет отображения. Сопоставление похоже на схему в базах данных SQL. Она определяет форму документов, которые будет принимать наш индекс. После его определения индекс будет отказываться принимать документы, которые не вписываются в это отображение (т.е. мы определили запасы как целое число ниже. Если мы попытаемся вставить строку с stocks=»none», операция не будет продолжена).

В ES можно заметить одну вещь: по умолчанию эти отображения являются разрешающими. Если я добавлю строку с новым атрибутом «perishable» = true, то когда я передам документ в ES, схема добавит этот атрибут и определит его тип данных. В данном случае она добавит новый атрибут в отображение для «perishable» с типом данных «boolean».

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

В этой команде мы создаем отображение для нашего только что созданного индекса.

PUT localhost:9200/mynewindex/_mapping

{
    "properties": {
        "product_id": {
            "type": "keyword"
        },
        "price": {
            "type": "float"
        },
        "stocks": {
            "type": "integer"
        },
        "published": {
            "type": "boolean"
        },
        "title": {
            "type": "text"
        },
        "sortable_title": {
            "type": "text"
        },
        "tags": {
            "type": "text"
        }
    }
}
Войти в полноэкранный режим Выход из полноэкранного режима

Большинство типов данных просты, за исключением Text и Keyword. В этой статье хорошо объясняется разница.

В двух словах, Text позволяет вам запрашивать слова внутри поля (например, запрос «Burger» покажет продукт «Cheese Burger with Fries»). Для этого каждое слово в тексте рассматривается как отдельные лексемы, которые можно искать: «сыр», «бургер», «с», «картофель фри».

С другой стороны, Keyword рассматривает содержимое поля как единое целое, поэтому если вы хотите получить чизбургер с картошкой фри, вам придется запросить: «Чизбургер с картофелем фри». Запрос «бургер» ничего не даст.

[4] Показать отображение индекса

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

GET localhost:9200/mynewindex
Войти в полноэкранный режим Выход из полноэкранного режима

B | Операции с данными с нашим индексом ES

Когда наш индекс уже настроен, давайте добавим данные и начнем изучать более интересные части ES!

[5] Создание данных для индекса

Для этого раздела отправим три последовательных post-запроса с разным телом запроса в каждом запросе. Это добавит 3 «строки» в наш индекс Elasticsearch.

POST localhost:9200/mynewindex/_doc

{
    "product_id": "123",
    "price": 99.75,
    "stocks": 10,
    "published": true,
    "sortable_title": "Kenny Rogers Chicken Sauce",
    "title": "Kenny Rogers Chicken Sauce",
    "tags": "chicken sauce poultry cooked party"
}

POST localhost:9200/mynewindex/_doc

{
    "product_id": "456",
    "price": 200.75,
    "stocks": 0,
    "published": true,
    "sortable_title": "Best Selling Beer Flavor",
    "title": "Best Selling Beer Flavor",
    "tags": "beer best-seller party"
}

POST localhost:9200/mynewindex/_doc


{
    "product_id": "789",
    "price": 350.5,
    "stocks": 200,
    "published": false,
    "sortable_title": "Female Lotion",
    "title": "Female Lotion",
    "tags": "lotion female"
}
Вход в полноэкранный режим Выход из полноэкранного режима

[6] Отображение всех данных

Теперь давайте посмотрим, попали ли три документа, которые мы вставили с помощью команды №5, в наш индекс. Эта команда показывает все документы внутри индекса:

POST localhost:9200/mynewindex/_search

{
    "query": {
        "match_all": {}
    }
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Есть!

[7] Точный поиск с идентификатором товара

Теперь давайте начнем с простого поиска. Давайте искать по идентификатору товара.

POST localhost:9200/mynewindex/_search

{
    "query": {
        "term": {
            "product_id": "456"
        }
    }
}
Войти в полноэкранный режим Выйти из полноэкранного режима

В приведенной выше команде мы используем «запрос термина», потому что ищем продукт с «product_id», который точно соответствует строке «456». Термический запрос работает, потому что тип данных «product_id» — «ключевое слово».

[8] Нечеткий поиск с названиями

Теперь перейдем к более интересным моментам.

ES известен своими широкими возможностями поиска. Давайте проверим это, создав наш первый нечеткий поиск. Нечеткий поиск позволяет нам искать продукты, набирая всего несколько слов вместо полного текста поля. Вместо того чтобы набирать полное название продукта (например, Incredible Tuna Mayo Jumbo 250), покупатель просто ищет ту часть продукта, которую он вспоминает (например, Tuna Mayo).

POST localhost:9200/mynewindex/_search

{
    "query": {
        "match": {
            "title": "Beer Flavor"
        }
    }
}
Вход в полноэкранный режим Выход из полноэкранного режима

При настройках по умолчанию мы можем получить продукт «Best Selling Beer Flavor» даже при нашем неполном запросе «Beer Flavor». Существуют и другие настройки, которые позволяют нам допускать опечатки или неполные слова для отображения результатов (например, Bee Flavo).

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

[9] Сортировка по ценам

Еще одна вещь, которую нам обычно приходится делать на сайте электронной коммерции, — это сортировка товаров по определенным категориям, таким как цена или рейтинг:

POST localhost:9200/mynewindex/_search

{
    "query": {
        "match_all": {}
    },
    "sort": [
        {"price": "desc"},
        "_score"
    ]
}
Войти в полноэкранный режим Выйти из полноэкранного режима

С помощью нашего запроса выше мы возвращаем все товары, отсортированные по цене от самых дорогих до самых дешевых. Обратите внимание, что параметр sort представляет собой список, что позволяет нам добавить несколько критериев для сортировки. Мы также добавили «_score», который является ключевым словом elasticsearch для релевантности поиска. Мы глубже изучим эту концепцию на последующих примерах.

[10] Поиск всех продуктов «пиво», которые ПУБЛИКУЮТСЯ и есть в наличии. Сортировка от самых дешевых до самых дорогих

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


POST localhost:9200/mynewindex/_doc

{
    "product_id": "111",
    "price": 350.55,
    "stocks": 10,
    "published": true,
    "sortable_title": "Tudor Beer Lights",
    "title": "Tudor Beer Lights",
    "tags": "beer tudor party"
}

POST localhost:9200/mynewindex/_doc

{
    "product_id": "222",
    "price": 700.50,
    "stocks": 500,
    "published": false,
    "sortable_title": "Stella Beer 6pack",
    "title": "Stella Beer 6pack",
    "tags": "beer stella party"
}

POST localhost:9200/mynewindex/_doc

{
    "product_id": "333",
    "price": 340,
    "stocks": 500,
    "published": true,
    "sortable_title": "Kampai Beer 6pack",
    "title": "Kampai Beer 6pack",
    "tags": "beer kampai party"
}

Вход в полноэкранный режим Выход из полноэкранного режима

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

{
    "query": {
        "bool": {
            "must": [
                {
                    "match": {
                        "title": "Beer"
                    }
                },
                {
                    "term": {
                        "published": true
                    }
                },
                {
                    "range": {
                        "stocks": {
                            "gt": 0
                        }
                    }
                }
            ]
        }
    },
   "sort": [
        {"price": "asc"},
        "_score"
    ]
}
Войти в полноэкранный режим Выход из полноэкранного режима

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

  • 456: Самый продаваемый пивной аромат
  • 111: Tudor Beer Lights
  • 222: Stella Beer 6pack
  • 333: Kampai Beer 6pack

Поскольку мы отфильтровываем товары, чей инвентарь равен нулю (или ниже), мы удаляем товар 456 из списка. Другой фильтр заключается в том, что товар должен быть опубликован (published = true). С помощью этого фильтра удаляется товар 222. Остаются 2 продукта, представленные ниже. Они должны быть отсортированы по принципу от самого дешевого к самому дорогому, как показано ниже:

  • 333: Kampai Beer 6pack (цена = 340)
  • 111: Tudor Beer Lights (цена = 350,55)

В этом примере использовался ключ «must», а его значением был список. Список содержит условия, которые должны быть выполнены вместе, чтобы требования запроса были удовлетворены. В этом примере «заголовок должен содержать слово «пиво»». И «атрибут published равен true» И «запасы больше нуля».

[11] Поиск всех продуктов, имеющих хотя бы 1 из следующих тегов [‘poultry, ‘kampai’, ‘best-seller’], которые опубликованы и есть на складе. Отсортировано от самых дешевых до самых дорогих

В нашем предыдущем запросе было всего три условия, которые должны быть ВСЕ ИСТИННЫМИ. Это эквивалентно «A и B и C».

В этом запросе у нас по-прежнему есть три условия, которые должны быть все истинными, но 1-е условие отмечается как истинное, если в нем есть либо «птица», либо «кампай», либо «бестселлер».В этом примере мы вводим синтаксис для «OR»:

{
    "query": {
        "bool": {
            "must": [
                {
                    "bool": {
                        "should": [
                            {
                                "match": {
                                    "tags": "poultry"
                                }
                            },
                            {
                                "match": {
                                    "tags": "kampai"
                                }
                            },
                            {
                                "match": {
                                    "tags": "best-seller"
                                }
                            }
                        ],
                        "minimum_should_match": 1
                    }
                },
                {
                    "term": {
                        "published": true
                    }
                },
                {
                    "range": {
                        "stocks": {
                            "gt": 0
                        }
                    }
                }
            ]
        }
    },
    "sort": [
        {
            "price": "asc"
        },
        "_score"
    ]
}
Войти в полноэкранный режим Выйти из полноэкранного режима

В этом запросе у нас все еще есть ключевое слово «должен», но его первое содержит ключевое слово «следует». Весь запрос эквивалентен: (A или B или C) И D И E. «Должен» подразумевает, что если выполняется одно условие, то утверждение (A или B или C) возвращает истину.

Мы можем изменить параметр «minimum_should_match» (msm) и потребовать, чтобы для истинности утверждения выполнялись два, три или N условий. В нашем примере, если msm=2, это означает, что продукт должен иметь два совпадающих тега, чтобы считаться истинным (т.е. продукт должен быть и птицей, и кампай).

Мы проанализируем запрос ниже:

  • Продукт должен иметь хотя бы 1 из этих тегов: птица, кампай, бестселлер.
    • Это соответствует 3 продуктам: птица (pid: 123), кампай (pid: 333) и бестселлер (pid: 456).
  • То есть опубликовано
    • Все 3 PID из предыдущего шага уже опубликованы. Поэтому никаких изменений.
  • Должны иметь запасы
    • Поскольку pid 456 не имеет запасов, нам остается pid 123 и pid 333.
  • Сортировка по цене
    • pid 333 — 340pesos
    • pid 123 — 99.75pesos
    • следовательно, заказ должен быть таким: pid 123 => pid 323

[12] Поиск всех продуктов, имеющих хотя бы 1 из следующих тегов [‘poultry, ‘kampai’, ‘best-seller’] и находящихся на складе. Цена должна быть только от 0 до 300. Отсортировано от самых дешевых до самых дорогих

Этот запрос похож на #11, но мы добавили еще один критерий — цена возвращаемых продуктов должна быть только от 0 до 300.

{
    "query": {
        "bool": {
            "must": [
                {
                    "bool": {
                        "should": [
                            {
                                "match": {
                                    "tags": "poultry"
                                }
                            },
                            {
                                "match": {
                                    "tags": "kampai"
                                }
                            },
                            {
                                "match": {
                                    "tags": "best-seller"
                                }
                            }
                        ],
                        "minimum_should_match": 1
                    }
                },
                {
                    "term": {
                        "published": true
                    }
                },
                {
                    "range": {
                        "stocks": {
                            "gt": 0
                        }
                    }
                },
                {
                    "range": {
                        "price": {
                            "gt": 0,
                            "lt": 300
                        }
                    }
                }
            ]
        }
    },
    "sort": [
        {
            "price": "asc"
        },
        "_score"
    ]
}
Вход в полноэкранный режим Выход из полноэкранного режима

В этом запросе используется ключевое слово «диапазон», которое позволяет нам отфильтровать элементы, если они соответствуют определенному диапазону значений. Для цены мы задаем условие, чтобы цена находилась в диапазоне от 0 до 300. Для акций мы задаем условие, чтобы цена была больше нуля.

Давайте проанализируем запрос:

  • Из результатов в #11 мы имеем pid 333 (340pesos) и pid 123 (99.75pesos).
  • С фильтром цены 0-300 единственным результатом будет pid 123 (99,75 песо).

Заключение

Начать работу с ElasticSearch очень просто! Но по мере роста потребностей вашего бизнеса поиск может усложняться. Эта шпаргалка поможет вам сориентироваться в этой сложности.

Альтернативой изучению синтаксиса ES на этом уровне является использование библиотеки DSL для Elasticsearch, которая «абстрагирует» длинный синтаксис Elasticsearch. Это мощный инструмент для использования ES в общих целях. Однако по мере роста ваших потребностей в запросах изучение синтаксиса в рамках этой DSL позволит вам быть в курсе того, какие опции можно добавить, чтобы сделать поиск более богатым.

А как насчет вас? Есть ли другой синтаксис ElasticSearch, который вы хотите изучить?

Возможно, я могу помочь! Напишите об этом в комментариях, и я постараюсь добавить это в статью.

Фото TK на Unsplash

Оцените статью
devanswers.ru
Добавить комментарий