ElasticSearch使用RestHighLevelClient进行搜索查询
阅读原文时间:2023年07月14日阅读:2

Elasticsearch Java API有四类client连接方式:TransportClient、  RestClient 、Jest、 Spring_Data_Elasticsearch。其中TransportClient、  RestClient是Elasticsearch原生的api,TransportClient会在8.0版本中完成删除,替代的是HighLevelRestClient,它使用HTTP请求而不是Java序列化请求。Spring_Data_Elasticsearch是spring集成的Elasticsearch开发包。在博客园 Elasticsearch 6.4基本操作 - Java版 一文中有简单的描述,不再过多引述。本文主要记录一下HighLevelRestClient在spingboot项目中的使用。

使用es主要是做一些非关系型数据文档的检索,公司用的最多的是配合kibana进行可视化的日志检索,非常方便。elasticsearch、kibana安装,配置和使用,有大量博客记录,此处不再说明。

@Configuration配置sping并启动容器 @Bean注册Bean

import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestClientBuilder.HttpClientConfigCallback;
import org.elasticsearch.client.RestClientBuilder.RequestConfigCallback;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;

@Configuration
public class ESConfig {

private static String hosts = "127.0.0.1"; // 集群地址,多个用,隔开  
private static int port = 9200; // 使用的端口号  
private static String schema = "http"; // 使用的协议  
private static ArrayList<HttpHost> hostList = null;

private static int connectTimeOut = 1000; // 连接超时时间  
private static int socketTimeOut = 30000; // 连接超时时间  
private static int connectionRequestTimeOut = 500; // 获取连接的超时时间

private static int maxConnectNum = 100; // 最大连接数  
private static int maxConnectPerRoute = 100; // 最大路由连接数  
static {  
    hostList = new ArrayList<>();  
    String\[\] hostStrs = hosts.split(",");  
    for (String host : hostStrs) {  
        hostList.add(new HttpHost(host, port, schema));  
    }  
}  
@Bean  
public RestHighLevelClient client(){  
    RestClientBuilder builder = RestClient.builder(hostList.toArray(new HttpHost\[0\]));  
    // 异步httpclient连接延时配置  
    builder.setRequestConfigCallback(new RequestConfigCallback() {  
        @Override  
        public Builder customizeRequestConfig(Builder requestConfigBuilder) {  
            requestConfigBuilder.setConnectTimeout(connectTimeOut);  
            requestConfigBuilder.setSocketTimeout(socketTimeOut);  
            requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeOut);  
            return requestConfigBuilder;  
        }  
    });  
    // 异步httpclient连接数配置  
    builder.setHttpClientConfigCallback(new HttpClientConfigCallback() {  
        @Override  
        public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {  
            httpClientBuilder.setMaxConnTotal(maxConnectNum);  
            httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);  
            return httpClientBuilder;  
        }  
    });  
    RestHighLevelClient client = new RestHighLevelClient(builder);  
    return client;  
}  

}

写一个service。

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Arrays;

@Service
public class ElasticSearchService {
private static final Logger log = LoggerFactory.getLogger(ElasticSearchService.class);

@Autowired  
private RestHighLevelClient client;

public String search() throws IOException {  
    BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();  
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();  
    MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("fields.entity\_id", "319");//这里可以根据字段进行搜索,must表示符合条件的,相反的mustnot表示不符合条件的  
   // RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("fields\_timestamp"); //新建range条件  
   // rangeQueryBuilder.gte("2019-03-21T08:24:37.873Z"); //开始时间  
   // rangeQueryBuilder.lte("2019-03-21T08:24:37.873Z"); //结束时间  
   // boolBuilder.must(rangeQueryBuilder);  
    boolBuilder.must(matchQueryBuilder);  
    sourceBuilder.query(boolBuilder); //设置查询,可以是任何类型的QueryBuilder。  
    sourceBuilder.from(0); //设置确定结果要从哪个索引开始搜索的from选项,默认为0  
    sourceBuilder.size(100); //设置确定搜素命中返回数的size选项,默认为10  

     sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); //设置一个可选的超时,控制允许搜索的时间。

    sourceBuilder.fetchSource(new String\[\] {"fields.port","fields.entity\_id","fields.message"}, new String\[\] {}); //第一个是获取字段,第二个是过滤的字段,默认获取全部  
    SearchRequest searchRequest = new SearchRequest("customer"); //索引  
    searchRequest.types("doc"); //类型  
    searchRequest.source(sourceBuilder);  
    SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);  
    SearchHits hits = response.getHits();  //SearchHits提供有关所有匹配的全局信息,例如总命中数或最高分数:  
    SearchHit\[\] searchHits = hits.getHits();  
    for (SearchHit hit : searchHits) {  
        log.info("search -> {}",hit.getSourceAsString());  
    }  
    return Arrays.toString(searchHits);  
}  

}



上面的ElasticSearchService 有几个常用的Builder类和方法需要了解下。

BoolQueryBuilder用来拼装查询条件。一般来说must的性能要低一些,因为他要进行打分评估,也就是说要进行_score,而filter则不会。

