SpringBoot 整合es(elasticsearch)使用elasticsearch-rest-high-level-client实现增删改查

 

  官方文档:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/6.5/java-rest-high-search.html  (这个版本是6.5的)根据自己的来选择

 

  • index可以类比为MySQL中的表这个概念,他是一类型数据存储的集合。
  • document其实就是index这个集合里面单条数据的一种称呼,这个概念和MySQL中的行记录比较类似。
  • type是这个代表document属于index中的哪个类别(type),一个index通常会划分为多个type,逻辑上对index中有些许不同的几类数据进行分类:因为一批相同的数据,可能有很多相同的fields,但是还是可能会有一些轻微的不同,可能会有少数fields是不一样的,举个例子,就比如说,商品,可能划分为电子商品,生鲜商品,日化商品,等等。

 

引入依赖

 <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>


        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.8.0</version>
        </dependency>
        <!-- elasticsearch的客户端 -->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.8.0</version>
        </dependency>
        <!-- elasticsearch依赖2.x的log4j -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.8.2</version>
        </dependency>

        <!-- 阿里JSON解析器 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.75</version>
        </dependency>

 

 

yml文件

#elasticsearch
esHostName: 192.168.1.25
esPort: 9200

 

 

ContentModel.java  根据自己的实际业务来
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;


/**
 * es存放实体类
 */
@Data
@Accessors(chain = true)
@ToString
public class ContentModel {

    private static final long serialVersionUID = 6320548148250372657L;

    private Integer contentId;

    private String title;


}

 

配置类

EsConfig.java

import org.apache.http.HttpHost;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author yvioo。
 */
@Configuration
public class EsConfig {


    @Value("${esHostName}")
    private String esHostName;

    @Value("${esPort}")
    private Integer esPort;


    public static final RequestOptions COMMON_OPTIONS;

    static {
        RequestOptions.Builder builder=RequestOptions.DEFAULT.toBuilder();
        COMMON_OPTIONS=builder.build();
    }

    @Bean
    public RestHighLevelClient esRestClient(){
        RestClientBuilder builder = RestClient.builder(new HttpHost(esHostName, esPort, "http"));
        RestHighLevelClient client=new RestHighLevelClient(builder);
        return client;
    }
}

 

常量

EsConstant.java  可以不用

/**
 * @author yvioo。
 */
public class EsConstant {

    public static final String CONTENT_INDEX="索引名称";


    public static final String CONTENT_TYPE="类型";

}

 

工具类

EsService.java

import com.alibaba.fastjson.JSON;
import com.example.es.elasticsearch.entity.ContentModel;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * es操作类
 *
 * @author 洪。
 */
@Slf4j
@Service
public class EsService {


    @Resource
    private RestHighLevelClient restHighLevelClient;


    /**
     * 批量插入文档数据
     * @return 返回true 表示有错误
     */
    public boolean batchEsContent(List<ContentModel> contentModelList) throws IOException {

        BulkRequest bulkRequest = new BulkRequest();
        List<Integer> delIds=new LinkedList<>();

        for (ContentModel model : contentModelList) {
            IndexRequest indexRequest = new IndexRequest(EsConstant.CONTENT_INDEX).type(EsConstant.CONTENT_TYPE);
            indexRequest.id(model.getContentId().toString());
            String s = JSON.toJSONString(model);
            indexRequest.source(s, XContentType.JSON);
            bulkRequest.add(indexRequest);

        }



        BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, EsConfig.COMMON_OPTIONS);

