Elasticsearch經過JAVA建立索引、Mapping以及數據的增刪該查操做

由於目前項目中用的JDK是1.7版本的,而ElasticSearch5.x版本須要使用JDK1.8版本,因此如下的代碼都是基於ElasticSearch 2.4.6版本的,如下的代碼是從項目中提取出來的,因此有些跟業務相關的代碼就不貼出來了,僅供本身只好參考使用,因此直接看如下代碼,可能不少代碼是看不懂的。java

引入Mavenapache

<dependency>
			<groupId>org.elasticsearch</groupId>
			<artifactId>elasticsearch</artifactId>
			<version>2.4.6</version>
		</dependency>

枚舉工具類json

package com.linewell.ccip.utils.es;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 枚舉工具類
 */
public class EnumUtils {

	// 枚舉字符串轉枚舉類型的轉換方法
	private static String FROM_STRING = "fromString";
	
	/**
	 * 供
	 * 解析通用查詢參數(分頁參數、排序參數)
	 * DataGridUtils.parseQueryInfo方法調用
	 * 
	 * 根據類、字段名稱、字段值(枚舉字符),若字段爲枚舉,返回枚舉值,不然直接返回字段值
	 * @param entityCls 類,如com.linewell.ccip.servicesbase.bean.log.OrgLog.class
	 * @param fieldName 字段名稱,如com.linewell.ccip.servicesbase.bean.log.type.OperType
	 * @param fieldVal 字段(枚舉字符串),如INSERT
	 * @return 若字段爲枚舉,返回枚舉值,不然直接返回字段值
	 */
	public static Object getValByField(Class<?> entityCls, String fieldName, Object fieldVal) {
		Object obj = null;
		try {
			// 字段類型
			Class<?> fieldCls = getFieldType(entityCls, fieldName);
			// 字段類型是否爲枚舉類型
			boolean isEnumCls = fieldCls.isEnum(); 
			
			// 是枚舉類
			if (isEnumCls) {
				obj = getEnum(fieldCls, (String)fieldVal);
			} else {
				obj = fieldVal;
			}
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return obj;
	}

	/**
	 * 根據枚舉字符串獲取枚舉值
	 * @param fieldCls	枚舉類
	 * @param fieldVal	枚舉字符串
	 * @return			枚舉值
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	private static Enum<?> getEnum(Class<?> fieldCls, String fieldVal)
			throws IllegalAccessException, InvocationTargetException {
		Enum<?> enumCls = null;
		// 所有的方法
		Method[] methods = fieldCls.getMethods();
		// 方法不爲空
		if (null != methods && 0 < methods.length) {
			// 方法名稱
			String metName = null;
			// 遍歷所有方法
			for (Method method : methods) {
				metName = method.getName();
				// 枚舉類的字符串轉枚舉的方法
				if (FROM_STRING.equalsIgnoreCase(metName)) {
					enumCls = (Enum<?>) method.invoke(fieldCls, fieldVal);
					break;
				}
			}
		}
		return enumCls;
	}
	
	/**
	 * 根據類、屬性名獲取其屬性類型
	 * @param cls
	 * @param findFieldName
	 * @return
	 */
	private static Class<?> getFieldType(Class<?> cls, String findFieldName) {
		// 字段類型
		Class<?> fieldCls = null;
		try {
			// 獲取該類自身所聲明的屬性,沒有獲取父類聲明的屬性
			List<Field> fields = getFields(cls);
			// 屬性不爲空
			if (null != fields) {
				// 是否找到屬性
				boolean isFind = false;
				// 屬性名
				String fieldName = "";
				// 變量屬性數組
				for (Field field : fields) {
					fieldName = field.getName();
					// 類自身找到屬性獲取其屬性類型
					if (findFieldName.equalsIgnoreCase(fieldName)) {
						isFind = true;
						fieldCls = field.getType();
						break;
					}
				}
				// 類自身沒有找到屬性獲取其屬性類型,查找其父類聲明的屬性
				if (false == isFind) {
					Field supField = cls.getSuperclass().getDeclaredField(findFieldName);
					fieldCls = supField.getType();
				}
			}
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}
		return fieldCls;
	}

	private static List<Field> getFields(Class<?> objClass) {
		Field[] fields = objClass.getDeclaredFields();
		List<Field> fieldList = new ArrayList<>();
		fieldList.addAll(Arrays.asList(fields));
		while (null != objClass) {
			fieldList.addAll(Arrays.asList(objClass.getDeclaredFields()));
			objClass = objClass.getSuperclass();
		}
		return fieldList;
	}
}

ElasticSearch工具類數組

package com.linewell.ccip.utils.es;

import com.google.common.collect.Lists;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.IndicesAdminClient;
import org.elasticsearch.client.Requests;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentBuilder;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.InetAddress;
import java.util.*;

import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;

/**
 * ElasticSearch工具類
 *
 * @author zchuanzhao
 * 2018/7/3
 */
public class EsHandler {
    /**
     * 須要分詞字段
     */
    private static List<String> ANALYZED_FIELD = Lists.newArrayList("userName", "authType");
    /**
     * 集羣名稱cluster.name
     */
    public static final String ES_CLUSTER_NAME = "logdb";
    /**
     * 主機IP
     */
    private static final String ES_HOST = "localhost";
    /**
     * 端口號
     */
    private static final int ES_TCP_PORT = 9300;

