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

通过之前两篇文章

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

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

  • 企业封装了ES原生的api,需要使用企业项目提供的接口实现 -------简单使用(本章节目的)
  • 项目会遇到更复杂的查询需求,需要进一步深入对ES的学习 -------复杂使用
  • 了解项目如何封装原生的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 ||…接收聚合结果,否则报错。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值