最简单的es理解 数据库视角看写 ES 加 java正删改查深度分页

最简单的es理解 数据库视角看写 ES 加 java正删改查深度分页

目录

介绍 

es数据结构

java 操作 

根据script update

mget可以批量的根据index,type,ids三个字段来获取一批数据

根据文档编号进行获取

验证ES查询对象

根据条件删除,谨慎使用,整不好就把整个索引清空了

删除文档库

插入文档(如果重复插入就会导致后面的将前面的数据进行覆盖)

批量bulk操作 已存在,覆盖(如果进行更新操作时,params中的数据需要和ES中的数据元素保持一致,不然就会丢失部分数据)

更新插入操作 upsert操作

通过主键批量更新

id更新文档

查表行数

条件查表行数

条件加游标SearchAfter深度分页

**分页返回对象***

***ES查询对象***

完整代码 

es 相关代码

ESDbUtils es工具类

ElasticsearchTemplate es链接

ESQueryObj 查询对象

EsScriptUtil 脚本工具

异常

SystemException

BusinessException

BaseException

BadArgumentException

分页代码

Page

PageRequest

ScrollPage

ScrollPageRequest

测试

查询


介绍 

用数据库角度看es 更容易理解,这里总结些es组件 及 使用java 代码正删改查深度分野 正删改查 

es数据结构

 1.索引index=数据库
 2.类型type = 表 实体类
 3.文档document = 行数据 行id不填自动出
 4.字段field = 列 可单独配置索引和属性
 5.映射mapping = 定义文档结构 字段数据类型,索引,分析器
 6.分片shard = 物理存储单元 ,每个索引多个分片,每个分片分步多个节点上
 7.副本replica = 分片备份提高可用性查询性能 
 8.节点Node = 集群中实例,负责存储和查询
 9.集群Cluster=单多节点组成共同处理存查
 10.分析器Analyzer=处理文本数据分词过滤标准化可自定义便于有效索引和搜索

java 操作 

根据script update

/** * 根据script update * * @param indexName indexName * @param typeName typeName * @param params 需要更新的参数 * @param scriptStr scriptStr */ public Long updateByScript(String indexName, String typeName, String id, Map<String, Object> params, String scriptStr) { Script script = new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, scriptStr, params); UpdateRequestBuilder urb = elasticsearchTemplate.getClient().prepareUpdate(indexName, typeName, id); urb.setScript(script); //设置在插入时是否运行脚本 urb.setScriptedUpsert(true); //必须有这个值,否则会报document missing exception(文档不存在时设置文档的_source) urb.setUpsert(new HashMap()); urb.setRetryOnConflict(RETRY_ON_CONFLICT); try { UpdateResponse resp = urb.execute().actionGet(); return resp.getVersion(); } catch (VersionConflictEngineException e) { // log.error("occurred version conflict engine exception", e); throw e; } catch (Exception e) { log.error("occurred error", e); log.warn("updateByScript has error param:{}", JSON.toJSONString(params)); throw new BusinessException("occurred error when update es"); } } 

mget可以批量的根据index,type,ids三个字段来获取一批数据

/** * mget可以批量的根据index,type,id三个字段来获取一批数据,它不能用来查询,最少得需要知道index 和 id两个字段的值,才能进行get,这一点与query是不一样的。 * * @param indexName 索引名 * @param typeName 表名 * @param docIds 文档编号集合 * @param targetClass 获取数据封装对象 */ public <T> List<T> multiGetDoc(String indexName, String typeName, List<Object> docIds, Class<T> targetClass) { List<T> result = new ArrayList<>(); MultiGetRequestBuilder prepareMultiGet = elasticsearchTemplate.getClient().prepareMultiGet(); docIds.forEach(docId -> prepareMultiGet.add(indexName, typeName, docId.toString())); MultiGetResponse multiGetItemResponses = prepareMultiGet.get(); for (MultiGetItemResponse itemResponse : multiGetItemResponses) { GetResponse response = itemResponse.getResponse(); if (response.isExists()) { String res = response.getSourceAsString(); if (StringUtils.isEmpty(res)) { continue; } try { result.add(JSON.parseObject(res, targetClass)); } catch (Exception e) { log.error("occurred error", e); throw new BusinessException(String.format("occurred error when parse es result to Object:%s", targetClass.getCanonicalName())); } } } return result; }

根据文档编号进行获取

 /** * 根据文档编号进行获取 * * @param indexName 索引名 * @param typeName 表名 * @param id 文档编号 * @param targetClass 获取数据封装对象 */ public <T> T getById(String indexName, String typeName, String id, Class<T> targetClass) { GetRequest getRequest = new GetRequest(); getRequest.index(indexName).type(typeName).id(id); try { GetResponse getResponse = elasticsearchTemplate.getClient().get(getRequest).get(); String result = getResponse.getSourceAsString(); if (StringUtils.isEmpty(result)) { return null; } return JSON.parseObject(result, targetClass); } catch (Exception e) { log.error("occurred error", e); throw new BusinessException("occurred error when query from es!"); } }

验证ES查询对象

 /** * 验证ES查询对象 * 抛出异常则未查到,正常则通过 */ private void validationESIndexAndType(ESQueryObj esQueryObj) { Preconditions.checkArgument(!StringUtils.isEmpty(esQueryObj.getIndexName()), "indexName can't be null"); Preconditions.checkArgument(!StringUtils.isEmpty(esQueryObj.getTypeName()), "typeName can't be null"); }

根据条件删除,谨慎使用,整不好就把整个索引清空了

/** * 根据条件删除,谨慎使用,整不好就把整个索引清空了 * @param indexName * @param boolQueryBuilder * @return */ public long deleteDocByQuery(String indexName, BoolQueryBuilder boolQueryBuilder) { DeleteByQueryRequestBuilder builder = DeleteByQueryAction.INSTANCE.newRequestBuilder(elasticsearchTemplate.getClient()).refresh(true).filter(boolQueryBuilder).source(indexName); long deleted = builder.get().getDeleted(); return deleted; }

删除文档库

/** * 删除文档库 * * @param indexName 索引名 * @param typeName 表名 * @param id 文档编号 */ public long deleteDoc(String indexName, String typeName, String id) { DeleteRequest deleteRequest = new DeleteRequest(); deleteRequest.id(id); deleteRequest.index(indexName); deleteRequest.type(typeName); deleteRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); try { DeleteResponse resp = elasticsearchTemplate.getClient().delete(deleteRequest).get(); return resp.getVersion(); } catch (Exception e) { log.error("occurred error", e); throw new BusinessException("occurred error when delete doc from es!"); } }

