Для удобства работы я выбрал традиционный метод установки через распаковку архива, а не через Docker.
Перейдите на официальный сайт: https://www.elastic.co Выберите историческую версию, я выбрал версию 6.6.2
# Распаковка tar-архива
tar -zxvf elasticsearch-6.6.2.tar.gz
# Запуск одного экземпляра Elasticsearch
cd elasticsearch-6.6.2/bin
sh elasticsearch
Посетите http://localhost:9200
Вы увидите следующее, что указывает на успешное запуск Elasticsearch.
По умолчанию имя кластера Elasticsearch равно elasticsearch
, а порт по умолчанию — 9200.
Elasticsearch-head — это специализированный клиент для Elasticsearch, это фронтенд-проект на основе node.js.
Установка node.js: http://www.runoob.com/nodejs/nodejs-install-setup.html Моя версия — V6.3.0.
Официальный GitHub-репозиторий elasticsearch-head: https://github.com/mobz/elasticsearch-head
git clone git://github.com/mobz/elasticsearch-head.git
cd elasticsearch-head
npm install
npm run start
Посетите: http://localhost:9100
В этот момент вы заметите, что значение здоровья кластера серого цвета, это связано с тем, что Elasticsearch и Elasticsearch-head — это два независимых процесса, и между ними есть проблема с кросс-доменом. Поэтому нам нужно изменить конфигурационный файл Elasticsearch.Откройте файл elasticsearch.yml
в папке config
Elasticsearch и добавьте следующее:
# Кросс-домен
http.cors.enabled: true
http.cors.allow-origin: "*"
Перезапустите Elasticsearch, и вы заметите, что значение здоровья кластера стало зеленым. Это указывает на то, что Elasticsearch-head успешно подключился к Elasticsearch.
Здесь я настрою один мастер-узел и два рабочих узла.
Сначала настроим мастер-узел, установим имя кластера в calvin
# Настройка мастера
cluster.name: calvin
node.name: master
node.master: true
network.host: 127.0.0.1
Перезапустите Elasticsearch, и вы увидите


