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

OSCHINA-MIRROR/zxporz-ESClientRHL

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
README.md 73 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
gitlife-traslator Отправлено 01.12.2024 02:58 2385356

EsClientRHL — это инструмент для вызова и работы с Elasticsearch на основе Springboot. Он основан на официальном RestHighLevelClient и включает в себя инструменты для работы со структурой индексов, их данными, а также инструменты поиска и анализа данных.

Инструмент позволяет легко интегрировать Elasticsearch и использовать его функции. EsClientRHL предоставляет следующие возможности:

  • выбор между TransportClient и RestHighLevelClient;
  • поддержка более широкого спектра API-вызовов по сравнению с Spring-Data-Elasticsearch;
  • упрощение использования Java Client API;
  • автоматизация создания структуры индексов и обновления сущностей;
  • возможность создания «чёрной магии» для взаимодействия с Elasticsearch через один интерфейс;
  • набор инструментов для работы с индексами, включая поиск, анализ и другие функции;
  • использование лучших практик в работе с Elasticsearch.

EsClientRHL разработан для Elasticsearch версии 7 и выше. В случае конфликта версий рекомендуется явно указать версию Elasticsearch в файле pom.xml проекта.

Быстрое использование

Для быстрого внедрения EsClientRHL можно использовать демонстрационную версию springboot, доступную по ссылке https://gitee.com/zxporz/esclientrhlDemo.

Выбор EsClientRHL

Причины выбора этого инструмента включают:

  • отказ от TransportClient в пользу RestHighLevelClient, рекомендованного Elasticsearch;
  • поддержку более широкого спектра вызовов API по сравнению со Spring-Data-Elasticsearch;
  • способность упростить использование Java Client API и постоянно обновлять его;
  • две функции автоматизации, которые облегчают работу разработчиков;
  • наличие в составе инструмента функций для работы с индексами и других API.

В EsClientRHL некоторые API объединены с лучшими практиками использования Elasticsearch. Инструмент может быть полезен разработчикам, и его авторы просят поставить звёздочку на странице проекта на Gitee, если он оказался полезным.

Версия и обновление

EsClientRHL разрабатывается на основе Elasticsearch версии 7. Версия Elasticsearch должна быть указана в файле pom.xml, чтобы избежать конфликтов с родительским проектом springboot.

Информация об обновлениях включает дату и описание изменений. Например, одно из обновлений содержит исправление ошибки в поиске и добавление новых функций, таких как удаление по условию и возможность поиска по нескольким индексам. Также добавлено сжатие пакета с тестовым кодом и документацией.

С каждым обновлением добавляются новые функции и исправляются ошибки. Последние обновления включают поддержку аутентификации пользователей, оптимизацию запросов и улучшение работы с различными типами данных. Поддержка Alias-запросов, возможность переключения Alias-индексов.

Агрегатные запросы:

  • нативные агрегатные запросы;
  • обычные агрегатные запросы;
  • групповые обычные агрегатные запросы;
  • двухуровневые агрегатные запросы;
  • статистические агрегатные запросы;
  • групповые статистические агрегатные запросы;
  • базовые запросы;
  • процентные агрегатные запросы;
  • процентильные агрегатные запросы;
  • запросы с фильтрами;
  • гистограммные агрегатные запросы;
  • агрегатные запросы с датами и гистограммами.

Структура исходного кода инструмента

Annotation

Содержит некоторые аннотации для упрощения использования компонентов.

Config

Основан на SpringBoot, включает автоматическую конфигурацию компонентов клиента ES.

Auto

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

Enums

Перечисление основных данных.

Index

Управление структурой индексов.

Repository

CURD + агрегатные функции.

Util

Внутренний пакет инструментов.

Начало работы

Пример использования

https://gitee.com/zxporz/esclientrhlDemo

Перед использованием

— Компоненты скомпилированы с использованием JDK1.8, обратите внимание на выбор версии JDK. — В настоящее время поддерживается только интеграция со Springboot, для интеграции с обычной системой Spring потребуется небольшая модификация. — Если вам не нужно использовать встроенный метод интеграции компонентов, просто обратитесь к способу интеграции с ES, обращая внимание на код в классе ElasticsearchTemplateImpl.

Зависимости Maven

pom-файл:

<dependency>
    <groupId>cn.zxporz</groupId>
    <artifactId>esclientrhl</artifactId>
    <version>7.0.0</version>
</dependency>

Обратите внимание: рекомендуется добавить номер версии Elasticsearch в pom-файл проекта Springboot, иначе он может быть перекрыт родительским проектом Springboot.

<properties>
……
<elasticsearch.version>7.3.1</elasticsearch.version>
……
</properties>

Добавление компонента

Добавление аннотации EnableESTools

Добавьте аннотацию @EnableESTools к классу запуска Springboot для автоматической инъекции сервисов инструментов, упрощённой конфигурации и автоматического обнаружения классов сущностей структуры индекса ES, а также для распознавания интерфейса ESCRepository и автоматической генерации прокси.

Использование аннотации @EnableESTools: Способ 1: полная конфигурация

@EnableESTools(
basePackages = {"Путь пакета интерфейса ESCRepository"},
entityPath = {"Путь пакета класса сущности"},
printregmsg = true)//См. раздел функций управления

Способ 2: минимальная конфигурация По умолчанию сканируются все классы в пакете, где находится класс запуска Springboot.

@EnableESTools

Способ 3: сканирование только пути класса сущности

@EnableESTools({"Путь пакета класса сущности"})

Добавьте аннотацию @EnableESTools в класс запуска Springboot:

@SpringBootApplication
@EnableESTools
public class EsdemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(EsdemoApplication.class, args);
    }
}
application.properties добавляет URI службы Elasticsearch

В файле application.properties добавьте URI службы Elasticsearch. Если есть несколько (кластерная ситуация), используйте запятые для разделения, и это обязательно.

elasticsearch.host=127.0.0.1:9200

application.properties добавляет параметры конфигурации пула соединений HTTP-клиента Elasticsearch

#Максимальное количество подключений в пуле подключений
elasticsearch.max_connect_total=30
#Количество запросов, которые могут быть одновременно получены от каждого маршрута
elasticsearch.max_connect_per_route=10
#Время ожидания получения соединения в HTTP-клиенте
elasticsearch.connection_request_timeout_millis=2000
#Тайм-аут ответа, если ответ не получен в течение этого времени, чтение ответа прекращается
elasticsearch.socket_timeout_millis=30000
#Время ожидания установления соединения
elasticsearch.connect_timeout_millis=2000
application.properties добавляет имя пользователя и пароль Elasticsearch (поддерживается только версия es7+)

Необязательно.

elasticsearch.username=elastic
elasticsearch.password=changeme

Использование компонента

Автоматически внедряет два встроенных сервиса инструментов ElasticsearchTemplate и ElasticsearchIndex в управляемый компонент Spring и вызывает соответствующий API.