插入文档(如果重复插入就会导致后面的将前面的数据进行覆盖)

 /** * 插入文档(如果重复插入就会导致后面的将前面的数据进行覆盖) * * @param indexName 索引名 * @param typeName 表名 * @param id 文档编号 * @param param 文档内容 * @return String */ public String insert(String indexName, String typeName, String id, Map<String, Object> param) { // 指定索引名称,type名称和documentId(documentId可选,不设置则系统自动生成)创建document IndexRequestBuilder indexRequestBuilder = elasticsearchTemplate.getClient().prepareIndex(indexName, typeName).setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); IndexResponse response = indexRequestBuilder.setSource(param).setId(id).get(); if (response.getResult().equals(DocWriteResponse.Result.CREATED)) { return response.getId(); } return null; }

批量bulk操作 已存在,覆盖(如果进行更新操作时,params中的数据需要和ES中的数据元素保持一致,不然就会丢失部分数据)

 /** * 批量bulk操作 已存在,覆盖(如果进行更新操作时,params中的数据需要和ES中的数据元素保持一致,不然就会丢失部分数据) * * @param indexName 索引名 * @param typeName 表名 * @param params 一次操作的数据量最好保持在5-15MB大小间。 * @param primaryKeyName params里面主键key,对应的主键ID不能为空 */ public void bulk(String indexName, String typeName, List<Map<String, Object>> params, String primaryKeyName) { BulkRequestBuilder bulkRequest = elasticsearchTemplate.getClient().prepareBulk(); for (Map<String, Object> param : params) { if (param.get(primaryKeyName) == null) { log.error("occurred error when bulk doc"); throw new BusinessException("occurred error when bulk es doc,the ID is null"); } bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); bulkRequest.add(elasticsearchTemplate.getClient().prepareIndex(indexName, typeName) .setOpType(DocWriteRequest.OpType.INDEX) .setId(String.valueOf(param.get(primaryKeyName))) .setSource(param)); } bulkRequest.execute().actionGet(); }

更新插入操作 upsert操作

 /** * upsert操作 * * @param indexName 索引名 * @param typeName 表名 * @param id 文档编号 */ public long upsertDoc(String indexName, String typeName, String id, Map<String, Object> param) { IndexRequest indexRequest = new IndexRequest(indexName, typeName, id); indexRequest.source(param); UpdateRequest updateRequest = new UpdateRequest(); updateRequest.index(indexName); updateRequest.type(typeName); updateRequest.id(id); updateRequest.doc(param); updateRequest.upsert(indexRequest); updateRequest.retryOnConflict(RETRY_ON_CONFLICT); updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); try { UpdateResponse resp = elasticsearchTemplate.getClient().update(updateRequest).get(); return resp.getVersion(); } catch (Exception e) { log.error("occurred error when update doc", e); throw new BusinessException("occurred error when upsert es doc"); } }

通过主键批量更新

/** * 通过主键批量更新 * * @param indexName 索引名称 * @param typeName 类型名称 * @param idToParams 主键ID及对应需要更新的参数和值 */ public void bulkUpdateByIds(String indexName, String typeName, Map<String, Map<String, Object>> idToParams) { BulkRequest bulkRequest = new BulkRequest(); for (Map.Entry<String, Map<String, Object>> entry : idToParams.entrySet()) { String id = entry.getKey(); Map<String, Object> paramFields = entry.getValue(); UpdateRequest updateRequest = new UpdateRequest(); updateRequest.index(indexName); updateRequest.type(typeName); updateRequest.id(id); updateRequest.doc(paramFields); updateRequest.retryOnConflict(RETRY_ON_CONFLICT); bulkRequest.add(updateRequest); } ActionFuture<BulkResponse> future = elasticsearchTemplate.getClient().bulk(bulkRequest); BulkResponse bulkResponse = future.actionGet(); if (bulkResponse.hasFailures()) { log.error("bulkUpdateByIds fail bulkResponse={}", JSON.toJSONString(bulkResponse)); throw new BusinessException("bulkUpdateByIds error"); } }

id更新文档

/** * 更新文档库 * * @param indexName 索引名 * @param typeName 表名 * @param id 文档编号 */ public long updateDoc(String indexName, String typeName, String id, Map<String, Object> param) { UpdateRequest updateRequest = new UpdateRequest(); updateRequest.index(indexName); updateRequest.type(typeName); updateRequest.id(id); updateRequest.doc(param); updateRequest.retryOnConflict(RETRY_ON_CONFLICT); updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); try { UpdateResponse resp = elasticsearchTemplate.getClient().update(updateRequest).get(); return resp.getVersion(); } catch (Exception e) { log.error("occurred error when update doc", e); throw new BusinessException("occurred error when update doc"); } }

scrollSearch 使用游标方式搜索, 适用于10000以上的数据获取,不支持排序

