Elasticsearch 的sql查询Java工具类

import com.alibaba.fastjson.JSONObject;
import com.unichain.statistics.utils.DateUtil;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.*;

public class EsQueryUtils {

    private static String esUrl = "http://127.0.0.1:9200/_xpack/sql?format=json";

    /** logger */
    private static final Logger log = LoggerFactory.getLogger(EsQueryUtils.class);

    /**
     * esSql查询 sql语句中需要用到参数的地方, 请用#{param} 的形式修饰,#{}符号中间的单词就是第二个参数中的某个键
     * @param sql sql语句
     * @param params 参数 一个key对应一个参数
     * @param className 目标类的class
     * @return
     */
    public static  List query(String sql, Map params, Class className) {
        if (StringUtils.isBlank(sql)) {
            return new ArrayList<>();
        }
        log.debug("es查询sql入参 >>> {}", sql);
        log.debug("es查询param入参 >>> {}", JSONObject.toJSONString(params));

        // 转换sql参数
        if (params != null && params.size() != 0) {
            params.keySet().forEach(key -> {
                sql.replace("#{" + key + "}", params.toString());
            });
        }

        Map query = new HashMap<>();
        query.put("query", sql);

        JSONObject response = JSONObject.parseObject(HttpUtils.doPost(esUrl, JSONObject.toJSONString(query)));

        List columns = JSONObject.parseArray(response.getString("columns"), Columns.class);
        List rows = JSONObject.parseArray(response.getString("rows"), List.class);
        EsModel esModel = new EsModel(columns, rows);

        return esModelToJavaObject(esModel, className);
    }

    /**
     * model转换实体类
     * @author [email protected]
     * @param esModel
     * @param className
     * @param 
     * @return
     */
    private static  List esModelToJavaObject(EsModel esModel, Class className) {
        Field[] fields = className.getDeclaredFields();
        List result = new ArrayList<>(esModel.getRows().size());
        esModel.getRows().forEach(row -> {
            try {
                // 判断是不是基本数据类型
                if (!isBasicType(className)) {
                    // 新增实体
                    T t = className.newInstance();
                    for (int i = 0; i < fields.length; i++) {
                        // 设置该属性可以修改
                        fields[i].setAccessible(true);
                        for (int j = 0; j < esModel.getColumns().size(); j++) {
                            // 判断属性名和es返回的列名一致
                            if (fields[i].getName().equals(esModel.getColumns().get(j).getName())) {
                                String type = esModel.getColumns().get(j).getType();
                                Object val = row.get(j);
                                // 时间转换Time  // 这里的弊端。时间转换没有办法识别。我只能通过这个列名有没有Time这个单词来判断是不是时间
                                if (esModel.getColumns().get(j).getName().toLowerCase().contains("time"))
                                    type = "time";
                                Object o = castValue(type, val);
                                fields[i].set(t, o);
                            }
                        }
                    }
                    result.add(t);
                }else {
                    String type = esModel.getColumns().get(0).type;
                    Object val = row.get(0);
                    // 基本数据类型
                    Object o = castValue(type, val);

                    result.add((T) o);
                }
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        });

        return result;
    }

    /**
     * 主要针对Es返回的类型转换成数据类型包装类
     * @author [email protected]
     * @time 23:11
     * @param type es结果集中返回的类型
     * @param val 需要转换的值
     */
    private static Object castValue(String type, Object val) {
        if (StringUtils.isBlank(type) || val == null) {
            return null;
        }
        if ("text".equals(type)) {
            try {
                return val.toString();
            // 防止时间转换失败
            }catch (IllegalArgumentException e) {
                return DateUtil.parseDateSecondFormat(val + "");
            }
        }else if ("long".equals(type)) {
            return Long.parseLong(val + "");
        } else if ("time".equals(type)) {
            // 防止时间转换错误
            try {
                return new Date(Long.parseLong(val + "")); // 时间戳转换
            }catch (NumberFormatException e) {
                return DateUtil.parseDateSecondFormat(val + ""); // 时间转换为yyyy-MM-dd HH:mm:ss 可以更换
            }
        }
        return null;
    }

    /**
     * 判断是不是基本数据类型包装类
     * @author [email protected]
     * @time 22:47
     * @params
     */
    private static boolean isBasicType(Class className) {
        if (className == null) {
            return false;
        } else if(className.equals(String.class)) {
            return true;
        } else if(className.equals(Integer.class)) {
            return true;
        } else if(className.equals(Long.class)) {
            return true;
        } else if(className.equals(Short.class)) {
            return true;
        } else if(className.equals(Double.class)) {
            return true;
        } else if(className.equals(Float.class)) {
            return true;
        } else if(className.equals(Character.class)) {
            return true;
        } else if(className.equals(Byte.class)) {
            return true;
        }

        return false;
    }


    public static void main(String[] args) {
        List query = query("select count(1) from apply_info group by accountId", null, Long.class);
        query.forEach(it -> System.out.println(JSONObject.toJSON(it)));
    }

    /**
     * 针对ES返回数据定义的Dto
     * @author [email protected]
     * @time 23:12
     */
    @Data
    static class EsModel{
        private List columns;
        private List rows;

        public EsModel(List columns, List rows) {
            this.columns = columns;
            this.rows = rows;
        }
    }

    /**
     * EsQuery中使用sql查询。他会返回的列
     * @author [email protected]
     * @time 23:13
     */
    @Data
    static class Columns{
        /**
         * 列名
         */
        private String name;

        /**
         * 列的类型
         */
        private String type;
    }
}

工具类有待完善,目前只对查询进行了一次封装。原理是ES6版本以后加入了xpack这个插件,然后插件可以通过sql查询,我仅仅是对他查询出来的结果做了一次封装。可以转换成你想要的目标类

后面我会封装增删改的操作。当然还是写sql,只不过后续改的话需要做一些。sql转换的步骤,写完的话我会及时更新的

你可能感兴趣的:(Utils)