    public ThreadLocal<SearchResponse> responseThreadLocal = new ThreadLocal<>();

    private static final Map<String, String> MAPPINGS = new HashMap<>();

//    Settings settings = Settings.settingsBuilder()
//            .put("cluster.name", "bropen")
//            .put("shield.user","bropen:password")
//            .build();

    static Settings settings = Settings.settingsBuilder().put("cluster.name", ES_CLUSTER_NAME).build();
    // 建立ES客戶端
    private static TransportClient client;

    static {
        try {
            client = TransportClient.builder().settings(settings).build().addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(ES_HOST), ES_TCP_PORT));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 取得ES客戶端
     */
    public static TransportClient getClient() {
        return client;
    }

    /**
     * 關閉客戶端
     *
     * @param client
     */
    public static void close(TransportClient client) {
        if (null != client) {
            client.close();
        }
    }

    /**
     * Mapping處理
     *
     * @param obj
     */
    public static void mapping(Object obj) {
        String type = obj.getClass().getSimpleName().toLowerCase();
        if (!MAPPINGS.containsKey(type)) {
            synchronized (EsHandler.class) {
                createIndex();
                //獲取全部的Mapping
                ImmutableOpenMap<String, MappingMetaData> mappings = client.admin().cluster().prepareState().execute()
                        .actionGet().getState().getMetaData().getIndices().get(ES_CLUSTER_NAME).getMappings();
                MappingMetaData mmd = mappings.get(type);
                if (null == mmd) {
                    createMapping(obj);
                } else {
                    CompressedXContent xContent = mappings.get(type).source();
                    if (xContent == null) {
                        createMapping(obj);
                    } else {
                        String mapping = xContent.toString();
                        MAPPINGS.put(type, mapping);
                    }
                }
            }
        }
    }

    /**
     * 建立Mapping
     *
     * @param obj
     */
    public static void createMapping(Object obj) {
        String type = obj.getClass().getSimpleName().toLowerCase();
        PutMappingRequest mapping = Requests.putMappingRequest(ES_CLUSTER_NAME).type(type).source(setMapping(obj));
        EsHandler.getClient().admin().indices().putMapping(mapping).actionGet();
    }