[filter](http://xbib.org/elasticsearch/2.1.1/apidocs/org/elasticsearch/index/query/BoolQueryBuilder.html#filter-org.elasticsearch.index.query.QueryBuilder-)([QueryBuilder](http://xbib.org/elasticsearch/2.1.1/apidocs/org/elasticsearch/index/query/QueryBuilder.html)&nbsp;queryBuilder)

Adds a query that must appear in the matching documents but will not contribute to scoring.

[must](http://xbib.org/elasticsearch/2.1.1/apidocs/org/elasticsearch/index/query/BoolQueryBuilder.html#must-org.elasticsearch.index.query.QueryBuilder-)([QueryBuilder](http://xbib.org/elasticsearch/2.1.1/apidocs/org/elasticsearch/index/query/QueryBuilder.html)&nbsp;queryBuilder)

Adds a query that must appear in the matching documents and will contribute to scoring.

[should](http://xbib.org/elasticsearch/2.1.1/apidocs/org/elasticsearch/index/query/BoolQueryBuilder.html#should-org.elasticsearch.index.query.QueryBuilder-)([QueryBuilder](http://xbib.org/elasticsearch/2.1.1/apidocs/org/elasticsearch/index/query/QueryBuilder.html)&nbsp;queryBuilder)

Adds a query that should appear in the matching documents.

简单来说:must 相当于 与 & = ;must not 相当于 非 ~   !=;should 相当于 或  |   or ;filter  过滤

//filter 效率比 must高的多
if (StringUtils.isNotBlank(query.getRouterDatabaseNo())) {
   boolQueryBuilder.filter(QueryBuilders.termQuery("routerDatabaseNo", query.getRouterDatabaseNo()));
}

//时间段 一定要有头有尾 不然会出现慢查询
if (null != query.getCreateTime() && null != query.getUpdateTime()) {
boolQueryBuilder.filter(QueryBuilders.rangeQuery("createTime").from( query.getCreateTime()).to(query.getUpdateTime()));
}

SearchSourceBuilder

SearchRequest searchRequest = new SearchRequest("customer"); //将请求限制为一个索引
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
searchRequest.types("doc"); //将请求限制为一个类型。
searchRequest.source(sourceBuilder); //将SearchSourceBuilder添加到SeachRequest

创建SeachRequest,没有参数,这将针对所有索引运行。有参数,则按参数所传值为索引,此处“customer”为索引值。大多数搜索参数都添加到SearchSourceBuilder中,它为搜索请求body中的所有内容提供了setter。

SearchSourceBuilder的排序:允许添加一个或多个SortBuilder实例,有四种特殊的实现(Field-,Score-,GeoDistance-和ScriptSortBuilder)。

sourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC)); //按_score降序排序(默认值)。
sourceBuilder.sort(new FieldSortBuilder("_uid").order(SortOrder.ASC));//也可以按_id字段进行升序排序

SearchSourceBuilder的源过滤:默认情况下,搜索请求会返回文档_source的内容,但与Rest API中的内容一样,你可以覆盖此行为,例如,你可以完全关闭_source检索:

sourceBuilder.fetchSource(false);

该方法还接受一个或多个通配符模式的数组,以控制以更精细的方式包含或排除哪些字段:

String[] includeFields = new String[] {"title", "user", "innerObject.*"};
String[] excludeFields = new String[] {"_type"};
sourceBuilder.fetchSource(includeFields, excludeFields);

SearchSourceBuilder的请求结果高亮显示:通过在SearchSourceBuilder上设置HighlightBuilder,可以实现高亮搜索结果,通过将一个或多个HighlightBuilder.Field实例添加到HighlightBuilder,可以为每个字段定义不同的高亮行为。

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
HighlightBuilder highlightBuilder = new HighlightBuilder(); //创建一个新的HighlightBuilder
HighlightBuilder.Field highlightTitle = new HighlightBuilder.Field("title"); //为title字段创建字段高光色。
highlightTitle.highlighterType("unified"); // 设置字段高光色类型。
highlightBuilder.field(highlightTitle); //将字段高光色添加到高亮构建器。
HighlightBuilder.Field highlightUser = new HighlightBuilder.Field("user");
highlightBuilder.field(highlightUser);
searchSourceBuilder.highlighter(highlightBuilder);

SearchSourceBuilder 更多api可以参考链接文章,归纳的很详细了,不再过多引述。



写一个controller用于测试

import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.slowcity.admin.service.ElasticSearchService;

@RestController
@RequestMapping("/test")
public class TestResource {

@Autowired  
private ElasticSearchService elasticSearchService;  
private static final Logger log = LoggerFactory.getLogger(TestResource.class);  
//条件 查询  
@PostMapping("/v1/test")  
public String query( ) {  
    String queryResult =null;  
    try {  
        queryResult = elasticSearchService.search();  
    } catch (IOException e) {  
        e.printStackTrace();  
    }  
    return queryResult;  
}  

}

首先在es中维护几条数据,如下:

postman测试一下,结果如下:

【end】