项目中使用的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;
}