В этом блоге мы узнаем, как писать и выполнять запросы в 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 и чат-ботах.