/** * 使用游标方式搜索, 适用于10000以上的数据获取,不支持排序 * * @param esQueryObj 查询条件 * @param scrollPageRequest 分页信息 * @param targetClass 需要封装的对象 * @return ScrollPage */ public <T> ScrollPage<T> scrollSearch(ESQueryObj esQueryObj, ScrollPageRequest scrollPageRequest, Class<T> targetClass) { ScrollPage<T> returnPage = new ScrollPage<>(); returnPage.setSize(scrollPageRequest.getPageSize()); SearchResponse scrollResp; // 没有ScrollId 说明是首次请求 if (StringUtils.isBlank(scrollPageRequest.getScrollId())) { SearchRequestBuilder srb = elasticsearchTemplate.getClient().prepareSearch(esQueryObj.getIndexName()).setTypes(esQueryObj.getTypeName()).setScroll(new TimeValue(scrollPageRequest.getScrollSeconds() * 1000)).setQuery(esQueryObj.getQuery()).setSize(scrollPageRequest.getPageSize()).setFetchSource(esQueryObj.getIncludeFields(), esQueryObj.getExcludeFields()); if (!esQueryObj.getSortField().isEmpty()) { Map<String, SortOrder> sortField = esQueryObj.getSortField(); for (String key : sortField.keySet()) { srb.addSort(key, sortField.get(key)); } } scrollResp = srb.execute().actionGet(); } else { // 使用ScrollId获取剩余的数据 scrollResp = elasticsearchTemplate.getClient().prepareSearchScroll(scrollPageRequest.getScrollId()).setScroll(new TimeValue(scrollPageRequest.getScrollSeconds() * 1000)).execute().actionGet(); } SearchHits searchHits = scrollResp.getHits(); long totalCount = searchHits.getTotalHits(); if (totalCount == 0) { return returnPage; } returnPage.setTotalElements((int) totalCount); for (SearchHit hit : searchHits.getHits()) { returnPage.getContent().add(JSON.parseObject(hit.getSourceAsString(), targetClass)); } returnPage.setScrollId(scrollResp.getScrollId()); return returnPage; } //对应分页实体类 import java.io.Serializable; public class ScrollPageRequest implements Serializable { private int pageSize = 100; private long scrollSeconds = 60L; private String scrollId; public ScrollPageRequest() { } public int getPageSize() { return this.pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public long getScrollSeconds() { return this.scrollSeconds; } public void setScrollSeconds(long scrollSeconds) { this.scrollSeconds = scrollSeconds; } public String getScrollId() { return this.scrollId; } public void setScrollId(String scrollId) { this.scrollId = scrollId; } } 

查表行数

 public Long queryCount(String indexName, String typeName) throws BusinessException, BadArgumentException, SystemException { SearchRequestBuilder esSearch = elasticsearchTemplate.getClient().prepareSearch(indexName); esSearch.setTypes(typeName); SearchResponse response = esSearch.execute().actionGet(); SearchHits searchHits = response.getHits(); return searchHits.getTotalHits(); }

条件查表行数

public Long queryCountByFilterQuery(ESQueryObj esQueryObj) throws BusinessException, BadArgumentException, SystemException { validationESIndexAndType(esQueryObj); //创建ES查询Request对象 SearchRequestBuilder esSearch = elasticsearchTemplate.getClient().prepareSearch(esQueryObj.getIndexName()); esSearch.setTypes(esQueryObj.getTypeName()).setSearchType(SearchType.QUERY_THEN_FETCH).setFrom(esQueryObj.getFromIndex()).setSize(esQueryObj.getSize()).setFetchSource(esQueryObj.getIncludeFields(), esQueryObj.getExcludeFields()); //执行查询 SearchResponse response = esSearch.execute().actionGet(); return response.getHits().getTotalHits(); }

条件加游标SearchAfter深度分页

/** * 根据过滤条件查询出数据列表.需要传递索引和表名 * * @param esQueryObj ES查询对象 * @param targetClass ES结果需要转换的类型 * @return Page<T> */ public <T> Page<T> queryObjectPageByFilterQuery(ESQueryObj esQueryObj, Class<T> targetClass) throws BusinessException, BadArgumentException, SystemException { validationESIndexAndType(esQueryObj); Page<T> page = new Page<>(); long startCountTime = System.currentTimeMillis(); if (esQueryObj.getFromIndex() + esQueryObj.getSize() > DEFAULT_MAX_SIZE) { throw new BadArgumentException("分页深度不能超过10000"); } //创建ES查询Request对象 SearchRequestBuilder esSearch = elasticsearchTemplate.getClient().prepareSearch(esQueryObj.getIndexName()); esSearch.setTypes(esQueryObj.getTypeName()).setSearchType(SearchType.QUERY_THEN_FETCH).setFrom(esQueryObj.getFromIndex()).setSize(esQueryObj.getSize()).setFetchSource(esQueryObj.getIncludeFields(), esQueryObj.getExcludeFields()); //添加查询条件 if (esQueryObj.getQuery() != null) { esSearch.setQuery(esQueryObj.getQuery()); } //添加多级排序 if (esQueryObj.getSortField() != null) { for (Map.Entry<String, SortOrder> entry : esQueryObj.getSortField().entrySet()) { esSearch.addSort(entry.getKey(), entry.getValue()); } } //深分页 if (esQueryObj.getSearchAfter() != null && esQueryObj.getSearchAfter().length != 0) { esSearch.searchAfter(esQueryObj.getSearchAfter()); } //执行查询 SearchResponse response = esSearch.execute().actionGet(); for (SearchHit hit : response.getHits()) { page.getContent().add(JSON.parseObject(hit.getSourceAsString(), targetClass)); } // Object[] sortValues = response.getHits().getAt(9).getSortValues(); // log.info("EsDbUtils queryObjectPageByFilterQuery search:,esQueryObj:{},time consuming:{}ms.", response.getHits().getTotalHits(), (System.currentTimeMillis() - startCountTime)); page.setTotalElements(response.getHits().getTotalHits()); page.setSize(esQueryObj.getSize()); return page; }

**分页返回对象***

 import java.io.Serializable; import java.util.ArrayList; import java.util.List; public class Page<T> implements Serializable { private long totalElements = 0L; private int size = 10; private int page = 1; private List<T> content = new ArrayList(); public Page() { } public int getSize() { return this.size; } public void setSize(int size) { this.size = size; } public long getTotalElements() { return this.totalElements; } public void setTotalElements(long totalElements) { this.totalElements = totalElements; } public long getTotalPage() { return this.totalElements / (long)this.size + (long)(this.totalElements % (long)this.size == 0L ? 0 : 1); } public List<T> getContent() { return this.content; } public void setContent(List<T> content) { this.content = content; } public int getPage() { return this.page; } public void setPage(int page) { this.page = page; } } 

***ES查询对象***

 import lombok.Data; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import org.elasticsearch.common.Strings; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.search.sort.SortOrder; import java.util.Map; /** * @description: ES查询对象 * */ @Data public class ESQueryObj { /** * ES索引名 */ private String indexName; /** * ES TYPE名(表名) */ private String typeName; /** * 查询条件组合,类似于 "boolQuery().must( QueryBuilders.termQuery("opTime", "2016-03-30")).must(QueryBuilders.termQuery("operErpID", "xingkai"))" */ private QueryBuilder query; /** * 排序字段键值对,可以添加多个,类似于("opTime","DESC") */ private Map<String, SortOrder> sortField; /** * 取值的起始位置,默认为0 */ private int fromIndex; /** * 返回数据数量,默认为100,最大不能超过100000 */ private int size = 100; /** * 需要返回的字段 */ private String[] includeFields; /** * 不需要返回的字段 */ private String[] excludeFields = Strings.EMPTY_ARRAY; //https://blog.ZEEKLOG.net/yiyiholic/article/details/81661919 /** * 通过提供一个live cursor来规避消耗存储和时间的性能问题,通过上一页的结果帮助检索下一页,用第一次检索的最后一个值作为下一个检索search_after的参数,当使用search_after参数时,from的值必须被设为0或者-1 * 使用时注意必须按照某一字段进行排序 */ private Object[] searchAfter; @Override public String toString() { return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } } 

完整代码 

es 相关代码

ESDbUtils es工具类

package com.esm.common; import com.alibaba.fastjson.JSON; import com.google.common.base.Preconditions; import com.commons.data.page.Page; import com.commons.data.page.ScrollPage; import com.commons.data.page.ScrollPageRequest; import com.commons.exception.BadArgumentException; import com.commons.exception.BusinessException; import com.commons.exception.SystemException; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.elasticsearch.action.ActionFuture; import org.elasticsearch.action.DocWriteRequest; import org.elasticsearch.action.DocWriteResponse; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkRequestBuilder; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.get.*; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.action.support.WriteRequest; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.action.update.UpdateRequestBuilder; import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.index.engine.VersionConflictEngineException; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.reindex.DeleteByQueryAction; import org.elasticsearch.index.reindex.DeleteByQueryRequestBuilder; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptType; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.sort.SortOrder; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * ES基础操作工具类 * */ @Slf4j @Component("eSDbUtils") public class ESDbUtils { /** * 获取数据的最大条数 */ private static final int DEFAULT_MAX_SIZE = 10000; /** * 并发更新存在版本冲突是重试次数 */ private static final int RETRY_ON_CONFLICT = 3; /** * ES 客户端工厂类 */ @Resource private ElasticsearchTemplate elasticsearchTemplate; /** * 根据过滤条件查询出数据列表.需要传递索引和表名 * * @param esQueryObj ES查询对象 * @param targetClass ES结果需要转换的类型 * @return Page<T> */ public <T> Page<T> queryObjectPageByFilterQuery(ESQueryObj esQueryObj, Class<T> targetClass) throws BusinessException, BadArgumentException, SystemException { validationESIndexAndType(esQueryObj); Page<T> page = new Page<>(); long startCountTime = System.currentTimeMillis(); if (esQueryObj.getFromIndex() + esQueryObj.getSize() > DEFAULT_MAX_SIZE) { throw new BadArgumentException("分页深度不能超过10000"); } //创建ES查询Request对象 SearchRequestBuilder esSearch = elasticsearchTemplate.getClient().prepareSearch(esQueryObj.getIndexName()); esSearch.setTypes(esQueryObj.getTypeName()).setSearchType(SearchType.QUERY_THEN_FETCH).setFrom(esQueryObj.getFromIndex()).setSize(esQueryObj.getSize()).setFetchSource(esQueryObj.getIncludeFields(), esQueryObj.getExcludeFields()); //添加查询条件 if (esQueryObj.getQuery() != null) { esSearch.setQuery(esQueryObj.getQuery()); } //添加多级排序 if (esQueryObj.getSortField() != null) { for (Map.Entry<String, SortOrder> entry : esQueryObj.getSortField().entrySet()) { esSearch.addSort(entry.getKey(), entry.getValue()); } } //深分页 if (esQueryObj.getSearchAfter() != null && esQueryObj.getSearchAfter().length != 0) { esSearch.searchAfter(esQueryObj.getSearchAfter()); } //执行查询 SearchResponse response = esSearch.execute().actionGet(); for (SearchHit hit : response.getHits()) { page.getContent().add(JSON.parseObject(hit.getSourceAsString(), targetClass)); } // Object[] sortValues = response.getHits().getAt(9).getSortValues(); // log.info("EsDbUtils queryObjectPageByFilterQuery search:,esQueryObj:{},time consuming:{}ms.", response.getHits().getTotalHits(), (System.currentTimeMillis() - startCountTime)); page.setTotalElements(response.getHits().getTotalHits()); page.setSize(esQueryObj.getSize()); return page; } public Long queryCountByFilterQuery(ESQueryObj esQueryObj) throws BusinessException, BadArgumentException, SystemException { validationESIndexAndType(esQueryObj); //创建ES查询Request对象 SearchRequestBuilder esSearch = elasticsearchTemplate.getClient().prepareSearch(esQueryObj.getIndexName()); esSearch.setTypes(esQueryObj.getTypeName()).setSearchType(SearchType.QUERY_THEN_FETCH).setFrom(esQueryObj.getFromIndex()).setSize(esQueryObj.getSize()).setFetchSource(esQueryObj.getIncludeFields(), esQueryObj.getExcludeFields()); //执行查询 SearchResponse response = esSearch.execute().actionGet(); return response.getHits().getTotalHits(); } public Long queryCount(String indexName, String typeName) throws BusinessException, BadArgumentException, SystemException { SearchRequestBuilder esSearch = elasticsearchTemplate.getClient().prepareSearch(indexName); esSearch.setTypes(typeName); SearchResponse response = esSearch.execute().actionGet(); SearchHits searchHits = response.getHits(); return searchHits.getTotalHits(); } /** * 使用游标方式搜索, 适用于10000以上的数据获取,不支持排序 * * @param esQueryObj 查询条件 * @param scrollPageRequest 分页信息 * @param targetClass 需要封装的对象 * @return ScrollPage */ public <T> ScrollPage<T> scrollSearch(ESQueryObj esQueryObj, ScrollPageRequest scrollPageRequest, Class<T> targetClass) { ScrollPage<T> returnPage = new ScrollPage<>(); returnPage.setSize(scrollPageRequest.getPageSize()); SearchResponse scrollResp; // 没有ScrollId 说明是首次请求 if (StringUtils.isBlank(scrollPageRequest.getScrollId())) { SearchRequestBuilder srb = elasticsearchTemplate.getClient().prepareSearch(esQueryObj.getIndexName()).setTypes(esQueryObj.getTypeName()).setScroll(new TimeValue(scrollPageRequest.getScrollSeconds() * 1000)).setQuery(esQueryObj.getQuery()).setSize(scrollPageRequest.getPageSize()).setFetchSource(esQueryObj.getIncludeFields(), esQueryObj.getExcludeFields()); if (!esQueryObj.getSortField().isEmpty()) { Map<String, SortOrder> sortField = esQueryObj.getSortField(); for (String key : sortField.keySet()) { srb.addSort(key, sortField.get(key)); } } scrollResp = srb.execute().actionGet(); } else { // 使用ScrollId获取剩余的数据 scrollResp = elasticsearchTemplate.getClient().prepareSearchScroll(scrollPageRequest.getScrollId()).setScroll(new TimeValue(scrollPageRequest.getScrollSeconds() * 1000)).execute().actionGet(); } SearchHits searchHits = scrollResp.getHits(); long totalCount = searchHits.getTotalHits(); if (totalCount == 0) { return returnPage; } returnPage.setTotalElements((int) totalCount); for (SearchHit hit : searchHits.getHits()) { returnPage.getContent().add(JSON.parseObject(hit.getSourceAsString(), targetClass)); } returnPage.setScrollId(scrollResp.getScrollId()); return returnPage; } /** * 更新文档库 * * @param indexName 索引名 * @param typeName 表名 * @param id 文档编号 */ public long updateDoc(String indexName, String typeName, String id, Map<String, Object> param) { UpdateRequest updateRequest = new UpdateRequest(); updateRequest.index(indexName); updateRequest.type(typeName); updateRequest.id(id); updateRequest.doc(param); updateRequest.retryOnConflict(RETRY_ON_CONFLICT); updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); try { UpdateResponse resp = elasticsearchTemplate.getClient().update(updateRequest).get(); return resp.getVersion(); } catch (Exception e) { log.error("occurred error when update doc", e); throw new BusinessException("occurred error when update doc"); } } /** * 通过主键批量更新 * * @param indexName 索引名称 * @param typeName 类型名称 * @param idToParams 主键ID及对应需要更新的参数和值 */ public void bulkUpdateByIds(String indexName, String typeName, Map<String, Map<String, Object>> idToParams) { BulkRequest bulkRequest = new BulkRequest(); for (Map.Entry<String, Map<String, Object>> entry : idToParams.entrySet()) { String id = entry.getKey(); Map<String, Object> paramFields = entry.getValue(); UpdateRequest updateRequest = new UpdateRequest(); updateRequest.index(indexName); updateRequest.type(typeName); updateRequest.id(id); updateRequest.doc(paramFields); updateRequest.retryOnConflict(RETRY_ON_CONFLICT); bulkRequest.add(updateRequest); } ActionFuture<BulkResponse> future = elasticsearchTemplate.getClient().bulk(bulkRequest); BulkResponse bulkResponse = future.actionGet(); if (bulkResponse.hasFailures()) { log.error("bulkUpdateByIds fail bulkResponse={}", JSON.toJSONString(bulkResponse)); throw new BusinessException("bulkUpdateByIds error"); } } /** * upsert操作 * * @param indexName 索引名 * @param typeName 表名 * @param id 文档编号 */ public long upsertDoc(String indexName, String typeName, String id, Map<String, Object> param) { IndexRequest indexRequest = new IndexRequest(indexName, typeName, id); indexRequest.source(param); UpdateRequest updateRequest = new UpdateRequest(); updateRequest.index(indexName); updateRequest.type(typeName); updateRequest.id(id); updateRequest.doc(param); updateRequest.upsert(indexRequest); updateRequest.retryOnConflict(RETRY_ON_CONFLICT); updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); try { UpdateResponse resp = elasticsearchTemplate.getClient().update(updateRequest).get(); return resp.getVersion(); } catch (Exception e) { log.error("occurred error when update doc", e); throw new BusinessException("occurred error when upsert es doc"); } } /** * 批量bulk操作 已存在,覆盖(如果进行更新操作时,params中的数据需要和ES中的数据元素保持一致,不然就会丢失部分数据) * * @param indexName 索引名 * @param typeName 表名 * @param params 一次操作的数据量最好保持在5-15MB大小间。 * @param primaryKeyName params里面主键key,对应的主键ID不能为空 */ public void bulk(String indexName, String typeName, List<Map<String, Object>> params, String primaryKeyName) { BulkRequestBuilder bulkRequest = elasticsearchTemplate.getClient().prepareBulk(); for (Map<String, Object> param : params) { if (param.get(primaryKeyName) == null) { log.error("occurred error when bulk doc"); throw new BusinessException("occurred error when bulk es doc,the ID is null"); } bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); bulkRequest.add(elasticsearchTemplate.getClient().prepareIndex(indexName, typeName) .setOpType(DocWriteRequest.OpType.INDEX) .setId(String.valueOf(param.get(primaryKeyName))) .setSource(param)); } bulkRequest.execute().actionGet(); } /** * 插入文档(如果重复插入就会导致后面的将前面的数据进行覆盖) * * @param indexName 索引名 * @param typeName 表名 * @param id 文档编号 * @param param 文档内容 * @return String */ public String insert(String indexName, String typeName, String id, Map<String, Object> param) { // 指定索引名称,type名称和documentId(documentId可选,不设置则系统自动生成)创建document IndexRequestBuilder indexRequestBuilder = elasticsearchTemplate.getClient().prepareIndex(indexName, typeName).setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); IndexResponse response = indexRequestBuilder.setSource(param).setId(id).get(); if (response.getResult().equals(DocWriteResponse.Result.CREATED)) { return response.getId(); } return null; } /** * 删除文档库 * * @param indexName 索引名 * @param typeName 表名 * @param id 文档编号 */ public long deleteDoc(String indexName, String typeName, String id) { DeleteRequest deleteRequest = new DeleteRequest(); deleteRequest.id(id); deleteRequest.index(indexName); deleteRequest.type(typeName); deleteRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); try { DeleteResponse resp = elasticsearchTemplate.getClient().delete(deleteRequest).get(); return resp.getVersion(); } catch (Exception e) { log.error("occurred error", e); throw new BusinessException("occurred error when delete doc from es!"); } } /** * 根据条件删除,谨慎使用,整不好就把整个索引清空了 * @param indexName * @param boolQueryBuilder * @return */ public long deleteDocByQuery(String indexName, BoolQueryBuilder boolQueryBuilder) { DeleteByQueryRequestBuilder builder = DeleteByQueryAction.INSTANCE.newRequestBuilder(elasticsearchTemplate.getClient()).refresh(true).filter(boolQueryBuilder).source(indexName); long deleted = builder.get().getDeleted(); return deleted; } /** * 验证ES查询对象 */ private void validationESIndexAndType(ESQueryObj esQueryObj) { Preconditions.checkArgument(!StringUtils.isEmpty(esQueryObj.getIndexName()), "indexName can't be null"); Preconditions.checkArgument(!StringUtils.isEmpty(esQueryObj.getTypeName()), "typeName can't be null"); } /** * 根据文档编号进行获取 * * @param indexName 索引名 * @param typeName 表名 * @param id 文档编号 * @param targetClass 获取数据封装对象 */ public <T> T getById(String indexName, String typeName, String id, Class<T> targetClass) { GetRequest getRequest = new GetRequest(); getRequest.index(indexName).type(typeName).id(id); try { GetResponse getResponse = elasticsearchTemplate.getClient().get(getRequest).get(); String result = getResponse.getSourceAsString(); if (StringUtils.isEmpty(result)) { return null; } return JSON.parseObject(result, targetClass); } catch (Exception e) { log.error("occurred error", e); throw new BusinessException("occurred error when query from es!"); } } /** * mget可以批量的根据index,type,id三个字段来获取一批数据,它不能用来查询,最少得需要知道index 和 id两个字段的值,才能进行get,这一点与query是不一样的。 * * @param indexName 索引名 * @param typeName 表名 * @param docIds 文档编号集合 * @param targetClass 获取数据封装对象 */ public <T> List<T> multiGetDoc(String indexName, String typeName, List<Object> docIds, Class<T> targetClass) { List<T> result = new ArrayList<>(); MultiGetRequestBuilder prepareMultiGet = elasticsearchTemplate.getClient().prepareMultiGet(); docIds.forEach(docId -> prepareMultiGet.add(indexName, typeName, docId.toString())); MultiGetResponse multiGetItemResponses = prepareMultiGet.get(); for (MultiGetItemResponse itemResponse : multiGetItemResponses) { GetResponse response = itemResponse.getResponse(); if (response.isExists()) { String res = response.getSourceAsString(); if (StringUtils.isEmpty(res)) { continue; } try { result.add(JSON.parseObject(res, targetClass)); } catch (Exception e) { log.error("occurred error", e); throw new BusinessException(String.format("occurred error when parse es result to Object:%s", targetClass.getCanonicalName())); } } } return result; } /** * 根据script update * * @param indexName indexName * @param typeName typeName * @param params 需要更新的参数 * @param scriptStr scriptStr */ public Long updateByScript(String indexName, String typeName, String id, Map<String, Object> params, String scriptStr) { Script script = new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, scriptStr, params); UpdateRequestBuilder urb = elasticsearchTemplate.getClient().prepareUpdate(indexName, typeName, id); urb.setScript(script); //设置在插入时是否运行脚本 urb.setScriptedUpsert(true); //必须有这个值,否则会报document missing exception(文档不存在时设置文档的_source) urb.setUpsert(new HashMap()); urb.setRetryOnConflict(RETRY_ON_CONFLICT); try { UpdateResponse resp = urb.execute().actionGet(); return resp.getVersion(); } catch (VersionConflictEngineException e) { // log.error("occurred version conflict engine exception", e); throw e; } catch (Exception e) { log.error("occurred error", e); log.wran("updateByScript has error param:{}", JSON.toJSONString(params))); throw new BusinessException("occurred error when update es"); } } } 

ElasticsearchTemplate es链接

package com.esm.common; import com.commons.exception.SystemException; import org.apache.commons.lang3.StringUtils; import org.elasticsearch.client.Client; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.transport.client.PreBuiltTransportClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.net.InetAddress; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Base64; /** * ES 客户端 */ @Service public class ElasticsearchTemplate { @Value("${es.clusterNodes}") private String clusterNodes; @Value("${es.clusterName}") private String clusterName; //是否扫描集群 @Value("${es.clientTransportSniff}") private Boolean clientTransportSniff; @Value("${es.userName}") private String securityUser; @Value("${es.password}") private String securityPassword; private Client client; //禁用ES设置netty进程数的配置 static { System.setProperty("es.set.netty.runtime.available.processors", "false"); } @PostConstruct public void init() { Settings settings = Settings.builder() .put("cluster.name", clusterName) .put("client.transport.sniff", clientTransportSniff) .put("request.headers.Authorization", basicAuthHeaderValue(securityUser, securityPassword)) //ElasticSearch5分钟内执行脚本编译超过75个,编译太多而拒绝编译。编译是非常耗时的,这是ES的自我保护功能。 //.put("script.max_compilations_rate", "100/1m") .put("script.cache.max_size", 200) .build(); if (StringUtils.isBlank(clusterNodes)) { throw new SystemException("clusterNodes is empty."); } //创建集群client并添加集群节点地址 PreBuiltTransportClient transportClient = new PreBuiltTransportClient(settings); try { String[] nodes = clusterNodes.split(","); for (String node : nodes) { String[] host = node.split(":"); transportClient.addTransportAddress(new TransportAddress(InetAddress.getByName(host[0]), Integer.parseInt(host[1]))); } } catch (Exception e) { throw new SystemException("ElasticsearchTemplate init error", e); } client = transportClient; } /** * 基础的base64生成 * * @param username 用户名 * @param passwd 密码 * @return String */ private static String basicAuthHeaderValue(String username, String passwd) { CharBuffer chars = CharBuffer.allocate(username.length() + passwd.length() + 1); byte[] charBytes = null; try { chars.put(username).put(':').put(passwd.toCharArray()); charBytes = toUtf8Bytes(chars.array()); String basicToken = Base64.getEncoder().encodeToString(charBytes); return "Basic " + basicToken; } finally { Arrays.fill(chars.array(), (char) 0); if (charBytes != null) { Arrays.fill(charBytes, (byte) 0); } } } /** * 编码 */ private static byte[] toUtf8Bytes(char[] chars) { CharBuffer charBuffer = CharBuffer.wrap(chars); ByteBuffer byteBuffer = StandardCharsets.UTF_8.encode(charBuffer); byte[] bytes = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit()); Arrays.fill(byteBuffer.array(), (byte) 0); return bytes; } /** * 服务销毁前关闭ES服务 */ @PreDestroy public void destory() { client.close(); } public Client getClient() { return client; } public void setClient(Client client) { this.client = client; } } 

ESQueryObj 查询对象

package com.esm.common; import lombok.Data; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import org.elasticsearch.common.Strings; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.search.sort.SortOrder; import java.util.Map; /** * @description: ES查询对象 */ @Data public class ESQueryObj { /** * ES索引名 */ private String indexName; /** * ES TYPE名(表名) */ private String typeName; /** * 查询条件组合,类似于 "boolQuery().must( QueryBuilders.termQuery("opTime", "2016-03-30")).must(QueryBuilders.termQuery("operErpID", "xingkai"))" */ private QueryBuilder query; /** * 排序字段键值对,可以添加多个,类似于("opTime","DESC") */ private Map<String, SortOrder> sortField; /** * 取值的起始位置,默认为0 */ private int fromIndex; /** * 返回数据数量,默认为100,最大不能超过100000 */ private int size = 100; /** * 需要返回的字段 */ private String[] includeFields; /** * 不需要返回的字段 */ private String[] excludeFields = Strings.EMPTY_ARRAY; //https://blog.ZEEKLOG.net/yiyiholic/article/details/81661919 /** * 通过提供一个live cursor来规避消耗存储和时间的性能问题,通过上一页的结果帮助检索下一页,用第一次检索的最后一个值作为下一个检索search_after的参数,当使用search_after参数时,from的值必须被设为0或者-1 * 使用时注意必须按照某一字段进行排序 */ private Object[] searchAfter; @Override public String toString() { return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); } } 

EsScriptUtil 脚本工具

package com.esm.common; import org.apache.commons.collections.CollectionUtils; import java.text.MessageFormat; import java.util.List; /** * 工具es脚本 */ public class EsScriptUtil { /** * 判断ES上下文中是否包含某个属性,如果不包含,则进行添加(前提是事先定义的mapping中有该字段) * * @param field 属性名称 * @return script */ public static String appendFieldToCtx(String field, String key) { return MessageFormat.format("if(!ctx._source.containsKey(''{0}''))'{'ctx._source.{0}=null}", field, key); } public static String appendArrFieldToCtx(String field, String key) { return MessageFormat.format("if(!ctx._source.containsKey(''{0}''))'{'ctx._source.{0}=[]}", field, key); } /** * 判断ES数组字段中是否包含某个值,如果不包含则进行追加 * * @param field 属性名称 * @return script */ public static String appendValueToArr(String field, String key) { return MessageFormat.format("if(ctx._source.{0}==='''' || ctx._source.{0}=== null || ctx._source.{0}===''null'')'{'ctx._source.{0}=[{1}.{0}];}" + "else if(ctx._source.{0}.indexOf({1}.{0}) === -1)'{'ctx._source.{0}.add({1}.{0});}", field, key); } /** * 判断ES数组字段中是否包含某个值,如果包含则进行删除 * * @param field 属性名称 * @return script */ public static String removeValueFromArr(String field, String key) { return MessageFormat.format("if(ctx._source.{0} !=='''' && ctx._source.{0}!== null && ctx._source.{0} !==''null''&& ctx._source.{0}.indexOf({1}.{0}) != -1)'{'ctx._source.{0}.remove(ctx._source.{0}.indexOf({1}.{0}));}", field, key); } /** * 更新某个字段 * * @param field 属性名称 * @return script */ public static String updateField(String field, String key) { return MessageFormat.format("ctx._source.{0} = {1}.{0};", field, key); } /** * 判断ES对象数组字段中是否包含某个值,如果不包含则进行追加 * * @param field 对象名称 * @param list 对象包含的所有属性名称 * @param key 更新map对象的名称 * @return script */ public static String appendValueToObjectArr(String field, List<String> list, String key) { StringBuilder sb = new StringBuilder(); if (CollectionUtils.isNotEmpty(list)) { sb.append(MessageFormat.format("for(int i=0; i<ctx._source.{0}.size(); i++)", field)).append("{"); for (int i = 0; i < list.size(); i++) { if (i == 0) { sb.append(MessageFormat.format("if (ctx._source.{0}[i][''{1}''] == {2}.{0}.{1}", field, list.get(i), key)); } else { sb.append(MessageFormat.format("&& ctx._source.{0}[i][''{1}'']== {2}.{0}.{1}", field, list.get(i), key)); } } sb.append(MessageFormat.format(")'{'ctx._source.{0}.remove(i);break;}}ctx._source.{0}.add({1}.{0});", field, key)); } else { //无需校验字段是否相等,直接进行添加 sb.append(MessageFormat.format("ctx._source.{0}.add({1}.{0});", field, key)); } return sb.toString(); } /** * 清空数组 */ public static String clearArr(String field) { return MessageFormat.format("ctx._source.{0}.clear();", field); } } 

异常

SystemException

 package com.commons.exception; public class SystemException extends BaseException { public SystemException(String message) { super(message); } public SystemException(String message, Throwable cause) { super(message, cause); } public SystemException(Throwable cause) { super(cause); } public SystemException() { } public SystemException(int code) { super(code); } public SystemException(int code, String message) { super(code, message); } } 

BusinessException

 package com.commons.exception; public class BusinessException extends BaseException { public BusinessException() { } public BusinessException(String message) { super(message); } public BusinessException(String message, Throwable cause) { super(message, cause); } public BusinessException(Throwable cause) { super(cause); } public BusinessException(int code) { super(code); } public BusinessException(int code, String message) { super(code, message); } } 

BaseException

 package com.commons.exception; public class BaseException extends RuntimeException { private int code; public BaseException() { } public BaseException(String message) { super(message); } public BaseException(String message, Throwable cause) { super(message, cause); } public BaseException(Throwable cause) { super(cause); } public BaseException(int code) { this.code = code; } public BaseException(int code, String message) { super(message); this.code = code; } public int getCode() { return this.code; } } 

BadArgumentException

 package com.commons.exception; public class BadArgumentException extends BaseException { public BadArgumentException() { } public BadArgumentException(String message) { super(message); } public BadArgumentException(String message, Throwable cause) { super(message, cause); } public BadArgumentException(Throwable cause) { super(cause); } public BadArgumentException(int code) { super(code); } public BadArgumentException(int code, String message) { super(code, message); } } 

分页代码

Page

 package com.commons.data.page; import java.io.Serializable; import java.util.ArrayList; import java.util.List; public class Page<T> implements Serializable { private long totalElements = 0L; private int size = 10; private int page = 1; private List<T> content = new ArrayList(); public Page() { } public int getSize() { return this.size; } public void setSize(int size) { this.size = size; } public long getTotalElements() { return this.totalElements; } public void setTotalElements(long totalElements) { this.totalElements = totalElements; } public long getTotalPage() { return this.totalElements / (long)this.size + (long)(this.totalElements % (long)this.size == 0L ? 0 : 1); } public List<T> getContent() { return this.content; } public void setContent(List<T> content) { this.content = content; } public int getPage() { return this.page; } public void setPage(int page) { this.page = page; } } 

PageRequest

 package com.commons.data.page; import java.io.Serializable; public class PageRequest implements Serializable { private int page = 1; private int pageSize = 10; public PageRequest() { } public int getPage() { return this.page; } public void setPage(int page) { this.page = page; } public int getPageSize() { return this.pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public long getOffset() { return (long)(this.page - 1) * (long)this.pageSize; } } 

ScrollPage

 package com.commons.data.page; import java.io.Serializable; import java.util.ArrayList; import java.util.List; public class ScrollPage<T> implements Serializable { private long totalElements = 0L; private int size = 100; private String scrollId; private List<T> content = new ArrayList(); public ScrollPage() { } public int getSize() { return this.size; } public void setSize(int size) { this.size = size; } public long getTotalElements() { return this.totalElements; } public void setTotalElements(long totalElements) { this.totalElements = totalElements; } public long getTotalPage() { return this.totalElements / (long)this.size + (long)(this.totalElements % (long)this.size == 0L ? 0 : 1); } public List<T> getContent() { return this.content; } public void setContent(List<T> content) { this.content = content; } public String getScrollId() { return this.scrollId; } public void setScrollId(String scrollId) { this.scrollId = scrollId; } } 

ScrollPageRequest

 package com.commons.data.page; import java.io.Serializable; public class ScrollPageRequest implements Serializable { private int pageSize = 100; private long scrollSeconds = 60L; private String scrollId; public ScrollPageRequest() { } public int getPageSize() { return this.pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public long getScrollSeconds() { return this.scrollSeconds; } public void setScrollSeconds(long scrollSeconds) { this.scrollSeconds = scrollSeconds; } public String getScrollId() { return this.scrollId; } public void setScrollId(String scrollId) { this.scrollId = scrollId; } } 

测试

查询

 public List<TestEntity> queryNotExpireDiscountTestFormES( Long id) { List<TestEntities> testEntities = new ArrayList<>(); ESQueryObj esQueryObj = new ESQueryObj(); BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); esQueryObj.setIndexName(ESConstans.INDEX_NAME); esQueryObj.setTypeName(ESConstans.TYPE_NAME); esQueryObj.setFromIndex(0); esQueryObj.setSize(50); if (id != null) { boolQuery.must(QueryBuilders.termQuery("id", id)); } esQueryObj.setQuery(boolQuery); Page<TestIndexBean> tEntityPage = esDbUtils.queryObjectPageByFilterQuery(esQueryObj, TestIndexBean.class); if (CollectionUtils.isNotEmpty(tEntityPage.getContent())) { testEntities = tEntityPage.getContent().stream().map(this::convertEsDataToTestEntity).collect(Collectors.toList()); } logger.info("查询出符合的实体testEntities:{}", JSON.toJSONString(testEntities)); return tEntityPage; } private TestEntity convertEsDataToTestEntity(TestIndexBean testIndexBean) { PromotionEntity promotionEntity = new PromotionEntity(); promotionEntity.setName(testIndexBean.getName()); return promotionEntity; }

持续更新

持续更新

持续更新

持续更新

Read more

华为OD机试双机位C卷:挑选宝石 (C/C++/Python/JAVA/JS/GO)

华为OD机试双机位C卷:挑选宝石 (C/C++/Python/JAVA/JS/GO)

挑选宝石 2025华为OD机试双机位C卷 - 华为OD上机考试双机位C卷 100分题型 华为OD机试双机位C卷真题目录点击查看: 华为OD机试双机位C卷真题题库目录|机考题库 + 算法考点详解 题目描述 游乐园有一款互动游戏,游戏开始时会提供n个宝石,每个宝石都一个属性值a1,a2,…an.玩家在游戏前可以挑选x颗宝石,将这些宝石的属性值相乘组成玩家的属性值。游戏玩家需要y点属性值,请帮助游戏玩家计算有多少种计算方式。 输入描述 第一行:三个整数n,x,y * 第一个整数n(0 < n <20)表示宝石总数量。 * 第二个整数x(0<x <=n),表示可以选择宝石个数 * 第三个整数y,表示通过游戏需要的属性值 第二行:n个整数,a1,a2,…an(-100 < ai < 100)

By Ne0inhk
【保姆级教程】从零入手:Python + Neo4j 构建你的第一个知识图谱

【保姆级教程】从零入手:Python + Neo4j 构建你的第一个知识图谱

摘要: 大数据时代,数据之间的关系往往比数据本身更有价值。传统的 SQL 数据库在处理复杂关系(如社交网络、推荐系统、风控分析)时显得力不从心,而 知识图谱 和 图数据库 Neo4j 正是为此而生。本文将带你从 0 基础出发,理解知识图谱核心概念,安装 Neo4j 环境,并手把手教你用 Python 代码构建一个生动的人物关系图谱。拒绝枯燥理论,全是实战干货! 一、 什么是知识图谱与 Neo4j? 在动手写代码之前,我们先用大白话把两个核心概念捋清楚。 1. 什么是知识图谱 (Knowledge Graph)? 不要被高大上的名字吓到。知识图谱本质上就是把世界上的事物(节点)和它们之间的联系(关系)画成一张巨大的网。 * Excel 思维: 罗列数据。例如:张三,25岁;李四,

By Ne0inhk
Python多版本管理与pip升级指南:从冲突解决到最佳实践

Python多版本管理与pip升级指南:从冲突解决到最佳实践

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[[email protected]] 📱个人微信:15279484656 🌐个人导航网站:www.forff.top 💡座右铭:总有人要赢。为什么不能是我呢? * 专栏导航: 码农阿豪系列专栏导航 面试专栏:收集了java相关高频面试题,面试实战总结🍻🎉🖥️ Spring5系列专栏:整理了Spring5重要知识点与实战演练,有案例可直接使用🚀🔧💻 Redis专栏:Redis从零到一学习分享,经验总结,案例实战💐📝💡 全栈系列专栏:海纳百川有容乃大,可能你想要的东西里面都有🤸🌱🚀 目录 * Python多版本管理与pip升级指南:从冲突解决到最佳实践 * 引言 * 一、问题背景:Python多版本与pip的混乱 * 1.1 典型问题场景 * 1.2 根本原因 * 二、

By Ne0inhk