java 聚合查询elasticsearch 返回错误的解决方案

作者:青山常在人不老   阅读 (1527)  |  收藏 (0)  |  点赞 (0)

摘要

java 对elasticsearch 进行聚合查询时,设置排序字段报Fielddata is disabled on text fields by default的最新解决方案。


原文链接:java 聚合查询elasticsearch 返回错误的解决方案

我在使用java 对elasticsearch 进行聚合查询,并对某个字段进行排序时,报错了 ,Java代码如下:

    public Map<String, Object> searchOnParamByPage(ElasticsearchConfig elasticsearchConfig,
                             String[] indices,
                             String sortField,
                             String fieldKey,
                             String fieldVal,
                             int from, int size) throws IOException
    {
        SearchRequest searchRequest = new SearchRequest(indices);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.matchPhraseQuery(fieldKey, fieldVal));
        sourceBuilder.from(from);
        sourceBuilder.size(size);
        sourceBuilder.timeout(new TimeValue(1000));
        sourceBuilder.trackTotalHits(true);
        sourceBuilder.sort(new FieldSortBuilder(sortField).order(SortOrder.DESC));
        searchRequest.source(sourceBuilder);
        
        if (client == null) {
            initClient(elasticsearchConfig);
        }
        
        SearchResponse searchResponse = client
            .search(searchRequest,
            RequestOptions.DEFAULT);
        SearchHits hits = searchResponse.getHits();
        TotalHits totalHits = hits.getTotalHits();
        long totalSize = totalHits.value;
        SearchHit[] searchHits = hits.getHits();
        
        Map<String, Object> resultMap = new HashMap<String, Object>();
        List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
        Map<String, Object> sourceMap = null;
        for (SearchHit searchHit : searchHits) {
            sourceMap = searchHit.getSourceAsMap();
            resultList.add(sourceMap);
        }
        closeClient();
        logger.info("单条件分页查询时,查询出的总条数为:【{}】", totalSize);
        resultMap.put(BobfintechContant.DATA_LIST, resultList);
        resultMap.put(BobfintechContant.DATA_SIZE, totalSize);
        return resultMap;
    }

报错信息如下:

Caused by: ElasticsearchException[Elasticsearch exception [type=illegal_argument_exception, reason=Fielddata is disabled on text fields by default. Set fielddata=true on [userName] 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.]]; nested: ElasticsearchException[Elasticsearch exception [type=illegal_argument_exception, reason=Fielddata is disabled on text fields by default. Set fielddata=true on [userName] 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.]];

看了下官方的文档,其说明如下(官方文档):

Fielddata can consume a lot of heap space, especially when loading high cardinality text fields. Once fielddata has been loaded into the heap, it remains there for the lifetime of the segment. Also, loading fielddata is an expensive process which can cause users to experience latency hits. This is why fielddata is disabled by default.
If you try to sort, aggregate, or access values from a script on a text field, you will see this exception:
Fielddata is disabled on text fields by default.  Set `fielddata=true` on
[`your_field_name`] in order to load  fielddata in memory by uninverting the
inverted index. Note that this can however use significant memory.

Fielddata is disabled on text fields by default `fielddata = true`最新解决办法

大意是说,使用字段查询非常消耗内存,因此默认是禁用字段查询,如果您非要使用字段进行排序,汇总或访问值的话,则会看到上面的那个异常,解决办法是在[`your_field_name`] 上设置`fielddata = true`,以通过反转取

反的索引将字段数据加载到内存中。但是这可能会占用大量内存。

有了上述官方说明,我们就知道了如何解决,剩下的就是如何把`fielddata = true`在程序中设置了。

按照官方的说法,查找了很多资料,都没找到具体在JAVA程序中该如何设置,只有通过语句查询方法

PUT you_index/_mapping/
{
  "properties": {
    "字段":{
      "type": "text",
      "fielddata": true
    }
  }
}

作为依赖JAVA操作程序的我们,怎么去转化为程序的参数设置呢,不好意思,我还真没找到,但是我找到了另外一种解决办法,那就是在你要排序的字段上加上“.keyword”

例如:

sourceBuilder.sort(new FieldSortBuilder(sortField + ".keyword").order(SortOrder.DESC));

上面的代码中,在对sortField排序时,在这个属性后面加上.keyword即可,给字段加上.keyword 表示使用完整的字段,无需修改es,也无需修改代码逻辑。

运行不在报错。

或者使用另一种实现方式:

    /**
     * 单条件分页查询
     *
     * @param elasticsearchConfig
     *            配置
     * @param indices
     *            索引(非必填)
     * @param sortField
     *            排序字段
     * @param fieldKey
     *            查询条件(KEY)
     * @param fieldVal
     *            查询条件(value)
     * @param from
     *            开始条数
     * @param size
     *            要查询的条数
     * @throws IOException
     */
    public Map<String, Object> testQueryByPage(ElasticsearchConfig elasticsearchConfig, String[] indices,
                                               String sortField,
                                String fieldKey, String fieldVal, int from, int size) throws IOException
    {
        BoolQueryBuilder boolQuery = new BoolQueryBuilder();
        RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery(sortField).gte(null); // "count"
        boolQuery.filter(rangeQuery);
        
        MatchQueryBuilder matchQuery = new MatchQueryBuilder(fieldKey, fieldVal);
        boolQuery.must(matchQuery);
        
        if (client == null) {
            initClient(elasticsearchConfig);
        }
        
        SearchResponse searchResponse = client
            .search(
            new SearchRequest(
                indices)
                    .source(new SearchSourceBuilder().query(boolQuery).from(from).size(size)
                        .trackTotalHits(true)),
            RequestOptions.DEFAULT);
        
        // System.out.println(response.getHits().getTotalHits());
        // System.out.println(response.toString());
        // closeClient();
        
        SearchHits hits = searchResponse.getHits();
        TotalHits totalHits = hits.getTotalHits();
        long totalSize = totalHits.value;
        SearchHit[] searchHits = hits.getHits();
        
        Map<String, Object> resultMap = new HashMap<String, Object>();
        List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
        Map<String, Object> sourceMap = null;
        for (SearchHit searchHit : searchHits) {
            sourceMap = searchHit.getSourceAsMap();
            resultList.add(sourceMap);
        }
        closeClient();
        logger.info("单条件分页查询时,查询出的总条数为:【{}】", totalSize);
        resultMap.put(BobfintechContant.DATA_LIST, resultList);
        resultMap.put(BobfintechContant.DATA_SIZE, totalSize);
        return resultMap;
    }
    
    /**
     * 关闭ES客户端
     */
    public void closeClient()
    {
        try {
            if (client != null) {
                client.close();
            }
            client = null;
        }
        catch (Exception e2) {
            e2.printStackTrace();
            System.out.println("关闭客户端失败");
        }
    }

注意,报错的代码是我自己定义的一些常量,自己改下就可以。

分类   Spring boot 开发
字数   6562

博客标签    ES 报错  

评论