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 getDynamicInformation(){
        List 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。这种不推荐,因为这样加载时候,会占用过多的内存(自己没试过这种方法,仅供参考)

你可能感兴趣的:(ElasticSearch,elasticsearch)