@Service
public class CompletionSuggestServiceImpl implements CompletionSuggestService {
    @Autowired
    ElasticsearchTemplate<Book,String> elasticsearchTemplate;

Если вы хотите использовать только некоторые простые основные функции, рекомендуется использовать интерфейс прокси. Определите интерфейс, наследуя от интерфейса ESCRepository.

public interface Main2Repository<Main2,String> extends ESCRepository<Main2,String> {
}

При использовании просто импортируйте определённый интерфейс.

@Autowired
Main2Repository main2Repository;

Используйте методы, аналогичные ElasticsearchTemplate, за исключением того, что некоторые базовые методы были удалены.

Main2 main2 = new Main2();
main2.setProposal_no("qq123549440");
main2.setBusiness_nature_name("渠道");
main2.setAppli_name("esclientrhl");
main2Repository.save(main2);
System.out.println(main2Repository.getById("22222"));

Map map2 = main2Repository.aggs("proposal_no", AggsType.count,null,"appli_name");
map2.forEach((o, o2) -> System.out.println(o + "=====" + o2));

Примечание: при использовании метода автоматического проксирования интерфейса необходимо учитывать следующие моменты:

  1. Интерфейс должен наследовать от ESCRepository, и при определении интерфейса необходимо указать реальный тип дженериков.
  2. Соответствующий класс сущности должен быть аннотирован ESMetaData, чтобы компонент мог автоматически распознавать его.
  3. Имя класса сущности не должно повторяться во всём проекте, иначе создание класса прокси завершится неудачно.

Функции управления индексами

Метаданные конфигурации

Используется для настройки метаданных структуры индекса, соответствующей классу сущности ES.

@ESMetaData(indexName = "index", number_of_shards = 5,number_of_replicas = 0)

Основные конфигурации включают:

/**
 * Имя индекса поиска, по умолчанию совпадает с indexName, не рекомендуется, рекомендуется использовать конкретные методы для межиндексного запроса
 */
String[] searchIndexNames() default {};
/**
 * Имя индекса, обязательное
 */
String indexName();
/**
 * Тип индекса, необязательно, рекомендуется иметь только один тип в каждом индексе
 */
String indexType() default "";
/**
 * Количество основных сегментов
 */
int number_of_shards() default 5;
/**
 * Количество резервных сегментов
 */
int number_of_replicas() default 1;
/**
 * Логирование включено
 * @return
 */
boolean printLog() default false;
/**
 * Если установлено значение true, то alias будет использоваться как индексное имя, после установки этой опции функция автоматического создания индекса будет отключена
 * indexName является именем alias
 * @return
 */
 boolean alias() default false;

/**
* Имя псевдонима, соответствующее индексу
*
``` ```
    currentConfigOnlyEffectiveWhenConfiguredAliasButNotRollover();

    *注意:所有配置的index必须存在*

    @return
*/
String[] aliasIndex() default {};

/**
*当配置了alias后,指定哪个index为writeIndex
*当前配置仅生效于配置了alias但没有配置rollover
*注意:配置的index必须存在切在aliasIndex中
*@return
*/
String writeIndex() default "";

/**
*当配置了rollover为true时,开启rollover功能(并忽略其他alias的配置)
*aliasName为indexName
*索引名字规格为:indexName-yyyy.mm.dd-00000n
*索引滚动生成策略如下
*@return
*/
boolean rollover() default false;

 /**
 *自动执行rollover相关配置
 *自动执行rollover开关
 *@return
 */
 boolean autoRollover() default false;

/**
*自动执行rollover相关配置
*项目启动后延迟autoRolloverInitialDelay时间后开始执行
*@return
*/
long autoRolloverInitialDelay() default 0L;

/**
*自动执行rollover相关配置
*项目启动后每间隔autoRolloverPeriod执行一次
*@return
*/
long autoRolloverPeriod() default 4L;

/**
*自动执行rollover相关配置
*单位时间配置,与autoRolloverPeriod、autoRolloverInitialDelay对应
*@return
*/
TimeUnit autoRolloverTimeUnit() default TimeUnit.HOURS;


/**
*当前索引超过此项配置的时间后生成新的索引
*@return
*/
long rolloverMaxIndexAgeCondition() default 0L;

/**
*与rolloverMaxIndexAgeCondition联合使用,对应rolloverMaxIndexAgeCondition的单位
*@return
*/
TimeUnit rolloverMaxIndexAgeTimeUnit() default TimeUnit.DAYS;

/**
*当前索引文档数量超过此项配置的数字后生成新的索引
*@return
*/
long rolloverMaxIndexDocsCondition() default 0L;

/**
*当前索引大小超过此项配置的数字后生成新的索引
*@return
*/
long rolloverMaxIndexSizeCondition() default 0L;

/**
*与rolloverMaxIndexSizeCondition联合使用,对应rolloverMaxIndexSizeCondition的单位
*@return
*/
ByteSizeUnit rolloverMaxIndexSizeByteSizeUnit() default ByteSizeUnit.GB;

/**
*最大分页深度
*@return
*/
long maxResultWindow() default 10000L;

/**
*索引名称是否自动包含后缀
*@return
*/
boolean suffix() default false;

/**
*是否自动创建索引
*@return
*/
boolean autoCreateIndex() default true;
索引结构配置

用于定制es索引结构对应实体类的索引结构,以简化创建索引工作。将相关注解配置于实体类field上,用于标识field对应elasticsearch索引结构字段的相关信息

@ESID
private String proposal_no;
@ESMapping(datatype = DataType.keyword_type)
private String risk_code;
@ESMapping(datatype = DataType.text_type)
private String risk_name;

@ESID标识es主键(自动对应es索引数据_id字段),注意:主键的类型需要与ElasticsearchTemplate的第二泛型一致

@ESMapping标识字段对应es索引结构字段的相关信息

/**
 *数据类型(包含 关键字类型)
 */
DataType datatype() default DataType.text_type;
/**
 *间接关键字
 */
boolean keyword() default true;
/**
 *关键字忽略字数
 */
int ignore_above() default 256;
/**
 *是否支持ngram,高效全文搜索提示(定制gram分词器,请参照官方例https://www.elastic.co/guide/en/elasticsearch/reference/7.x/analysis-ngram-tokenizer.html)
 */
boolean ngram() default false;
/**
 *是否支持suggest,高效前缀搜索提示
 */
boolean suggest() default false;
/**
 *索引分词器设置(研究类型)
 */
Analyzer analyzer() default Analyzer.standard;
/**
 *搜索内容分词器设置
 */
Analyzer search_analyzer() default Analyzer.standard;
/**
 *是否允许被搜索
 */
boolean allow_search() default true;

/**
 *拷贝到哪个字段,代替_all
 */
String copy_to() default "";

/**
*null_value指定,默认空字符串不会为mapping添加null_value
*对于值是null的进行处理,当值为null是按照注解指定的‘null_value’值进行查询可以查到
*需要注意的是要与根本没有某字段区分(没有某字段需要用Exists Query进行查询)
*建议设置值为NULL_VALUE
*@return
*/
String null_value() default "";

/**
*nested对应的类型,默认为Object.Class。
*对于DataType是nested_type的类型才需要添加的注解,通过这个注解生成嵌套类型的索引
*例如:
*@ESMapping(datatype = DataType.nested_type, nested_class = EsFundDto.class)
*
*@return
*/
Class nested_class() default Object.class;

如果对字段类型要求没有那么高,则不配置,组件可以支持自动适配mapping

根据配置信息自动创建索引结构mapping

项目启动时,组件会自动识别es实体类上配置的@ESMetaData注解,如果对应的索引结构没有创建,自动根据mapping注解配置创建相关索引结构。

Если实体类不在启动类的包路径下,如需启用此功能,需要在启动注解上配置实体类路径。

@EnableESTools(entityPath = "com.*.esdemo.domain")
GEO类型

https://www.elastic.co/guide/en/elasticsearch/client/java-api/7.9/java-geo-queries.html

如果需要支持经纬度搜索,则需要增加一个经纬度的字段

