RestHighLevelClient官方文档: https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-create-index.html.
spring-data-elasticsearch官方文档: http://jvm123.com/doc/es/index.html#elasticsearch.clients.rest.
1). elasticsearch5.5 index支持多种type,elasticsearch7.6 索引将去除type 没有类型的概念了。
官网原文如下:
在编辑器中创建索引时候也可以看到已被弃用的方法,如图,我们点进去看
可以看到有个@Deprecated,这个注解的含义是 这个方法或类不再建议使用。在新版本中有其他方法或类可以代替这个使用,以后的版本也不会再更新这个方法或类。注释上写的也是差不多这个意思。
2).在Elasticsearch Java客户端也有区别。在 Elasticsearch 7.6 中不建议使用TransportClient,并且在8.0中会完全删除TransportClient。因此,官方更建议我们用Java High Level REST Client ,而在低版本中则使用Java Low Level REST Client。
cn.hutool
hutool-all
5.3.2
org.elasticsearch.client
elasticsearch-rest-high-level-client
7.6.2
org.springframework.data
spring-data-elasticsearch
4.0.1.RELEASE
我们使用RestHighLevelClient 来操作elasticsearch
package org.java.demo.config;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.RestClients;
import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration;
public class RestClientConfig extends AbstractElasticsearchConfiguration {
@Override
@Bean
public RestHighLevelClient elasticsearchClient() {
final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo("localhost:9200")
.build();
return RestClients.create(clientConfiguration).rest();
}
}
创建索引对象
package org.java.demo;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import java.io.Serializable;
@Document(indexName = "javashop")
public class GoodsIndex implements Serializable {
@Id
private Integer goodsId;
@Field(analyzer = "ik_max_word")
private String goodsName;
/**
* 农贸市场ID
* */
private String connet;
public GoodsIndex() {
}
public String getConnet() {
return connet;
}
public void setConnet(String connet) {
this.connet = connet;
}
public Integer getGoodsId() {
return goodsId;
}
public void setGoodsId(Integer goodsId) {
this.goodsId = goodsId;
}
public String getGoodsName() {
return goodsName;
}
public void setGoodsName(String goodsName) {
this.goodsName = goodsName;
}
@Override
public String toString() {
return "GoodsIndex{" +
"goodsId=" + goodsId +
", goodsName='" + goodsName + '\'' +
", connet='" + connet + '\'' +
'}';
}
}
这里着重讲一下查询,termQuery与matchQuery的区别
TermQueryBuilder:
词条查询是ElasticSearch的一个简单查询。它仅匹配在给定字段中含有该词条的文档,而且是确切的、未经分析的词条。term查询会查找我们设定的准确值。term查询本身很简单,它接受一个字段名和我们希望查找的值。
TermsQueryBuilder:
词条查询(Term Query)允许匹配单个未经分析的词条,多词条查询(Terms Query)可以用来匹配多个这样的词条。只要指定字段包含任一我们给定的词条,就可以查询到该文档。
package org.java.demo;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.json.JSONObject;
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.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import cn.hutool.core.collection.CollUtil;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.client.indices.*;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
@RestController
@RequestMapping("/elasticsearch")
public class HelloController {
@Autowired
RestHighLevelClient highLevelClient;
private ElasticsearchOperations elasticsearchOperations;
public HelloController(ElasticsearchOperations elasticsearchOperations) {
this.elasticsearchOperations = elasticsearchOperations;
}
@GetMapping("/template")
public void putTemplate()throws IOException{
PutIndexTemplateRequest request = new PutIndexTemplateRequest("goods_template");
//别名,所有根据该模版创建的index 都会添加这个别名。查询时可查询别名,就可以同时查询多个名称不同的index,根据此方法可实现index每天或每月生成等逻辑。
request.alias(new Alias("goods_index"));
request.order(10);
//匹配哪些index。在创建index时会生效。
request.patterns(CollUtil.newArrayList("goods_index*"));
request.settings(Settings.builder()
//数据插入后多久能查到,实时性要求高可以调低
.put("index.refresh_interval", "1s")
//传输日志,对数据安全性要求高的 设置 request,默认值:request
.put("index.translog.durability", "async")
.put("index.translog.sync_interval", "120s")
//分片数量
.put("index.number_of_shards", "5")
//副本数量
.put("index.number_of_replicas", "0")
//单次最大查询数据的数量。默认10000。不要设置太高,如果有导出需求可以根据查询条件分批次查询。
.put("index.max_result_window", "100000"));
//使用官方提供的工具构建json。可以直接拼接一个json字符串,也可以使用map嵌套。
XContentBuilder jsonMapping = XContentFactory.jsonBuilder();
//所有数据类型 看官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.4/mapping-types.html#_core_datatypes
jsonMapping.startObject().startObject("properties")
.startObject("goodsName").field("type", "text").field("analyzer", "ik_max_word").endObject()
.startObject("goodsId").field("type", "integer").endObject()
//keyword类型不会分词存储
.startObject("connet").field("type", "text").endObject()
//指定分词器
.endObject().endObject();
request.mapping(jsonMapping);
//设置为true只强制创建,而不是更新索引模板。如果它已经存在,它将失败
request.create(false);
AcknowledgedResponse response = highLevelClient.indices().putTemplate(request, RequestOptions.DEFAULT);
if (response.isAcknowledged()) {
Console.log("创建模版成功!");
} else {
Console.log("创建模版失败!");
}
}
@DeleteMapping("")
public void deleteIndex(Integer id) throws IOException {
// DeleteIndexRequest request = new DeleteIndexRequest("goods_index*");
DeleteRequest request = new DeleteRequest("goods_index",id.toString());
DeleteResponse delete = highLevelClient.delete(request,RequestOptions.DEFAULT);
// AcknowledgedResponse response = highLevelClient.indices().delete(request, RequestOptions.DEFAULT);
}
@PostMapping("/create")
public void createIndex() throws IOException {
CreateIndexRequest request = new CreateIndexRequest("goods_index_tmp");
CreateIndexResponse createIndexResponse = highLevelClient.indices().create(request, RequestOptions.DEFAULT);
if (createIndexResponse.isAcknowledged()) {
Console.log("创建index成功!");
} else {
Console.log("创建index失败!");
}
}
@PostMapping("")
public void insertIndex() throws IOException {
BulkRequest request = new BulkRequest("goods_index_" + DateUtil.format(new Date(), "yyyyMM"));
for (int i = 0; i < 5; i++) {
GoodsIndex testData = new GoodsIndex();
testData.setGoodsId(i);
testData.setConnet(i+"号商品简介----------------");
testData.setGoodsName("商品---------------"+i);
IndexRequest indexRequest = new IndexRequest("goods_index_" + DateUtil.format(new Date(), "yyyyMM"));
indexRequest.id(testData.getGoodsId().toString());
indexRequest.source(new JSONObject(testData).toString()
, XContentType.JSON);
request.add(indexRequest);
}
BulkResponse response = highLevelClient.bulk(request, RequestOptions.DEFAULT);
Console.log("插入状态:{} 数量:{} ",response.status(),response.getItems().length);
}
@PutMapping("")
public void update(Integer id) throws IOException {
UpdateRequest updateRequest = new UpdateRequest("goods_index", id.toString());
GoodsIndex goodsIndex=new GoodsIndex();
goodsIndex.setGoodsId(id);
goodsIndex.setGoodsName("未知商品");
goodsIndex.setConnet("未知内容");
updateRequest.doc(new JSONObject(goodsIndex).toString()
, XContentType.JSON);
highLevelClient.update(updateRequest, RequestOptions.DEFAULT);
}
@GetMapping("")
public void query(String keyword,Integer id) throws IOException {
SearchRequest searchRequest = new SearchRequest("goods_index");
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
QueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("goodsName", keyword)
.fuzziness(Fuzziness.AUTO)
.analyzer("ik_max_word")
.operator(Operator.AND)
.prefixLength(3)
.maxExpansions(10);
boolQueryBuilder.must(QueryBuilders.termQuery("goodsId", id));
boolQueryBuilder.must(matchQueryBuilder);
searchSourceBuilder.query(boolQueryBuilder);
searchSourceBuilder.from(0);
searchSourceBuilder.size(5);
searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
searchSourceBuilder.sort(new FieldSortBuilder("goodsId").order(SortOrder.ASC));
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
for (SearchHit hit : searchHits) {
Map map = hit.getSourceAsMap();
System.out.println(hit);
}
}
}