欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

仿级联查询|Java通过DSL字符串查询ES(es8dsljava)

时间:2023-04-16
模拟aws中级联查询

一、需求二、设计

1、背景2、思路 三、Java代码实现四、DSL表达式五、前端拼接 DSL 字符串六、Java使用ES查询DSL字符串七、通过 Apifox 测试八、前端展示效果 一、需求

1、实现一个搜索框,可以实现所有的字段的查询,并且每个字段可以支持不同的查询方式
如下图所示

2、点击任何一个字段,弹出该字段支持的查询方式

二、设计 1、背景

由于项目是前后端分离项目,这里就需要前端的配合
由于我们的数据库选择是 mysql+es
今天这篇文章主要是使用es进行业务查询

2、思路

如何获取该表的所有列字段?如果根据字段类型给与对应的查询条件?

这里我是使用 Java开发的,所以第一点直接想到的就是使用反射

实现思路

首先需要将所有列表,创建对应的实体类(即:每一列对应实体每个字段)然后前端传入具体为哪一个类的类型,通过反射获取其所有字段名然后我们这里会根据字段的数据类型,决定使用的判断方式(即:string:使用 “=”, “!=”, “:”, “!:” )最后组装数据返回前端前端使用 DSL 表达式 ,拼接 DSL字符串回传java进行查询Java根据DSL表达式查询 并返回结果 三、Java代码实现

这里定义了2种判断条件

STRING = {"=", “!=”, “:”, “!:”};OTHER = {"=", “>”, “<”, “!=”};

@Slf4j@Service("AwsScanService")public class AwsScanServiceImpl implements AwsScanService { // string 类型下 private static final String[] STRING = {"=", "!=", ":", "!:"}; // 非 string 类型下 private static final String[] OTHER = {"=", ">", "<", "!="}; @Override public R getScanSearchFields(ScanBasicVo index) { Class cls = getObject(index.getServiceId()); log.info("获取当前对象的类型为:" + cls); Field[] fields = cls.getDeclaredFields(); Map res = new HashMap<>(); for (int i = 0; i < fields.length; i++) { Field f = fields[i]; f.setAccessible(true); try { //f.getName()得到对应字段的属性名,f.get(o)得到对应字段属性值,f.getGenericType()得到对应字段的类型 log.info("属性名:" + f.getName() + ";字段类型:" + f.getGenericType()); if ("class java.lang.String".equals(f.getGenericType())) { res.put(f.getName(), STRING); } res.put(f.getName(), OTHER); } catch (IllegalArgumentException e) { e.printStackTrace(); log.info("ReflectUtil error:" + e.toString()); } } return R.ok().put("data", res); } private Class getObject(int serviceId) { switch (serviceId) { case 1: return AwsDynamodbVo.class; case 2: return AwsEc2CompareVo.class; case 3: return AwsEc2Vo.class; case 4: return AwsElasticacheVo.class; case 5: return AwsIAMVo.class; case 6: return AwsOpensearchVo.class; case 7: return AwsRdsVo.class; case 8: return AwsRiVo.class; case 9: return AwsS3Vo.class; case 10: return AwsVpcVo.class; } return null; }}

具体的对应的每个vo就不在这里一一展示了
下面来看一下最后的执行返回结果

{ "msg": "success", "code": 20000, "data": { "dyTableName": [ "=", ">", "<", "!=" ], "tableStatus": [ "=", ">", "<", "!=" ], "tableSizeBytes": [ "=", ">", "<", "!=" ], "itemCount": [ "=", ">", "<", "!=" ] }}

四、DSL表达式

# 等于GET /aws_1_1_ec2/_search{ "query": { "match": { "instanceName": "unipus-ucont-apiworker102" } }}# 不等于GET /aws_1_1_ec2/_search{ "query": { "bool": { "must_not": { "term": { "instanceName": "unipus-ucont-apiworker102" } } } }}# 模糊查询GET /aws_1_1_ec2/_search{ "query": { "wildcard": { "instanceName":{"value":"*ucont*"} } }}# 不包含GET aws_1_1_ec2/_search{ "query":{ "bool" : { "must_not" : { "wildcard" : { "type" : "*c4*" } } } } }# 范围内查询GET /aws_1_1_ec2/_search{ "query": { "bool": { "must": { "range": { "cpuMax": { "gte": 15, "lte": 18 } } } } }}# 多关系查询GET aws_1_1_ec2/_search{ "query": { "bool": { "should": [ { "wildcard": { "type": "*c5*" } }, { "bool": { "must_not": [ { "wildcard": { "vpcName": { "value": "*Test*" } } } ] } } ] } }}

五、前端拼接 DSL 字符串

这里需要注意,java接收的dsl字符串不能包含最外层的 「query」关键字
比如上面的DSL查询转化为字符串
"{ “match”:{ “platform”:“windows” } } "

这里目前还没有给前端找到更好的插件,也欢迎在前端拼接过DSL的朋友留言!!!

六、Java使用ES查询DSL字符串

查询dsl字符串查询es的方法

@PostMapping("/dsl/query") public PageUtils queryDslToEs(@RequestBody ScanCommonVo scanCommonVo) throws IOException { String dsl = scanCommonVo.getDsl(); String index = scanCommonVo.getIndex(); //分页 long curPage = scanCommonVo.getPage() == 0 ? 1 : scanCommonVo.getPage(); long limit = scanCommonVo.getLimit() == 0 ? 10 : scanCommonVo.getLimit(); // 返回结果 List arrayRes = new ArrayList<>();// String dsl = "{ "match":{ "platform":"windows" } } "; // 判断索引是否存在 GetIndexRequest getIndexRequest = new GetIndexRequest(index); try { // 如果不存在则返回 if (!restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT)) { return new PageUtils(arrayRes, 0, (int) limit, (int) curPage); } // 如果存在则继续查询 dsl WrapperQueryBuilder queryBuilder = new WrapperQueryBuilder(dsl); SearchRequest searchRequest = new SearchRequest(); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // 设置分页 searchSourceBuilder.query(queryBuilder).from((int)curPage).size((int)limit); searchRequest.source(searchSourceBuilder).indices(index); SearchResponse searchResp = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); // 计算返回的条数 CountRequest countRequest = new CountRequest(index); countRequest.query(queryBuilder); long count = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT).getCount(); SearchHit[] searchHitArr = searchResp.getHits().getHits(); for (SearchHit searchHit : searchHitArr) { Map temp = searchHit.getSourceAsMap(); // es自动生成的主键,然后插入现有的结果集中// temp.put("id", searchHit.getId()); arrayRes.add(temp); } return new PageUtils(arrayRes, (int) count, (int) limit, (int) curPage); } catch (IOException e) { e.printStackTrace(); throw new RRException(BizCodeEnum.SEARCH_OPENSEARCH_INDEX_ERROR.getMessage(), BizCodeEnum.SEARCH_OPENSEARCH_INDEX_ERROR.getCode()); } }

传入的vo

@Datapublic class ScanCommonVo extends BasicVo { @NotBlank(message = "dsl 表达式不能为空") private String dsl; @NotBlank(message = "索引") private String index;}@Data@ApiModel(description = " aws 基类")public class BasicVo { @ApiModelProperty(value = "当前页索引") private Long page; @ApiModelProperty(value = "每页大小") private Long limit;}

七、通过 Apifox 测试

关键词查询与分页查询都ok

八、前端展示效果

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。