Elasticsearch如何查询JSON对象数组?Spring Boot实现疑问
问题
我的Elasticsearch中存储的campaign对象数据格式如下:
{id:"c1", tags:[{key:"k1",value:"v1"}, {key:"k2",value:"v2"}, {key:"k3",value:"v3"}]} {id:"c2", tags:[{key:"k1",value:"v1"}, {key:"k4",value:"v4"}]} {id:"c3", tags:[{key:"k5",value:"v5"}, {key:"k2",value:"v2"}]}
客户端会传入一组tag对象列表,需返回匹配的campaign对象,示例如下:
示例1
请求:
[{key:"k1",value:"v1"}]
响应:
{id:"c1", tags:[{key:"k1",value:"v1"}, {key:"k2",value:"v2"}, {key:"k3",value:"v3"}]} {id:"c2", tags:[{key:"k1",value:"v1"}, {key:"k4",value:"v4"}]}
示例2
请求:
[{key:"k3",value:"v3"},{key:"k5",value:"v5"}]
响应:
{id:"c2", tags:[{key:"k1",value:"v1"}, {key:"k4",value:"v4"}]} {id:"c3", tags:[{key:"k5",value:"v5"}, {key:"k2",value:"v2"}]}
我的服务基于Spring Boot开发,应该使用哪种QueryBuilder(termsQuery、nestedQuery)实现该需求?我曾尝试以下查询,但返回空列表:
boolQueryBuilder.filter( QueryBuilders.termsQuery("tags", TAG_LIST));
解答
你需要使用nestedQuery来实现需求,核心原因和实现方式如下:
为什么不能用termsQuery
- 若
tags是嵌套对象类型,Elasticsearch会将每个tag独立索引,termsQuery无法关联同一个tag内的key和value,只会把字段扁平化处理,无法匹配键值对的组合关系; - 若
tags未设置为嵌套类型,Elasticsearch会自动扁平化存储tags.key和tags.value,此时termsQuery同样无法关联对应键值,导致查询失效。
正确实现代码
首先确保你的tags字段在Elasticsearch mapping中定义为nested类型,之后用以下代码构建查询:
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); // 遍历传入的每个tag,构建嵌套查询条件 for (Tag tag : TAG_LIST) { // 匹配单个tag的key和value,确保两个条件属于同一个tag对象 BoolQueryBuilder tagMatchQuery = QueryBuilders.boolQuery() .must(QueryBuilders.termQuery("tags.key", tag.getKey())) .must(QueryBuilders.termQuery("tags.value", tag.getValue())); // 将tag匹配条件包装为nested查询 boolQuery.should(QueryBuilders.nestedQuery( "tags", tagMatchQuery, ScoreMode.None // filter场景不需要评分,设置为None提升性能 )); } // 设置至少匹配一个传入的tag boolQuery.minimumShouldMatch(1); // 将最终查询加入filter boolQueryBuilder.filter(boolQuery);
代码说明
- 遍历每个传入的tag,用
boolQuery组合tags.key和tags.value的精准匹配,确保两个条件对应同一个tag对象; - 用
nestedQuery将上述条件绑定到tags嵌套字段,保证Elasticsearch在单个嵌套对象内进行匹配; - 通过
should和minimumShouldMatch(1)实现“匹配任意一个传入tag即可返回”的逻辑。
内容的提问来源于stack exchange,提问作者code121
相关产品推荐
相关产品推荐