Затем мы копируем распакованный пакет, создаем узел salve1. Изменяем elasticsearch.yml. Обратите внимание, что имя кластера должно совпадать с именем кластера узла master.
cluster.name: calvin node.name: salve1
network.host: 127.0.0.1
http.port: 8200
discovery.zen.ping.unicast.hosts: ["127.0.0.1"]
Настройка узла salve2 аналогична настройке salve1, только имя узла node.name изменено на salve2, а порт port изменен на 7200. Конкретные настройки следующие:```
# Настройка slave
cluster.name: calvin
node.name: salve2
# Привязанный IP
network.host: 127.0.0.1
# Настройка порта, чтобы избежать конфликта портов с master
http.port: 7200
# Настройка одноранговой связи кластера, подключение к узлу master
discovery.zen.ping.unicast.hosts: ["127.0.0.1"]
Запустите узлы slave1 и slave2, обновите Elasticsearch-head, и вы увидите, что узлы master и два узла slave уже отображены.
Индекс: набор документов с одинаковыми свойствами
Тип: индекс может определять один или несколько типов, документы должны принадлежать к типу
Документ: документ — это базовая единица данных, которую можно индексировать
Фрагмент: каждый индекс имеет несколько фрагментов, каждый фрагмент — это Lucene-индекс
Резервная копия: копирование фрагмента создает резервную копию фрагмента
Аналогично базе данных, индекс соответствует базе данных, тип — таблице, а документ — записи в таблице. Более подходящий аналог: система поиска информации, где есть индекс автомобилей, индекс книг, индекс мебели. Например, индекс книг может быть разделен на научно-популярные типы, типы романов и т.д., каждый тип содержит множество книг, а каждая книга — это документ.
Основной формат API: http://:/<индекс>/<тип>/<документid> Основные HTTP-методы: GET/PUT/POST/DELETE
* Неструктурированное создание
Индекс --> Создать индекс, по умолчанию количество основных фрагментов равно 5, количество резервных равно 1.

Где толстые черные рамки обозначают основные фрагменты, а тонкие черные рамки обозначают резервные копии основных фрагментов.
При нажатии на информацию под book --> Информация об индексе, можно увидеть, что mappings пустые, что указывает на то, что этот индекс является неструктурированным.

* Структурированное создание

Метод запроса изменен на PUT, данные запроса:
{ "settings":{ "number_of_shards":3, "number_of_replicas":1 }, "mappings":{ "man":{ "properties":{ "name":{ "type":"text" }, "country":{ "type":"keyword" }, "age":{ "type":"integer" }, "date":{ "type":"date", "format":"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis" } } } } }
Это создает индекс `people` с тремя основными фрагментами и одной резервной копией, типом `man` и свойствами `name`, `country`, `age`, `date`.При переходе в elasticsearch-head и нажатии на информацию --> Информация об индексе, можно увидеть:

Важно отметить, что версии 6.0 и выше не допускают наличие нескольких типов в одном индексе, и официальные разработчики сообщают, что типы будут удалены в версии 7.0.
#### (2) Вставка
* Вставка с указанием идентификатора документа

Метод запроса изменен на PUT, данные запроса:
{ "name":"calvin", "country":"China", "age":27, "date":"1993-12-20" }
При обновлении elasticsearch-head, можно увидеть, что количество документов равно 1.

При переходе к просмотру данных, можно увидеть вставленные нами данные.

* Автоматически генерируемый документный идентификатор вставляется

Метод запроса изменен на POST, данные запроса:
{ "name":"sheng", "country":"China", "age":30, "date":"1990-05-24" }
После этого обновите elasticsearch-head, чтобы увидеть, что документ был автоматически создан.
#### (3) Изменение
Измените информацию о документе, например, измените значение атрибута name в документе с id=1

Метод запроса изменен на POST, данные запроса:
{ "doc":{ "name":"周杰伦" } }
Обновите elasticsearch-head, чтобы увидеть, что значение name в документе с id=1 изменилось с calvin на 周杰伦.

#### (4) Удаление
Например, если нам нужно удалить запись с id=1

Метод запроса - DELETE. Обновите elasticsearch-head, чтобы увидеть, что запись с id=1 удалена.

Аналогично, если нам нужно удалить тип, URL-запрос изменяется на: http://localhost:9200/people/man/ для удаления индекса - на: http://localhost:9200/people/
Конечно, мы также можем удалить индекс напрямую в elasticsearch-head, например, удалим ранее созданный индекс book.

Можно видеть, что индекс book успешно удален.

Измените тексты в кавычках на русский язык:
"周杰伦" на "Чжань Цзэлун"
"calvin" на "калвин"
"people/man/" на "люди/мужчина/"
"people/" на "люди/"
"book" на "книга"#### (5) Поиск
Для тестирования я создал несколько новых записей.

* Простой поиск

* Условный поиск
Если требуется выполнить поиск всех данных в индексе people, запрос будет отправлен по URL: http://localhost:9200/people/_search.

Метод запроса изменяется на POST, а данные запроса будут следующими:
{ "query":{ "match_all":{} } }
Указываем количество возвращаемых данных и с какого элемента начинать. Модифицируем запрос следующим образом:
{ "query":{ "match_all":{} }, "from": 1, "size": 1 }

Фильтруем данные по возрасту 25 и сортируем по дате (дата рождения) в порядке убывания.
Метод запроса изменяется на POST, а данные запроса будут следующими:
{ "query":{ "match":{ "age":25 } }, "sort":[ { "date":{ "order":"desc" } } ] }
Возвращаемые данные:```
{
"took": 39,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 3,
"max_score": null,
"hits": [
{
"_index": "people",
"_type": "man",
"_id": "3",
"_score": null,
"_source": {
"name": "Ли Сы",
"country": "China",
"age": 25,
"date": "1995-10-17"
},
"sort": [
813888000000
]
},
{
"_index": "people",
"_type": "man",
"_id": "4",
"_score": null,
"_source": {
"name": "Ван Ву",
"country": "China",
"age": 25,
"date": "1995-09-18"
},
"sort": [
811382400000
]
},
{
"_index": "people",
"_type": "man",
"_id": "5",
"_score": null,
"_source": {
"name": "Ван Лу",
"country": "China",
"age": 25,
"date": "1995-06-18"
},
"sort": [
803433600000
]
}
]
}
}
```* Агрегирующий запросСначала выполним запрос для агрегации по свойству age. Запрос имеет следующий вид:
{ "aggs":{ "group_by_age":{ "terms":{ "field":"age" } } } }
В данном запросе `group_by_age` можно настраивать по своему усмотрению.
```markdown
{
"took": 8,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 5,
"max_score": 1,
"hits": [
{
"_index": "people",
"_type": "man",
"_id": "iIHS5GoBkW5tmvoc_T_u",
"_score": 1,
"_source": {
"name": "sheng",
"country": "China",
"age": 30,
"date": "1990-05-24"
}
},
{
"_index": "people",
"_type": "man",
"_id": "2",
"_score": 1,
"_source": {
"name": "张三",
"country": "China",
"age": 28,
"date": "1992-11-20"
}
},
{
"_index": "people",
"_type": "man",
"_id": "4",
"_score": 1,
"_source": {
"name": "王五",
"country": "China",
"age": 25,
"date": "1995-09-18"
}
},
{
"_index": "people",
"_type": "man",
"_id": "5",
"_score": 1,
"_source": {
"name": "王六",
"country": "China",
"age": 25,
"date": "1995-06-18"
}
},
{
"_index": "people",
"_type": "man",
"_id": "3",
"_score": 1,
"_source": {
"name": "李四",
"country": "China",
"age": 25,
"date": "1995-10-17"
}
}
]
},
"aggregations": {
"group_by_age": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 25,
"doc_count": 3
},
{
"key": 28,
"doc_count": 1
}
]
}
}
}
``````markdown
"key": 30,
"doc_count": 1
}
]
}
}
}
```Можно заметить, что по данным, сгруппированным по возрасту (age), у нас есть 3 человека в возрасте 25 лет, по одному человеку в возрасте 28 и 30 лет.
```Для анализа поля age можно использовать метод stats. Запрос данных выглядит следующим образом:
```json
{
"aggs": {
"group_by_age": {
"stats": {
"field": "age"
}
}
}
}
```Возвращаемые данные имеют следующий вид:
{ "took": 4, "timed_out": false, "_shards": { "total": 3, "successful": 3, "skipped": 0, "failed": 0 }, "hits": { "total": 5, "max_score": 1, "hits": [ { "_index": "people", "_type": "man", "_id": "iIHS5GoBkW5tmvoc_T_u", "_score": 1, "_source": { "name": "sheng", "country": "China", "age": 30, "date": "1990-05-24" } }, { "_index": "people", "_type": "man", "_id": "2", "_score": 1, "_source": { "name": "张三", "country": "China", "age": 28, "date": "1992-11-20" } }, { "_index": "people", "_type": "man", "_id": "4", "_score": 1, "_source": { "name": "王五", "country": "China", "age": 25, "date": "1995-09-18" } }, { "_index": "people", "_type": "man", "_id": "5", "_score": 1, "_source": { "name": "王六", "country": "China", "age": 25, "date": "1995-06-18" } }, { "_index": "people", "_type": "man", "_id": "3", "_score": 1, "_source": { "name": "李四", "country": "China", "age": 25, "date": "1995-10-17" } } ] }, "aggregations": { "group_by_age": { "count": 5, "min": 25, "max": 30, "avg": 26.6, "sum": 133 } } } ``````Можно видеть анализ по полю age, включая общее количество, максимальное значение, минимальное значение, среднее значение и сумму.```#### (6) Расширенные запросы
Перед выполнением расширенных запросов нам нужно подготовить некоторые данные. Создаем индекс book
, тип которого novel
, и создаем 10 документов.
Для создания индекса и документов можно воспользоваться примерами из раздела people
выше. Из-за ограничений по объему текста, скрипт доступен по адресу: https://gitee.com/calvin-sheng/Technical-Document/blob/master/Создание_индекса_book_и_документов.txt. Пользователи могут самостоятельно скопировать и вставить его в Postman для выполнения.
В процессе выполнения запроса Elasticsearch вычисляет значение _SCORE
, которое указывает на степень соответствия документа запросу.
(1) Использование ключевого слова `match` для нечеткого поиска
{
"query":{
"match":{
"title":"введение"
}
}
}
```Возвращаемые данные
```{
"took": 7,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 2.4861822,
"hits": [
{
"_index": "book",
"_type": "novel",
"_id": "3",
"_score": 2.4861822,
"_source": {
"author": "Ли Сы",
"title": "Введение в Python",
"word_count": 2000,
"publish_date": "2005-10-01"
}
},
{
"_index": "book",
"_type": "novel",
"_id": "2",
"_score": 1.7968802,
"_source": {
"author": "Чжан Сын",
"title": "Введение в Java",
"word_count": 2000,
"publish_date": "2010-10-02"
}
},
{
"_index": "book",
"_type": "novel",
"_id": "4",
"_score": 1.7968802,
"_source": {
"author": "Ван У",
"title": "Введение в ElasticSearch",
"word_count": 1000,
"publish_date": "2010-10-01"
}
}
]
}
}
(2) Использование ключевого слова match_phrase
для точного соответствия фразы```json
{
"query":{
"match_phrase":{
"title":"ElasticSearch"
}
}
}
Возвращаемые данные
```json
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 1.4226693,
"hits": [
{
"_index": "book",
"_type": "novel",
"_id": "4",
"_score": 1.4226693,
"_source": {
"author": "Вань",
"title": "Введение в ElasticSearch",
"word_count": 1000,
"publish_date": "2010-10-01"
}
},
{
"_index": "book",
"_type": "novel",
"_id": "10",
"_score": 1.2430911,
"_source": {
"author": "Чжоу Вэнь",
"title": "ElasticSearch в действии",
"word_count": 10000,
"publish_date": "2015-09-28"
}
}
]
}
}
(3) Использование multi_match для поиска данных, содержащих calvin в поле автор или заголовок
{
"query":{
"multi_match":{
"query":"calvin",
"fields":["author","title"]
}
}
}
``````json
{
"took": 11,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 1.4599355,
"hits": [
{
"_index": "book",
"_type": "novel",
"_id": "1",
"_score": 1.4599355,
"_source": {
"author": "calvin",
"title": "Тайцзицюань",
"word_count": 1000,
"publish_date": "2000-10-01"
}
},
{
"_index": "book",
"_type": "novel",
"_id": "9",
"_score": 0.96669346,
"_source": {
"author": "Ван Цзюнь",
"title": "Калвин's绝命传说",
"word_count": 6000,
"publish_date": "2008-10-09"
}
}
]
}
}
```(4) Использование query_string для синтаксического поиска```json
{
"query":{
"query_string":{
"query":"(ElasticSearch AND 实战) OR Python"
}
}
}
Возвращаемые данные
{
"took": 5,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 3.9337728,
"hits": [
{
"_index": "book",
"_type": "novel",
"_id": "10",
"_score": 3.9337728,
"_source": {
"author": "周文",
"title": "ElasticSearch实战",
"word_count": 10000,
"publish_date": "2015-09-28"
}
},
{
"_index": "book",
"_type": "novel",
"_id": "3",
"_score": 1.3112576,
"_source": {
"author": "李四",
"title": "Python入门",
"word_count": 2000,
"publish_date": "2005-10-01"
}
}
]
}
}
(5) Использование query_string для поиска по нескольким полям
{
"query":{
"query_string":{
"fields":["title","author"],
"query":"ElasticSearch OR calvin"
}
}
}
```Возвращаемые данные```markdown
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 4,
"max_score": 1.4599355,
"hits": [
{
"_index": "book",
"_type": "novel",
"_id": "1",
"_score": 1.4599355,
"_source": {
"author": "calvin",
"title": "Тайцзицюань",
"word_count": 1000,
"publish_date": "2000-10-01"
}
},
{
"_index": "book",
"_type": "novel",
"_id": "4",
"_score": 1.4226693,
"_source": {
"author": "Ван Ву",
"title": "Введение в ElasticSearch",
"word_count": 1000,
"publish_date": "2010-10-01"
}
},
{
"_index": "book",
"_type": "novel",
"_id": "10",
"_score": 1.3112576,
"_source": {
"author": "Чжоу Вэнь",
"title": "ElasticSearch в действии",
"word_count": 10000,
"publish_date": "2015-09-28"
}
},
{
"_index": "book",
"_type": "novel",
"_id": "9",
"_score": 0.96669346,
"_source": {
"author": "Ван Цзюнь",
"title": "Легенда о смертельной битве Калвина",
"word_count": 6000,
"publish_date": "2008-10-09"
}
}
]
}
}
```2. Поиски на уровне полей: для структурированных данных, таких как числа, даты и т.д.
(1) Поиск книг с определенным количеством слов (1000)
{ "query":{ "term":{ "word_count":1000 } } }
Возвращаемые данные
{ "took": 14, "timed_out": false, "_shards": { "total": 3, "successful": 3, "skipped": 0, "failed": 0 }, "hits": { "total": 2, "max_score": 1, "hits": [ { "_index": "book", "_type": "novel", "_id": "4", "_score": 1, "_source": { "author": "Ван Вэй", "title": "Введение в ElasticSearch", "word_count": 1000, "publish_date": "2010-10-01" } }, { "_index": "book", "_type": "novel", "_id": "1", "_score": 1, "_source": { "author": "калвин", "title": "Тайцзицюань", "word_count": 1000, "publish_date": "2000-10-01" } } ] } }
(2) Поиск книг с количеством слов в определенном диапазоне (от 1000 до 2000)
{ "query":{ "range":{ "word_count":{ "gte":1000, "lte":2000 } } } }
```{
"took": 3,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 4,
"max_score": 1,
"hits": [
{
"_index": "book",
"_type": "novel",
"_id": "2",
"_score": 1,
"_source": {
"author": "张三",
"title": "Введение в Java",
"word_count": 2000,
"publish_date": "2010-10-02"
}
},
{
"_index": "book",
"_type": "novel",
"_id": "4",
"_score": 1,
"_source": {
"author": "王五",
"title": "Введение в ElasticSearch",
"word_count": 1000,
"publish_date": "2010-10-01"
}
},
{
"_index": "book",
"_type": "novel",
"_id": "3",
"_score": 1,
"_source": {
"author": "李四",
"title": "Введение в Python",
"word_count": 2000,
"publish_date": "2005-10-01"
}
},
{
"_index": "book",
"_type": "novel",
"_id": "1",
"_score": 1,
"_source": {
"author": "calvin",
"title": "Тайцзицюань",
"word_count": 1000,
"publish_date": "2000-10-01"
}
}
]
}
}
(3) Поиск книг, опубликованных в определённом диапазоне дат (с 01.01.2017 по 31.12.2017)```json { "query": { "range": { "publish_date": { "gte": "2015-01-01", "lte": "2018-12-31" } } } }
Возвращаемые данные
```json
{
"took": 8,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "book",
"_type": "novel",
"_id": "10",
"_score": 1,
"_source": {
"author": "周文",
"title": "ElasticSearch实战",
"word_count": 10000,
"publish_date": "2015-09-28"
}
}
]
}
}
(1) Поиск книг, содержащих 1000 слов
{
"query": {
"bool": {
"filter": {
"term": {
"word_count": 1000
}
}
}
}
}
Возвращаемые данные
{
"took": 10,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 0,
"hits": [
{
"_index": "book",
"_type": "novel",
"_id": "4",
"_score": 0,
"_source": {
"author": "王五",
"title": "ElasticSearch入门",
"word_count": 1000,
"publish_date": "2010-10-01"
}
},
{
"_index": "book",
"_type": "novel",
"_id": "1",
"_score": 0,
"_source": {
"author": "calvin",
"title": "太极拳",
"word_count": 1000,
"publish_date": "2000-10-01"
}
}
]
}
}
{
"author": "周文",
"title": "ElasticSearch实战",
"word_count": 10000,
"publish_date": "2015-09-28"
}
{
"author": "王五",
"title": "ElasticSearch入门",
"word_count": 1000,
"publish_date": "2010-10-01"
}
{
"author": "calvin",
"title": "太极拳",
"word_count": 1000,
"publish_date": "2000-10-01"
}
(1) Полный текстовый поиск - книги, в которых в заголовке содержится слово Elasticsearch
"took": 4,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 2,
"hits": [
{
"_index": "book",
"_type": "novel",
"_id": "4",
"_score": 2,
"_source": {
"author": "Ван Ву",
"title": "Введение в Elasticsearch",
"word_count": 1000,
"publish_date": "2010-10-01"
}
},
{
"_index": "book",
"_type": "novel",
"_id": "10",
"_score": 2,
"_source": {
"author": "Чжоу Вэнь",
"title": "Elasticsearch в действии",
"word_count": 10000,
"publish_date": "2015-09-28"
}
}
]
}
}
(2) Булев запрос - should (удовлетворяет любому условию)
``````markdown
{
"took": 5,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 1.4599355,
"hits": [
{
"_index": "book",
"_type": "novel",
"_id": "1",
"_score": 1.4599355,
"_source": {
"author": "calvin",
"title": "Тайцзицюань",
"word_count": 1000,
"publish_date": "2000-10-01"
}
},
{
"_index": "book",
"_type": "novel",
"_id": "8",
"_score": 1.1507283,
"_source": {
"author": "Сунь Юй",
"title": "Бескомпромиссный президент",
"word_count": 7600,
"publish_date": "2010-10-01"
}
}
]
}
}
(3) Булев запрос - должен удовлетворять хотя бы одному условию
{
"query": {
"bool": {
"should": [
{
"match": {
"author": "calvin"
}
},
{
"match": {
"title": "霸道总裁"
}
}
]
}
}
}
``````json
{
"query": {
"bool": {
"must": [
{
"match": {
"author": "周文"
}
},
{
"match": {
"title": "ElasticSearch"
}
}
]
}
}
}
Возвращаемые данные
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 3.586249,
"hits": [
{
"_index": "book",
"_type": "novel",
"_id": "10",
"_score": 3.586249,
"_source": {
"author": "周文",
"title": "ElasticSearch实战",
"word_count": 10000,
"publish_date": "2015-09-28"
}
}
]
}
}
(4) Использование must и filter для составного запроса
{
"query": {
"bool": {
"must": [
{
"match": {
"author": "周文"
}
},
{
"match": {
"title": "ElasticSearch"
}
}
],
"filter": [
{
"term": {
"word_count": 10000
}
}
]
}
}
}
Возвращаемые данные
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 3.586249,
"hits": [
{
"_index": "book",
"_type": "novel",
"_id": "10",
"_score": 3.586249,
"_source": {
"author": "周文",
"title": "ElasticSearch实战",
"word_count": 10000,
"publish_date": "2015-09-28"
}
}
]
}
}
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 3.586249,
"hits": [
{
"_index": "book",
"_type": "novel",
"_id": "10",
"_score": 3.586249,
"_source": {
"author": "周文",
"title": "ElasticSearch实战",
"word_count": 10000,
"publish_date": "2015-09-28"
}
}
]
}
}
```Добавление зависимостей elasticSearch.transport в файл pom.xml
```xml
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>5.6.1</version>
</dependency>
Создание конфигурационного класса для ElasticSearch
package com.calvin.es.config;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Title EsConfig
* @Description Конфигурационный класс для ElasticSearch
* @author calvin
* @date: 2019/5/27 1:23 PM
*/
@Configuration
public class EsConfig {
@Bean
public TransportClient client() throws UnknownHostException {
InetSocketTransportAddress node = new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300);
Settings settings = Settings.builder()
// имя кластера ES
.put("cluster.name", "calvin")
.build();
TransportClient client = new PreBuiltTransportClient(settings);
client.addTransportAddress(node);
return client;
}
}
/**
* Поиск одного документа
* @param id идентификатор документа
* @return
*/
@GetMapping(value = "get/book/novel")
public ResponseEntity<?> getAll(@RequestParam(name = "id", defaultValue = "") String id) {
if (id.isEmpty()) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
GetResponse result = this.client.prepareGet("book", "novel", id).get();
if (!result.isExists()) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>(result.getSource(), HttpStatus.OK);
}
Используя elasticsearch-head, можно увидеть, что документ с id=8 является тем, который нашел наш запрос.

/**

Обновите elasticsearch-head, чтобы увидеть новый созданный документ

#### Изменение отдельного документа```
/**
* Обновление отдельного документа
* @param book Класс-оболочка Book
* @param id Идентификатор документа
* @return
*/
@PutMapping(value = "/update/book/novel/{id}")
public ResponseEntity<?> update(@RequestBody Book book, @PathVariable(value = "id") String id) {
UpdateRequest update = new UpdateRequest("book", "novel", id);
try {
XContentBuilder builder = XContentFactory.jsonBuilder()
.startObject();
if (!StringUtils.isEmpty(book.getTitle())) {
builder.field("title", book.getTitle());
}
if (!StringUtils.isEmpty(book.getAuthor())) {
builder.field("author", book.getAuthor());
}
builder.endObject();
update.doc(builder);
UpdateResponse result = this.client.update(update).get();
return new ResponseEntity<>(result.toString(), HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
```
Обновление elasticsearch-head показало, что ранее созданные документы были изменены, и их заголовок и автор были обновлены.

#### Удаление одного документа
/**

Обновление elasticsearch-head показало, что ранее созданные документы были удалены.

#### Составной запрос
Фильтрация документов, где заголовок содержит "введение", и количество слов больше 2000, но меньше 20000.```
/**
* Compound query
* @param title title
* @param gtWordCount number of words greater than
* @param ltWordCount number of words less than
* @return
*/
@GetMapping("/query/book/novel")
public ResponseEntity<?> query(
@RequestParam(name = "title", required = false) String title,
@RequestParam(name = "gt_word_count", defaultValue = "0") int gtWordCount,
@RequestParam(name = "lt_word_count", required = false) Integer ltWordCount) {
// Creating boolean query
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
if (!StringUtils.isEmpty(title)) {
boolQuery.must(QueryBuilders.matchQuery("title", title));
}
// Creating range query
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("word_count").from(gtWordCount);
if (ltWordCount != null && ltWordCount > 0) {
rangeQuery.to(ltWordCount);
}
// Using filter to build query
boolQuery.filter(rangeQuery);
SearchRequestBuilder builder = this.client.prepareSearch("book")
.setTypes("novel")
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setQuery(boolQuery)
.setFrom(0)
.setSize(10);
log.info("[ES query parameters]:" + builder);
SearchResponse response = builder.get();
List<Map<String, Object>> result = new ArrayList<>();
for (SearchHit hit : response.getHits()) {
result.add(hit.getSource());
}
return new ResponseEntity<>(result, HttpStatus.OK);
}
Проверил результаты, отфильтрованные программой, и не обнаружил проблем.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )