Java 泛型的使用,日志入ES

ES支持哪些数据类型??

① 基本字段类型
字符串:text(分词),keyword(不分词)   StringField(不分词文本),TextFiled(要分词文本)
              text默认为全文文本,keyword默认为非全文文本
数字:long,integer,short,double,float
日期:date
逻辑:boolean
② 复杂数据类型
对象类型:object
数组类型:array
地理位置:geo_point,geo_shape

在这里插入图片描述

在这里插入图片描述

注意:如果已经有数据,不能直接做映射,先删除掉,在添加映射,再添加数据
***简单映射***

POST {indexName}/{typeName}/_mapping
{
    "{typeName}": {
        "properties": {
            "id": {
                "type": "long"
            },
            "content": {
                "type": "text",
                "analyzer": "ik_smart",
                "search_analyzer": "ik_smart"
            }
        }
    }


注意:你可以在第一次创建索引的时候指定映射的类型。此外,你也可以晚些时候为新类型添加映射(或者为已有的类型更新映射)。

你可以向已有映射中增加字段,但你不能修改它。如果一个字段在映射中已经存在,这可能意味着那个字段的数据已经被索引。如果你改变了字段映射,那已经被索引的数据将错误并且不能被正确的搜索到。

我们可以更新一个映射来增加一个新字段,但是不能把已有字段的类型那个从 analyzed  改到 not_analyzed。
**同时对多个类型的映射配置方式(推荐)**
PUT {indexName}
{
  "mappings": {
    "user": {
      "properties": {
        "id": {
          "type": "integer"
        },
        "info": {
          "type": "text",
          "analyzer": "ik_smart",
          "search_analyzer"
        }
      }
    },
    "dept": {
      "properties": {
        "id": {
          "type": "integer"
        },
        ...更多字段映射配置
      }
    }
  }
}

对象及数组类型映射

在这里插入图片描述

数组与对象数组 --> 注意:数组中元素的类型必须一致。

在这里插入图片描述

)对象数组 - 里面所有对象字段的类型是一样的–>只需映射一个就好

在这里插入图片描述

注意1:同内联对象一样,对象数组也会被扁平化索引

在这里插入图片描述

注意2:扁平化后,对象属性的相关性已经丢失,因为每个多值字段只是一个数值集,不是排序的数组。

比如查询:哪个女朋友的年龄是18岁? 这个是无法查询到答案,如果需要保留关系,需要使用嵌套对象nested objects。

全局映射

  • 【 全局映射可以通过动态模板和默认设置两种方式实现 】
    
ex:员工类型的id要改为integer,而且部门类型的也要改为integer,甚至所有的都要改.这时每个都去修改非常麻烦.可以设置全局映射

默认方式:default

[ 一般用来设置_all不要了 ]
索引下所有的类型映射配置会继承_default_的配置,user类型的文档中将不会合并所有字段到_all,而dept会 如:

在这里插入图片描述

动态模板:dynamic_templates

注意:ES会默认把string类型的字段映射为text类型(默认使用标准分词器)和对应的keyword类型,如:

在这里插入图片描述
在实际应用场景中,一个对象的属性中,需要全文检索的字段较少,大部分字符串不需要分词,因此,需要利用全局模板覆盖自带的默认模板:
在这里插入图片描述

说明:上例中定义了两种动态映射模板string_as_text和string_as_keyword
在实际的类型字段映射时,会依次匹配:
    ①字段自定义配置
    ②全局dynamic_templates[string_as_text、string_as_keyword]
    ③索引dynamic_templates[...]
    ④ES自带的string类型映射,以最先匹配上的为准。
注意:索引库在创建的时候会继承当前最新的dynamic_templates,索引库创建后,修改动态模板,无法应用到已存在的索引库。

实践:映射的配置会影响到后续数据的索引过程,因此,在实际项目中应遵循如下顺序规则: 【有数据不做映射+根据优先级倒序来】

① 配置全局动态模板映射(覆盖默认的string映射)
② 配置字段映射(由于基本类型主要用于过滤和普通查询,因此,字段映射主要对需要全文检索的字段进行配置)
③ 创建、更新和删除文档
④ 搜索

优化后的代码

@Data
public class InvokeRequest {
    /**
     * 请求地址
     */
    private String url;
    /**
     * 请求接口名称
     */
    private String interfaceName;
    /**
     * 请求参数
     */
    private Object request;
    /**
     * 请求方法
     */
    private String method;
    /**
     * 编码方式
     */
    private String codeScheme;
    /**
     * 接口路径
     */
    private String interfacePath;

}
import **************************;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Slf4j
@Service
@AllArgsConstructor
@NoArgsConstructor
public class InvokeService {

    @Value("${method.address}")
    private String address;

    @Resource
    private RequestContext requestContext;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private LogService logService;

    public <E extends BaseResponse> E invoke(InvokeRequest invokeRequest, Class<E> responseClazz) {
        log.info("调用 {} 接口请求信息: {}", invokeRequest.getInterfacePath(), invokeRequest);

        String token = tokenService.getToken();
        String result = "";
        TimeInterval timeInterval = new TimeInterval();
        ICommonParam commonParam = requestContext.getCommonParam() == null ? new BaseCommonParam() : requestContext.getCommonParam();

        // 定义需要返回的对象
        E response = null;

        String url = address + "/openapi/httpService/" + invokeRequest.getInterfacePath() + "?access_token=" + token + "&method=" + invokeRequest.getMethod() + "&format=json";
        String requestParm = CustomJsonUtil.objectToJson(invokeRequest.getRequest());
        try {
            response = responseClazz.newInstance();

            if (StrUtil.isEmpty(token)) {
                response.setResCode("-1");
                response.setResDesc("未获取到token");
            }

            result = HttpRequestUtil.sendPost(url, requestParm, invokeRequest.getCodeScheme());

            log.info("调用 {} 接口返回信息: {} ", invokeRequest.getInterfaceName(), result);

            response = (E) CustomJsonUtil.jsonToObject(result, responseClazz);
        } catch (Exception e) {
            log.error(" error", e);
            response.fail(e.getMessage());
        } finally {
            log.info("调用 {} 接口用时: {} 毫秒", invokeRequest.getInterfaceName(), timeInterval.interval());
            logService.addLog(invokeRequest, url, commonParam, requestParm, result, response.getResCode(), timeInterval.interval());
        }

        return response;
    }

}

addLog() ,日志入es

import **************;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;

import lombok.extern.slf4j.Slf4j;
import org.frameworkset.elasticsearch.ElasticSearchHelper;
import org.frameworkset.elasticsearch.client.ClientInterface;
import org.frameworkset.spi.async.annotation.Async;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Date;

/**
 * 记录接口日志
 */
@Slf4j
@Service
public class LogService {

    private static final String BASE_INDEX_NAME_LOG_CMOP = "ubp-log-cmop";
    public static final String CREATE_CMOP_LOG = "createCmopLog";
    private static String INDEX_NAME;
    private String mappath = "esmapper/LogCmop.xml";

    @Autowired
    private ProjectProperties projectProperties;

    @PostConstruct
    public void LogApiEsService() {
        // ubp-log-cmop-stage-ubp
        INDEX_NAME = BASE_INDEX_NAME_LOG_CMOP.concat(StrUtil.DASHED).concat(ProjectProperties.env).concat(StrUtil.DASHED).concat(projectProperties.getGroup());
    }

    @Async
    public void addLog(InvokeRequest invokeRequest, String url, ICommonParam commonParam, String requestParm, String result, String returnCode, long interval) {
        LogCmop logCmop = new LogCmop();
        logCmop.setRequestUrl(url);
        logCmop.setRequestParam(StrUtil.subPre(requestParm, 2000));
        logCmop.setMethodName(invokeRequest.getMethod());
        logCmop.setRemark(invokeRequest.getInterfaceName());
        logCmop.setDuration(interval);
        logCmop.setReturnCode(returnCode);
        logCmop.setReturnMessage(StrUtil.subPre(result, 5000));
        logCmop.setChainId(commonParam.getChainId());
        logCmop.preInsert();

        ClientInterface client = ElasticSearchHelper.getConfigRestClientUtil(mappath);
        String dynamicIndexName = this.createDynamicIndexIfNotExist(client);

        LogCmopES logCmopES = new LogCmopES();
        BeanUtils.copyProperties(logCmop, logCmopES);
        logCmopES.setUserId(logCmop.getCreateBy());
        logCmopES.setTimestamp(DateUtil.format(new Date(), DatePattern.UTC_MS_WITH_ZONE_OFFSET_PATTERN));

        client.addDocument(dynamicIndexName, logCmopES);
    }

    private String createDynamicIndexIfNotExist(ClientInterface client) {
        String dynamicIndexName = client.getDynamicIndexName(INDEX_NAME);

        boolean existence = client.existIndice(dynamicIndexName);
        if (!existence) {
            client.createIndiceMapping(dynamicIndexName, CREATE_CMOP_LOG);
        }
        return dynamicIndexName;
    }

}

日志的实体类

