В этом блоге мы узнаем, как писать и выполнять запросы в Elasticsearch.
Как поставщик решений блокчейн, мы в DLT Labs ™ используем различные сети блокчейнов. Получение данных блокчейна со сложными запросами занимает много времени. Таким образом, мы синхронизируем данные блокчейна с Elasticsearch для получения данных путем написания сложного запроса за минимальное время.
Как разработчик программного обеспечения, когда я начал писать запросы Elasticsearch, я не знал о синтаксисе и шаблоне этих запросов. В этом блоге я просто объясняю то, что узнал о них, на простом примере.
Мы научимся писать запросы соответствия, термина, диапазона, условий и подстановочных знаков. Также мы увидим, как получить в ответ выборочные поля.
Прежде чем продолжить, давайте рассмотрим Elasticsearch.
Elasticsearch - популярная поисковая и аналитическая система, которая хранит сложные структуры данных в виде документов JSON (JavaScript Object Notation).
Когда в кластере несколько узлов Elasticsearch, сохраненные документы будут распределены. Он проиндексирован и доступен для поиска в течение нескольких секунд с любого узла.
Elasticsearch может быть без схемы. Это означает, что документы можно индексировать без явного указания типа полей, которые могут встречаться в документе.
Когда динамическое сопоставление включено, Elasticsearch обнаруживает и добавляет в индекс любые новые поля. Такое поведение по умолчанию упрощает индексацию и поиск данных.
Elasticsearch позволяет нам работать с данными любым удобным для нас способом. Мы можем использовать RESTful API, языковые клиенты, DSL запросов Elasticsearch и SQL для запроса данных в Elasticsearch.
Elasticsearch предоставляет пакет, который позволяет выполнять запросы из кода Node.js.
Представляем пример:
В этом блоге мы увидим, как написать базовый запрос Elasticsearch с помощью Query DSL. Query DSL - это предметно-ориентированный язык, который Elasticsearch предоставляет нам для написания запросов в JSON. Он содержит 2 типа оговорок:
1. Предложение листового запроса
Этот тип предложения будет искать поле или значение, используя запросы совпадений, терминов или диапазонов.
2. Предложение о составном запросе
Этот тип предложения представляет собой оболочку, которая различными способами объединяет результаты нескольких других запросов.
Чтобы запросить Elasticsearch, нам нужно знать, как будут выглядеть данные, т. Е. Структуру JSON, и где запрашивать; в частности, нам понадобится URL-адрес узла и имя индекса.
А теперь давайте посмотрим на пример. Предположим, у нас есть данные студентов с полями ниже:
Рассмотрим следующие два вопроса:
Запрос 1: получить все записи.
DSL: GET student / _search // здесь студенты - это индексное имя
{ “query”: { “match_all”: {} } } Response of above query will look like: { “took”: 0, “timed_out”: false, “_shards”: { “total”: 1, “successful”: 1, “skipped”: 0, “failed”: 0 }, “hits”: { “total”: { “value”: 4, “relation”: “eq” }, “max_score”: 5.7439184, “hits”: [{ “_index”: “students”, “_type”: “_doc”, “_id”: “10”, “_score”: 5.7439184, “_source”: { “rollNo”: 10, “name”: “john”, “age”: 20, “subject”: “English”, “marks”: 60 } }, { “_index”: “students”, “_type”: “_doc”, “_id”: “20”, “_score”: 5.7439184, “_source”: { “rollNo”: 20, “name”: “jia”, “age”: 19, “subject”: “English”, “marks”: 70 } }, { “_index”: “students”, “_type”: “_doc”, “_id”: “30”, “_score”: 5.7439184, “_source”: { “rollNo”: 30, “name”: “rahul”, “age”: 21, “subject”: “Hindi”, “marks”: 70 } }, { “_index”: “students”, “_type”: “_doc”, “_id”: “40”, “_score”: 5.7439184, “_source”: { “rollNo”: 40, “name”: “hinal”, “age”: 20, “subject”: “Math”, “marks”: 80 } } ] } }
Запрос 2: получите все записи, любимая тема которых - английский.
DSL:
Используя "match", мы получаем следующее:
GET students/_search { “query”: { “match”: { “subject” : “English” } } }
Используя "термин", мы получаем следующее:
GET students/_search { “query”: { “term”: { “subject.keyword” : “English” } } }
Некоторые часто задаваемые вопросы об Elasticsearch
1. Есть ли разница между двумя запросами?
A : Да, существует разница между запросами на совпадение и поисковыми запросами. Поиск совпадений выполняется без учета регистра, а поиск по запросу - с учетом регистра.
2. В чем разница между «subject» и «subject.keyword»?
О: Когда мы добавляем какое-либо поле, например «subject», с таким динамическим отображением:
{ “subject”: { “type” “text”, “fields”: { “keyword”: { “type”: “keyword”, “ignore_above”: 256 } } } }
Это позволяет использовать поле 'subject' для полнотекстового поиска, а поле 'subject.keyword' - в запросах по термину для выполнения точного поиска, подстановочных знаков и агрегирования.
Если я изменю вышеуказанные запросы, как показано ниже, запрос термина ничего не вернет, но запрос соответствия будет работать и возвращать следующие данные:
Использование соответствия:
GET students/_search{ “query”: { “match”: { “subject” : “english” } } }
Ответ на вышеуказанный запрос:
{ “took”: 0, “timed_out”: false, “_shards”: { “total”: 1, “successful”: 1, “skipped”: 0, “failed”: 0 }, “hits”: { “total”: { “value”: 2, “relation”: “eq” }, “max_score”: 5.7439184, “hits”: [{ “_index”: “students”, “_type”: “_doc”, “_id”: “10”, “_score”: 5.7439184, “_source”: { “rollNo”: 10, “name”: “john”, “age”: 20, “subject”: “English”, “marks”: 60 } }, { “_index”: “students”, “_type”: “_doc”, “_id”: “20”, “_score”: 5.7439184, “_source”: { “rollNo”: 20, “name”: “jia”, “age”: 19, “subject”: “English”, “marks”: 70 } } ] } }
Использование термина:
GET students/_search { “query”: { “term”: { “subject.keyword” : “english” } } }
Ответ на вышеуказанный запрос:
{ “took”: 0, “timed_out”: false, “_shards”: { “total”: 1, “successful”: 1, “skipped”: 0, “failed”: 0 }, “hits”: { “total”: { “value”: 0, “relation”: “eq” }, “max_score”: null, “hits”: [] } }
Давайте рассмотрим еще несколько примеров запросов.
Запрос 3: Получите список Нет учеников, чей любимый предмет - английский.
Чтобы выбрать несколько полей или вернуть выбранные поля в ответ, Elasticsearch обеспечивает фильтрацию источника. Например, здесь я хочу получить в выводе только «rollNo», поэтому я упомяну rollNo в массиве «includes» исходной фильтрации.
Фильтрацию источников можно использовать следующим образом:
DSL: ПОЛУЧИТЕ студентов / _search
{ “_source”: { “includes”: [“rollNo”] }, “query”: { “term”: { “subject.keyword”: “English” } } }
Ответ на вышеуказанный запрос:
{ “took”: 0, “timed_out”: false, “_shards”: { “total”: 1, “successful”: 1, “skipped”: 0, “failed”: 0 }, “hits”: { “total”: { “value”: 2, “relation”: “eq” }, “max_score”: 5.7439184, “hits”: [{ “_index”: “students”, “_type”: “_doc”, “_id”: “10”, “_score”: 5.7439184, “_source”: { “rollNo”: 10 } }, { “_index”: “students”, “_type”: “_doc”, “_id”: “20”, “_score”: 5.7439184, “_source”: { “rollNo”: 20 } } ] } }
Запрос 4: Получите список
Чтобы получить записи, попадающие в указанный числовой диапазон, в Elasticsearch есть запрос диапазона.
Например, здесь мы хотим получить записи с оценками от 70 до 80; то есть 70 ‹= оценок‹ = 80.
Запрос диапазона можно использовать, как показано ниже:
DSL: GET students/_search { “_source”: { “includes”: [“rollNo”] }, “query”: { “range”: { “marks”: { “gte”: 70, “lte”: 80 } } } }
Ответ на вышеуказанный запрос:
{ “took”: 0, “timed_out”: false, “_shards”: { “total”: 1, “successful”: 1, “skipped”: 0, “failed”: 0 }, “hits”: { “total”: { “value”: 3, “relation”: “eq” }, “max_score”: 5.7439184, “hits”: [{ “_index”: “students”, “_type”: “_doc”, “_id”: “20”, “_score”: 5.7439184, “_source”: { “rollNo”: 20 } }, { “_index”: “students”, “_type”: “_doc”, “_id”: “30”, “_score”: 5.7439184, “_source”: { “rollNo”: 30 } }, { “_index”: “students”, “_type”: “_doc”, “_id”: “40”, “_score”: 5.7439184, “_source”: { “rollNo”: 40 } } ] } }
Запрос 5: Получите rollNo учащихся, чьи оценки составляют от 70 до 90 И возраст от 20 до 22.
Это еще один пример запроса диапазона, но с условием И.
Поскольку есть 2 условия, одно - И, другое - ИЛИ. Здесь, в Elasticsearch:
- «Must» используется для фильтрации AND.
- «Следует» используется для фильтрации ИЛИ.
В этом запросе мы хотим получить rollNo учащихся с условием:
70 ‹= points‹ = 90 && 20 ‹= age‹ = 22
DSL: GET students/_search { “_source”: { “includes”: [“rollNo”] }, “query”: { “bool”: { “must”: [{ “range”: { “marks”: { “gte”: 70, “lte”: 90 } } }, { “range”: { “age”: { “gte”: 20, “lte”: 22 } } }] } } }
Ответ на запрос выше:
{ “took”: 0, “timed_out”: false, “_shards”: { “total”: 1, “successful”: 1, “skipped”: 0, “failed”: 0 }, “hits”: { “total”: { “value”: 2, “relation”: “eq” }, “max_score”: 5.7439184, “hits”: [{ “_index”: “students”, “_type”: “_doc”, “_id”: “30”, “_score”: 5.7439184, “_source”: { “rollNo”: 30 } }, { “_index”: “students”, “_type”: “_doc”, “_id”: “40”, “_score”: 5.7439184, “_source”: { “rollNo”: 40 } } ] } }
Запрос 6: узнайте имена учащихся 20 или 21 года.
В Elasticsearch, используя запросы терминов, мы можем искать несколько значений для одного поля.
В этом запросе мы хотим получить имена студентов с условием:
возраст = 20 || Возраст = 21 год.
Поскольку мы запрашиваем в одном и том же поле конкретные значения (20 или 21), мы можем использовать запрос условий следующим образом:
DSL: GET students/_search { “_source”: { “includes”: [“name”] }, “query”: { “bool”: { “must”: [{ “terms”: { “age”: [21, 20] } }] } } }
Мы также можем написать вышеупомянутый запрос с «следует», потому что здесь в этом запросе условие - ИЛИ. Запрос можно записать следующим образом:
GET students/_search { “_source”: { “includes”: [“name”] }, “query”: { “bool”: { “should”: [{ “term”: { “age”: 20 } }, { “term”: { “age”: 21 } }] } } }
Ответ на вышеуказанный запрос:
{ “took”: 0, “timed_out”: false, “_shards”: { “total”: 1, “successful”: 1, “skipped”: 0, “failed”: 0 }, “hits”: { “total”: { “value”: 3, “relation”: “eq” }, “max_score”: 5.7439184, “hits”: [{ “_index”: “students”, “_type”: “_doc”, “_id”: “10”, “_score”: 5.7439184, “_source”: { “name”: “john” } }, { “_index”: “students”, “_type”: “_doc”, “_id”: “30”, “_score”: 5.7439184, “_source”: { “name”: “rahul” } }, { “_index”: “students”, “_type”: “_doc”, “_id”: “40”, “_score”: 5.7439184, “_source”: { “name”: “jinal” } } ] } }
Теперь рассмотрим некоторые другие данные, как показано ниже:
Запрос 7: узнайте имена учащихся, имена которых начинаются с «джи».
Elasticsearch позволяет нам выполнять поиск частично, используя подстановочные знаки. «*» соответствует 0 или более символам и «?» будет соответствовать только одному символу.
Запрос с подстановочными знаками можно записать, как в следующем примере:
DSL: ПОЛУЧИТЕ студентов / _search
{ “_source”: { “includes”: [“name”] }, “query”: { “wildcard”: { “name.keyword”: “ji*” } } }
Ответ на запрос выше:
{ “took”: 0, “timed_out”: false, “_shards”: { “total”: 1, “successful”: 1, “skipped”: 0, “failed”: 0 }, “hits”: { “total”: { “value”: 2, “relation”: “eq” }, “max_score”: 5.7439184, “hits”: [{ “_index”: “students”, “_type”: “_doc”, “_id”: “101”, “_score”: 5.7439184, “_source”: { “name”: “jia” } }, { “_index”: “students”, “_type”: “_doc”, “_id”: “102”, “_score”: 5.7439184, “_source”: { “name”: “jinal” } } ] } }
Выполнение запросов с помощью Node.js
Elasticsearch предоставляет пакет, который позволяет выполнять запросы из кода Node.js.
Например:
const {Client} = require(‘@elastic/elasticsearch’); const client = new Client({node: ‘0.0.0.0:9200’}); const {body} = client.search({index: ‘students’, body: query,from:0,size:100}); console.log(body.hits.hits);
В приведенной выше логике выполнения from и size предназначены для разбивки на страницы. Если бы я дал от: 10, размер: 100, он вернул бы мне 100 записей после пропуска первых 10.
Это небольшая часть Elasticsearch, которую я сегодня обсуждал. В будущих блогах по этой теме я планирую обсудить, как писать вложенные запросы, функции сценариев, агрегированные запросы и многое другое.
Спасибо!
Elasticsearch - товарный знак Elasticsearch BV, зарегистрированный в США и других странах. Node.js является товарным знаком Joyent, Inc. (мы не аффилированы). DLT Labs является товарным знаком DLT Global, Inc.
Автор - Лина Талеле, DLT Labs ™
Об авторе: Лина - разработчик Nodejs, который всегда с энтузиазмом узнает что-то новое. Она является частью команды ASIK в DLT Labs и хорошо разбирается в java, python и чат-ботах.