EsClientRHL — это инструмент для вызова и работы с Elasticsearch на основе Springboot. Он основан на официальном RestHighLevelClient и включает в себя инструменты для работы со структурой индексов, их данными, а также инструменты поиска и анализа данных.
Инструмент позволяет легко интегрировать Elasticsearch и использовать его функции. EsClientRHL предоставляет следующие возможности:
EsClientRHL разработан для Elasticsearch версии 7 и выше. В случае конфликта версий рекомендуется явно указать версию Elasticsearch в файле pom.xml проекта.
Быстрое использование
Для быстрого внедрения EsClientRHL можно использовать демонстрационную версию springboot, доступную по ссылке https://gitee.com/zxporz/esclientrhlDemo.
Выбор EsClientRHL
Причины выбора этого инструмента включают:
В EsClientRHL некоторые API объединены с лучшими практиками использования Elasticsearch. Инструмент может быть полезен разработчикам, и его авторы просят поставить звёздочку на странице проекта на Gitee, если он оказался полезным.
Версия и обновление
EsClientRHL разрабатывается на основе Elasticsearch версии 7. Версия Elasticsearch должна быть указана в файле pom.xml, чтобы избежать конфликтов с родительским проектом springboot.
Информация об обновлениях включает дату и описание изменений. Например, одно из обновлений содержит исправление ошибки в поиске и добавление новых функций, таких как удаление по условию и возможность поиска по нескольким индексам. Также добавлено сжатие пакета с тестовым кодом и документацией.
С каждым обновлением добавляются новые функции и исправляются ошибки. Последние обновления включают поддержку аутентификации пользователей, оптимизацию запросов и улучшение работы с различными типами данных. Поддержка Alias-запросов, возможность переключения Alias-индексов.
Содержит некоторые аннотации для упрощения использования компонентов.
Основан на SpringBoot, включает автоматическую конфигурацию компонентов клиента ES.
Управляет структурой индекса автоматически. Автоматически генерирует прокси-серверы для интерфейсов.
Перечисление основных данных.
Управление структурой индексов.
CURD + агрегатные функции.
Внутренний пакет инструментов.
https://gitee.com/zxporz/esclientrhlDemo
— Компоненты скомпилированы с использованием JDK1.8, обратите внимание на выбор версии JDK. — В настоящее время поддерживается только интеграция со Springboot, для интеграции с обычной системой Spring потребуется небольшая модификация. — Если вам не нужно использовать встроенный метод интеграции компонентов, просто обратитесь к способу интеграции с ES, обращая внимание на код в классе ElasticsearchTemplateImpl.
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 к классу запуска 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. Если есть несколько (кластерная ситуация), используйте запятые для разделения, и это обязательно.
elasticsearch.host=127.0.0.1:9200
#Максимальное количество подключений в пуле подключений
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
Необязательно.
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));
Примечание: при использовании метода автоматического проксирования интерфейса необходимо учитывать следующие моменты:
Используется для настройки метаданных структуры индекса, соответствующей классу сущности 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
项目启动时,组件会自动识别es实体类上配置的@ESMetaData
注解,如果对应的索引结构没有创建,自动根据mapping注解配置创建相关索引结构。
Если实体类不在启动类的包路径下,如需启用此功能,需要在启动注解上配置实体类路径。
@EnableESTools(entityPath = "com.*.esdemo.domain")
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_type
为DataType.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);
Частичное обновление отличается от полного обновления тем, что оно обновляет только установленные значения полей.
**Пакетное обновление данных индекса**
/**
// Обновить 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; }
* * *
// Пользовательские условия запроса
/**
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() + "...");
});
Базисный запрос
/**
* Базисный запрос, который возвращает приблизительное значение и не всегда является точным
* @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)
);
###### Гистограмма-агрегация: запрос
/**
Гистограммная агрегация — это статистический анализ, который группирует данные по определённому полю и подсчитывает значения метрики для каждой группы.
// Подсчёт количества 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 )