    @ESMapping(datatype = DataType.geo_point_type)
    GeoEntity geo;

data_typeDataType.geo_point_type,实体类固定为GeoEntity

参考代码如下:

GeoEntity gp1 = new GeoEntity(1,1);
GeoPojo g1 = new GeoPojo();
g1.setGeo(gp1);
g1.setPlace("1");
g1.setUserId(1L);
g1.setUserName("1");
elasticsearchTemplate.save(Arrays.asList(g1));
GeoPoint topLeft = new GeoPoint(32.030249,118.789703);
        GeoPoint bottomRight = new GeoPoint(32.024341,118.802171);
        GeoBoundingBoxQueryBuilder **CRUD-функционал: описание**

**Низкоуровневый клиент: запрос**

Этот метод обычно используется для прямого запроса или операции с сервером Elasticsearch, без большого количества обёрток. Он сохраняет исходные параметры ввода и вывода.

// Автоматическое внедрение инструментального класса @Autowired ElasticsearchTemplate elasticsearchTemplate;

// Выполнение запроса Request request = new Request("GET", "/esdemo/_search"); request.setEntity(new NStringEntity("{"query":{"match_all":{"boost":1.0}}}", ContentType.APPLICATION_JSON)); Response response = elasticsearchTemplate.request(request); RequestLine requestLine = response.getRequestLine(); HttpHost host = response.getHost(); int statusCode = response.getStatusLine().getStatusCode(); Header[] headers = response.getHeaders(); String responseBody = EntityUtils.toString(response.getEntity()); System.out.println(responseBody);


**Добавление данных в индекс**

Если не указано иное, все запросы ниже предполагают использование инструментальных классов. Первый универсальный тип инструментального класса — это класс структуры индекса, который нужно изменить, а второй универсальный тип — это класс первичного ключа индекса.

@Autowired ElasticsearchTemplate<Main2, String> elasticsearchTemplate;

Здесь Main2 — тип первичного ключа, который является строкой.

@ESMetaData(indexName = "index", number_of_shards = 5, number_of_replicas = 0) public class Main2 implements Serializable { private static final long serialVersionUID = 1L; @ESID private String proposal_no; }

Main2 main = new Main2(); main.setProposal_no("main2"); main.setAppli_code("123"); main.setAppli_name("456"); elasticsearchTemplate.save(main);

Можно настроить поле маршрутизации (routing), чтобы указать, на какой сегмент будет помещён элемент данных.

Main2 main2 = new Main2(); main2.setProposal_no("qq360"); main2.setAppli_name("zzxxpp"); elasticsearchTemplate.save(main2, "R01");


**Пакетное добавление данных в индекс**

List list = new ArrayList<>(); Main2 main1 = new Main2(); main1.setProposal_no("main1"); main1.setAppli_code("123"); main1.setAppli_name("456"); Main2 main2 = new Main2(); main2.setProposal_no("main2"); main2.setAppli_code("123"); main2.setAppli_name("456"); Main2 main3 = new Main2(); main3.setProposal_no("main3"); main3.setAppli_code("123"); main3.setAppli_name("456"); list.add(main1); list.add(main2); list.add(main3); elasticsearchTemplate.save(list);


**Разделение пакетного добавления данных на части**

По сравнению с пакетным добавлением данных разделение на части учитывает ограничения памяти сервера Elasticsearch при пакетной обработке данных и разделяет передаваемый список данных на более мелкие части для последовательной индексации. Вы можете изменить значения переменных в классе конфигурации org.zxp.esclientrhl.util.Constant, чтобы адаптировать его к лучшим практикам. По умолчанию размер пакета составляет 5000 элементов.

Разделение на части предоставляет новый метод:

Main2 main1 = new Main2(); main1.setProposal_no("aaa"); main1.setBusiness_nature_name("aaaaaa2"); Main2 main2 = new Main2(); main2.setProposal_no("bbb"); main2.setBusiness_nature_name("aaaaaa2"); Main2 main3 = new Main2(); main3.setProposal_no("ccc"); main3.setBusiness_nature_name("aaaaaa2"); Main2 main4 = new Main2(); main4.setProposal_no("ddd"); main4.setBusiness_nature_name("aaaaaa2"); elasticsearchTemplate.saveBatch(Arrays.asList(main1, main2, main3, main4));


**Частичное обновление данных индекса**

Main2 main1 = new Main2(); main1.setProposal_no("main1"); main1.setInsured_code("123"); elasticsearchTemplate.update(main1);


**Полное обновление данных индекса**

Main2 main1 = new Main2(); main1.setProposal_no("main1"); main1.setInsured_code("123"); elasticsearchTemplate.updateCover(main1);

Частичное обновление отличается от полного обновления тем, что оно обновляет только установленные значения полей.

**Пакетное обновление данных индекса**

/**

  • Согласно результатам запроса queryBuilder, обновить поля, удовлетворяющие условиям, до значений t.
  • @param queryBuilder
  • @param t Удовлетворяет условиям запроса queryBuilder и обновляет значения соответствующих полей до t
  • @param clazz
  • @param limitcount Максимальное количество обновляемых полей
  • @param asyn true асинхронная обработка, иначе синхронная обработка
  • @return
  • @throws Exception */ public BulkResponse batchUpdate(QueryBuilder queryBuilder, T t, Class clazz, int limitcount, boolean asyn) throws Exception;

// Обновить sum_amount до 1000 для всех результатов запроса, где appli_name равно «123», асинхронно, максимум 30 обновлений Main2 main1 = new Main2(); main1.setSum_amount(1000); elasticsearchTemplate.batchUpdate(QueryBuilders.matchQuery("appli_name", "123"), main1, Main2.class, 30, true);

Пакетное обновление не поддерживает полное обновление.

**Разделение пакетного обновления данных на части**

Стратегия разделения на части описана в разделе «Разделение пакетного добавления данных на части». **Текст запроса написан на языке Java.**

В запросе содержатся фрагменты кода, которые представляют собой примеры использования различных методов для работы с данными в Elasticsearch. 

**Переведённый текст:**

main3.setBusiness_nature_name("aaaaaa2"); Main2 main4 = new Main2(); main4.setProposal_no("ddd"); main4.setBusiness_nature_name("aaaaaa2"); elasticsearchTemplate.bulkUpdateBatch(Arrays.asList(main1,main2,main3,main4));


* * *  

// Удаление индекса данных

Main2 main1 = new Main2(); main1.setProposal_no("main1"); main1.setInsured_code("123"); elasticsearchTemplate.delete(main1); // Через объект удаляем, ID должен иметь значение

// Через ID удаляем elasticsearchTemplate.deleteById("main1", Main2.class);


* * *

// Настройка удаления информации о маршрутизации

// Только если информация о маршрутизации указана правильно, можно удалить успешно elasticsearchTemplate.delete(main2,"R02"); // Независимо от того, указана ли информация о маршрутизации в индексе данных, её можно удалить elasticsearchTemplate.delete(main2);


* * *

// Согласно условиям запроса удаляем индекс данных

elasticsearchTemplate.deleteByCondition(QueryBuilders.matchQuery("appli_name","2"),Main5.class);


* * *

// Определяем, существует ли индекс данных

Main2 main1 = new Main2(); main1.setProposal_no("main1"); main1.setInsured_code("123"); boolean exists = elasticsearchTemplate.exists("main1",Main2.class); System.out.println(exists);


* * *

// Исходный запрос

searchRequest — это официальный исходный запрос ввода, этот метод используется, когда инструмент не может удовлетворить требования

SearchRequest searchRequest = new SearchRequest(new String[]{"index"}); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(new MatchAllQueryBuilder()); searchSourceBuilder.from(0); searchSourceBuilder.size(10); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = elasticsearchTemplate.search(searchRequest);

SearchHits hits = searchResponse.getHits(); SearchHit[] searchHits = hits.getHits(); for (SearchHit hit : searchHits) { Main2 t = JsonUtils.string2Obj(hit.getSourceAsString(), Main2.class); System.out.println(t); }


* * *

// Поддержка запросов через URI

Используя способ URI + параметры (запрос строки), запрашиваем и возвращаем результаты

api использует официальные документы: https://www.elastic.co/guide/en/elasticsearch/reference/7.0/search-uri-request.html

// "q=aaa" поиск поля, содержащего aaa, возвращает результат List list = elasticsearchTemplate.searchUri("q=aaa",Main2.class); // "q=sum_premium:100" поиск sum_premium равен 100, возвращает результат List list = elasticsearchTemplate.searchUri("q=sum_premium:100",Main2.class);

Примечание: некоторые расширенные функции запроса URI (например, запросы диапазона) могут быть недоступны


* * *

// Поддерживает SQL-запросы

Передайте оператор SQL (поддерживающий синтаксис MySQL) в метод и верните результаты в различных формах (метод возвращает текст)

Следует отметить, что этот метод не поддерживает автоматическое определение индексов, необходимо правильно указать индекс после from (различать прописные и строчные буквы) Кроме того, этот метод также не поддерживает автоматическую трансляцию типов

// Полный запрос String result = elasticsearchTemplate.queryBySQL("SELECT * FROM index ORDER BY sum_premium DESC LIMIT 5", SqlFormat.TXT); // Запрос количества String result = elasticsearchTemplate.queryBySQL("SELECT count(*) FROM index ", SqlFormat.TXT); // Групповой запрос String result = elasticsearchTemplate.queryBySQL("SELECT risk_code,sum(sum_premium) FROM index group by risk_code", SqlFormat.TXT);

Этот метод имеет второй параметр, который является перечислением возвращаемого результата, список типов см. ниже:

CSV("csv","text/csv"), JSON("json","application/json"), TSV("tsv","text/tab-separated-values"), TXT("txt","text/plain"), YAML("yaml","application/yaml"), CBOR("cbor","application/cbor"), SMILE("smile","application/smile");


* * *

// Автоматическое преобразование SQL-запросов

Без параметров

List indexDemos = elasticsearchTemplate.queryBySQL("select * from index_demo where (appli_code = 123 and appli_name = 2) or (appli_code = 123 and appli_name = 5)", IndexDemo.class); indexDemos.forEach(System.out::println);

Динамические параметры

String sql = "select * from index_demo where (appli_code = #{a} and appli_name = #{b}) or (appli_code = #{c} and appli_name = #{d})"; Map<String,String> map = new HashMap<>(); map.put("a","1"); map.put("b","2"); map.put("c","3"); map.put("d","4"); System.out.println(renderString(sql,map));

public static String renderString(String content, Map<String,String> map) { Set<Map.Entry<String, String>> entries = map.entrySet(); for (Map.Entry<String, String> e : map.entrySet()) { String regex = "\#\{" + e.getKey() + "\}"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(content); content = matcher.replaceAll(e.getValue()); } return content; }


* * *

// Пользовательские условия запроса

/**

  • Непагинальный запрос
  • В настоящее время временно передаётся тип класса
  • @param queryBuilder условие запроса
  • @param clazz соответствующий класс типа дженериков
  • @return набор результатов запроса сущности класса индекса ES, определённого дженериками
  • @throws Exception */ public List search(QueryBuilder queryBuilder, Class clazz) throws Exception;

elasticsearchTemplate.searchTemplate (парам, «tempdemo1», Main2.класс).для каждого (s -> System.out.println (s));

**```**
**/**
*** Template方式搜索,Template内容以参数方式传入**
*** @param template_params 模版参数**
*** @param templateSource 模版内容**
*** @param clazz**
*** @return**
***/**
**public List<T> searchTemplateBySource(Map<String, Object> template_params, String templateSource, Class<T> clazz) throws Exception;**

публичный лист <т> сеарчтемплатебайсорс (карта <строка, объект> шаблон_парамс, строка шаблонсорс, класс <т> класс) выбрасывает исключение;

Прямой перенос содержимого шаблона для поиска.

**```**
**Map param = new HashMap();**
**param.put("name","123");**
**String templatesource = "{\n" +**
**"      \"query\": {\n" +**
**"        \"term\": {\n" +**
**"          \"appli_name\": \"{{name}}\"\n" +**
**"        }\n" +**
**"      }\n" +**
**"}";**
**elasticsearchTemplate.searchTemplateBySource(param, templatesource, Main2.class).forEach(s -> System.out.println(s));**

мап парам = новый хэшмэп ();
парам.пут («нэйм», «123»);
стринг темплэйтсорс = «{\n» +
«  \"запрос\": {\n» +
«    \"терм\": {\n» +
«      \"аппли_нэйм\": \"{{нэйм}}\"\n» +
"    }\n" +
"  }\n" +
"}";
эластич сёрч темплейт бай сорс (пары, темплэйт сорс, мэйн ту. класс).фор эч (с -> систем точка аут точка принтлн (с));

***Поиск по предложению завершения***

Функция поиска предложений позволяет быстро предлагать контент для поиска (см. функцию поиска на Baidu), поле поиска предложений должно быть настроено с помощью свойства suggest, установленного в значение true.

**```**
**/**
 *** метод поиска предложения**
 *** @param fieldName поле для поиска (необходимо настроить это поле с помощью конфигурации mapping, установив свойство suggest в значение true)**
 *** @param fieldValue содержимое для поиска**
 *** @param clazz**
 *** @return возвращает список результатов поиска, количество результатов поиска по умолчанию равно 10**
 *** @throws Exception**
 ***/**
**public List<String> completionSuggest(String fieldName, String fieldValue, Class<T> clazz) throws Exception;**

публичный список <строка> комплитшн саджэст (строка филднэйм, строка филдвэлэ, класс <т> класс) выбрасывает исключение;

Список строк листинг = эластичный сёрч темплэйт.комплитшн саджэст («аппли нэйм», «1», мэйн ту класс);
листинг.фор эч (мэйн ту -> систем точка аут точка принтлн (мэйн ту));

@ESMapping (suggest = true)
приватная строка аппили нэйм;

***Предложение фразы поиска***

**```**
**/**
** * Предложение Phrace Suggester**
** * @param fieldName**
** * @param fieldValue**
** * @param param настраивает параметры Phrace Suggester**
** * @param clazz**
** * @return**
** * @throws Exception**
** */**
**public List<String> phraseSuggest(String fieldName, String fieldValue, ElasticsearchTemplateImpl.PhraseSuggestParam param, Class<T> clazz) throws Exception;**

публичный список <строка> фразэ саджэст (строка филднэйм, строка филд вэлэ, эластичный сёрч темп лэйт импл. фразэ саджэст пэрэм, класс <т> класс) выбрасывает исключение;

эластичный сёрч темп лэйт импл фразэ саджэст парэм пэрэм = новый эластичный сёрч темп лэйт импл фразэ саджэст парэм (5, 1, нулл, «олвэйз»);
эластичный сёрч темп лэйт.фразэ саджэст («боди», «кто хороший мальчик чжан синьпэн может быть хорошим», парэм, сугг класс).фор эч (с -> систем точка аут точка принтлн (с));
// можно использовать параметры по умолчанию, передавая null в param
эластичный сёрч темп лэйт.фразэ саджэст («боди», «кто хороший мальчик чжан синьпэн может быть хорошим», нулл, сугг класс).фор эч (с -> система точка аут точка принтлн (с));

Параметры определяются в соответствии с официальной документацией:
https://www.elastic.co/guide/en/elasticsearch/reference/7.3/search-suggesters.html

***Запрос по идентификатору***

**```**
**/**
** * Запрос по ID**
** * @param id первичный ключ, соответствующий второму универсальному типу**
** * @param clazz**
** * @return**
** * @throws Exception**
** */**
**public T getById(M id, Class<T> clazz) throws Exception;**

публичный т гет байд (м ид, класс <т> класс) выбрасывает исключение;

мэйн ту майн ту = эластичный сёрч темп лэйт.гет байд («мэйн ту», мэйн ту класс);
систем точка аут точка принтлн (майн ту);

***Запрос mget по идентификатору***

**```**
**/**
** * Пакетный запрос по ID**
** * @param ids массив первичных ключей**
** * @param clazz**
** * @return**
** * @throws Exception**
** */**
**public List<T> mgetById(M[] ids, Class<T> clazz) throws Exception;**

публичный список <т> мгэт байд (м ай дис, класс <т> класс) выбрасывает исключение;

стринг листинг = [«мэйн ту», «мэйн три»];
лист результат = эластичный сёрч темп лэйт.мгэт байд (листинг, мэйн ту класс);
результат.фор эч (мейн -> систем точка аут точка принтлн (мейн));

Демонстрация использования QueryBuilder

***Точное соответствие***

необходимо установить атрибут keyword для поля точного соответствия (по умолчанию атрибут имеет значение true), при поиске необходимо добавить .keyword к имени поля

кьюэри билдер кьюэри билдэрс терм кьюэри («аппли нэйм».кьюэри, «456»);
лист листинг = эластичный сёрч.кью (кьюэри билдер, мэйн ту класс);
листинг.фор эч (мэйн ту -> система точка аут точка принтлн (мэйн ту));

если тип поля напрямую является ключевым словом, то .keyword можно не добавлять

***Соответствие фразы***

китайский хороший мужчина

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

кьюэри билдер кьюэри билдэрс матч фраз кьюэри («аппли нэйм», «го хань»);

***Релевантность запроса***

китайский хороший мужчина

слоп установлен на 2, максимум два перемещения и завершение сопоставления

кьюэри билдер кьюэри билдэрс матч фраз кьюэри («аппли нэйм», «чжун нань»).слоп (2);

***Диапазон запроса***

сумма премии

от 1 до 3

кьюэри билдер кьюэри билдэрс диапазон кьюэри («сам премия»).от (1).то (3);

***Полное соответствие***

аппли нэйм

матч кьюэри кьюэри билдэрс («аппли нэйм», «чжун нань эр мэй ли жэнь шэн»);

минимальное совпадение параметров

«чжун нань эр мэй ли жэнь шэн» минимальное совпадение слов составляет 75%, этот запрос не даст информации

кьюэри билдер кьюэри билдэрс матч кьюэри («аппли нэйм», «чжун нань эр мэй ли жэнь шэн»).мин матч («75%»);

***Матч-запрос интегрирует нечеткий запрос исправления ошибок***

аппли нэйм

нечеткость установлена на AUTO

кьюэри билдер = кьюэри билдэрс матч кьюэри («аппли нэйм», «сптэнг»);
((матч кьюэрибилдер) феззинес (феззинесс.авто); **QueryBuilders.matchQuery("appli_name","spring sps").operator(Operator.AND);**

Выполняет запрос с использованием оператора AND, который ищет документы, соответствующие обоим условиям:
* значение поля appli_name должно точно соответствовать строке «spring sps».

**```
//原文是spring,查询条件输入为spting也能查询到结果
QueryBuilder queryBuilder = QueryBuilders.fuzzyQuery("appli_name","spting");
```**

Запускает запрос с использованием fuzzy-поиска, который находит документы со значением поля appli_name, похожим на строку «spting».

**```
//查询结果appli_name为spring的会被优先展示其次456,再次123
QueryBuilder queryBuilder1 = QueryBuilders.termQuery("appli_name.keyword","spring").boost(5);
QueryBuilder queryBuilder2 = QueryBuilders.termQuery("appli_name.keyword","456").boost(3);
QueryBuilder queryBuilder3 = QueryBuilders.termQuery("appli_name.keyword","123");
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
queryBuilder.should(queryBuilder1).should(queryBuilder2).should(queryBuilder3);
```**

Создаёт запрос с использованием булевого поиска, который сначала выполняет поиск документов со значением поля appli_name равным «spring», затем документов со значением «456» и после этого документов со значением «123».

**```
//性能差,扫描整个倒排索引,前缀越短,要处理的doc越多,性能越差,尽可能用长前缀搜索
//查询appli_name字段值前缀为1的内容
QueryBuilder queryBuilder = QueryBuilders.prefixQuery("appli_name","1");
```** 

Осуществляет поиск документов, в которых значение поля appli_name начинается с подстроки «1».

**```
//performance较差不建议使用
//?:任意字符
//*:0个或任意多个字符
QueryBuilder queryBuilder = QueryBuilders.wildcardQuery("appli_name","1?3");
```**

Находит документы, в которых поле appli_name содержит подстроку «1?» или «3».

**```
//performance较差不建议使用
QueryBuilder queryBuilder = QueryBuilders.regexpQuery("appli_name","[0-9].+");
//[0-9]:指定范围内的数字
//[a-z]:指定范围内的字母
//.:一个字符
//+:前面的正则表达式可以出现一次或多次
```**

Ищет документы, в которых значения поля appli_name соответствуют регулярному выражению «[0-9].+» — содержат цифру, за которой следует один или более символов.

**```
//select * from Main2 where (appli_name = 'spring' or appli_name = '456') and risk_code = '0101' and proposal_no != '1234567'
QueryBuilder queryBuilder1 = QueryBuilders.termQuery("appli_name.keyword","spring");
QueryBuilder queryBuilder2 = QueryBuilders.termQuery("appli_name.keyword","456");
QueryBuilder queryBuilder3 = QueryBuilders.termQuery("risk_code","0101");
QueryBuilder queryBuilder4 = QueryBuilders.termQuery("proposal_no.keyword","1234567");
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
queryBuilder.should(queryBuilder1).should(queryBuilder2);
queryBuilder.must(queryBuilder3);
queryBuilder.mustNot(queryBuilder4);
```**

Формирует запрос, который выбирает документы, удовлетворяющие следующим условиям:
* поле appli_name равно «spring» или «456»;
* поле risk_code равно «0101»;
* поле proposal_no не равно «1234567».

**```
//假设
//第一条数据title匹配bryant fox的分数为0.8 body匹配bryant fox的分数为0.1,这条数据最终得分为0.8
//第二条数据title匹配bryant fox的分数为0.6 body匹配bryant fox的分号为0.7,这条数据最终得分为0.7
//dis_max查询后第一条数据相关度评分更高,排在第二条数据的前面
//如果不用dis_max,则第二条数据的得分为1.4高于第一条数据的0.9
//如果再附加其他匹配结果的分数,需要指定tieBreaker
//获得最佳匹配语句句的评分_score
//将其他匹配语句句的评分与tie_breaker 相乘
//对以上评分求和并规范化
//Tier Breaker:介于0-1 之间的浮点数(0代表使⽤用最佳匹配;1 代表所有语句句同等重要)
QueryBuilders.disMaxQuery()
.add(QueryBuilders.matchQuery("title", "bryant fox"))
.add(QueryBuilders.matchQuery("body", "bryant fox"))
.tieBreaker(0.2f);
```**

Реализует disMax-запрос, который объединяет результаты двух запросов matchQuery по полям title и body и выбирает документ с наивысшим баллом. tieBreaker определяет, насколько важен этот балл относительно других возможных совпадений.

**```
QueryBuilders.multiMatchQuery("Quick pets", "title","body")
.minimumShouldMatch("20%")
.type(MultiMatchQueryBuilder.Type.BEST_FIELDS)
.tieBreaker(0.2f);
```**

Использует multiMatch-запрос для поиска документов, содержащих слова «Quick» и «pets» в полях title или body. minimumShouldMatch указывает, что хотя бы 20 % полей должны содержать эти слова. Тип BEST_FIELDS означает, что будет выбран документ, наиболее соответствующий запросу. tieBreaker задаёт вес этого соответствия относительно других документов.

**```
PUT /mult/_doc/1
{
    "s1": "shanxi shanxi shanxi shanxi shanxi",
    "s2": "shanxi",
    "s3": "ttttt",
    "s4": "Brown rabbits are commonly seen."
}
PUT /mult/_doc/2
{
    "s1": "datong",
    " "s2": "datong",
    "s3": "datong",
    "s4": "Brown rabbits are commonly seen."
}
//虽然shanxi在s1中出现了很多次,但是只出现了两个字段s1 s2
//datong出现在了三个字段s123,所以优先更多出现字段的这条记录
//doc2的分数大于doc1的分数
QueryBuilders.multiMatchQuery("shanxi datong", "s1","s2","s3","s4")
.type(MultiMatchQueryBuilder.Type.MOST_FIELDS);
```**

Применяет multiMatch-запрос с типом MOST_FIELDS для поиска документов, которые содержат слова «shanxi» и «datong» хотя бы в одном из полей s1, s2, s3 или s4. Будет выбран документ, в котором эти слова встречаются в наибольшем количестве полей.

**```
PUT /mult/_doc/3
{
    "s1": "sichuan sichuan",
    "s2": "sichuan",
    "s3": "eee",
    "s4": "sichuan"
}

PUT /mult/_doc/4
{
    "s1": "chengdu t chengdu chengdu",
    "s2": "rr",
    "s3": "ss",
    "s4": "Brown rabbits are commonly seen."
}
//虽然chengdu在s1中出现了3次,但是合在一起显然doc3更匹配(TF更高、文档长度小,IDF一致)
//所以doc3分数更高
QueryBuilders.multiMatchQuery("chengdu sichuan", "s1","s2","s3","s4")
.type(MultiMatchQueryBuilder.Type.CROSS_FIELDS);
```**

Использует multiMatch-запрос типа CROSS_FIELDS для поиска документов, содержащих слова «chengdu» и «sichuan». Будет выбран документ с наибольшим количеством совпадений этих слов во всех полях. GeoPoint(32.030249, 118.789703);
GeoPoint bottomRight = new GeoPoint(32.024341, 118.802171);

GeoBoundingBoxQueryBuilder geoBoundingBoxQueryBuilder = QueryBuilders.geoBoundingBoxQuery("geo")
    .setCorners(topLeft, bottomRight);
List<GeoPojo> search = elasticsearchTemplate.search(geoBoundingBoxQueryBuilder, GeoPojo.class);

GeoDistanceQueryBuilder

Запрашивает координаты в заданном диапазоне расстояний от заданной широты и долготы.

QueryBuilders.geoDistanceQuery("pin.location")                             
    .point(40, -70)                                          
    .distance(200, DistanceUnit.KILOMETERS);  

GeoPolygonQueryBuilder

Запрос возвращает координаты в пределах заданного многоугольника.

List<GeoPoint> points = new ArrayList<>();           
points.add(new GeoPoint(40, -70));
points.add(new GeoPoint(30, -80));
points.add(new GeoPoint(20, -90));
QueryBuilders.geoPolygonQuery("pin.location", points);

Агрегация запросов

Основные агрегационные запросы
/**
 * Базовый метод агрегации, который используется для выполнения агрегационных запросов, которые не могут быть выполнены с помощью инструментов.
 * @param aggregationBuilder — содержимое агрегации.
 * @param queryBuilder — условия поиска.
 * @param clazz — класс.
 * @return результаты агрегации (официальные результаты агрегации).
 * @throws Exception
 */
public Aggregations aggs(AggregationBuilder aggregationBuilder, QueryBuilder queryBuilder, Class<T> clazz) throws Exception;
SumAggregationBuilder aggregation = AggregationBuilders.sum("agg").field("sum_amount");
Aggregations aggregations = elasticsearchTemplate.aggs(aggregation, null, Main2.class);
Sum agg = aggregations.get("agg");
double value = agg.getValue();
System.out.println(value);

Для получения более подробной информации о применении обратитесь к официальной документации: https://www.elastic.co/guide/en/elasticsearch/client/java-api/6.6/_metrics_aggregations.html

Официальные документы по всем агрегационным конструкторам доступны здесь: https://www.elastic.co/guide/en/elasticsearch/client/java-rest/6.6/java-rest-high-aggregation-builders.html

Обычные агрегационные запросы
/**
 * Метрическое измерение с использованием типов метрик, без группировки, прямое агрегирование статистики поля metricName.
 * @param metricName — поле, которое нужно проанализировать.
 * @param aggsType — тип метрики (сумма, количество, среднее значение, минимум, максимум).
 * @param queryBuilder — условие запроса, если оно не требуется, можно передать null.
 * @param clazz
 * @return результат суммы, количества, среднего значения, минимума и максимума.
 * @throws Exception
 */
public double aggs(String metricName, AggsType aggsType, QueryBuilder queryBuilder, Class<T> clazz) throws Exception;
double sum = elasticsearchTemplate.aggs("sum_premium", AggsType.sum, null, Main2.class);
double count = elasticsearchTemplate.aggs("sum_premium", AggsType.count, null, Main2.class);
double avg = elasticsearchTemplate.aggs("sum_premium", AggsType.avg, null, Main2.class);
double min = elasticsearchTemplate.aggs("sum_premium", AggsType.min, null, Main2.class);
// Если перевести на SQL: select max(sum_premium) from Main2
double max = elasticsearchTemplate.aggs("sum_premium", AggsType.max, null, Main2.class);


System.out.println("sum====" + sum);
System.out.println("count====" + count);
System.out.println("avg====" + avg);
System.out.println("min====" + min);
System.out.println("max====" + max);
Групповые обычные агрегационные запросы
/**
* Обычный агрегационный запрос, наиболее часто используемый.
* Группировка с использованием bucket для измерения типа метрики.
* @param bucketName — группировка с использованием поля bucketName, в ES это понятие «корзины».
* @param metricName — поле для анализа.
* @param aggsType
* @param clazz
* @return
*/
public Map aggs(String metricName, AggsType aggsType,QueryBuilder queryBuilder, Class<T> clazz, String bucketName) throws Exception;
// Если перевести на SQL: select appli_name,max(sum_premium) from Main2 group by appli_name
Map map = elasticsearchTemplate.aggs("sum_premium", AggsType.sum,null,Main2.class,"appli_name");
map.forEach((k,v) -> System.out.println(k+"     "+v));

== По умолчанию результаты агрегации сортируются в порядке убывания ==

Вложенные (двухуровневые) агрегационные запросы
/**
 * Вложенный агрегационный запрос (без стратегии сортировки по умолчанию), двухуровневая группировка.
 * Обратите внимание, что в настоящее время этот метод поддерживает только двухуровневую группировку.
 * Группировка с использованием bucket для метрического измерения.
 * @param metricName — поле для статистического анализа.
 * @param aggsType — тип метрической группировки.
 * @param queryBuilder
 * @param clazz
 * @param bucketNames — поля для вложенной группировки.
 * @return
 * @throws Exception
 */
public List<Down> aggswith2level(String metricName, AggsType aggsType,QueryBuilder queryBuilder, Class<T> clazz ,String... bucketNames) throws Exception;
// select appli_name,risk_code,sum(sumpremium) from Main2 group by appli_name,risk_code
List<Down> list = elasticsearchTemplate.aggswith2level("sum_premium", AggsType.sum,null,Main2.class,"appli_name","risk_code");
list.forEach(down ->
{
    System.out.println("1:"+down.getLevel_1_key());

``` ```
System.out.println("2:" + down.getLevel_2_key() + "    " + down.getValue());
}
);

Статистический агрегационный запрос

/**
 * Статистическая агрегация метрики
 * @param metricName Поле, которое нужно проанализировать
 * @param queryBuilder
 * @param clazz
 * @return
 * @throws Exception
 */
public Stats statsAggs(String metricName, QueryBuilder queryBuilder, Class<T> clazz) throws Exception;
//Этот метод может вернуть значения показателей sum, count, avg, min, max для статистического анализа поля metricName за один запрос
Stats stats = elasticsearchTemplate.statsAggs("sum_premium", null, Main2.class);
System.out.println("max:" + stats.getMax());
System.out.println("min:" + stats.getMin());
System.out.println("sum:" + stats.getSum());
System.out.println("count:" + stats.getCount());
System.out.println("avg:" + stats.getAvg());

Групповой статистический агрегационный запрос

/**
 * Групповая статистическая агрегация метрики
 * @param bucketName Группировка по полю bucketName
 * @param metricName Поле, которое нужно проанализировать
 * @param queryBuilder
 * @param clazz
 * @return
 * @throws Exception
 */
public Map<String, Stats> statsAggs(String metricName, QueryBuilder queryBuilder, Class<T> clazz, String bucketName) throws Exception;

По сравнению с предыдущим методом, этот метод добавляет функцию группировки.

Map<String, Stats> stats = elasticsearchTemplate.statsAggs("sum_premium", null, Main2.class, "risk_code");
stats.forEach((k, v) -> {
    System.out.println(k + "    count:" + v.getCount() + " sum:" + v.getSum() + "...");
});

Базисный запрос

https://www.elastic.co/guide/en/elasticsearch/reference/7.4/search-aggregations-metrics-cardinality-aggregation.html

/**
 * Базисный запрос, который возвращает приблизительное значение и не всегда является точным
 * @param metricName Поле, которое нужно проанализировать
 * @param queryBuilder
 * @param clazz
 * @return
 * @throws Exception
 */
public long cardinality(String metricName, QueryBuilder queryBuilder, Class<T> clazz) throws Exception;

/**
    * Базисный запрос. Рекомендуется использовать вместе с https://gitee.com/zxporz/ESClientRHL/wikis/Elasticsearch-ESClientRHL
    * @param metricName Имя поля метрики
    * @param queryBuilder Условия запроса
    * @param precisionThreshold Установите precisionThreshold, по умолчанию 3000 максимум 40000
    * @param clazz Тип класса индекса pojo
    * @return
    * @throws Exception
*/
public long cardinality(String metricName, QueryBuilder queryBuilder, long precisionThreshold, Class<T> clazz) throws Exception;
//select count(distinct proposal_no) from Main2
long value = elasticsearchTemplate.cardinality("proposal_no", null, Main2.class);
System.out.println(value);
Эквивалентно
long value = elasticsearchTemplate.cardinality("proposal_no", null, 3000L, Main2.class);

Процентный агрегационный запрос

/**
 * Процентная агрегация по умолчанию выполняется в соответствии с 50%, 95%, 99% (TP50 TP95 TP99)
 * @param metricName Поле для анализа, должно быть числового типа
 * @param queryBuilder
 * @param clazz
 * @return
 * @throws Exception
 */
public Map percentilesAggs(String metricName, QueryBuilder queryBuilder, Class<T> clazz) throws Exception;

/**
 * Агрегация на основе процента с использованием пользовательских процентных сегментов
 * @param metricName Поле для анализа, должно быть числового типа
 * @param queryBuilder
 * @param clazz
 * @param customSegment Пользовательские процентные сегменты
 * @return
 * @throws Exception
 */
public Map percentilesAggs(String metricName, QueryBuilder queryBuilder, Class<T> clazz, double... customSegment) throws Exception;

Процентная агрегация — это запрос статистики поля с определённым процентом данных в пределах какого значения.

//Следующий пример берёт поле sum_premium и получает TP50 TP95 TP99
Map map = elasticsearchTemplate.percentilesAggs("sum_premium", null, Main2.class);
map.forEach((k, v) -> {
    System.out.println(k + "     " + v);
});
//Вывод:
50.0     3.5
95.0     6.0
99.0     6.0
//То есть 50% данных sum_premium меньше 3,5
//То есть 95% данных sum_premium меньше 6,0
//То есть 99% данных sum_premium меньше 6,0

//Также можно настроить процентные сегменты
Map map = elasticsearchTemplate.percentilesAggs("sum_premium", null, Main2.class, 10, 20, 30, 50, 60, 90, 99);

Агрегационный запрос на основе процентного ранга

/**
 * Агрегация на основе процентного ранга (статистика того, сколько процентов данных находится в каком диапазоне значений)
 * @param metricName Поле для анализа, должно быть числового типа
 * @param queryBuilder
 * @param clazz
 * @param customSegment
 * @return
 * @throws Exception
 */
public Map percentileRanksAggs(String metricName, QueryBuilder queryBuilder, Class<T> clazz, double... customSegment) throws Exception;

Агрегация на основе процентного ранга — это предоставление диапазона значений и запрос о том, какой процент данных попадает в этот диапазон.

//Мы предоставляем диапазон значений поля sum_premium: 1, 4, 5, 9, то есть ниже 1, ниже 4, ниже 5 и ниже 9
//Получаем процент данных, попадающих в эти диапазоны
Map map = elasticsearchTemplate.percentileRanksAggs("sum_premium", null, Main2.class, 1, 4, 5, 9);
map.forEach((k, v) -> {
    System.out.println(k + "     " + v);
});

//Вывод:
``` **8.333333333333332      1.0**

**58.333333333333336     4.0** 

**75.0                   5.0**  

**100.0                  9.0**   

// Именно 8,3% данных sum_premium поля имеют значение меньше или равное 1
// Именно 58,3% данных sum_премиум поля имеют значение меньшее или равное 4
// Именно 75% данных sum_премиум поля имеют значение меньшее или равное 5
// Именно 100% данных sum_премиум поля имеют значение меньшее или равное 9
Фильтр-агрегатор: объединение запросов
/**
 * Агрегация с фильтром: можно «менять» группы
 * @param metricName Поле для статистического анализа
 * @param aggsType Тип статистики
 * @param clazz
 * @param queryBuilder
 * @param фильтры FiltersAggregator фильтр-обёртка, каждый результат фильтра может быть использован как ведро
 * @return
 * @throws Exception
 */
public Map filterAggs(String metricName, AggsType aggsType, QueryBuilder queryBuilder, Class<T> clazz, FiltersAggregator.KeyedFilter... filters) throws Exception;

Фильтр-агрегатор позволяет гибко настраивать группировку в агрегации Elasticsearch, делая её очень гибкой.

// Пример ниже: данные разделены на две группы: одна с risk_code = 0101, другая с risk_code = 0103 или 0104. В каждой группе вычисляется сумма sum_premium
Map map = elasticsearchTemplate.filterAggs("sum_premium", AggsType.sum, null, Main2.class,
        new FiltersAggregator.KeyedFilter("0101", QueryBuilders.matchPhraseQuery("risk_code", "0101")),
        new FiltersAggregator.KeyedFilter("0103 или104", QueryBuilders.matchQuery("risk_code", "0103 0104")));
map.forEach((k, v) ->
    System.out.println(k + "    " + v)
);
###### Гистограмма-агрегация: запрос

/**

  • Гистограммная агрегация
  • @param metricName Поле, которое нужно проанализировать
  • @param aggsType Тип статистики
  • @param queryBuilder
  • @param clazz
  • @param bucketName Группировка по bucketName
  • @param интервал Интервал значений bucket
  • @return
  • @throws Исключение */ public Map histogramAggs (String metricName, AggsType aggsType,QueryBuilder queryBuilder,Class clazz,String bucketName,double interval) throws Exception;
Гистограммная агрегация — это статистический анализ, который группирует данные по определённому полю и подсчитывает значения метрики для каждой группы.

// Подсчёт количества proposal_no для каждого значения sum_premium, кратного 3 Map map = elasticsearchTemplate.histogramAggs("proposal_no", AggsType.count, null,Main2.class,"sum_premium",3); map.forEach((k, v) -> System.out.println(k + " " + v) ); // Вывод: 0.0 2 3.0 3 6.0 1


Датированная гистограмма-агрегация: запрос
/**
* Датированная гистограммная агрегация
* @param metricName Поле, которое нужно проанализировать
* @param aggsType Тип статистики
* @param queryBuilder
* @param clazz
* @param bucketName
* @param интервал Датированный интервал группировки
* @return
* @throws Исключение
*/
public Map dateHistogramAggs(String metricName, AggsType aggsType, QueryBuilder queryBuilder, Class<T> clazz, String bucketName, DateHistogramInterval interval) throws Exception;

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

// Суммирование sum_premium за каждые два часа input_date
Map map = elasticsearchTemplate.dateHistogramAggs("sum_premium", AggsType.sum, null,Main2.class,"input_date", DateHistogramInterval.hours(2));
map.forEach((k, v) ->
        System.out.println(k + "    " + v)
);
###### Другие способы агрегации запросов
ES поддерживает множество других способов агрегации, и этот инструмент предоставляет только некоторые из наиболее часто используемых методов для упрощения кода.

Например, если вам нужна агрегация диапазона, вы можете использовать следующий пример:

// Группировка по диапазону sum_premium и подсчет количества sum_premium для каждой группы AggregationBuilder aggregation = AggregationBuilders.range("range").field("sum_premium").addUnboundedTo(1).addRange(1,4).addRange(4,100).addUnboundedFrom(100); aggregation.subAggregation(AggregationBuilders.count("agg").field("proposal_no.keyword")); Aggregations aggregations = elasticsearchTemplate.aggs(aggregation,null,Main2.class); Range range = aggregations.get("range"); for (Range.Bucket entry : range.getBuckets()) { ValueCount count = entry.getAggregations().get("agg"); long value = count.getValue(); System.out.println(entry.getKey() + " " + value); }

> Дополнительные сведения о способах использования API агрегации см. на странице https://www.elastic.co/guide/en/elasticsearch/client/java-rest/6.6/java-rest-high-aggregation-builders.html

## Функции управления

###### Печать журнала запросов ES-сервиса
Если вам нужно отладить, вам необходимо получить JSON-сообщение запроса ES, вы можете настроить аннотацию индекса структуры сущности класса @ESMetaData (indexName = «index», number_of_shards = 5,number_of_replicas = 0,printLog = true)

@ESMetaData(indexName = "index", number_of_shards = 5,number_of_replicas = 0,printLog = true) public class Main2 implements Serializable {

Эта настройка по умолчанию отключена, она поддерживает только несколько общих функций ведения журнала при включении. Если вам нужно поддерживать больше функций, добавьте следующий код в соответствующее место:

if(metaData.isPrintLog()){ logger.info(searchSourceBuilder.toString()); }



###### Распечатать информацию о регистрации
Если вам необходимо подтвердить регистрацию (включая информацию о создании индекса и информацию о генерации прокси-класса ESCRepository), вы можете настроить EnableESTools аннотацию printregmsg атрибут равен true

@EnableESTools(entityPath = {printregmsg = true)


Особая благодарность компании JetBrains (https://www.jetbrains.com/?from=Elasticsearch-ESClientRHL) за продукт IDEA.

Спасибо активным участникам проекта: jangojing (https://gitee.com/jangojing) и tongxuefang (tongxuefang@hztianque.com). Приглашаем всех активно участвовать в Elasticsearch-ESClientRHL.

Опубликовать ( 0 )

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

1
https://api.gitlife.ru/oschina-mirror/zxporz-ESClientRHL.git
git@api.gitlife.ru:oschina-mirror/zxporz-ESClientRHL.git
oschina-mirror
zxporz-ESClientRHL
zxporz-ESClientRHL
es7