    /**
     * 設置對象的ElasticSearch的Mapping
     *
     * @param obj
     * @return
     */
    public static XContentBuilder setMapping(Object obj) {
        List<Field> fieldList = getFields(obj);
        XContentBuilder mapping = null;
        try {
            mapping = jsonBuilder().startObject().startObject("properties");
            for (Field field : fieldList) {
                //修飾符是static的字段不處理
                if (Modifier.isStatic(field.getModifiers())){
                    continue;
                }
                String name = field.getName();
                if (ANALYZED_FIELD.contains(name)) {
                    mapping.startObject(name)
                            .field("type", getElasticSearchMappingType(field.getType().getSimpleName().toLowerCase()))
                            .field("index", "analyzed")
                            //使用IK分詞器
                            .field("analyzer", "ik_max_word")
                            .field("search_analyzer", "ik_max_word")
                            .endObject();
                } else {
                    mapping.startObject(name)
                            .field("type", getElasticSearchMappingType(field.getType().getSimpleName().toLowerCase()))
                            .field("index", "not_analyzed")
                            .endObject();
                }
            }
            mapping.endObject().endObject();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return mapping;
    }

    /**
     * 獲取對象全部自定義的屬性
     *
     * @param obj
     * @return
     */
    private static List<Field> getFields(Object obj) {
        Field[] fields = obj.getClass().getDeclaredFields();
        List<Field> fieldList = new ArrayList<>();
        fieldList.addAll(Arrays.asList(fields));
        Class objClass = obj.getClass();
        while (null != objClass) {
            fieldList.addAll(Arrays.asList(objClass.getDeclaredFields()));
            objClass = objClass.getSuperclass();
        }
        return fieldList;
    }

    /**
     * java類型與ElasticSearch類型映射
     *
     * @param varType
     * @return
     */
    private static String getElasticSearchMappingType(String varType) {
        String es;
        switch (varType) {
            case "date":
                es = "date";
                break;
            case "double":
                es = "double";
                break;
            case "long":
                es = "long";
                break;
            case "int":
                es = "long";
                break;
            default:
                es = "string";
                break;
        }
        return es;
    }

    /**
     * 判斷ElasticSearch中的索引是否存在
     */
    private static boolean indexExists() {
        IndicesAdminClient adminClient = client.admin().indices();
        IndicesExistsRequest request = new IndicesExistsRequest(ES_CLUSTER_NAME);
        IndicesExistsResponse response = adminClient.exists(request).actionGet();
        if (response.isExists()) {
            return true;
        }
        return false;
    }

    /**
     * 建立索引
     */
    private static void createIndex() {
        if (!indexExists()) {
            CreateIndexRequest request = new CreateIndexRequest(ES_CLUSTER_NAME);
            client.admin().indices().create(request);
        }
    }
}

ElasticSearch查詢條件操做工具類app

package com.linewell.ccip.utils.es;

import com.linewell.ccip.common.bean.datalist.engine.QueryInfo;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.sort.SortOrder;

import java.util.Map;
import java.util.Set;

/**
 * ElasticSearch查詢條件操做工具類
 * @author zchuanzhao
 * 2018/7/5
 */
public class EsDataGridUtils {

    /**
     * 排序字段
     */
    private static final String SORT_FIELD = "sortField";

    /**
     * 排序類型
     */
    private static final String SORT_ORDER = "sortOrder";

    /**
     * 查詢字段
     */
    private static final String QUERY_KEY = "query";

    /**
     * 相等條件
     */
    private static final String EQUALS_KEY = "equals";

    /**
     * 模糊匹配條件
     */
    private static final String LIKE_KEY = "like";

    /**
     * 大於等於條件
     */
    private static final String GREATER_EQUALS_KEY = "ge";

    /**
     * 小於等於條件
     */
    private static final String LESS_EQUALS_KEY = "le";

    /**
     * 查詢條件關係
     */
    private static final String SELECT_KEY = "select";

    /**
     * AND條件關係
     */
    private static final String AND_KEY = "and";
    /**
     * ASC
     */
    private static final String ASC_KEY = "asc";

