栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

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

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

模拟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

@Data
public 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

八、前端展示效果

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号