1. POM 配置
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.6.2</version>
</dependency>
2. 建立ES集群连接
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost(IP, PORT, "http")));
同样,如果我们要连接集群中多个ES节点时,只需要在RestClient 的 builder 方法中多添加几个HttpPost对象即可
String ipPort = "10.xx:9200,10.xx:9200,10.xx:9200";
String[] ipPortArry = ipPort.split(",");
List<HttpHost> httpHostsList = new ArrayList();
for(String ips : ipPortArry){
String[] ipArray = ips.split(":");
httpHostsList.add(new HttpHost(ipArray[0], Integer.parseInt(ipArray[1]), "http"));
}
RestHighLevelClient client = new RestHighLevelClient( RestClient.builder(httpHostsList.toArray(new HttpHost[httpHostsList.size()])));
补充:
Java配置多个ES节点时,请求的时候会随机选一个节点作为协调节点负责分发请求和处理结果,所以Java链接ES节点数量的多少,不会影响到Java请求ES查询结果的速度,只是其中某个节点宕机时,其他节点可以保证正常的查询和操作。
ES 端口9200与9300的区别:
9200作为Http协议,主要用于外部通讯
9300作为Tcp协议,jar之间就是通过tcp协议通讯
ES集群之间是通过9300进行通讯
3. 简单的查询并获取查询结果
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("localhost", 9200, "http")));
SearchRequest searchRequest = new SearchRequest("my_index");
//或者
/*
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices("my_index");
*/
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
//配置source源字段过虑,1显示的,2排除的
searchSourceBuilder.fetchSource(new String[]{"name","studymodel","description"},new String[]{});
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest);
//获取所有搜索结果、总匹配数量
SearchHits hits = searchResponse.getHits();
long totalHits = hits.getTotalHits(); //如果总是超过1万, index没有设置,则返回1万
SearchHit[] searchHits = hits.getHits();
//遍历结果
for(SearchHit searchHit:searchHits){
String index = searchHit.getIndex();
String type = searchHit.getType();
String id = searchHit.getId();
float score = searchHit.getScore();
String sourceAsString = searchHit.getSourceAsString();
Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
String name = (String) sourceAsMap.get("name");
String studymodel = (String) sourceAsMap.get("studymodel");
String description = (String) sourceAsMap.get("description");
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}
//关闭链接
client.close()
es的dsl:
{
"query": {
"match_all": {}
},
"_source" : ["name","studymodel","description"]
}
4. 使用es的json 拼接查询语句
StringBuffer dsl = new StringBuffer();
dsl.append("{\"bool\": {");
dsl.append(" \"must\": [");
dsl.append(" {");
dsl.append(" \"term\": {");
dsl.append(" \"mdid.keyword\": {");
dsl.append(" \"value\": \"2fa9d41e1af460e0d47ce36ca8a98737\"");
dsl.append(" }");
dsl.append(" }");
dsl.append(" }");
dsl.append(" ]");
dsl.append(" }");
dsl.append("}");
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices("my_index");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(ueryBuilders.wrapperQuery(dsl.toString()));
//配置source源字段过虑,1显示的,2排除的
searchSourceBuilder.fetchSource(new String[]{"name","studymodel","description"},new String[]{});
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest);
5. query
5.0 QueryBuilders转换为JSON字符串,方便调试
QueryBuilder query = QueryBuilders.termQuery("name", "John");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(query);
String json = sourceBuilder.toString();
System.out.println(json);
并将其转换为JSON字符串
toString()方法返回的字符串是格式化的,可以在控制台中方便地查看和调试。
5.1 Term Query
{
"query": {
"term" : {
"name": "spring"
}
},
"_source" : ["name","studymodel"]
}
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.termQuery("name","spring"));
searchSourceBuilder.fetchSource(new String[]{"name","studymodel","description"}, new String[]{});
5.2 terms query ES提供根据多个id值匹配的方法
{
"query": {
"terms": {
"systemAssignedTo.keyword": [
"1",
"2"
]
}
}
}
select * from mr_zcy where systemAssignedTo in ('1','2')
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
String[] ids = {"1", "2"};
searchSourceBuilder.query(QueryBuilders.termsQuery("systemAssignedTo.keyword",ids));
5.3 match query (匹配单个字段)
{
"query": {
"match": {
"name": {
"query": "spring开发",
"operator": "or"
}
}
},
"_source" : ["name"]
}
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchQuery("name","spring开发").operator(Operator.OR));
searchSourceBuilder.fetchSource(new String[]{"name"}, new String[]{});
5.4 minimum_should_match
{
"query": {
"match": {
"description": {
"query": "spring开发框架",
"minimum_should_match": "80%"
}
}
}
}
spring开发框架 会被分为三个词:spring、开发、框架
设置 minimum_should_match:80% 表示,三个词在文档的匹配占比为 80%,即 3 * 0.8=2.4,向上取整得2,表示至少有 两个词 在文档中要匹配成功。
searchSourceBuilder.query(QueryBuilders.matchQuery("description","spring开发框架").minimumShouldMatch("80%"));
5.5 multi query (匹配多个字段)
{
"query": {
"multi_match": {
"query": "spring框架",
"minimum_should_match": "50%",
"fields": [
"name^10",
"description"
]
}
}
}
拿关键字 spring css去匹配 name 和 description 字段。
name^10 表示权重提升 10 倍,执行上边的查询,发现 name 中包括 spring 关键字的文档排在前边
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("spring框架", "name", "description").minimumShouldMatch("50%");
multiMatchQueryBuilder.field("name",10);
searchSourceBuilder.query(multiMatchQueryBuilder);
5.6 布尔查询
{
"_source": [
"name",
"studymodel",
"description"
],
"from": 0,
"size": 1,
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "spring框架",
"minimum_should_match": "50%",
"fields": [
"name^10",
"description"
]
}
},
{
"term": {
"studymodel": "201001"
}
}
]
}
}
}
//创建multiMatch查询
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("spring框架", "name", "description").minimumShouldMatch("50%");
multiMatchQueryBuilder.field("name",10);
//创建term查询
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("studymodel", 201001);
//创建布尔查询
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(multiMatchQueryBuilder);
boolQueryBuilder.must(termQueryBuilder);
5.7 过滤器
{
"_source": [
"name",
"studymodel",
"description",
"price"
],
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "spring框架",
"minimum_should_match": "50%",
"fields": [
"name^10",
"description"
]
}
}
],
"filter": [
{
"term": {
"studymodel": "201001"
}
},
{
"range": {
"price": {
"gte": 60,
"lte": 100
}
}
}
]
}
}
}
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//创建multiMatch查询
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("spring框架", "name", "description").minimumShouldMatch("50%");
multiMatchQueryBuilder.field("name",10);
//布尔查询
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(multiMatchQueryBuilder);
//过虑条件
boolQueryBuilder.filter(QueryBuilders.termQuery("studymodel", "201001"));
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(60).lte(100));
searchSourceBuilder.query(boolQueryBuilder);
5.8 排序
可以在字段上添加一个或多个排序,支持在 keyword、date、float 等类型上添加,text 类型的字段上不允许添加排序。
{
"_source": [
"name",
"studymodel",
"description",
"price"
],
"query": {
"bool": {
"filter": [
{
"range": {
"price": {
"gte": 0,
"lte": 100
}
}
}
]
}
},
"sort": [
{
"studymodel": "desc"
},
{
"price": "asc"
}
]
}
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//boolQuery搜索方式
//定义一个boolQuery
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//定义过虑器
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(0).lte(100));
searchSourceBuilder.query(boolQueryBuilder);
//添加排序
searchSourceBuilder.sort("studymodel", SortOrder.DESC);
searchSourceBuilder.sort("price", SortOrder.ASC);
searchSourceBuilder.fetchSource(new String[]{"name","studymodel","description"}, new String[]{});
//向搜索请求对象中设置搜索源
searchRequest.source(searchSourceBuilder);
5.9 高亮
public void testHighlight() throws IOException, ParseException {
//搜索请求对象
SearchRequest searchRequest = new SearchRequest("xc_course");
//指定类型
searchRequest.types("doc");
//搜索源构建对象
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//boolQuery搜索方式
//先定义一个MultiMatchQuery
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("开发框架", "name", "description")
.minimumShouldMatch("50%")
.field("name", 10);
//定义一个boolQuery
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(multiMatchQueryBuilder);
//定义过虑器
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(0).lte(100));
searchSourceBuilder.query(boolQueryBuilder);
//设置源字段过虑,第一个参数结果集包括哪些字段,第二个参数表示结果集不包括哪些字段
searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"},new String[]{});
//设置高亮
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.preTags("<tag>");
highlightBuilder.postTags("</tag>");
highlightBuilder.fields().add(new HighlightBuilder.Field("name"));
// highlightBuilder.fields().add(new HighlightBuilder.Field("description"));
searchSourceBuilder.highlighter(highlightBuilder);
//向搜索请求对象中设置搜索源
searchRequest.source(searchSourceBuilder);
//执行搜索,向ES发起http请求
SearchResponse searchResponse = client.search(searchRequest);
//搜索结果
SearchHits hits = searchResponse.getHits();
//匹配到的总记录数
long totalHits = hits.getTotalHits();
//得到匹配度高的文档
SearchHit[] searchHits = hits.getHits();
//日期格式化对象
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for(SearchHit hit:searchHits){
//文档的主键
String id = hit.getId();
//源文档内容
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
//源文档的name字段内容
String name = (String) sourceAsMap.get("name");
//取出高亮字段
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
if(highlightFields!=null){
//取出name高亮字段
HighlightField nameHighlightField = highlightFields.get("name");
if(nameHighlightField!=null){
Text[] fragments = nameHighlightField.getFragments();
StringBuffer stringBuffer = new StringBuffer();
for(Text text:fragments){
stringBuffer.append(text);
}
name = stringBuffer.toString();
}
}
//由于前边设置了源文档字段过虑,这时description是取不到的
String description = (String) sourceAsMap.get("description");
//学习模式
String studymodel = (String) sourceAsMap.get("studymodel");
//价格
Double price = (Double) sourceAsMap.get("price");
//日期
Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp"));
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}
}
5.10 聚合
#聚合搜索 address 中包含 mill 的所有人的年龄分布以及平均薪资
GET bank/_search
{
"query":{
"match": {
"address": "mill"
}
},
"aggs": {
"ageAgg": {
"terms": {
"field": "age",
"size": 10
}
},
"balanceAvg":{
"avg":{
"field": "balance"
}
}
},
"size": 0
}
SearchRequest searchRequest = new SearchRequest();
//指定索引
searchRequest.indices("bank");
//指定DSL 检索条件
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchQuery("address","mill"));
//按照年龄只分布进行聚合
TermsAggregationBuilder ageAgg = AggregationBuilders.terms("ageAgg").field("age").size(10);
searchSourceBuilder.aggregation(ageAgg);
//计算平均薪资
AvgAggregationBuilder balanceAvg = AggregationBuilders.avg("balanceAvg").field("blance");
searchSourceBuilder.aggregation(balanceAvg);
//打印检索条件
System.out.println("检索条件:"+searchSourceBuilder);
searchRequest.source(searchSourceBuilder);
//执行检索
SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = search.getHits();
SearchHit[] searchHits = hits.getHits();
for (SearchHit hit: searchHits){
String sourceAsString = hit.getSourceAsString();
Accout accout = JSON.parseObject(sourceAsString, Accout.class);
System.out.println(accout.toString());
}
//获取检索的分析信息
Aggregations aggregations = search.getAggregations();
// for (Aggregation aggregation : aggregations.asList()) {
// System.out.println("当前聚合名字:"+aggregation.getName());
// }
//分类聚合
Terms ageAgg1 = aggregations.get("ageAgg");
for (Terms.Bucket bucket : ageAgg1.getBuckets()) {
String keyAsString = bucket.getKeyAsString();
System.out.println("年龄:" + keyAsString + "人数:"+bucket.getDocCount());
}
//平局值
Avg balanceAvg1 = aggregations.get("balanceAvg");
System.out.println("平均薪资"+ balanceAvg1.getValue());
6.分页查询
6.1 from,size
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
//分页查询,设置起始下标,从0开始
searchSourceBuilder.from(0);
//每页显示个数
searchSourceBuilder.size(10);
//source源字段过虑
searchSourceBuilder.fetchSource(new String[]{"name","studymodel"}, new String[]{});
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest);
6.2 searchAfter
searchSourceBuilder.query(QueryBuilders.wrapperQuery(dsl.toString()));
searchSourceBuilder.size(10);
searchSourceBuilder.sort("id", SortOrder.ASC);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHit[] searchHits = searchResponse.getHits().getHits();
while (searchHits.length > 0) {
SearchHit last = searchHits[searchHits.length - 1];
sourceBuilder.searchAfter(last.getSortValues());
searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
searchHits = searchResponse.getHits().getHits();
}
6.3 Scroll分页
Elasticsearch-Scroll分页-Java示例-CSDN博客
searchSourceBuilder.query(QueryBuilders.wrapperQuery(dsl.toString()));
searchSourceBuilder.size(10);
searchSourceBuilder.sort("id", SortOrder.ASC);
searchRequest.source(searchSourceBuilder);
// 指定超时时间
searchRequest.scroll(new TimeValue(5000));
SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT);
long length = searchResponse.getHits().getHits().length;
String scrollId = null;
while (length > 0) {
consumer.accept(searchResponse);
scrollId = searchResponse.getScrollId();
SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId)
.scroll(keepAlive);
searchResponse = highLevelClient.scroll(scrollRequest, RequestOptions.DEFAULT);
length = searchResponse.getHits().getHits().length;
}
// 清空快照记录,避免内存占用
if (isClearScroll && scrollId != null) {
ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
clearScrollRequest.addScrollId(scrollId);
highLevelClient.clearScrollAsync(clearScrollRequest, RequestOptions.DEFAULT, new ActionListener<ClearScrollResponse>() {
@Override
public void onResponse(ClearScrollResponse clearScrollResponse) {
}
@Override
public void onFailure(Exception e) {
throw new ElasticsearchException(e);
}
});
}