    /**
     *  解析通用查詢參數(分頁參數、排序參數)
     * @param builder
     * @param queryInfo 查詢信息
     * @param beanClass 查詢對象
     * @param defaultSort 默認排序
     */
    public static void parseQueryInfo(SearchRequestBuilder builder, QueryInfo queryInfo, Class beanClass, String defaultSort) {
        Map<String, String> requestMap = queryInfo.getRequestMap();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 排序類型
        SortOrder sortOrder = SortOrder.DESC;
        // 排序字段
        String sortField = defaultSort;
        // 查詢字段
        if (requestMap != null) {
            //獲取排序信息
            if (requestMap.containsKey(SORT_ORDER)) {
                String sortOrderValue = requestMap.get(SORT_ORDER);
                if (ASC_KEY.equals(sortOrderValue)){
                    sortOrder = SortOrder.ASC;
                }
            }
            if (requestMap.containsKey(SORT_FIELD) && null !=  requestMap.get(SORT_FIELD)) {
                sortField = requestMap.get(SORT_FIELD);
            }
            //獲取查詢條件信息
            if (requestMap.containsKey(QUERY_KEY)) {
                String queryStr = requestMap.get(QUERY_KEY);
                if(!StringUtils.isEmpty(queryStr)) {
                    JSONObject queryObj = JSONObject.fromObject(queryStr);
                    // 相等的字段
                    JSONObject equalsObj = queryObj.optJSONObject(EQUALS_KEY);
                    // 匹配字段
                    JSONObject likeObj = queryObj.optJSONObject(LIKE_KEY);
                    // 匹配字段
                    JSONObject geObj = queryObj.optJSONObject(GREATER_EQUALS_KEY);
                    // 匹配字段
                    JSONObject leObj = queryObj.optJSONObject(LESS_EQUALS_KEY);
                    if(equalsObj != null) {
                        Set<String> set = equalsObj.keySet();
                        // 字段值
                        Object objVal;
                        // 字段值
                        Object fieldVal;
                        for (String fieldName: set) {
                            fieldVal = equalsObj.opt(fieldName);
                            // 若字段爲枚舉,返回枚舉值,不然直接返回字段值
                            objVal = EnumUtils.getValByField(beanClass, fieldName, fieldVal);
                            boolQueryBuilder.must(QueryBuilders.matchQuery(fieldName, objVal));
                        }
                    }
                    JSONObject selectObj = queryObj.optJSONObject(SELECT_KEY);
                    boolean queryAnd = false;
                    if (null != selectObj) {
                        queryAnd = (Boolean) selectObj.get(AND_KEY);
                    }
                    if(likeObj != null) {
                        Set<String> set = likeObj.keySet();
                        for(String key: set) {
                            QueryBuilder termQuery = QueryBuilders.termQuery(key, likeObj.optString(key));
                            if (queryAnd){
                                boolQueryBuilder.must(termQuery);
                            }else {
                                boolQueryBuilder.should(termQuery);
                            }
                        }
                    }
                    //大於等於
                    if(geObj != null) {
                        Set<String> set = geObj.keySet();
                        for(String key: set) {
                            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery(key).gte(geObj.optString(key));
                            if (queryAnd){
                                boolQueryBuilder.must(rangeQuery);
                            }else {
                                boolQueryBuilder.should(rangeQuery);
                            }
                        }
                    }
                    //小於等於
                    if(leObj != null) {
                        Set<String> set = leObj.keySet();
                        for(String key: set) {
                            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery(key).lte(leObj.optString(key));
                            if (queryAnd){
                                boolQueryBuilder.must(rangeQuery);
                            }else {
                                boolQueryBuilder.should(rangeQuery);
                            }
                        }
                    }
                }
            }
        }
        builder.setQuery(boolQueryBuilder);

        //分頁查詢,設置偏移量和每頁查詢數量
        builder.setFrom(queryInfo.getCurrentPageNum() * queryInfo.getCountPerPage()).setSize(queryInfo.getCountPerPage());

        //排序
        builder.addSort(sortField, sortOrder);
    }
}

ElasticSearch操做類接口elasticsearch

package com.linewell.ccip.services.es;

import com.linewell.ccip.common.bean.datalist.engine.QueryInfo;
import com.linewell.ccip.servicesbase.bean.GridData;
import com.linewell.ccip.servicesbase.bean.log.LogBeanEntity;

/**
 * ElasticSearch操做類接口
 * @author zchuanzhao
 * 2018/7/2
 */
public interface IEsManager {
    /**
     * 保存對象
     * @param obj
     * @return
     */
    boolean save(Object obj);

    /**
     * 更新
     * @param obj
     * @return
     */
    boolean update(Object obj);

    /**
     * 刪除
     * @param unid
     * @param beanClass
     * @return
     */
    boolean delete(String unid, Class beanClass);

    /**
     * 獲取單個對象
     * @param unid
     * @param beanClass
     * @param <T>
     * @return
     */
    <T extends LogBeanEntity> T get(String unid, Class<T> beanClass);

    /**
     * 獲取分頁列表
     * @param queryInfo
     * @param beanClass
     * @param defaultSort
     * @param <T>
     * @return
     */
    <T extends LogBeanEntity> GridData<T> getList(QueryInfo queryInfo, Class<T> beanClass, String defaultSort);
}

ElasticSearch操做類ide

package com.linewell.ccip.services.es.impl;

import com.linewell.ccip.common.bean.datalist.engine.QueryInfo;
import com.linewell.ccip.services.es.IEsManager;
import com.linewell.ccip.servicesbase.bean.GridData;
import com.linewell.ccip.servicesbase.bean.log.LogBeanEntity;
import com.linewell.ccip.utils.es.EsHandler;
import com.linewell.ccip.utils.es.EsDataGridUtils;
import net.sf.json.JSONObject;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.ClearScrollRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import java.util.ArrayList;
import java.util.List;


/**
 * ElasticSearch操做類
 * @author zchuanzhao
 * 2018/7/2
 */
public class EsManagerImpl implements IEsManager {