@Data
@EqualsAndHashCode(callSuper = true)
@TableName("tb_log_cmop")
public class LogCmop extends BaseEntity {
    /**
     * 请求URL
     */
    private String requestUrl;
    /**
     * 请求参数
     */
    private String requestParam;
    /**
     * 方法名称
     */
    private String methodName;
    /**
     * 请求耗时
     */
    private Long duration;
    /**
     * 返回码
     */
    private String returnCode;
    /**
     * 返回信息
     */
    private String returnMessage;
    /**
     * 链路ID
     */
    private String chainId;
}

ES日志实体


@Data
public class LogCmopES {
    /**
     * 请求URL
     */
    private String requestUrl;
    /**
     * 请求参数
     */
    private String requestParam;
    /**
     * 方法名称
     */
    private String methodName;
    /**
     * 请求耗时
     */
    private Long duration;
    /**
     * 返回码
     */
    private String returnCode;
    /**
     * 返回信息
     */
    private String returnMessage;
    /**
     * 接口名称(中文)
     */
    private String interfaceName;
    /**
     * 链路ID
     */
    private String chainId;
    /**
     * 格林尼治时间
     */
    private String timestamp;
    /**
     * 用户id
     */
    private Long userId;
}

esmapper.xml

<properties>

    <property name="createCmopLog">
        <![CDATA[{
        "settings": {
            "number_of_shards": 1,
            "number_of_replicas": 0
        },
        "mappings": {
            "properties": {
                "requestUrl": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "requestParam": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "methodName": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "duration": {
                    "type": "integer"
                },
                "returnCode": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "returnMessage": {
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "type": "keyword",
                            "ignore_above": 256
                        }
                    }
                },
                "interfaceName": {
                    "type": "keyword"
                },
                "chainId": {
                    "type": "keyword"
                },
				"userId": {
					"type": "keyword"
				},
                "timestamp": {
                    "type": "date"
                }
            }
        }
        }]]>
    </property>

</properties>

未优化的代码

import *********************import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.frameworkset.spi.async.annotation.Async;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * 记录接口日志
 */
@Slf4j
@Service
@AllArgsConstructor
@NoArgsConstructor
public class LogServiceImpl  implements LogService {
    @Autowired
    private RequestContext requestContext;
    @Autowired
    private LogCmopService logCmopService;
    @Value("${method.address}")
    private String address;


    @Async
    @Override
    public <T, E extends BaseResponse> E invoke(LogRecordRequest recordRequest, Class<E> responseClazz) {
        log.info("调用 {} 接口", recordRequest.getInterfacePath());
        String result = "";
        TimeInterval timeInterval = new TimeInterval();
        ICommonParam commonParam = requestContext.getCommonParam() == null ? new BaseCommonParam() : requestContext.getCommonParam();
        //定义需要返回的对象
        E response = null;
        String token = recordRequest.getToken();
        if (StrUtil.isEmpty(token)) {
            response.setResCode("-1");
            response.setResDesc("未获取到token");
        } else {
            String url = address + recordRequest.getInterfacePath() + "?access_token=" + token + "&method=" + recordRequest.getMethod() + "&format=json";
            try {
                response = responseClazz.newInstance();
                result = HttpRequestUtil.sendPost(url, recordRequest.getRequest(), recordRequest.getCodeScheme());
                log.info("调用 {} 接口返回信息: {} ",recordRequest.getInterfaceName(), result);
                response = (E) CustomJsonUtil.jsonToObject(result, recordRequest.getT().getClass());
            } catch (Exception e) {
                log.error(" error", e);
                response.setResCode(AdapterEnum.CODE_1004.getCode());
                response.setResDesc(AdapterEnum.CODE_1004.getValue());
                return response;
            } finally {
                log.info("调用 {} 接口用时: {} 毫秒",recordRequest.getInterfaceName(), timeInterval.interval());
                LogCmopAddRequest logCmopAddRequest = new LogCmopAddRequest();
                logCmopAddRequest.setRequestUrl(recordRequest.getUrl());
                logCmopAddRequest.setRequestParam(StrUtil.subPre(recordRequest.getRequest(), 2000));
                logCmopAddRequest.setMethodName(recordRequest.getMethod());
                logCmopAddRequest.setDuration(timeInterval.interval());
                logCmopAddRequest.setReturnCode(response.getResCode());
                logCmopAddRequest.setReturnMessage(StrUtil.subPre(result, 5000));
                logCmopAddRequest.setChainId(commonParam.getChainId());
                logCmopService.add(logCmopAddRequest);
            }
        }
        return response;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值