当前位置: 首页 > article >正文

ES在企业项目中的实战总结,彻底掌握ES的使用

通过之前两篇文章

  • 了解了ES的核心概念和基础使用
  • 学习进阶的DSL语法处理复杂的查询

这段时间通过在本企业代码中对ES框架的使用,总结了不少经验。主要分为三点

  • 企业封装了ES原生的api,需要使用企业项目提供的接口实现 -------简单使用(本章节目的)
  • 项目会遇到更复杂的查询需求,需要进一步深入对ES的学习 -------复杂使用
  • 了解项目如何封装原生的api,学习设计思想 --------深入学习

目录

  • 1. Term查询
    • 1.1 原生api实现term查询
    • 1.2 企业api实现term查询
  • 2. 复合查询__must
    • 2.1 原生api实现must查询
    • 2.2 企业api实现must查询
  • 3. 复合查询__should
  • 4. 复合查询__mustnot
  • 5. 分页和排序
    • 5.1 原生api实现分页和排序
    • 5.2 企业api实现分页和排序
  • 6 聚合查询
    • 6.1 原生api实现桶聚合
    • 6.2 企业api实现桶聚合

------------------------------本章节核心目的是梳理出 本企业项目提供的api原生ES提供的api 的使用区别--------------------------------





本企业将ES的api大致封装成了两个核心类
EsOperater类

方法说明
String[] indexes()
Integer from()分页
Integer size()分页
List sort()排序
QueryBuilder queryBuilder()普通查询/复合查询
EsOperaterBuiler esOperaterBuiler()继承类
SearchResponse execute()执行查询
CountResponse queryTotal()
SearchResponse executeScroll()
QueryBuilder buildQueryBuilder()
QueryBuilder buildQueryBuilderByQueryType(EsQueryInfoBean queryInfo)根据查询信息bean构造相应的查询器
List buildAggBuilder()根据aggMap创建聚合器,包括单层聚合和多层聚合
AggregationBuilder makeChildAgg(EsAggInfoBean esAggInfo, EsAggInfoBean parentAggInfo)递归创建聚合器
EsOperater build()

EsOperaterBuiler类(重点关注)

方法说明
EsOperaterBuiler indexes(String… indexes)设置索引集合
EsOperaterBuiler from(Integer from)设置分页参数的查询数量
EsOperaterBuiler size(Integer size)设置分页参数的查询数量
EsOperaterBuiler sort(String sort)设置排序字段
EsOperaterBuiler sortOrder(SortOrder sortOrder)设置排序排序方式(升序、降序)
EsOperaterBuiler queryBuilder(QueryBuilder queryBuilder)设置查询构建器(QueryBuilder),如果操作构建器(EsOperater)中buildQueryBuilder()方法构造不出需要的查询构建起,
Boolean isAliasExists(String indexName)查询别名是否存在

1. Term查询

1.1 原生api实现term查询

@Test
void TermQuery(){
    // 获取client
    这里默认已经获取
        
    // 1. 准备request (参数为索引名称)
    SearchRequest request = new SearchRequest("indexName");
    
    // 2. 构建DSL
    	// 2.1 获取建造者
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		// 2.2 建造者调用DSL
    searchSourceBuilder.termQuery("name","zjh");
    	// 2.3 组装
    request.source(searchSourceBuilder);
  
    	// 3. 发送请求
    SearchResponse reponse = client.search(request, RequestOptions.ESFAULT);
    
    	// 4. 解析数据,得到_source数据
    SearchHit[] hits = response.getHits().getHits();
    for (SearchHit hit : hits) {
       System.out.println(hit.getSourceAsString());
     }
    
}

此时就可以获取到source的数据了。上述写法也可以简化,如下

