如何在Spring Data Elasticsearch中为嵌套列表构建QueryBuilders查询及Lucene格式查询
Spring Data Elasticsearch嵌套文档查询实现方案
针对你要查询包含嵌套列表的MyDocument文档,要求同一个SubDocument子文档中code="test"且value包含"nested"的需求,我整理了两种实现方式,能有效避免跨子文档匹配的错误结果:
1. 使用QueryBuilders构建嵌套查询
因为你的subDoc字段被定义为Nested类型,必须用nestedQuery来约束两个条件作用于同一个子文档。具体代码如下:
import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.NestedQueryBuilder; // 构建子查询:同时满足code精确匹配"test",value包含"nested" BoolQueryBuilder subCondition = QueryBuilders.boolQuery() // 若CODE字段是Keyword类型,用termQuery更高效;若为Text类型,也可改用matchQuery并指定精确匹配 .must(QueryBuilders.termQuery("SUB_DOC.CODE", "test")) .must(QueryBuilders.matchQuery("SUB_DOC.VALUE", "nested")); // 构建嵌套查询,指定嵌套字段路径为SUB_DOC NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery( "SUB_DOC", // 对应MyDocument类中@Field的name属性 subCondition, org.springframework.data.elasticsearch.core.query.Query.DEFAULT_BOOLEAN ); // 后续可将nestedQuery传入ElasticsearchRestTemplate的search方法,或Repository的自定义查询中
小提示:如果CODE字段主要用于精确匹配,建议把它的FieldType改成Keyword,这样查询效率会更高,也能避免Text类型分词带来的意外匹配。
2. 使用查询字符串实现嵌套查询
用查询字符串方式时,同样要确保两个条件在同一个嵌套子文档的上下文中,需要借助Elasticsearch的{!nested path=...}语法来指定路径,具体代码如下:
import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.AbstractQueryBuilder; // 构建查询字符串:指定嵌套路径为SUB_DOC,同时满足code等于test和value包含nested String stringQuery = "{!nested path=SUB_DOC}CODE:\"test\" AND VALUE:*nested*"; AbstractQueryBuilder<?> query = QueryBuilders.queryStringQuery(stringQuery);
如果你习惯用+表示“必须满足”的逻辑,也可以写成:
String stringQuery = "+{!nested path=SUB_DOC}CODE:\"test\" +{!nested path=SUB_DOC}VALUE:*nested*";
注意事项:
*nested*是通配符匹配,虽然能满足包含需求,但开头用通配符的查询效率较低。如果VALUE是Text类型,直接写VALUE:nested会更高效(基于分词匹配)。- 一定要把两个条件都放在同一个
{!nested path=SUB_DOC}上下文里,否则Elasticsearch会允许不同子文档分别满足不同条件,导致不符合预期的结果。
额外补充:Spring Data Repository简化实现
如果你用Spring Data Elasticsearch的Repository接口,还可以用更简洁的方式实现:
public interface MyDocumentRepository extends ElasticsearchRepository<MyDocument, String> { // 方法命名查询,自动生成符合要求的嵌套查询 List<MyDocument> findBySubDocCodeAndSubDocValueContaining(String code, String value); // 或者用@Query注解自定义DSL查询 @Query("{\"nested\": {\"path\": \"SUB_DOC\", \"query\": {\"bool\": {\"must\": [{\"term\": {\"SUB_DOC.CODE\": \"?0\"}}, {\"match\": {\"SUB_DOC.VALUE\": \"?1\"}}]}}}}") List<MyDocument> findBySubDocCodeAndValueContaining(String code, String value); }
内容的提问来源于stack exchange,提问作者Grzegorz Kawalec
相关产品推荐
相关产品推荐

