如何使用 Elastic Search Low Level API 构造请求进行搜索

场景:

需要在客户端构造请求调解, 调用 Elastic Search 的 API 取到结果,并且能够使用 ES 的授权机制。

方案:

一、在客户端构造 Low Level API 。

二、Low Level API 直接请求 ES 的 HTTP地址,传入 ES 的用户名,密码。

三、Low Level API 取到 JSON 格式的返回结果后,结果反序列化成 Java 对象。这个步骤里面的 Java 类定义,使用前面博客里提到的方法, 从 json 文件中来生成代码。

另外也需要在客户端, 根据不同的条件构造出来 Json 格式的请求调解。

我们分4个步骤来看。

 

1). 构造 Low Level API Client

public class ElasticSearchRestClient {
    private static final Logger logger = LoggerFactory.getLogger(ElasticSearchRestClient.class);

    private RestClient restClient;

    public void init(String elasticsearchAddress, String userName, String password){
        try {
            // Elasticsearch集群需要basic auth验证。
            final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
            //访问用户名和密码为您创建Elasticsearch实例时设置的用户名和密码,也是Kibana控制台的登录用户名和密码。
            credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(userName, password));

            // 通过builder创建rest client,配置http client的HttpClientConfigCallback。
            RestClientBuilder builder = RestClient.builder(new HttpHost(elasticsearchAddress, 9200))
                .setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                    @Override
                    public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                        return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                    }
                });

            // lower level client
            restClient = builder.build();
        } catch (Exception e) {
            logger.error("Failed to initialize Elastic Search client, server:{}, userName:{}", elasticsearchAddress, userName, e);
        }
    }
}

2).指定要搜索的索引发出搜索请求

            // low level api:
            Request request = new Request("POST", "/" + indexName +  "/_search");
            request.setJsonEntity(queryJson );

            Response response = restClient.performRequest(request);

3).取到 JSON 格式的返回结果,结果反序列化成 Java 对象

前面的文章有介绍,如何从 Json 格式的数据定义中生产 Java 类的代码

我们以 ES HTTP 请求返回的 Json 为例,ES 返回的 Json 格式数据 跟 Kibana 控制台 Dev Tools -> Console 里面发送请求, 看到的返回结果格式是一样的。 比如发送这个请求:

GET  media/_search
{
  "query": {"match_all": {}}
  
}

能看到返回的这个结果

右边返回的 Json 内容保存为文件 elastic.response.json, 内容如下:

{
  "took" : 113,
  "timed_out" : false,
  "_shards" : {
    "total" : 10,
    "successful" : 9,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 16.761106,
    "hits" : [
      {
        "_index" : "media",
        "_type" : "doc",
        "_id" : "176",
        "_score" : 16.761106,
        "_source" : {
          "publish_state" : "Published",
          "media_id" : "226bb012c46e1ef4e52b788cf3312345",
          "id" : 176,
          "url" : "http://www.abcd.com/20190317152813791092",
          "owner_id" : 1438747659963495,
          "media_info" : "",
          "description" : null,
          "env" : 1,
          "cover_url" : null,
          "gmt_create" : "2016-03-17T07:29:18.000Z",
          "gmt_modified" : "2016-06-16T06:50:48.000Z",
          "state" : "Normal",
          "title" : "20160317152813791092",
          "tags" : null,
          "@version" : "1",
          "@timestamp" : "2021-04-06T14:36:17.393Z"
        }
      }
    ]
  }
}

然后执行命令:

jsonschema2pojo -T json --source elastic.response.json --target java

就能够自动生成这几个类:

ElasticResponse.java, Hit.java, Hits.java, Shards.java, Source.java

生成的 ElasticResponse 类是这样的,可以稍做调整,或者重构适应实际的需求:

 @Generated("jsonschema2pojo")
 public class ElasticResponse {

     @JsonProperty("took")
     private Integer took;
     @JsonProperty("timed_out")
     private Boolean timedOut;
     @JsonProperty("_shards")
     private Shards shards;
     @JsonProperty("hits")
     private Hits hits;

     @JsonProperty("took")
     public Integer getTook() {
         return took;
     }

     @JsonProperty("took")
     public void setTook(Integer took) {
         this.took = took;
     }

     @JsonProperty("timed_out")
     public Boolean getTimedOut() {
         return timedOut;
     }

     @JsonProperty("timed_out")
     public void setTimedOut(Boolean timedOut) {
         this.timedOut = timedOut;
     }

     @JsonProperty("_shards")
     public Shards getShards() {
         return shards;
     }
     //....
}

4). 构造 JSON 格式 请求条件

以上请求发起调用的完整代码:

    public ElasticResponse search(String indexName, String queryJson){
        try {
            if(StringUtils.isEmpty(queryJson)){
                ElasticResponse response = new ElasticResponse();

                JSONObject errorInfo = new JSONObject();
                errorInfo.put("message", "empty json");
                response.setError(errorInfo);

                response.setError(errorInfo);
                return response;
            }

            // low level api:
            Request request = new Request("POST", "/" + indexName +  "/_search");
            request.setJsonEntity(queryJson );

            Response response = restClient.performRequest(request);
            String jsonResponse = EntityUtils.toString(response.getEntity());
            ElasticResponse finalResponse = JSON.parseObject(jsonResponse, ElasticResponse.class);

            return finalResponse;

        } catch (IOException e) {
            logger.error("Failed to search for index:{}", indexName, e);
        }

        return null;
    }

那么这里 json 格式的请求条件 queryJson 如何构造, 比如要查询 指定 owner_id, 且  publish_state不是删除状态,id 小于某个限定值的数据,可以这样构造:

        MatchQueryBuilder ownerQuery = QueryBuilders.matchQuery("owner_id", ownerId);
        BoolQueryBuilder finalQuery = QueryBuilders.boolQuery();
        finalQuery.must(ownerQuery);

        // id <= #id#
        if(upperId>1){
            RangeQueryBuilder lessThanUpperIdQuery = QueryBuilders.rangeQuery("id").to(upperId, true);
            finalQuery.must(lessThanUpperIdQuery);
        }


        // publish_state !='Deleted'
        MatchQueryBuilder inDeletedQuery = QueryBuilders.matchQuery("publish_state", "Deleted");
        finalQuery.mustNot(inDeletedQuery);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(finalQuery);

        //ORDER BY gmt_create DESC,id DESC

        FieldSortBuilder createSort = SortBuilders.fieldSort("gmt_create").order(SortOrder.DESC);
        searchSourceBuilder.sort(createSort);

        FieldSortBuilder idSort = SortBuilders.fieldSort("id").order(SortOrder.DESC);
        searchSourceBuilder.sort(idSort);

        String queryJson = searchSourceBuilder.toString();

然后就能使用这个构造出来的 queryJson 来发送 ElasticSearch 的请求了。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值