// 此方式常用
@Test
void TermQuery(){
    // 获取client
    这里默认已经获取
        
    // 1. 准备request (参数为索引名称)
    SearchRequest request = new SearchRequest("indexName");
    
	// 2. 构建DSL语句
    request.source().query(QueryBuilders.termQuery("name","zjh"));
    
    // 3. 发送请求
    SearchResponse reponse = client.search(request, RequestOptions.ESFAULT);
    
    // 4. 解析数据,得到_source数据
    SearchHit[] hits = response.getHits().getHits();
    for (SearchHit hit : hits) {
       System.out.println(hit.getSourceAsString());
     }
    
}

1.2 企业api实现term查询

@Test
void TermQuery(){
    // 构建索引名称
    String indexName = ElasticSearchConst.UNSTRUCTURE_FILE_SCAN_RESULT + taskId;
    
    // 1. 设置索引集合
    EsOperater.EsOperaterBuiler builder = EsOperater.esOperaterBuiler().indexes(indexName);
    
    // 2. 设置查询构建器 + 准备DSL语句
    builder.queryBuilder(QueryBuilders.termQuery("name","zjh"));
    
    // 3. 发送请求
    SearchResponse response = builder.build().execute();
    
    //  4. 解析数据,得到_source数据
    SearchHit[] hits = response.getHits().getHits();
    for (SearchHit hit : hits) {
       System.out.println(hit.getSourceAsString());
     }

}

解释:

步骤一:需要将 索引名 存到 esOperaterBuiler类 的全局变量中,以便其他方法调用

步骤二:需要将 DSL语句 存到 esOperaterBuiler类 的全局变量中,以便其他方法调用

步骤三:需要从esOperaterBuiler类 切换到 esOperater类,再执行最核心的 execute() 方法,这个方法会进行一些列操作,将最终的结果返回给 response

2. 复合查询__must

2.1 原生api实现must查询

@Test
void MustQuery(){
    // 获取client
    这里默认已经获取
        
    // 1. 准备request (参数为索引名称)
    SearchRequest request = new SearchRequest("indexName");
    
	// 2. 构建DSL语句
    	// 2.1 创建bool查询
    	BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
    	// 2.2 添加must条件
        boolQuery.must(QueryBuilders.termQuery("name", "zjh"));
 		// 2.3 构建请求内容
   		request.source().query(boolQuery);
    
    // 3. 发送请求
    SearchResponse reponse = client.search(request, RequestOptions.ESFAULT);
    
    // 4. 解析数据,得到_source数据
    SearchHit[] hits = response.getHits().getHits();
    for (SearchHit hit : hits) {
       System.out.println(hit.getSourceAsString());
     }
    
}

2.2 企业api实现must查询

@Test
void TermQuery(){
    // 构建索引名称
    String indexName = ElasticSearchConst.UNSTRUCTURE_FILE_SCAN_RESULT + taskId;
    
    // 1. 设置索引集合
    EsOperater.EsOperaterBuiler builder = EsOperater.esOperaterBuiler().indexes(indexName);
    
    // 2. 设置查询构建器 + 准备DSL语句
    	// 2.1 创建bool查询
    	BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
    	// 2.2 添加must条件
        boolQuery.must(QueryBuilders.termQuery("name", "zjh"));
    	// 此行代码的作用就是将构造的must条件,存放到EsOperater类的全局变量
    	builder.queryBuilder(boolQuery);
    
    // 3. 发送请求
    SearchResponse response = builder.build().execute();
    
    //  4. 解析数据,得到_source数据
    SearchHit[] hits = response.getHits().getHits();
    for (SearchHit hit : hits) {
       System.out.println(hit.getSourceAsString());
     }

}
解释一下步骤二:
    可能会疑惑为什么不这样写
    BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
    BoolQueryBuilder mustQuery = boolQuery.must(QueryBuilders.termQuery("name", "zjh"));
    builder.queryBuilder(mustQuery);

	因为must(参数)底层会将参数传给boolQuery.must()的boolQuery对象,是递增的逻辑

解释:

步骤一:需要将 索引名 存到 esOperaterBuiler类 的全局变量中,以便其他方法调用

步骤二:需要将 DSL语句(布尔查询) 存到 esOperaterBuiler类 的全局变量中,以便其他方法调用

