赞
踩
maven依赖,使用了RestHighLevelClient6.4.0版本
- <dependency>
- <groupId>org.elasticsearch.client</groupId>
- <artifactId>elasticsearch-rest-high-level-client</artifactId>
- <version>6.4.0</version>
- </dependency>
首先RestHighLevelClient配置,采用注入方式,启动就注册客户端bean
- @Configuration
- public class ESHighLevelRestClient {
-
- public static final int CONNECT_TIMEOUT = 5000;
- public static final int SOCKET_TIMEOUT = 60000;
- public static final int MAX_RETRY_TIMEOUT = 60000;
- public static final int WORK_THREADS = Runtime.getRuntime().availableProcessors();
- private final String authEnable = "enable";
- // 配置类,里面配置了es的地址,用户,密码
- @Autowired
- private ElasticsearchConfig elasticsearchConfig;
-
- @Bean
- public RestHighLevelClient restHighLevelClient() throws UnsupportedEncodingException {
-
- ArrayList<HttpHost> httpHosts = Lists.newArrayList();
-
- Map<String, String> hostsMap = Splitter.on(',').trimResults().omitEmptyStrings()
- .withKeyValueSeparator(":")
- .split(elasticsearchConfig.getHosts());
-
- hostsMap.entrySet().stream().forEach(x -> {
- httpHosts.add(new HttpHost(x.getKey(), Integer.valueOf(x.getValue()), "http"));
- });
-
- RestClientBuilder restClientBuilder = RestClient.builder(httpHosts.toArray(new HttpHost[httpHosts.size()]));
-
- // set es connection timeout
- restClientBuilder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
- @Override
- public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) {
- return requestConfigBuilder
- .setConnectTimeout(CONNECT_TIMEOUT)
- .setSocketTimeout(SOCKET_TIMEOUT);
- }
- }).setMaxRetryTimeoutMillis(MAX_RETRY_TIMEOUT);
-
- // set es client works numbers
- restClientBuilder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
- @Override
- public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
- return httpClientBuilder.setDefaultIOReactorConfig(
- IOReactorConfig.custom().setIoThreadCount(WORK_THREADS).build());
- }
- });
-
- if (authEnable.equalsIgnoreCase(elasticsearchConfig.getAuth())) {
- Header[] defaultHeaders = new Header[]{new BasicHeader("Authorization", getToken(elasticsearchConfig.getUsername(), elasticsearchConfig.getPassword()))};
- restClientBuilder.setDefaultHeaders(defaultHeaders);
- }
-
- return new RestHighLevelClient(restClientBuilder);
- }
-
- private String getToken(String username, String password) throws UnsupportedEncodingException {
- StringBuilder tokenBuilder = new StringBuilder();
- tokenBuilder.append(username);
- tokenBuilder.append(":");
- tokenBuilder.append(password);
- String token = new String(Base64.getEncoder().encode(tokenBuilder.toString().getBytes()), StandardCharsets.UTF_8);
- return "Basic " + token;
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
封装abstract类,想要操作ES的实体需要继承这个类,重写packageElasticSearchBody()方法,封装查询条件
- @Getter
- @Setter
- public abstract class BaseElasticSearchEntity {
-
- /**
- * ES的INDEX
- */
- private String esIndex;
- /**
- * ES的TYPE
- */
- private String esType;
- /**
- * ES唯一值ID
- */
- private String esId;
-
- protected BaseElasticSearchEntity() {
- }
-
- protected BaseElasticSearchEntity(String esIndex, String esType) {
- this.esIndex = esIndex;
- this.esType = esType;
- }
-
- protected BaseElasticSearchEntity(String esIndex, String esType, String esId) {
- this.esIndex = esIndex;
- this.esType = esType;
- this.esId = esId;
- }
-
- /**
- * 供子类封装查询条件
- *
- * @param boolQueryBuilder bool条件
- */
- public abstract void packageElasticSearchBody(BoolQueryBuilder boolQueryBuilder);
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
操作ES的mapper
- public interface ElasticSearchMapper<T extends BaseElasticSearchEntity> {
-
- /**
- * 创建ES索引库
- *
- * @param index index
- * @param type type
- * @param mapping 映射,为json字符串,
- * 例如:{\"properties\":{\"name\":{\"type\":\"keyword\"},\"date1\":{\"type\":\"date\"},\"date2\":{\"type\":\"date\"},\"updateTime\":{\"type\":\"date\"}}}
- * @return 是否创建成功
- * @throws IOException 异常
- */
- boolean createIndex(String index, String type, String mapping) throws IOException;
-
- /**
- * 删除索引
- *
- * @param index index
- * @return 是否删除成功
- * @throws IOException 异常
- */
- boolean deleteIndex(String index) throws IOException;
-
- /**
- * 根据id查询数据是否存在于ES中
- *
- * @param entry index和type和id
- * @return 是否存在
- */
- boolean isExists(T entry);
-
- /**
- * 插入ES,指定id
- *
- * @param entry 实体
- * @return 插入结果
- */
- String insert(T entry);
-
- /**
- * 更新ES,指定id
- *
- * @param entry 实体
- * @return 更新结果
- */
- String update(T entry);
-
- /**
- * 删除ES,指定id
- *
- * @param entry index和type和id
- * @return 删除结果
- */
- String delete(T entry);
-
- /**
- * 根据id查询ES
- *
- * @param entry index和type和id
- * @return 查询数据结果json字符串
- */
- String selectById(T entry);
-
- /**
- * 多条件查询,正序排序
- *
- * @param entry 封装的查询条件
- * @param sortField 排序字段的字段名,如:updateTime
- * @param page 页码
- * @param length 每页条数
- * @return 查询结果,es封装
- */
- ElasticSearchResponseEntity selectByMultiConditionAsc(T entry, String sortField, Integer page, Integer length);
-
- /**
- * 多条件查询,倒序排序
- *
- * @param entry 封装的查询条件
- * @param sortField 排序字段的字段名,如:updateTime
- * @param page 页码
- * @param length 每页条数
- * @return 查询结果,es封装
- */
- ElasticSearchResponseEntity selectByMultiConditionDesc(T entry, String sortField, Integer page, Integer length);
-
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
mapper的实现类,具体增删改查方法
- @Slf4j
- @Repository("elasticSearchMapperImpl")
- public class ElasticSearchMapperImpl<T extends BaseElasticSearchEntity> implements ElasticSearchMapper<T> {
-
- @Autowired
- private RestHighLevelClient restClient;
-
- @Override
- public boolean createIndex(String index, String type, String mapping) throws IOException {
- CreateIndexRequest indexRequest = new CreateIndexRequest(index);
- indexRequest.mapping(type, mapping, XContentType.JSON);
- IndicesClient indicesClient = restClient.indices();
- CreateIndexResponse createIndexResponse = indicesClient.create(indexRequest, RequestOptions.DEFAULT);
- return createIndexResponse.isAcknowledged();
- }
-
- @Override
- public boolean deleteIndex(String index) throws IOException {
- DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(index);
- IndicesClient indicesClient = restClient.indices();
- AcknowledgedResponse delete = indicesClient.delete(deleteIndexRequest, RequestOptions.DEFAULT);
- return delete.isAcknowledged();
- }
-
- @Override
- public boolean isExists(T entry) {
- GetRequest getRequest = new GetRequest(entry.getEsIndex(), entry.getEsType(), entry.getEsId());
- getRequest.fetchSourceContext(new FetchSourceContext(false));
- getRequest.storedFields("_none_");
- try {
- boolean exists = restClient.exists(getRequest, RequestOptions.DEFAULT);
- log.info("查询ES是否存在数据,isExists:{},id:{}", exists, getRequest.id());
- return exists;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public String insert(T entry) {
- IndexRequest request = new IndexRequest(entry.getEsIndex(), entry.getEsType(), entry.getEsId());
- request.source(JSONObject.toJSONString(entry), XContentType.JSON);
- request.create(true);
- IndexResponse response;
- try {
- response = restClient.index(request, RequestOptions.DEFAULT);
- String name = response == null ? null : response.getResult().name();
- log.info("ES执行插入:index:{},type:{},id:{}", request.index(), request.type(), request.id());
- return name;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public String update(T entry) {
- UpdateRequest request = new UpdateRequest(entry.getEsIndex(), entry.getEsType(), entry.getEsId());
- request.doc(JSONObject.toJSONString(entry), XContentType.JSON);
- UpdateResponse response;
- try {
- response = restClient.update(request, RequestOptions.DEFAULT);
- String name = response == null ? null : response.getResult().name();
- log.info("ES执行更新:index:{},type:{},id:{}", request.index(), request.type(), request.id());
- return name;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public String delete(T entry) {
- DeleteRequest request = new DeleteRequest(entry.getEsIndex(), entry.getEsType(), entry.getEsId());
- try {
- DeleteResponse response = restClient.delete(request, RequestOptions.DEFAULT);
- String name = response == null ? null : response.getResult().name();
- log.info("ES执行删除:index:{},type:{},id:{}", request.index(), request.type(), request.id());
- return name;
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
-
- @Override
- public String selectById(T entry) {
- GetRequest request = new GetRequest(entry.getEsIndex(), entry.getEsType(), entry.getEsId());
- try {
- GetResponse response = restClient.get(request, RequestOptions.DEFAULT);
- if (response.isExists()) {
- return response.getSourceAsString();
- } else {
- return null;
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
-
- @Override
- public ElasticSearchResponseEntity selectByMultiConditionDesc(T entry, String sortField, Integer page, Integer length) {
- return packageSelectData(selectByMultiCondition(entry, sortField, SortOrder.DESC, page, length));
- }
-
- @Override
- public ElasticSearchResponseEntity selectByMultiConditionAsc(T entry, String sortField, Integer page, Integer length) {
- return packageSelectData(selectByMultiCondition(entry, sortField, SortOrder.ASC, page, length));
- }
-
- /**
- * 封装成ElasticSearchResponseEntity返回
- *
- * @param searchHits es查询的数据
- * @return ElasticSearchResponseEntity
- */
- private ElasticSearchResponseEntity packageSelectData(SearchHits searchHits) {
- if (searchHits == null || searchHits.totalHits < 1) {
- return new ElasticSearchResponseEntity(0L, new LinkedList<>());
- }
- List<String> list = new LinkedList<>();
- Arrays.stream(searchHits.getHits()).forEach(hit -> {
- String source = hit.getSourceAsString();
- log.debug("ES查询数据:{}", source);
- list.add(source);
- });
- return new ElasticSearchResponseEntity(searchHits.getTotalHits(), list);
- }
-
- /**
- * 多条件查询,包含排序规则和分页功能
- *
- * @param entry 封装的查询条件
- * @param sortField 排序字段的字段名
- * 如果在mapping中未指定排序字段的类型为精确类型(如date或keyword),则此排序字段必须加上 .keyword 后缀,表示精准匹配,否则报错:[type=search_phase_execution_exception, reason=all shards failed]
- * 例如:username.keyword,如果mapping指定了字段类型为date或者keyword,则直接传字段名即可,例如:keywordName1、updateTime
- * @param sortOrder 排序规则,正序还是倒序
- * @return 查询结果,es封装
- */
- private SearchHits selectByMultiCondition(T entry, String sortField, SortOrder sortOrder, Integer page, Integer length) {
- SearchRequest searchRequest = new SearchRequest(entry.getEsIndex());
- searchRequest.types(entry.getEsType());
- try {
- BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();
- entry.packageElasticSearchBody(boolBuilder);
- SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
- sourceBuilder.sort(new FieldSortBuilder(sortField).order(sortOrder));
- sourceBuilder.query(boolBuilder);
- setPaging(sourceBuilder, page, length);
- searchRequest.source(sourceBuilder);
- SearchResponse searchResponse = restClient.search(searchRequest, RequestOptions.DEFAULT);
- return searchResponse.getHits();
- } catch (Exception e) {
- log.error("===》 es【多条件】查询,报错!entry={}", searchRequest.source().toString(), e);
- return null;
- }
- }
-
- /**
- * 设置es查询的分页配置
- *
- * ElasticSearchConstant.MAX_SIZE = ES默认10000条,这个自定义的常量无法超过默认值
- * @param sourceBuilder builder
- * @param page 页码
- * @param length 每页条数
- */
- private void setPaging(SearchSourceBuilder sourceBuilder, Integer page, Integer length) {
- if (page != null && length != null) {
- length = Math.min(length, ElasticSearchConstant.MAX_SIZE);
- int from = (page - 1) * length;
- sourceBuilder.from(from);
- sourceBuilder.size(length);
- }
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
返回值封装实体
- public class ElasticSearchResponseEntity {
-
- private Long total;// 查询总数
- private List<String> list;// 数据集合
-
- public ElasticSearchResponseEntity(Long total, List<String> list) {
- this.total = total;
- this.list = list;
- }
-
- public Long getTotal() {
- return total;
- }
-
- public void setTotal(Long total) {
- this.total = total;
- }
-
- public List<String> getList() {
- return list;
- }
-
- public void setList(List<String> list) {
- this.list = list;
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
使用:
0.ES查询所需的QueryBuilder的封装,简单封装一下,如有需要可以自行增减
- public class QueryBuilder {
-
- /**
- * 大于等于
- */
- public static final String GTE = "gte";
- /**
- * 小于等于
- */
- public static final String LTE = "lte";
- /**
- * 大于
- */
- public static final String GT = "gt";
- /**
- * 小于
- */
- public static final String LT = "lt";
-
- /**
- * 不会对搜索词进行分词处理,而是作为一个整体与目标字段进行匹配,若完全匹配,则可查询到。
- *
- * @param key
- * @param value
- * @return
- */
- public static TermQueryBuilder term(String key, Object value) {
- return QueryBuilders.termQuery(key, value);
- }
-
- /**
- * 一次匹配多个值,即 in()查询
- *
- * @param key key
- * @param values 值集合
- * @return TermsQueryBuilder
- */
- public static TermsQueryBuilder terms(String key, Collection<?> values) {
- return QueryBuilders.termsQuery(key, values);
- }
-
- /**
- * 一次匹配多个值,即 in()查询,keyword全值匹配,精确查询
- *
- * @param key
- * @param values
- * @return
- */
- public static TermsQueryBuilder termsKeyword(String key, Collection<?> values) {
- return QueryBuilders.termsQuery(key + ".keyword", values);
- }
-
-
- /**
- * 会将搜索词分词,再与目标查询字段进行匹配,若分词中的任意一个词与目标字段匹配上,则可查询到。
- *
- * @param key
- * @param value
- * @return
- */
- public static MatchQueryBuilder match(String key, Object value) {
- return QueryBuilders.matchQuery(key, value);
- }
-
- /**
- * 分词模糊查询
- *
- * @param key
- * @param value
- * @return
- */
- public static FuzzyQueryBuilder fuzzy(String key, Object value) {
- return QueryBuilders.fuzzyQuery(key, value);
- }
-
- /**
- * 范围查询
- *
- * @param key
- * @param value
- * @return
- */
- public static RangeQueryBuilder range(String key, Object value, String rangeType) {
- RangeQueryBuilder builder = QueryBuilders.rangeQuery(key);
- switch (rangeType) {
- case GTE:
- return builder.gte(value);
- case LTE:
- return builder.lte(value);
- case GT:
- return builder.gt(value);
- case LT:
- return builder.lt(value);
- default:
- return builder.gt(value);
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
1.定义数据实体类,继承BaseElasticSearchEntity,并重写父类方法,封装查询条件(省略getter/setter/toString/空参构造器等)
- public class Student extends BaseElasticSearchEntity {
-
- private Long id;
- private String name;
- private Date birth;
- private String nikename;
-
- // 父类构造器,用来操作ES指定的索引和Type
- public Student(String esIndex, String esType, String esId) {
- super(esIndex, esType, esId);
- }
-
- public Student(String esIndex, String esType) {
- super(esIndex, esType);
- }
-
- // 重写父类方法,封装查询的条件
- @Override
- public void packageElasticSearchBody(BoolQueryBuilder boolQueryBuilder) {
- // 相当于IN查询
- if (StringUtils.isNotEmpty(this.name)) {
- List<String> nameList = new ArrayList<>(Arrays.asList(this.name.split(",")));
- boolQueryBuilder.must(QueryBuilder.termsKeyword("name", nameList));
- }
- // 日期范围查询,日期存入yyyy-MM-dd HH:mm:ss格式时配置不当可能会报错,建议存入时间戳
- if (StringUtils.isNotEmpty(this.startTime)) {
- boolQueryBuilder.must(QueryBuilder.range("birth", DateUtil.convertTimeToLong(this.startTime, DateUtil.YYYY_MM_DD_HH_MM_SS), QueryBuilder.GTE));
- }
- if (StringUtils.isNotEmpty(this.endTime)) {
- boolQueryBuilder.must(QueryBuilder.range("birth", DateUtil.convertTimeToLong(this.endTime, DateUtil.YYYY_MM_DD_HH_MM_SS), QueryBuilder.LTE));
- }
- // match精准查询
- if (StringUtils.isNotEmpty(this.nikename)) {
- boolQueryBuilder.must(QueryBuilder.match("nikename", this.carId));
- }
- // 其他查询要求可以自行百度
-
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
2.service层的操作,忽略了业务逻辑,省略接口,直接上实现类了
- @Slf4j
- @Service("studentElasticSearchService")
- public class StudentElasticSearchServiceImpl implements StudentElasticSearchService {
-
- @Autowired
- @Qualifier("elasticSearchMapperImpl")
- private ElasticSearchMapper<Student> elasticSearchMapper;
-
- private final String TYPE = "student_type";
- private final String INDEX_NAME = "student_index";
-
- @Override
- public boolean isExists(String id) {
- return elasticSearchMapper.isExists(new Student(INDEX_NAME, TYPE, id));
- }
-
- @Override
- public String insert(Student entry) {
- entry.setEsIndex(INDEX_NAME);
- entry.setEsType(TYPE);
- entry.setEsId(entry.getId());
- return elasticSearchMapper.insert(entry);
- }
-
- @Override
- public Student selectById(String id) {
- String jsonString = elasticSearchMapper.selectById(new Student(INDEX_NAME, TYPE, id));
- return StringUtils.isEmpty(jsonString) ? null : JSONObject.parseObject(jsonString, Student.class);
- }
-
- @Override
- public String update(Student entry) {
- entry.setEsIndex(INDEX_NAME);
- entry.setEsType(TYPE);
- entry.setEsId(entry.getId());
- return elasticSearchMapper.update(entry);
- }
-
- @Override
- public String delete(String id) {
- return elasticSearchMapper.delete(new Student(INDEX_NAME, TYPE, id));
- }
-
- @Override
- public ElasticSearchResponseEntity selectByMultiCondition(Student entry, Integer page, Integer length) {
- try {
- entry.setEsIndex(INDEX_NAME);
- entry.setEsType(TYPE);
- return elasticSearchMapper.selectByMultiConditionDesc(entry, "birth", page, length);
- } catch (Exception e) {
- log.error("出错!", e);
- }
- return null;
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
3.直接调用service层的接口,传入封装的实体或者唯一id,即可操作ES的增删改查,代码就不用贴了,到这一步,傻子都会用了
如有更好的建议和写法,请告知我,先感谢能让我提升代码质量的任何朋友。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。