        List<String> collect = Arrays.stream(bulk.getItems()).map(item -> {
            return item.getId();
        }).collect(Collectors.toList());
        log.error("内容索引生成:{}", collect);
        return bulk.hasFailures();
    }


    /**
     * 判断是否存在文档数据
     *
     * @param id 索引的ID
     * @return
     * @throws IOException
     */
    public boolean existIndex(Integer id) throws IOException {
        GetRequest getRequest = new GetRequest(
                EsConstant.CONTENT_INDEX,
                id.toString());
        getRequest.fetchSourceContext(new FetchSourceContext(false));
        getRequest.storedFields("_none_");
        return restHighLevelClient.exists(getRequest, EsConfig.COMMON_OPTIONS);
    }


    /**
     * 删除文档数据
     * @param id
     * @return
     * @throws IOException
     */
    public boolean deleteIndex(Integer id) throws IOException {
        DeleteRequest request = new DeleteRequest(
                EsConstant.CONTENT_INDEX,
                id.toString());
        DeleteResponse deleteResponse = restHighLevelClient.delete(
                request,  EsConfig.COMMON_OPTIONS);
        if (deleteResponse.status().getStatus()== RestStatus.OK.getStatus()){
            return true;
        }
        return false;
    }


    /**
     * 批量删除索引
     * @param ids
     * @return 返回true 表示有错误
     * @throws IOException
     */
    public boolean deleteBatchIndex(List<Integer> ids) throws IOException {

        // 批量删除数据
        BulkRequest request = new BulkRequest();

        ids.forEach(s->{
            request.add(new DeleteRequest().index(EsConstant.CONTENT_INDEX).type(EsConstant.CONTENT_TYPE).id(s.toString()));
        });


        BulkResponse response = restHighLevelClient.bulk(request, EsConfig.COMMON_OPTIONS);
        return response.hasFailures();
    }


    /**
     * 更新文档数据
     * @param contentModel
     * @return
     * @throws IOException
     */
    public boolean updateIndex(ContentModel contentModel) throws IOException {
        // 修改数据
        UpdateRequest request = new UpdateRequest();
        request.index(EsConstant.CONTENT_INDEX).id(contentModel.getContentId().toString());
        String s = JSON.toJSONString(contentModel);
        request.doc(s, XContentType.JSON);

        UpdateResponse updateResponse = restHighLevelClient.update(request, EsConfig.COMMON_OPTIONS);
        if (updateResponse.status().getStatus()== RestStatus.OK.getStatus()){
            return true;
        }
        return false;
    }




}

 

使用直接注入 EsService 然后调用里面的方法即可

 

 

由于每种业务查询的写法都不一定,没有通用性  所以这里只提供一些基础的方法

官网地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.3/java-rest-high-search.html

基础的查询所有的demo 

@Resource
    private RestHighLevelClient restHighLevelClient;

 

 

//创建检索请求
SearchRequest searchRequest = new SearchRequest("这里可以直接指定索引"); 
//创建检索条件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 
//这个表示查询所有
searchSourceBuilder.query(QueryBuilders.matchAllQuery()); 

searchRequest.source(searchSourceBuilder); 

//执行检索
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

SearchHits searchHits = searchResponse.getHits();
//所有条数
long totalHits = searchHits.getTotalHits();

//遍历结果
for (SearchHit hit : searchHits) {
    ContentDto content = new ContentDto();
    Map<String, Object> sourceAsMap = hit.getSourceAsMap();
    //取出对应的结果
    String documentTitle = (String) sourceAsMap.get("title");
}

 数据量超过一万条1w就需要加下面这个才会反正正确的页码

searchSourceBuilder.trackTotalHits(true);

但是也可以报错 查询报错参考: Elasticsearch(es)查询报错:Result window is too large, from + size must be less than or equal to: [10000] but was [20000 

 

 

 

精确查询匹配多个字段

  BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("db.database", "库"))
                .must(QueryBuilders.termQuery("db.table", "表"))
                .must(QueryBuilders.termQuery("addressId", "地址"));

 

 

模糊查询

 

BoolQueryBuilder builder = QueryBuilders.boolQuery();

// 手机号模糊查询
String phone = bo.getPhone();
if (StringUtils.isNotBlank(phone)) {
    phone = "*"+phone+"*";
    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
    WildcardQueryBuilder phoneBuilder = QueryBuilders.wildcardQuery("phone", phone);
    WildcardQueryBuilder mobileBuilder = QueryBuilders.wildcardQuery("mobile", phone);

    boolQueryBuilder.should(phoneBuilder);
    boolQueryBuilder.should(mobileeBuilder);

    builder.must(boolQueryBuilder);
}

 

 

聚合函数-统计某个字段的值

  // 构建搜索请求
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.aggregation(AggregationBuilders.sum("field_sum").field("your_field"));

使用 sum 聚合来计算指定字段的总和。将 your_field 替换为你实际想要统计的字段名。

取值

 // 获取聚合结果
        Sum sumAgg = response.getAggregations().get("field_sum");
        double sumValue = sumAgg.getValue();

下面的field_sum与上面查询设置的对应

 

 

分页

sourceBuilder.from((query.getPageNo() > 0 ? (query.getPageNo() - 1) : 0) * query.getPageSize());

sourceBuilder.size(query.getPageSize());

 

 

数值范围筛选,大于0

 query.must(QueryBuilders.rangeQuery("total").gt(0));

 

posted @ 2021-05-25 13:51  yvioo  阅读(1605)  评论(0编辑  收藏  举报