步骤三:需要从esOperaterBuiler类 切换到 esOperater类,再执行最核心的 execute() 方法,这个方法会进行一些列操作,将最终的结果返回给 response

可以进一步简化

@Test
void TermQuery(){
    // 构建索引名称
    String indexName = ElasticSearchConst.UNSTRUCTURE_FILE_SCAN_RESULT + taskId;
    
    // DSL语句
    BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
    boolQuery.must(QueryBuilders.termQuery("name", "zjh"));
    
    // 使用企业api实现查询
    EsOperater.EsOperaterBuiler builder = EsOperater.esOperaterBuiler();
    
    SearchResponse response = builder.index(indexName).queryBuilder(boolQuery).build().execute();
   
    //  4. 解析数据,得到_source数据
    SearchHit[] hits = response.getHits().getHits();
    for (SearchHit hit : hits) {
       System.out.println(hit.getSourceAsString());
     }

}

3. 复合查询__should

同理

4. 复合查询__mustnot

同理

5. 分页和排序

5.1 原生api实现分页和排序

// 此方式常用
@Test
void TermQuery(){
    // 获取client
    这里默认已经获取
        
    // 1. 准备request (参数为索引名称)
    SearchRequest request = new SearchRequest("indexName");
    
		//2.查询__构建DSL语句
    	request.source().query(QueryBuilders.termQuery("name","zjh"));
    
    	//  分页
    	request.source().from.size(5);
    
    	//  时间排序
    	request.source().sort(“logTime”,SortOrder.ASC);
    
    // 3. 发送请求
    SearchResponse reponse = client.search(request, RequestOptions.ESFAULT);
    
    // 4. 解析数据,得到_source数据
    SearchHit[] hits = response.getHits().getHits();
    for (SearchHit hit : hits) {
       System.out.println(hit.getSourceAsString());
     }
    
}

5.2 企业api实现分页和排序

@Test
void TermQuery(){
    // 构建索引名称
    String indexName = ElasticSearchConst.UNSTRUCTURE_FILE_SCAN_RESULT + taskId;
    
    // 1. 设置索引集合
    EsOperater.EsOperaterBuiler builder = EsOperater.esOperaterBuiler().indexes(indexName);
    
    // 2. 查询
    builder.queryBuilder(QueryBuilders.termQuery("name","zjh"));
    
    //  分页
    builder.queryBuilder(QueryBuilders.termQuery("name","zjh")).size(5);
    
    //  排序
    builder.queryBuilder(QueryBuilders.termQuery("name","zjh")).sort("logTime").sortOrder(SortOrder.DESC);
    
    // 3. 发送请求
    SearchResponse response = builder.build().execute();
    
    //  4. 解析数据,得到_source数据
    SearchHit[] hits = response.getHits().getHits();
    for (SearchHit hit : hits) {
       System.out.println(hit.getSourceAsString());
     }

}

6 聚合查询

6.1 原生api实现桶聚合

// 需求:实现对城市、品牌的聚合。即用户输入城市、品牌,得到搜索结果
@Test
void TermQuery(){
    // 获取client
    这里默认已经获取
        
    // 1. 准备request (参数为索引名称)
    SearchRequest request = new SearchRequest("indexName");
    
	//2.查询
    	// CityName:自定义桶名; city:根据城市聚合
     	AggregationBuilder aggregationBuilder1 = AggregationBuilders.terms("CityName").field("city");
    	AggregationBuilder aggregationBuilder2 = AggregationBuilders.terms("BrandName").field("brand");
    	
    	request.source().aggregation(aggregationBuilder1);
    	request.source().aggregation(aggregationBuilder2);
    
    // 3. 发送请求
    SearchResponse reponse = client.search(request, RequestOptions.ESFAULT);
    
    // 4. 解析数据
    Aggreagtions aggreagtions = response.getAggreagtions();
    List<? extends Terms.Bucket> buckets1 =  aggreagtions.get("CityName").getBuckets();
    for (Terms.Bucket bucket : buckets) {
       //打印结果是:西安 或者 上海
       System.out.println(bucket.getKeyAsString());
     }
    
     List<? extends Terms.Bucket> buckets2 =  aggreagtions.get("BrandName").getBuckets();
    for (Terms.Bucket bucket : buckets) {
       //打印结果是:星巴克 或者 瑞幸
       System.out.println(bucket.getKeyAsString());
     }
    
}