    /**
     * TCP鏈接客戶端
     */
    private TransportClient client;

    public EsManagerImpl() {
        this.client = EsHandler.getClient();
    }

    /**
     * 保存對象
     * @param obj
     * @return
     */
    @Override
    public boolean save(Object obj) {
        EsHandler.mapping(obj);
        String className = obj.getClass().getSimpleName().toLowerCase();
        JSONObject json = JSONObject.fromObject(obj);
        json.put("id",json.get("unid"));
        IndexResponse response = client.prepareIndex(EsHandler.ES_CLUSTER_NAME, className, String.valueOf(json.get("id"))).setSource(json).get();
        return response.isCreated();
    }

    /**
     * 更新
     * @param obj
     * @return
     */
    @Override
    public boolean update(Object obj) {
        String className = obj.getClass().getSimpleName().toLowerCase();
        JSONObject json = JSONObject.fromObject(obj);
        UpdateResponse response = client.prepareUpdate(EsHandler.ES_CLUSTER_NAME, className, String.valueOf(json.get("id")))
                .setDoc(json)
                .get();

        return !response.isCreated();
    }


    /**
     * 刪除
     * @param unid
     * @param beanClass
     * @return
     */
    @Override
    public boolean delete(String unid, Class beanClass) {
        DeleteResponse response = client.prepareDelete(EsHandler.ES_CLUSTER_NAME, beanClass.getSimpleName().toLowerCase(), unid).get();
        return response.isFound();
    }

    /**
     * 獲取單個對象
     * @param unid
     * @param beanClass
     * @param <T>
     * @return
     */
    @Override
    public <T extends LogBeanEntity> T get(String unid, Class<T> beanClass) {
        GetResponse response = client.prepareGet(EsHandler.ES_CLUSTER_NAME, beanClass.getSimpleName().toLowerCase(), unid).get();
        if (response.isExists()) {
            String jsonStr = response.getSourceAsString();
            JSONObject json = JSONObject.fromObject(jsonStr);
            //TODO json中beanFlag保存的是null字符串,轉成bean會報錯,因此暫時先設置爲null
            json.put("beanFlag",null);
            T bean = (T) JSONObject.toBean(json, beanClass);
            //TODO json -> bean後,time會變成系統當前時間,暫時先用如下方式解決
            bean.setTime(json.getLong("time"));
            return bean;
        }
        return null;
    }

    /**
     * 獲取分頁列表
     * @param queryInfo
     * @param beanClass
     * @param defaultSort
     * @param <T>
     * @return
     */
    @Override
    public <T extends LogBeanEntity> GridData<T> getList(QueryInfo queryInfo, Class<T> beanClass, String defaultSort) {
        SearchRequestBuilder builder = client.prepareSearch(EsHandler.ES_CLUSTER_NAME).setTypes(beanClass.getSimpleName().toLowerCase()).
                setSearchType(SearchType.DEFAULT);
        //設置查詢條件信息
        EsDataGridUtils.parseQueryInfo(builder, queryInfo, beanClass, defaultSort);

        SearchResponse response = builder.execute().actionGet();
        SearchHits hits = response.getHits();
        List<T> list = new ArrayList<>();
        for (int i = 0; i < hits.getHits().length; i++) {
            String jsonStr = hits.getHits()[i].getSourceAsString();
            JSONObject json = JSONObject.fromObject(jsonStr);
            //TODO json中beanFlag保存的是null字符串,轉成bean會報錯,因此暫時先設置爲null
            json.put("beanFlag", null);
            T bean = (T) JSONObject.toBean(json, beanClass);
            //TODO json -> bean後,time會變成系統當前時間,暫時先用如下方式解決
            bean.setTime(json.getLong("time"));
            list.add(bean);
        }

        GridData<T> gridData = new GridData<>();
        gridData.setData(list);
        gridData.setTotal(response.getHits().getTotalHits());
        return gridData;
    }
}

這裏分頁使用的是from+size方式,由於咱們業務是須要跳頁和上一頁下一頁的,因此沒法使用scoll方式,可是使用from+size默認只能查詢10000之內的數據,因此使用ElasticSearch沒法實現咱們目前的業務,因此改用了solr。工具

相關文章
相關標籤/搜索