Api Client 选择
客户端 | 优点 | 缺点 | 说明 |
---|---|---|---|
Java Low Level Rest Client | 与ES版本之间没有关系,适用于作为所有版本ES的客户端 | ||
Java High Level Rest Client | 使用最多 | 使用需与ES版本保持一致 | 基于Low Level Rest Client,注意:7.15版本之后将被弃用
|
TransportClient | 使用Transport 接口进行通信,能够使用ES集群中的一些特性,性能最好 | JAR包版本需与ES集群版本一致,ES集群升级,客户端也跟着升级到相同版本 | 过时产品,7版本之后不再支持
|
Elasticsearch Java API Client | 最新的es客户端 | 文档少 |
最稳方案:Java High Level Rest Client
官方文档:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html
spring starter官方依赖版本信息:https://docs.spring.io/spring-data/elasticsearch/docs/3.2.4.RELEASE/reference/html/#elasticsearch.versions
spring 官方对es的支持:https://docs.spring.io/spring-data/elasticsearch/docs/3.2.4.RELEASE/reference/html/#reference
ElasticSearch组件RestHighLevelClient用法详解:https://juejin.cn/post/6921479614304878599
注意:因为 Java High Level Rest Client 在使用的时候版本必须高度统一,springboot提供的starter:spring-data-elasticsearch 依赖版本是跟随springboot走,我们如果想要统一 es服务、分词器、api 客户端,最好是不使用官方 starter ,手动导入 Java High Level Rest Client 的pom依赖;
以下文档基于
es 7.7.0
,只给出关键的pom,部分api根据版本略有不同
<properties>
<elasticsearch.varsion>7.7.0</elasticsearch.varsion>
</properties>
......
<!-- https://mvnrepository.com/artifact/org.elasticsearch/elasticsearch -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.elasticsearch.client/elasticsearch-rest-high-level-client -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
创建客户端
@Configuration
public class HighLevelClientConfig {
@Bean(destroyMethod = "close")
public RestHighLevelClient restHighLevelClient() {
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("ip:xxx.xxx.xxx.xxx", 9200, "http")));
return client;
}
}
RestClient.builder 的参数是个可变参数,集群模式下,增加节点配置即可(多个new HttpHost)
使用客户端的时候注入即可,下文中所有
esClient
都来自这个类
索引操作
添加索引 - 方式一
特点:方便,不用每次设置分词器
private static Map<String, Object> fieldAttr(EsFieldTypeEnum type) {
Map<String, Object> result = new HashMap<>();
result.put("type", type.k);
if ("text".equals(type.k)) {
/*
插入文档时,将text类型的字段做分词然后插入倒排索引
ik_max_word:最细粒度分词(文档中的字可以反复出现)
ik_smart:最粗粒度分词(每个字只会出现一次)
*/
result.put("analyzer", "ik_max_word");
result.put("search_analyzer", "ik_max_word");
/*
存储内容过长导致报错:Exceeding maximum length of field in elasticsearch - error in kibana
可以开启下面的设置
*/
// result.put("ignore_above", "");
result.put("term_vector", "with_positions_offsets");
}
return result;
}
public void createIndexM1() {
try {
/*
设置索引名称
*/
String IndexName = "test_index_create_1";
CreateIndexRequest createIndexRequest = new CreateIndexRequest(IndexName);
/*
设置字段以及字段类型
*/
Map<String, Object> properties = new HashMap<>();
properties.put("id", fieldAttr(EsFieldTypeEnum.FIELD_INTEGER));
properties.put("title", fieldAttr(EsFieldTypeEnum.FIELD_TEXT));
properties.put("tag", fieldAttr(EsFieldTypeEnum.FIELD_KEYWORD));
properties.put("content", fieldAttr(EsFieldTypeEnum.FIELD_TEXT));
/*
设置properties
*/
Map<String, Object> mapping = new HashMap<>();
mapping.put("properties", properties);
/*
设置mapping
mapping的结构:mapping : { properties : { fields } }
*/
createIndexRequest.mapping(mapping);
/*
设置分片
*/
createIndexRequest.settings(
Settings.builder()
.put("index.number_of_shards", 3)
.put("index.number_of_replicas", 2));
/*
执行创建请求
*/
CreateIndexResponse createIndexResponse = esClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
/*
判断成功与否
*/
boolean acknowledged = createIndexResponse.isAcknowledged();
log.info("acknowledged:{}", acknowledged);
boolean shardsAcknowledged = createIndexResponse.isShardsAcknowledged();
log.info("shardsAcknowledged:{}", shardsAcknowledged);
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
添加索引二
特点:和请求体查询高度相似,灵活度高,方便控制每个字段的属性,但是写法比较繁琐
public void createIndexM2() {
try {
/*
设置索引名称
*/
String indexName = "test_index_create_2";
CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject()
.startObject("mappings").startObject("properties")
.startObject("id")
.field("type", EsFieldTypeEnum.FIELD_INTEGER.k)
.endObject()
.startObject("title")
.field("type", EsFieldTypeEnum.FIELD_TEXT.k)
.field("analyzer","ik_max_word")
.field("search_analyzer","ik_smart")
.endObject()
.startObject("tag")
.field("type", EsFieldTypeEnum.FIELD_KEYWORD.k)
.endObject()
.startObject("content")
.field("type", EsFieldTypeEnum.FIELD_TEXT.k)
.field("analyzer","ik_max_word")
.field("search_analyzer","ik_smart")
.endObject()
.endObject().endObject()
.startObject("settings")
.field("number_of_shards",3)
.field("number_of_replicas",1)
.endObject()
.endObject();
createIndexRequest.source(builder);
CreateIndexResponse createIndexResponse = esClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
/*
判断成功与否
*/
boolean acknowledged = createIndexResponse.isAcknowledged();
log.info("acknowledged:{}", acknowledged);
boolean shardsAcknowledged = createIndexResponse.isShardsAcknowledged();
log.info("shardsAcknowledged:{}", shardsAcknowledged);
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
文档操作
CRUD
插入文档
public void insertDoc() {
try {
/*
准备数据
*/
String indexName = "test_index_create_2";
int id = 12;
Article article = new Article();
article.setId(id);
article.setTitle("java是世界上最好的语言");
article.setTag("语言");
article.setContent("程序员们放下手里的鼠标和键盘,抄起凳子打了起来");
/*
创建操作索引的request对象,设置目标索引
*/
IndexRequest indexRequest = new IndexRequest(indexName);
/*
请求数据填充
id:建议id和数据库主键保持同步
source:文档数据
*/
indexRequest.id(String.valueOf(id));
indexRequest.source(JSON.toJSONString(article), XContentType.JSON);
/*
插入文档依赖:RestHighLevelClient.index 方法
*/
IndexResponse indexResponse = esClient.index(indexRequest, RequestOptions.DEFAULT);
log.info("indexResponse: " + JSON.toJSONString(indexResponse));
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
获取文档
public void getDoc() {
try {
/*
指定要查询的索引名称和文档id
*/
String indexName = "test_index_create_2";
String id = "123";
/*
创建查询request对象
*/
GetRequest request = new GetRequest(indexName, id);
/*
获取文档依赖:RestHighLevelClient.get 方法
*/
GetResponse response = esClient.get(request, RequestOptions.DEFAULT);
if (response.isExists()) {
String sourceAsString = response.getSourceAsString();
log.info("source: " + sourceAsString);
}
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
删除文档
public void deleteDoc() {
try {
/*
指定要删除的索引名称和文档id
*/
String indexName = "test_index_create_2";
String id = "123";
/*
创建删除request对象
*/
DeleteRequest request = new DeleteRequest(indexName, id);
/*
删除文档依赖:RestHighLevelClient.delete 方法
*/
DeleteResponse response = esClient.delete(request, RequestOptions.DEFAULT);
if (response.status() == RestStatus.OK) {
log.info("删除成功");
}
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
修改文档
public void updateDoc() {
try {
/*
指定要修改的索引名称和文档id
*/
String indexName = "test_index_create_2";
String id = "12";
/*
注意:这里的修改并不会覆盖原有数据,只是修改了部分数据
*/
Article article = new Article();
article.setTitle("java是世界上最好的语言-update");
article.setContent("程序员们放下手里的鼠标和键盘,抄起凳子打了起来-update");
/*
创建 修改request对象
*/
UpdateRequest request = new UpdateRequest(indexName, id);
/*
请求数据填充
*/
request.doc(JSON.toJSONString(article), XContentType.JSON);
/*
修改文档依赖:RestHighLevelClient.update 方法
*/
UpdateResponse response = esClient.update(request, RequestOptions.DEFAULT);
log.info("response: " + JSON.toJSONString(response));
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
文档搜索
分页搜索
public void pageSearch() {
try {
/*
设置目标索引
*/
String indexName = "test_index_create_2";
/*
创建 搜索request对象
*/
SearchRequest request = new SearchRequest(indexName);
/*
构建搜索条件
*/
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.from(0); // 从第几条开始
builder.size(10); // 查几个
builder.sort("id", SortOrder.DESC); // 根据什么排序
builder.query(QueryBuilders.matchAllQuery()); // 查询全部
/*
请求数据填充
*/
request.source(builder);
/*
搜索文档依赖:RestHighLevelClient.search 方法
*/
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
if (response.status() != RestStatus.OK) {
throw new Exception("搜索错误");
}
SearchHits hits = response.getHits();
log.info("数据总数:" + hits.getTotalHits());
log.info("搜索用时:" + response.getTook());
log.info("搜索结果:");
for (SearchHit hit : hits) {
log.info("字符串" + hit.getSourceAsString());
log.info("java对象:" + JSON.toJavaObject(JSON.parseObject(hit.getSourceAsString()), Article.class));
log.info("map对象" + hit.getSourceAsMap().toString());
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
简单搜索
public void simpleSearch() {
try {
/*
创建 搜索request,设置目标索引
*/
SearchRequest request = new SearchRequest("test_index_create_2");
/*
构建搜索条件
*/
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.size(10);
/*
单个字段匹配
*/
MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", "update");
/*
完全匹配
*/
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("content", "update");
/*
复合查询
*/
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(matchQueryBuilder).must(termQueryBuilder);
/*
请求数据填充
*/
request.source(searchSourceBuilder.query(boolQueryBuilder));
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
printResp(response);
}catch (Exception e) {
log.error(e.getMessage(), e);
}
}
常用的条件构造器:
QueryBuilders.termQuery(“key”, obj) 完全匹配
QueryBuilders.termsQuery(“key”, obj1, obj2…) 一次匹配多个值
QueryBuilders.matchQuery(“key”, Obj) 单个匹配, field不支持通配符, 前缀具高级特性
QueryBuilders.multiMatchQuery(“text”, “field1”, “field2”…) 匹配多个字段, field有通配符忒行
QueryBuilders.matchAllQuery() 匹配所有文件复合条件构造器:
QueryBuilders.boolQuery()文章来源:https://www.toymoban.com/news/detail-615132.html
.must(termQuery(“content”, “test1”)) 相当于 与 & =
.mustNot(termQuery(“content”, “test2”)) 相当于 非 ~ !=
.should(termQuery(“content”, “test3”)) 相当于 或 | or
.filter(termQuery(“content”, “test5”)); 过滤文章来源地址https://www.toymoban.com/news/detail-615132.html
高亮搜索
public void highLightSearch() {
try {
/*
单字段匹配
*/
MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("title", "java");
/*
高亮设置
*/
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.preTags("<span style=\"color:red\">");
highlightBuilder.postTags("</span>");
highlightBuilder.fields().add(new HighlightBuilder.Field("title"));
/*
构建搜索条件
*/
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(matchQueryBuilder);
searchSourceBuilder.highlighter(highlightBuilder);
/*
创建 搜索request,设置目标索引
*/
SearchRequest request = new SearchRequest("test_index_create_2");
request.source(searchSourceBuilder);
SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
log.info(JSON.toJSONString(response));
SearchHits hits = response.getHits();
for (SearchHit hit : hits) {
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
HighlightField highlightField = highlightFields.get("title");
Text[] fragments = highlightField.getFragments();
for (Text fragment : fragments) {
log.info("高亮字段:" + fragment.toString());
}
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
到了这里,关于Elasticsearch Java客户端的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!