项目中使用的ElasticSearch 版本为7.9.3。

一、引入pom依赖

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.2.1</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.2.1</version>
</dependency>

二、创建ES客户端Bean

@Configuration
public class ElasticsearchClient {

    /**
     * es集群地址
     */
    @Value("${es.hosts}")
    private String hostlist;

    @Value("${es.username:}")
    private String esUsername;
    @Value("${es.password:}")
    private String esPassword;
    /**
     * logger.
     */
    private Logger logger = LoggerFactory.getLogger(ElasticsearchClient.class);

    private static final String URL_REGEX = ".+:\\d{0,5}$";

    /**
     * 获取客户端连接
     *
     * @return RestHighLevelClient
     */
    @Bean(name = "restHighLevelClient")
    public RestHighLevelClient getClient() {
        logger.info("es.hosts{}", hostlist);
        //解析hostlist配置信息
        String[] split = hostlist.split(",");
        //创建HttpHost数组,其中存放es主机和端口的配置信息
        HttpHost[] httpHostArray = new HttpHost[split.length];
        for (int i = 0; i < split.length; i++) {
            String item = split[i];
            Pattern p = Pattern.compile(URL_REGEX);
            Matcher m = p.matcher(item);
            if (m.find()) {
                httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http");
            } else {
                httpHostArray[i] = new HttpHost(item);
            }
        }
        RestClientBuilder builder = RestClient.builder(httpHostArray);

        if (!StringUtils.isAnyBlank(esUsername, esPassword)) {
            logger.info("init es credential config");

            final CredentialsProvider credentialProvider = new BasicCredentialsProvider();
            credentialProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(esUsername, esPassword));

            builder.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialProvider));
        }

        //创建RestHighLevelClient客户端
        return new RestHighLevelClient(builder);
    }

}

三、操作ES

1. 创建索引

@PostConstruct
public void initIndex() throws IOException {
    if (!restHighLevelClient.indices().exists(new GetIndexRequest(FLFG_INDEX), RequestOptions.DEFAULT)) {
        // 如果索引不存在
        log.error("索引不存在");
        CreateIndexRequest createIndexRequest = new CreateIndexRequest(FLFG_INDEX);
        createIndexRequest.settings("{\"max_result_window\": 1000000,\"number_of_replicas\": 0}", XContentType.JSON);
        createIndexRequest.aliases("{\"fzjs\": {}}", XContentType.JSON);
        createIndexRequest.mapping("{\"properties\":{\"bh\":{\"type\":\"text\"},\"flfgmc\":{\"type\":\"text\",\"analyzer\":\"ik_max_word\",\"fields\":{\"keyword\":{\"type\":\"keyword\"}}},\"zhaiyao\":{\"type\":\"text\",\"analyzer\":\"ik_max_word\"},\"yxx\":{\"type\":\"keyword\"},\"fbsj\":{\"type\":\"date\",\"format\":\"yyyy-MM-dd||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS||strict_date_optional_time||epoch_millis\"},\"content\":{\"type\":\"text\",\"analyzer\":\"ik_max_word\"}}}",
                                   XContentType.JSON);
        log.info("自动创建成功");
        restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
    }
}  

mapping部分的 JSON格式

{
  "properties": {
    "bh": {
      "type": "text"
    },
    "flfgmc": {
      "type": "text",
      "analyzer": "ik_max_word",
      "fields": {
        "keyword": {
          "type": "keyword"
        }
      }
    },
    "zhaiyao": {
      "type": "text",
      "analyzer": "ik_max_word"
    },
    "yxx": {
      "type": "keyword"
    },
    "fbsj": {
      "type": "date",
      "format": "yyyy-MM-dd||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS||strict_date_optional_time||epoch_millis"
    },
    "content": {
      "type": "text",
      "analyzer": "ik_max_word"
    }
  }
}

2. 新增字段

public void addField() throws IOException {
    if (restHighLevelClient.indices().exists(new GetIndexRequest("flfg"), RequestOptions.DEFAULT)) {
        PutMappingRequest putMappingRequest = new PutMappingRequest("flfg");
        //{"properties":{"pzjg": {"type": "keyword"}}};
        XContentBuilder builder = XContentFactory.jsonBuilder();
        builder.startObject();        // {
        builder.startObject("properties");  // "properties":{
        builder.startObject("pzjg");   // "pzjg":{
        builder.field("type", "keyword");  // "type": "keyword"
        builder.endObject();  // }
        builder.endObject();  // }
        builder.endObject();  // }
        putMappingRequest.source(builder);
        restHighLevelClient.indices().putMapping(putMappingRequest, RequestOptions.DEFAULT);
    }
}

