欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 后台管理


新闻资讯

MENU

软件开发知识
原文出处: 琴水玉

概述

假设我们要从一个 ES 索引(相当于一张DB表)查询数据,昆山软件公司,ES表有 order_no, order_type, state 等字段, 而应用工具则有属性 orderNo, orderType, state等。这样,就谋面对“将应用工具的属性与ES字段对应起来”的问题。

当然可以通过注释来说明,不外这样显得较量生硬。因为注释并不起实际浸染,代码里还得写一套映射干系,就会存在注释与代码纷歧致的环境。 那么,是否可以将这种对应干系的注释用代码形式来办理呢? Java 注解可以办理这个问题。

实现

界说注解

首先界说注解类。注解类需要提供对应的ES字段名 name、范例 type 以及是否必传 required。

  • @Retention 指明注解在何时起浸染,这里是在运行时。
  • @Target 指明注解应用于何种工具,这里应用于字段。
  • java; gutter: true">@Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    @Documented
    public @interface EsField {
    
      /**
       * 对应的ES字段名
       */
      String name();
    
      /**
       * 对应的ES字段的值范例
       * @return
       */
      String type() default "";
    
      /**
       * 是否必传
       */
      boolean required() default false;
    
    }

    应用规模工具

    接着,将注解应用到应用规模工具。为简捷,应用规模工具只有四个字段。

    java; gutter: true">@Data
    public class CustomerDomain implements DomainSearch {
    
      /** 店肆ID */
      @EsField(name="shop_id", required = true)
      private Long shopId;
    
      /** 订单编号 */
      @EsField(name="order_no")
      private String orderNo;
    
      /** 订单状态 */
      @EsField(name="state", type="list")
      private List<Integer> state;
    
      /** 订单范例 */
      @EsField(name="order_type", type="list")
      private List<Integer> orderType;
    
    }

    注解理会器

    接着,需要提供注解理会器,将对应的映射干系转成ES查询工具的一部门。

  • 利用接口的默认要领来实现,是为了支持差异的业务类自动可以转化为ES查询串;
  • 注解理会器需要利用Java反射机制,昆山软件开发,来获取相应的字段,以及字段上的注解界说,然后按照字段的范例、值、注解界说来做相应处理惩罚;
  • 利用反射来处理惩罚字段时,昆山软件开发,由于字段一般是私有的,因此必需先配置为可会见的,处理惩罚完成后还原为不行会见;
  • EsField field = f.getAnnotation(EsField.class) 用来获取字段上的注解信息(name, type, required);Object value = f.get(customerDomain) 用来获取字段的值;字段的其他范例信息可以通过 Field 的要领拿到。
  • public interface DomainSearch {
    
      Log logger = LogFactory.getLog(DomainSearch.class);
    
      default String toEsQuery() {
        Object customerDomain = this;
        EsQuery esQuery = new EsQuery();
        Field[] fields = this.getClass().getDeclaredFields();
        for (Field f: fields) {
          try {
            if (Modifier.isStatic(f.getModifiers())) {
              continue;
            }
    
            f.setAccessible(true);
    
            Object value = f.get(customerDomain);
    
            if (f.getAnnotation(EsField.class) != null) {
              EsField field = f.getAnnotation(EsField.class);
    
              if (field.required() && value == null) {
                throw new RuntimeException("field '" + field + "' is required. value is null");
              }
    
              if (isNeedOmitted(value)) {
                f.setAccessible(false);
                continue;
              }
    
              if ((value instanceof List) && ((List)value).size() == 1) {
                // 针对 List 中单个值做优化查询
                esQuery = esQuery.addTermFilter(field.name(), ((List)value).get(0));
              }
              else {
                esQuery = esQuery.addTermFilter(field.name(), value);
              }
            }
    
            f.setAccessible(false);
    
          } catch (Exception ex) {
            logger.error("failed to build es query for field: " + f.getName(), ex);
            throw new RuntimeException(ex.getCause());
          }
        }
        return esQuery.toJsonString();
      }
    
      /**
       * 判定是否需要忽略该字段的查询
       * @param value 字段值
       * @return 是否要忽略
       */
      default boolean isNeedOmitted(Object value) {
        if (value == null) {
          return true;
        }
    
        // 空字符串搜索值忽略
        if ((value instanceof String) && StringUtils.isBlank(value.toString())) {
          return true;
        }
    
        // 空列表串忽略
        if ((value instanceof List) && ((List)value).isEmpty()) {
          return true;
        }
        return false;
      }
    
    }

    查询工具

    ES查询工具将所有生成的查询条件转化为ES可以接管的查询字符串。

    public class EsQuery {
    
      private static int DEFAULT_SIZE = 100;
    
      private final Map<String, Object> termFilter;
      private final Map<String, Range> rangeFilter;
      private final Map<String, Match> matchFilter;
      private int size;
      private String orderBy = null;
      private String order = null;
    
      // query 查询语法, 是否需要 filtered, filter 这两层
      // 5.x 版本不再需要这两层
      private boolean isNeedFilterLayer = true;
    
      private Integer from;
    
      private final Map<String, Object> mustNotTermFilter;
    
      private final Map<String,Object> shouldTermFilter;
      private Integer shouldMatchMinimum;
    
      private List<String> includes;
      private List<String> excludes;
    
      public EsQuery() {
        this.termFilter = new HashMap<>();
        this.rangeFilter = new HashMap();
        this.matchFilter = new HashMap();
        this.mustNotTermFilter = new HashMap<>();
        this.shouldTermFilter = new HashedMap();
        this.size = DEFAULT_SIZE;
        this.includes = new ArrayList<>();
        this.excludes = new ArrayList<>();
      }
    
      public EsQuery addTermFilter(String key, Object value) {
        this.termFilter.put(key, value);
        return this;
      }
    
      public EsQuery addMustNotTermFilter(String key, Object value) {
        this.mustNotTermFilter.put(key, value);
        return this;
      }
    
      public EsQuery addAllMustNotTermFilter(Map<String,Object> mustNot) {
        if (mustNot != null && !mustNot.isEmpty()) {
          this.mustNotTermFilter.putAll(mustNot);
        }
        return this;
      }
    
      public EsQuery addShouldTermFilter(String key, Object value) {
        this.shouldTermFilter.put(key, value);
        return this;
      }
    
      public EsQuery addAllShouldTermFilter(Map<String,Object> should) {
        if (should != null && !should.isEmpty()) {
          this.shouldTermFilter.putAll(should);
        }
        return this;
      }
    
      public EsQuery addRangeFilter(String key, long gte, long lte){
        this.rangeFilter.put(key, new Range(gte, lte));
        return this;
      }
    
      public EsQuery addMatchFilter(String key, Match value) {
        this.matchFilter.put(key, value);
        return this;
      }
    
      public EsQuery addIncludeFields(List<String> includes) {
        this.includes.addAll(includes);
        return this;
      }
    
      public EsQuery addExcludeFields(List<String> excludes) {
        this.excludes.addAll(excludes);
        return this;
      }
    
    
      @Override
      public String toString() {
        return toJsonString();
      }
    
      public String toJsonString() {
        Map<String, Object> finalQuery = new HashMap<>();
        Map<String, Object> queryMap = new HashMap<>();
        Map<String, Object> filteredMap = new HashMap<>();
        Map<String, Object> filterMap = new HashMap<>();
        Map<String, Object> boolMap = new HashMap<>();
    
        List<Object> mustList = obtainTermFilterList(this.termFilter);
    
        List<Object> mustNotList = obtainTermFilterList(this.mustNotTermFilter);
    
        List<Object> shouldList = obtainTermFilterList(this.shouldTermFilter);
    
        if(!this.rangeFilter.isEmpty()){
          for(Map.Entry<String, Range> e: this.rangeFilter.entrySet()){
            Map<String, Object> rangeMap = new HashMap<>();
            Map<String, Object> rangeEntityMap = new HashMap<>();
            rangeEntityMap.put(e.getKey(), e.getValue().toMap());
            rangeMap.put(Constant.range, rangeEntityMap);
            mustList.add(rangeMap);
          }
        }
    
        if(!this.matchFilter.isEmpty()){
          this.matchFilter.forEach(
              (key, match) -> {
                Map<String, String> matchEntityMap = new HashMap<>();
                Map<String, Map> matchMap = new HashMap<>();
                Map<String, Map> subMatchMap = new HashMap<>();
                matchEntityMap.put(Constant.query, match.getQuery());
                matchEntityMap.put(Constant.should_minum, match.getMinimumShouldMatch());
                matchMap.put(key, matchEntityMap);
                subMatchMap.put(Constant.match, matchMap);
                mustList.add(subMatchMap);
              });
        }
    
        boolMap.put(Constant.must, mustList);
        if (!mustNotList.isEmpty())
          boolMap.put(Constant.mustNot, mustNotList);
        if (!shouldList.isEmpty()) {
          // 有 minimum_should_match 不带过滤器
          boolMap.put(Constant.should, shouldList);
          boolMap.put(Constant.should_minum, shouldMatchMinimum);
          queryMap.put(Constant.bool, boolMap);
        }
        else {
          if (isNeedFilterLayer) {
            filterMap.put(Constant.bool, boolMap);
            filteredMap.put(Constant.filter, filterMap);
            queryMap.put(Constant.filtered, filteredMap);
          }
          else {
            queryMap.put(Constant.bool, boolMap);
          }
        }
        finalQuery.put(Constant.query, queryMap);
    
        Map<String, Object> orderMap = new HashMap<>();
        Map<String, Object> orderItem = new HashMap<>();
    
        if(order != null && orderBy != null){
          orderItem.put(Constant.order, this.order);
          orderMap.put(this.orderBy, orderItem);
          finalQuery.put(Constant.sort, orderMap);
        }
    
        Map<String,Object> source = new HashMap<>();
        if (!includes.isEmpty()) {
          source.put(Constant.includes, this.includes);
        }
        if (!excludes.isEmpty()) {
          source.put(Constant.excludes, this.excludes);
        }
        if (!source.isEmpty()) {
          finalQuery.put(Constant.source, source);
        }
    
        finalQuery.put(Constant.size, this.size);
        if (from != null) {
          finalQuery.put(Constant.from, from.intValue());
        }
        return JSON.toJSONString(finalQuery);
      }
    
      public List<Object> obtainTermFilterList(Map<String, Object> termFilter) {
        List<Object> termFilterList = new ArrayList<>();
        for (Map.Entry<String, Object> e: termFilter.entrySet()){
          Map<String, Object> termMap = new HashMap<>();
          Map<String, Object> itemMap = new HashMap<>();
          itemMap.put(e.getKey(), e.getValue());
          if(e.getValue() instanceof List){
            termMap.put(Constant.terms, itemMap);
          }else{
            termMap.put(Constant.term, itemMap);
          }
          termFilterList.add(termMap);
        }
        return termFilterList;
      }
    
      public String getOrderBy() {
        return orderBy;
      }
    
      public void setOrderBy(String orderBy) {
        this.orderBy = orderBy;
      }
    
      public String getOrder() {
        return order;
      }
    
      public void setOrder(String order) {
        this.order = order;
      }
    
      public int getSize() {
        return size;
      }
    
      public void setSize(int size) {
        this.size = size;
      }
    
      public Integer getFrom() {
        return from;
      }
    
      public void setFrom(Integer from) {
        this.from = from;
      }
    
      public Map<String, Object> getTermFilter() {
        return Collections.unmodifiableMap(termFilter);
      }
    
      public Map<String, Range> getRangeFilter() {
        return Collections.unmodifiableMap(rangeFilter);
      }
    
      public Map<String, Object> getMustNotTermFilter() {
        return Collections.unmodifiableMap(mustNotTermFilter);
      }
    
      public Map<String, Object> getShouldTermFilter() {
        return Collections.unmodifiableMap(shouldTermFilter);
      }
    
      public Map<String, Match> getMatchFilter() {
        return matchFilter;
      }
    
      public void setShouldMatchMinimum(Integer shouldMatchMinimum) {
        this.shouldMatchMinimum = shouldMatchMinimum;
      }
    
      public Integer getShouldMatchMinimum() {
        return shouldMatchMinimum;
      }
    
      public Map<String, Object> getRangeMap(String key) {
        return Collections.unmodifiableMap(rangeFilter.get(key).toMap());
      }
    
      public List<String> getIncludes() {
        return Collections.unmodifiableList(includes);
      }
    
      public boolean isNeedFilterLayer() {
        return isNeedFilterLayer;
      }
    
      public void setNeedFilterLayer(boolean needFilterLayer) {
        isNeedFilterLayer = needFilterLayer;
      }
    
      @Override
      public boolean equals(Object o) {
        // for you to write
      }
    
      @Override
      public int hashCode() {
        // for you to write
    }

    小结