elasticsearch 如何做分页和排序

19 min read

elasticsearch 如何做分页和排序

NativeSearchQueryBuilder 的方式

SearchQuery searchQuery = new NativeSearchQueryBuilder()
        .withFields("createDate","updateDate").withQuery(matchAllQuery()).withPageable(new PageRequest(0,Integer.MAX_VALUE)).build();

Sort 的方式

public SearchRequest createRequest2(QueryBuilder queryBuilder, PageRequest pageRequest) {
        SearchRequest searchRequest = new SearchRequest(seekerIndexName);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        sourceBuilder.size(pageRequest.getPageSize());
        sourceBuilder.from(pageRequest.getPageNumber() * pageRequest.getPageSize());
        Sort sort = pageRequest.getSort();
        Iterator<Sort.Order> sortIterator =  sort.stream().iterator();
        while (sortIterator.hasNext()) {
            Sort.Order order = sortIterator.next();

            SortOrder sortOrder = order.getDirection().isAscending() ? SortOrder.ASC : SortOrder.DESC;
            sourceBuilder.sort( new FieldSortBuilder(order.getProperty()).order(sortOrder));

        }
        sourceBuilder.query(queryBuilder);
        searchRequest.source(sourceBuilder);
        return searchRequest;
    }

用通配符搜索QueryBuilders.wildcardQuery实现单个字搜索。当搜索关键词多个词时wildcardQuery就显得并不智能了,所以使用 match搜索+ik_max_word分词。说了这么多献上部分源码:

QueryBuilder queryBuilder = null;
        // 判断搜索关键字是否是一个汉字,如果是使用通配符搜索 wildcardQuery
        if(keyword.length() == 1){
            // 通配符搜索 wildcardQuery就不支持分词了
            WildcardQueryBuilder name = QueryBuilders.wildcardQuery("name", "*" + keyword + "*");
            WildcardQueryBuilder text = QueryBuilders.wildcardQuery("text", "*" + keyword + "*");
            queryBuilder = QueryBuilders
                    .boolQuery()
                    .should(name)
                    .should(text);
        }else{
            MatchQueryBuilder queryBuilder_name = QueryBuilders.matchQuery("name", keyword);
            MatchQueryBuilder queryBuilder_text = QueryBuilders.matchQuery("text", keyword);
            queryBuilder = QueryBuilders
                    .boolQuery()
                    .should(queryBuilder_name)
                    .should(queryBuilder_text);
        }

boolQuery的使用是因为有两个字段进行搜索匹配。

提一下,两个字段都支持分词的话,前面在创建该索引时mapping里记得给这俩字段都设置上search_analyzer = ik_max_word:

XContentBuilder jsonBuilder = XContentFactory.jsonBuilder();
            jsonBuilder.startObject();
            {
                jsonBuilder.startObject("properties");
                {
                    jsonBuilder.startObject("name");
                    {
                        jsonBuilder.field("type", "text");
                        jsonBuilder.field("analyzer", "ik_max_word");
                        jsonBuilder.field("search_analyzer", "ik_max_word");  // ik_smart
                    }
                    jsonBuilder.endObject();
                    jsonBuilder.startObject("text");
                    {
                        jsonBuilder.field("type", "text");
                        jsonBuilder.field("analyzer", "ik_max_word");
                        jsonBuilder.field("search_analyzer", "ik_max_word");  // ik_smart
                    }
                    jsonBuilder.endObject();
                }
                jsonBuilder.endObject();
            }
            jsonBuilder.endObject();
            request.mapping(jsonBuilder);