6.2 企业api实现桶聚合

// 需求:实现对城市、品牌的聚合。即用户输入城市、品牌,得到搜索结果
@Test
void TermQuery(){
    // 获取client
    这里默认已经获取
        
    // 1. 准备request (参数为索引名称)
    SearchRequest request = new SearchRequest("indexName");
    
	//2.查询
   	List<AggregationBuilder> aggregationBuilderList = new ArrayList<>();
    aggregationBuilderList.add(AggregationBuilders.terms("CityName").field("city"));;
    aggregationBuilderList.add(AggregationBuilders.terms("BrandName").field("brand"));
    // aggBuilderList()企业封装的工具,将聚合参数赋值到全局变量上
    builder.aggBuilderList(aggregationBuilderList);

    
    // 3. 发送请求
    SearchResponse response = builder.size(1).build().execute();
    
    // 4. 解析数据
    Aggreagtions aggreagtions = response.getAggreagtions();
    // 注意ParsedStringTerms,还有ParsedLongTerms、ParsedDoubleTerms...
    ParsedStringTerms CityName =  aggreagtions.get("CityName");
    
    for (Terms.Bucket bucket : CityName.getBuckets()) {
       //打印结果是:西安 或者 上海
       System.out.println(bucket.getKeyAsString());
     }
    
    ParsedStringTerms BrandName =  aggreagtions.get("BrandName");
    for (Terms.Bucket bucket : BrandName.getBuckets()) {
       //打印结果是:星巴克 或者 瑞幸
       System.out.println(bucket.getKeyAsString());
     }
    
}

这里需要解释一下步骤四中的 ParsedStringTerms

ES会将聚合结果封装到特定的类中,方便你来处理不同类型的聚合结果。

ParsedLongTerms:

  • 这个类用于处理长整型(long)类型的聚合结果。

ParsedStringTerms:

  • 这个类用于处理字符串(String)类型的聚合结果。

什么意思呢?在ES中对"CityName"进行聚合。

返回结果中可以看到如下信息,表示星巴克有三家(西安)

  • key:“星巴克” (字符串类型)

  • doc_count : 3 (long类型)

因此根据key的类型,正确选择使用ParsedStringTerms || ParsedLongTerms ||…接收聚合结果,否则报错。

示例图:
在这里插入图片描述


http://www.kler.cn/a/104652.html

相关文章:

  • mysql日志(错误日志、binlog日志、查询日志、慢日志)
  • S7net【C#】
  • SQL查询优化---关联查询索引优化
  • 与AI对话,如何写好prompt?
  • 【ceph】ceph集群的节点机器重启,导致磁盘的lvm消失,如何恢复呢~~满满的都是干货
  • 【Java集合类面试二十二】、Map和Set有什么区别?
  • 元宇宙游戏大爆炸,UTONMOS元宇宙游戏成爆品
  • [Ubuntu 18.04] 搭建文件夹共享之Samba服务器
  • 量变引起质变:安卓改多了,就是自己的OS
  • 【黑马程序员】mysql基础篇笔记
  • PyTorch中的intrusive_ptr
  • 计算机网络——理论知识总结(上)
  • 传智教育研究院重磅发布Java学科新研发《智慧养老》项目
  • 数据结构零基础C语言版 严蔚敏-线性表、顺序表
  • mybatis写sql
  • 如何实现Android视音频数据对接到GB28181平台(SmartGBD)
  • FLStudio2024汉化破解版在哪可以下载?
  • 2023-10-25 数据库-数据库体系架构的理解-将数据库理论融入自身-记录与分析
  • 基于STM32温室智能监测控制系统设计
  • mysql请求阻塞