使用RestHighLevelClient-6.4.0客户端实现ES增删改查-操作工具类简单封装

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;
    }
}

封装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);
}

操作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);

}

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);
        }
    }
}

返回值封装实体

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;
    }
}

使用:

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);
        }
    }

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));
        }
        // 其他查询要求可以自行百度

    }
}

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;
    }
}

3.直接调用service层的接口,传入封装的实体或者唯一id,即可操作ES的增删改查,代码就不用贴了,到这一步,傻子都会用了

 

如有更好的建议和写法,请告知我,先感谢能让我提升代码质量的任何朋友。

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RestHighLevelClientElasticsearch官方提供的Java客户端,用于与Elasticsearch进行增删改查操作。据引用中的Maven依赖所示,使用RestHighLevelClient需要引入elasticsearch-rest-high-level-client库,并指定版本号为6.4.0。 对于RestHighLevelClient增删改查操作,可以通过调用相应的方法来实现。具体的操作方法包括: 1. 增加(Indexing):使用RestHighLevelClient的index方法将文档添加到Elasticsearch索引中。可以传递一个文档的JSON字符串或者一个Map对象作为参数,指定文档的索引、类型和唯一标识ID。此操作会创建一个新的文档或更新已存在的文档。 2. 更新(Updating):使用RestHighLevelClient的update方法更新已存在的文档。可以传递一个文档的JSON字符串、一个Map对象或者一个XContentBuilder对象作为参数,指定需要更新的文档的索引、类型和唯一标识ID。 3. 删除(Deleting):使用RestHighLevelClient的delete方法删除指定索引、类型和唯一标识ID的文档。 4. 查询(Searching):使用RestHighLevelClient的search方法进行查询操作。可以传递一个SearchRequest对象作为参数,该对象包含查询的详细信息,例如查询条件、排序、过滤等。执行查询后,可以通过SearchResponse对象获取查询结果。 以上是使用RestHighLevelClient进行增删改查的基本操作方法。根据具体需求,可以结合引用中的返回值封装实体ElasticSearchResponseEntity进行结果的封装和处理。引用中提到的直接调用service层的接口传入封装的实体或唯一ID即可操作ES增删改查。 需要注意的是,具体的操作代码需要根据项目的具体需求和业务逻辑进行编写。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [使用RestHighLevelClient-6.4.0客户端实现ES增删改查-操作工具类简单封装](https://blog.csdn.net/weixin_36440307/article/details/108239400)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值