Java Rest High Level Client实现搜索出的内容按自定义字段Field排序

一、应用场景

实际项目开发中要求记录下用户的操作日志,创建一个时间轴展示相关操作日志信息,要求按时间降序显示。其中,操作日志采用ES存储。

二、实际代码
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.taobao.rigel.rap.model.CustomOperationLog;
import com.taobao.rigel.rap.utils.PrettyTimeTool;
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.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.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping(value = "api/umeapiplus/log")
public class CustomOperationLogController {
    private static final Gson gson = new Gson();

    @Autowired
    private RestHighLevelClient client;

    public SearchHit[] findSearchHits(){
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.fetchSource(new String[]{"log_operation_datetime", "log_operation_object"}, new String[]{});
        sourceBuilder.size(10000); //设置确定搜素命中返回数的size选项,默认为10
        sourceBuilder.sort(new FieldSortBuilder("log_operation_datetime").order(SortOrder.DESC));
//        sourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));

        SearchRequest searchRequest = new SearchRequest("umeapi-logstash");
        searchRequest.source(sourceBuilder);
        try{
            SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits hits = response.getHits();
            SearchHit[] searchHits = hits.getHits();
            System.out.println("searchHits数组长度:" + searchHits.length);
            return searchHits;
        }catch (IOException e){
            e.printStackTrace();
        }
        return null;
    }

    @RequestMapping(value = "/getDynamicInformation", method = RequestMethod.GET)
    public List<CustomOperationLog> getDynamicInformation(){
        List<CustomOperationLog> returnList = new ArrayList<>();
        SearchHit[] searchHits = findSearchHits();
        for(SearchHit hit : searchHits){
            System.out.println("search -> " + hit.getSourceAsString());
            JSONObject totalJson = JSONObject.parseObject(hit.getSourceAsString());
            String operationObjStr = (String)totalJson.get("log_operation_object");
            System.out.println("operationObjStr: " + operationObjStr);
            if(null != operationObjStr){
                try {
                    CustomOperationLog temp = gson.fromJson(operationObjStr, CustomOperationLog.class);
                    temp.setHowLongBefore(PrettyTimeTool.getLastUpdateTimeStr(temp.getDateTime()));
                    returnList.add(temp);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
        return returnList;
    }
}

代码分析:

sourceBuilder.sort(new FieldSortBuilder("log_operation_datetime").order(SortOrder.DESC));

这行代码实现了按自定义字段“log_operation_datetime”降序排序的需求

三、ES排序

ES提供了默认排序和自定义排序,默认排序通常都是按_score来排序的。自定义排序通常是使用sourceBuilder.sort(new FieldSortBuilder("字段名").order(SortOrder.DESC));实现的。SearchSourceBuilder允许添加一个或多个SortBuilder实例。SortBuilder有四种特殊的实现,分别是:FieldSortBuilder、GeoDistanceSortBuilder、ScoreSortBuilder、ScriptSortBuilder

  • FieldSortBuilder:根据某个特殊字段排序
  • ScoreSortBuilder:根据score排序
  • GeoDistanceSortBuilder:根据地理位置排序
  • ScriptSortBuilder:根据自定义脚本排序
四、遇到问题

1、调用接口时,报如下错误
“Fielddata is disabled on text fields by default. Set fielddata=true on [name] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead.”
这个问题是由于我指定的字段“log_operation_datetime”是 text 类型。在ES搜索排序中,字段的类型必须是:integer、double、long或者keyword。否则使用该字段进行查询、排序、聚合时候,就会出现Fielddata is disabled on text fields by default.

解决办法:

  1. 把字段的索引类型改成keyword或者数值型(实际使用了本方法,解决了问题)
  2. 索引字段类型还是text,但是在mapping中加上fielddata=true。这种不推荐,因为这样加载时候,会占用过多的内存(自己没试过这种方法,仅供参考)
可以使用JavaElasticsearch High Level REST Client实现根据某个字段值正序查询的功能。具体的实现步骤如下: 1. 创建Elasticsearch客户端连接: ```java RestHighLevelClient client = new RestHighLevelClient( RestClient.builder(new HttpHost("localhost", 9200, "http"))); ``` 2. 构造查询请求: ```java SearchRequest searchRequest = new SearchRequest("index_name"); // 设置索引名称 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.matchAllQuery()); // 设置查询条件,这里使用 matchAllQuery() 匹配所有文档 searchSourceBuilder.sort(new FieldSortBuilder("field_name").order(SortOrder.ASC)); // 设置排序规则,这里使用正序排序 searchRequest.source(searchSourceBuilder); ``` 其中,"index_name"代表要查询的索引名称,"field_name"代表要根据哪个字段排序。 3. 执行查询请求: ```java SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); ``` 4. 处理查询结果: ```java SearchHits hits = searchResponse.getHits(); for (SearchHit hit : hits) { // 处理每个文档的数据 } ``` 完整的示例代码如下: ```java RestHighLevelClient client = new RestHighLevelClient( RestClient.builder(new HttpHost("localhost", 9200, "http"))); SearchRequest searchRequest = new SearchRequest("index_name"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.matchAllQuery()); searchSourceBuilder.sort(new FieldSortBuilder("field_name").order(SortOrder.ASC)); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); SearchHits hits = searchResponse.getHits(); for (SearchHit hit : hits) { // 处理每个文档的数据 } client.close(); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值