1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/calvin-sheng-springboot-elasticsearch

В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
Elasticsearch安装使用及SpringBoot集成ES.md 54 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 04.06.2025 06:43 6af58fb

Установка и использование Elasticsearch и интеграция с Spring Boot

Для удобства работы я выбрал традиционный метод установки через распаковку архива, а не через Docker.

1. Установка Elasticsearch

Перейдите на официальный сайт: 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.

2. Установка elasticsearch-head

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. Вставьте описание изображения

3. Горизонтальное масштабирование Elasticsearch

Здесь я настрою один мастер-узел и два рабочих узла.

Сначала настроим мастер-узел, установим имя кластера в calvin

# Настройка мастера
cluster.name: calvin
node.name: master
node.master: true

Привязанный IP

network.host: 127.0.0.1


Перезапустите Elasticsearch, и вы увидите
![введите описание изображения здесь](https://images.gitee.com/uploads/images/2019/1024/113317_14e6d423_880818.jpeg "15585392045650.jpg")
![введите описание изображения здесь](https://images.gitee.com/uploads/images/2019/1024/113403_29a4e5f4_880818.jpeg "15585392212388.jpg")


Затем мы копируем распакованный пакет, создаем узел salve1. Изменяем elasticsearch.yml. Обратите внимание, что имя кластера должно совпадать с именем кластера узла master.

Настройка salve

cluster.name: calvin node.name: salve1

Привязанный IP

network.host: 127.0.0.1

Настройка порта, чтобы избежать конфликта портов с master

http.port: 8200

Настройка одноранговой связи кластера, подключение к узлу master

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 уже отображены.

введите описание изображения здесь

4. Основные понятия и операции Elasticsearch

Индекс: набор документов с одинаковыми свойствами
Тип: индекс может определять один или несколько типов, документы должны принадлежать к типу
Документ: документ — это базовая единица данных, которую можно индексировать
Фрагмент: каждый индекс имеет несколько фрагментов, каждый фрагмент — это Lucene-индекс
Резервная копия: копирование фрагмента создает резервную копию фрагмента

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

Основной формат API: http://:/<индекс>/<тип>/<документid> Основные HTTP-методы: GET/PUT/POST/DELETE


* Неструктурированное создание
![введите описание изображения здесь](https://images.gitee.com/uploads/images/2019/1024/114024_4eb04233_880818.jpeg "15586142780923.jpg")Индекс --> Создать индекс, по умолчанию количество основных фрагментов равно 5, количество резервных равно 1.
![введите описание изображения здесь](https://images.gitee.com/uploads/images/2019/1024/114041_fcc93740_880818.jpeg "15586143555329.jpg")

Где толстые черные рамки обозначают основные фрагменты, а тонкие черные рамки обозначают резервные копии основных фрагментов.

При нажатии на информацию под book --> Информация об индексе, можно увидеть, что mappings пустые, что указывает на то, что этот индекс является неструктурированным.
![введите описание изображения здесь](https://images.gitee.com/uploads/images/2019/1024/114133_098ee19e_880818.jpeg "15586145091344.jpg")

* Структурированное создание
![введите описание изображения здесь](https://images.gitee.com/uploads/images/2019/1024/114211_d25bc51d_880818.jpeg "15586161176392.jpg")

Метод запроса изменен на 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 и нажатии на информацию --> Информация об индексе, можно увидеть:
![введите описание изображения здесь](https://images.gitee.com/uploads/images/2019/1024/115513_9af0fbd8_880818.jpeg "15586162566402.jpg")

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

#### (2) Вставка

* Вставка с указанием идентификатора документа
![введите описание изображения здесь](https://images.gitee.com/uploads/images/2019/1024/115617_0fe2d6d5_880818.jpeg "15586168652587.jpg")

Метод запроса изменен на PUT, данные запроса:

{ "name":"calvin", "country":"China", "age":27, "date":"1993-12-20" }


При обновлении elasticsearch-head, можно увидеть, что количество документов равно 1.
![введите описание изображения здесь](https://images.gitee.com/uploads/images/2019/1024/115648_68ad6422_880818.jpeg "15586169527481.jpg")

При переходе к просмотру данных, можно увидеть вставленные нами данные.
![введите описание изображения здесь](https://images.gitee.com/uploads/images/2019/1024/115706_68b19a5f_880818.jpeg "15586170136479.jpg")

* Автоматически генерируемый документный идентификатор вставляется
![Введите описание изображения](https://images.gitee.com/uploads/images/2019/1024/115732_d3585673_880818.jpeg "15586172392479.jpg")

Метод запроса изменен на POST, данные запроса:

{ "name":"sheng", "country":"China", "age":30, "date":"1990-05-24" }


После этого обновите elasticsearch-head, чтобы увидеть, что документ был автоматически создан.![Введите описание изображения](https://images.gitee.com/uploads/images/2019/1024/120048_38bb5f8b_880818.jpeg "15586173182129.jpg")

#### (3) Изменение

Измените информацию о документе, например, измените значение атрибута name в документе с id=1
![Введите описание изображения](https://images.gitee.com/uploads/images/2019/1024/120120_5395cad7_880818.jpeg "15586176292879.jpg")

Метод запроса изменен на POST, данные запроса:

{ "doc":{ "name":"周杰伦" } }


Обновите elasticsearch-head, чтобы увидеть, что значение name в документе с id=1 изменилось с calvin на 周杰伦.

![Введите описание изображения](https://images.gitee.com/uploads/images/2019/1024/141057_5efb5399_880818.jpeg "15586177882096.jpg)

#### (4) Удаление

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

![Введите описание изображения](https://images.gitee.com/uploads/images/2019/1024/141219_9dc89b55_880818.jpeg "15586181587864.jpg")

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

![Введите описание изображения](https://images.gitee.com/uploads/images/2019/1024/141244_f1d0bfc8_880818.jpeg "15586182220012.jpg)

Аналогично, если нам нужно удалить тип, URL-запрос изменяется на: http://localhost:9200/people/man/ для удаления индекса - на: http://localhost:9200/people/

Конечно, мы также можем удалить индекс напрямую в elasticsearch-head, например, удалим ранее созданный индекс book.

![Введите описание изображения](https://images.gitee.com/uploads/images/2019/1024/141309_6140b19d_880818.jpeg "15586185334397.jpg)

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

![Введите описание изображения](https://images.gitee.com/uploads/images/2019/1024/141337_24a23ee1_880818.jpeg "15586185659653.jpg")

Измените тексты в кавычках на русский язык:

"周杰伦" на "Чжань Цзэлун"
"calvin" на "калвин"
"people/man/" на "люди/мужчина/"
"people/" на "люди/"
"book" на "книга"#### (5) Поиск

Для тестирования я создал несколько новых записей.

![Введите описание изображения](https://images.gitee.com/uploads/images/2019/1024/141703_fb6ef83c_880818.jpeg "15586196565163.jpg")

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

![Введите описание изображения](https://images.gitee.com/uploads/images/2019/1024/141853_9772674a_880818.jpeg "15586188772725.jpg")

* Условный поиск

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

![Вставьте изображение здесь](https://images.gitee.com/uploads/images/2019/1024/145110_68871ea0_880818.jpeg "15586197159082.jpg")

Метод запроса изменяется на POST, а данные запроса будут следующими:

{ "query":{ "match_all":{} } }


Указываем количество возвращаемых данных и с какого элемента начинать. Модифицируем запрос следующим образом:

{ "query":{ "match_all":{} }, "from": 1, "size": 1 }


![Вставьте изображение здесь](https://images.gitee.com/uploads/images/2019/1024/145147_4e47ffa2_880818.jpeg "15586197560644.jpg")

Фильтруем данные по возрасту 25 и сортируем по дате (дата рождения) в порядке убывания.

Метод запроса изменяется на POST, а данные запроса будут следующими:

{ "query":{ "match":{ "age":25 } }, "sort":[ { "date":{ "order":"desc" } } ] }


![Вставьте изображение здесь](https://images.gitee.com/uploads/images/2019/1024/145225_8074c441_880818.jpeg "15586201694685.jpg")Возвращаемые данные:```
{
    "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` можно настраивать по своему усмотрению.

![Входное изображение](https://images.gitee.com/uploads/images/2019/1024/145348_42532691_880818.jpeg "Входное изображение")```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 для выполнения.

Изображение

1. Запрос с подусловиями: указывает на поиск по определенному полю с определенным значением.
  • Запросный контекст

В процессе выполнения запроса Elasticsearch вычисляет значение _SCORE, которое указывает на степень соответствия документа запросу.

  1. Полный текстовый запрос: для данных типа текст
(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"
                }
            }
        ]
    }
}
2. Фильтрация
(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"
                }
            }
        ]
    }
}
3. Комбинированные условия: объединение подусловий с помощью логических операторов
{
    "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"
                }
            }
        ]
    }
}

5. Интеграция SpringBoot с ES

{
    "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 является тем, который нашел наш запрос.

![введите описание изображения здесь](https://images.gitee.com/uploads/images/2019/1024/155419_c895ae20_880818.jpeg "15589715183562.jpg)

Добавление одного документа```

/**

  • Добавление отдельного документа
  • @param book Класс-оболочка Book
  • @return */ @PostMapping("/add/book/novel") public ResponseEntity<?> add(@RequestBody Book book) { try { XContentBuilder content = XContentFactory.jsonBuilder() .startObject() .field("title", book.getTitle()) .field("author", book.getAuthor()) .field("word_count", book.getWordCount()) .field("publish_date", DateUtils.formatDate(book.getPublishDate(), "yyyy-MM-dd")) .endObject(); IndexResponse result = this.client.prepareIndex("book", "novel").setSource(content).get(); return new ResponseEntity<>(result.getId(), HttpStatus.OK); } catch (IOException e) { e.printStackTrace(); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } }

![введите описание изображения здесь](https://images.gitee.com/uploads/images/2019/1024/155538_bc888fcd_880818.jpeg "15589705072698.jpg")

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

![введите описание изображения здесь](https://images.gitee.com/uploads/images/2019/1024/155641_a904fb39_880818.jpeg "15589705366987.jpg")

#### Изменение отдельного документа``` 
/**
 * Обновление отдельного документа
 * @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);
    }
}
```![введите описание изображения здесь](https://images.gitee.com/uploads/images/2019/1024/155727_c53a4e25_880818.jpeg "15589707378643.jpg")
Обновление elasticsearch-head показало, что ранее созданные документы были изменены, и их заголовок и автор были обновлены.

![Вставьте описание изображения](https://images.gitee.com/uploads/images/2019/1024/155756_10c2502a_880818.jpeg "15589707614813.jpg")

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

/**

  • Удаление одного документа
  • @param id идентификатор документа
  • @return */ @DeleteMapping(value = "/delete/book/novel/{id}") public ResponseEntity<?> delete(@PathVariable(value = "id") String id) { DeleteResponse result = this.client.prepareDelete("book", "novel", id).get(); return new ResponseEntity<>(result.toString(), HttpStatus.OK); }

![Вставьте описание изображения](https://images.gitee.com/uploads/images/2019/1024/155833_530c1233_880818.jpeg "15589708827979.jpg")
Обновление elasticsearch-head показало, что ранее созданные документы были удалены.

![Вставьте описание изображения](https://images.gitee.com/uploads/images/2019/1024/155858_298a328d_880818.jpeg "15589709287896.jpg")

#### Составной запрос
Фильтрация документов, где заголовок содержит "введение", и количество слов больше 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 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/calvin-sheng-springboot-elasticsearch.git
git@api.gitlife.ru:oschina-mirror/calvin-sheng-springboot-elasticsearch.git
oschina-mirror
calvin-sheng-springboot-elasticsearch
calvin-sheng-springboot-elasticsearch
master