You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复Elasticsearch查询以返回嵌套_source中的指定字段(Java)

问题描述

我正在用Java的ElasticSearchClient查询Elasticsearch,返回的数据量太大,想只获取需要的字段,但_source里的variables是嵌套数组结构。

示例索引响应(多个索引结构一致):

[
    {
        "_index": "kn-tas-20200630",
        "_type": "_doc",
        "_id": "1122334455",
        "_score": null,
        "_source": {
            "variables": [
                {
                    "rawValue": "DEFH",
                    "name": "MANAGER"
                },
                {
                    "rawValue": "ABCD",
                    "name": "EMPLOYEE"
                },
                {
                    "rawValue": "[{\"rowId\":102030,\"rowType\":\"SIM\"}]",
                    "name": "extData"
                }
            ]
        },
        "sort": [
            1665735632119
        ]
    }
]

需要实现的查询目标:

  • 根据name获取对应的rawValue(比如指定MANAGER,返回DEFH)
  • 获取extData中的rowType值(指定extData+rowType,返回SIM)

当前的查询语句:

{
    "from": 0,
    "size": 100,
    "query": {
        "bool": {
            "must": [
                {
                    "terms": {
                        "prcKey": [
                            "K-112"
                        ],
                        "boost": 1.0
                    }
                }
            ],
            "must_not": [
                {
                    "exists": {
                        "field": "endDate",
                        "boost": 1.0
                    }
                },
                {
                    "term": {
                        "personInCharge": {
                            "value": "ABC",
                            "boost": 1.0
                        }
                    }
                }
            ],
            "adjust_pure_negative": true,
            "boost": 1.0
        }
    },
    "_source": {
        "includes": [
            "variables.name",
            "variables.rawValue"
        ],
        "excludes": []
    },
    "sort": [
        {
            "createTime": {
                "order": "desc"
            }
        }
    ]
}

尝试过嵌套查询但没成功,求修复方法。

解决方案

单纯用_source过滤无法直接从数组里提取指定元素,需要用**脚本字段(Script Fields)**来处理逻辑,同时extData的rawValue是JSON字符串,需要先解析再提取rowType。

1. 修改后的查询语句

以下查询通过脚本字段分别提取目标值:

{
    "from": 0,
    "size": 100,
    "query": {
        "bool": {
            "must": [
                {
                    "terms": {
                        "prcKey": ["K-112"],
                        "boost": 1.0
                    }
                }
            ],
            "must_not": [
                {
                    "exists": {
                        "field": "endDate",
                        "boost": 1.0
                    }
                },
                {
                    "term": {
                        "personInCharge": {
                            "value": "ABC",
                            "boost": 1.0
                        }
                    }
                }
            ],
            "adjust_pure_negative": true,
            "boost": 1.0
        }
    },
    "script_fields": {
        "manager_value": {
            "script": {
                "source": """
                    for (item in doc['variables.name']) {
                        if (item.value == 'MANAGER') {
                            def idx = doc['variables.name'].indexOf(item);
                            return doc['variables.rawValue'][idx].value;
                        }
                    }
                    return null;
                """
            }
        },
        "ext_data_row_type": {
            "script": {
                "source": """
                    for (item in doc['variables.name']) {
                        if (item.value == 'extData') {
                            def idx = doc['variables.name'].indexOf(item);
                            def rawJson = doc['variables.rawValue'][idx].value;
                            def jsonObj = JSON.parse(rawJson);
                            return jsonObj[0].rowType;
                        }
                    }
                    return null;
                """
            }
        }
    },
    "_source": false, // 关闭原始_source返回,只取脚本字段结果
    "sort": [
        {
            "createTime": {
                "order": "desc"
            }
        }
    ]
}

2. Java代码实现(SearchSourceBuilder)

对应上述查询,用ElasticSearchClient的Java API构建:

import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;

import java.io.IOException;
import java.util.Collections;

public class EsQueryExample {
    public static void main(String[] args) throws IOException {
        RestHighLevelClient client = new RestHighLevelClient(/* 此处填入你的客户端配置 */);

        // 构建bool查询条件
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
                .must(QueryBuilders.termsQuery("prcKey", "K-112"))
                .mustNot(QueryBuilders.existsQuery("endDate"))
                .mustNot(QueryBuilders.termQuery("personInCharge", "ABC"));

        // 提取MANAGER对应的rawValue脚本
        Script managerScript = new Script(
                ScriptType.INLINE,
                "painless",
                """
                    for (item in doc['variables.name']) {
                        if (item.value == 'MANAGER') {
                            def idx = doc['variables.name'].indexOf(item);
                            return doc['variables.rawValue'][idx].value;
                        }
                    }
                    return null;
                """,
                Collections.emptyMap()
        );

        // 提取extData中的rowType脚本
        Script extDataScript = new Script(
                ScriptType.INLINE,
                "painless",
                """
                    for (item in doc['variables.name']) {
                        if (item.value == 'extData') {
                            def idx = doc['variables.name'].indexOf(item);
                            def rawJson = doc['variables.rawValue'][idx].value;
                            def jsonObj = JSON.parse(rawJson);
                            return jsonObj[0].rowType;
                        }
                    }
                    return null;
                """,
                Collections.emptyMap()
        );

        // 构建查询源
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder()
                .query(boolQuery)
                .from(0)
                .size(100)
                .sort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                .fetchSource(false)
                .scriptField("manager_value", managerScript)
                .scriptField("ext_data_row_type", extDataScript);

        // 执行查询(此处省略SearchRequest构建与执行逻辑)
        // SearchRequest searchRequest = new SearchRequest("kn-tas-*").source(sourceBuilder);
        // SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
    }
}

注意事项

  • 确保Elasticsearch版本支持Painless脚本与JSON解析(6.0及以上版本均支持)
  • 若variables数组规模较大,脚本遍历可能影响性能,建议后续优化数据结构(比如将数组改为键值对嵌套对象)
  • 如需提取多个指定name的字段,在script_fields中添加对应脚本即可

内容的提问来源于stack exchange,提问作者user3147473

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 04:30:52