startObject() → {

endObject() → }

startArray() → [

endArray() → ]

3. 新增文档

private void insertToES(FlfgVO flfgVO, String bh) throws IOException {
    IndexRequest indexRequest = new IndexRequest(FLFG_INDEX);
    indexRequest.id(bh);
    indexRequest.source(JSON.toJSONString(flfgVO), XContentType.JSON);
    restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
}

4. 更新文档

public void update(FlfgVO flfgVO, String content) throws IOException {
    // 处理ES数据
    String zhaiYaoString = FileTextReadUtil.getZhaiYaoString(content);
    flfgVO.setZhaiyao(zhaiYaoString);
    // 更新ES
    UpdateRequest updateRequest = new UpdateRequest(FLFG_INDEX, flfgVO.getBh());
    updateRequest.doc(JSON.toJSONString(flfgVO), XContentType.JSON);
    restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
}

5. 删除文档

public void deleteES(String id) throws IOException {
    DeleteRequest deleteRequest = new DeleteRequest("flfg", id);
    DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
}

6. 查询并高亮显示

public Map<String, Object> search(QueryVO queryVO) throws IOException {
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    // bool组合查询
    BoolQueryBuilder builder = new BoolQueryBuilder();

    buildKeyword(sourceBuilder, builder, queryVO);

    // 分页-排序
    sourceBuilder.from(queryVO.getFrom()).size(queryVO.getSize());
    sourceBuilder.sort(SortBuilders.scoreSort());
    sourceBuilder.sort("fbsj", SortOrder.DESC);

    SearchRequest searchRequest = new SearchRequest(INDEX_FLFG);
    searchRequest.source(sourceBuilder);
    SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

    Map<String, Object> result = this.dealSearchResult(response);
    result.put("lastParam", queryVO.getLastParam());
    return result;
}

/**
 * 构建查询关键词
 */
private void buildKeyword(SearchSourceBuilder sourceBuilder, BoolQueryBuilder builder, QueryVO queryVO) {
    String keyword = queryVO.getKeyword();
    if (StringUtils.isBlank(keyword)) {
        builder.must(new MatchAllQueryBuilder());
        return;
    }

    MultiMatchQueryBuilder multiMatchQuery = QueryBuilders.multiMatchQuery(keyword);
    HighlightBuilder highlightBuilder = new HighlightBuilder().fragmentSize(100)
        .numOfFragments(2).preTags("<span style='color: red'>").postTags("</span>");

    String type = queryVO.getType();
    if (StringUtils.equals("0", type) || StringUtils.equals("1", type)) {
        multiMatchQuery.field("flfgmc", 1.5f);
        highlightBuilder.field("flfgmc");
    }
    if (StringUtils.equals("0", type) || StringUtils.equals("2", type)) {
        multiMatchQuery.field("content", 1.0f);
        highlightBuilder.field("content");
    }
    multiMatchQuery.type(MultiMatchQueryBuilder.Type.BEST_FIELDS);
    builder.should(multiMatchQuery);
    builder.minimumShouldMatch(1);
    sourceBuilder.highlighter(highlightBuilder);
}

/**
 * 处理返回结果
 */
public Map<String, Object> dealSearchResult(SearchResponse response) {
    Map<String, Object> searchMap = new HashMap<>();
    if (RestStatus.OK.equals(response.status())) {
        // 处理返回字段及高亮
        SearchHits searchHits = response.getHits(); //获取命中次数
        JSONArray jsonArray = dealHit(searchHits);
        // 其他处理过程
        // TODO ……
        searchMap.put("data", jsonArray);
        searchMap.put("sum", searchHits.getTotalHits().value);
    } else {
        throw new ElasticsearchException("搜索返回异常");
    }
    return searchMap;
}

/**
 * 处理高亮返回结果
 * @param searchHits 命中结果
 */
private JSONArray dealHit(SearchHits searchHits) {
    JSONArray returnArray = new JSONArray();
    for (SearchHit hit : searchHits) {
        JSONObject resultJson = JSON.parseObject(hit.getSourceAsString());
        //处理高亮信息
        Map<String, HighlightField> highlightFields = hit.getHighlightFields();
        for (Map.Entry<String, HighlightField> highlightField : highlightFields.entrySet()) {
            String highlightFieldKey = highlightField.getKey();
            //添加源字段
            resultJson.put(highlightFieldKey + "_source", resultJson.get(highlightFieldKey));
            String value = highlightField.getValue().getFragments()[0].toString();
            resultJson.put(highlightFieldKey, value);
        }

        resultJson.put("highLight", highlightFields);
        resultJson.put("_id", hit.getId());
        returnArray.add(resultJson);
    }

    return returnArray;
}