如何用Elasticsearch Java API Client编写多嵌套字段查询及API选择疑问
问题描述
我有如下示例文档(存储在Elasticsearch的product索引中):
{ "id" : "1", "title" : "test", "description" : "test", "price" : 100.0, "category_id" : "1", "characteristics" : [ { "characteristic_id" : "1", "text_value" : "red" }, { "characteristic_id" : "2", "numeric_value" : 15 }, { "characteristic_id" : "3", "numeric_value" : 20 } ] }, { "id" : "2", "title" : "test", "description" : "test", "price" : 200.0, "category_id" : "1", "characteristics" : [ { "characteristic_id" : "1", "text_value" : "blue" }, { "characteristic_id" : "2", "numeric_value" : 10 }, { "characteristic_id" : "3", "numeric_value" : 5 } ] }
需要执行如下查询:
GET product/_search { "query": { "bool": { "must": [ { "nested": { "path": "characteristics", "query": { "bool": { "must": [ { "term": { "characteristics.characteristic_id": 1 } }, { "term": { "characteristics.text_value": "blue" } } ] } } } }, { "nested": { "path": "characteristics", "query": { "bool": { "must": [ { "term": { "characteristics.characteristic_id": 3 } }, { "range": { "characteristics.numeric_value": { "gte": 1, "lte": 7 } } } ] } } } }, { "term": { "category_id": 1 } }, { "range": { "price": { "gt": 10.0, "lt": 500.0 } } } ], "should": [ { "match": { "title": "te" } } ] } } }
请问如何用新版Elasticsearch Java API Client编写该查询?另外官方相关资料很少,我应该用这个API还是手动编写所有请求?
解决方案
一、新版Elasticsearch Java API Client查询实现
假设你已经初始化好ElasticsearchClient实例(命名为client),以下是对应查询的代码实现:
import co.elastic.clients.elasticsearch.core.SearchRequest; import co.elastic.clients.elasticsearch.core.SearchResponse; import co.elastic.clients.elasticsearch._types.query_dsl.*; import co.elastic.clients.json.JsonData; public class ProductSearch { public void executeSearch(ElasticsearchClient client) throws Exception { // 第一个嵌套查询:匹配characteristic_id=1且text_value=blue的特征 Query nestedQuery1 = NestedQuery.of(n -> n .path("characteristics") .query(q -> q .bool(b -> b .must(m -> m.term(t -> t.field("characteristics.characteristic_id").value(1))) .must(m -> m.term(t -> t.field("characteristics.text_value").value("blue"))) ) ) )._toQuery(); // 第二个嵌套查询:匹配characteristic_id=3且numeric_value在1-7之间的特征 Query nestedQuery2 = NestedQuery.of(n -> n .path("characteristics") .query(q -> q .bool(b -> b .must(m -> m.term(t -> t.field("characteristics.characteristic_id").value(3))) .must(m -> m.range(r -> r .field("characteristics.numeric_value") .gte(JsonData.of(1)) .lte(JsonData.of(7)) )) ) ) )._toQuery(); // category_id精确匹配查询 Query categoryTermQuery = TermQuery.of(t -> t.field("category_id").value(1))._toQuery(); // price范围查询 Query priceRangeQuery = RangeQuery.of(r -> r .field("price") .gt(JsonData.of(10.0)) .lt(JsonData.of(500.0)) )._toQuery(); // title模糊匹配查询(should子句) Query titleMatchQuery = MatchQuery.of(m -> m.field("title").query("te"))._toQuery(); // 组装顶层bool查询 BoolQuery boolQuery = BoolQuery.of(b -> b .must(nestedQuery1, nestedQuery2, categoryTermQuery, priceRangeQuery) .should(titleMatchQuery) ); // 构建搜索请求 SearchRequest request = SearchRequest.of(s -> s .index("product") .query(q -> q.bool(boolQuery)) ); // 执行查询并处理结果 SearchResponse<Object> response = client.search(request, Object.class); response.hits().hits().forEach(hit -> { System.out.println("文档ID: " + hit.id()); System.out.println("文档内容: " + hit.source()); }); } }
代码说明
- 每个查询组件通过对应Query的
of方法构建,最终调用_toQuery()统一转为Query类型,方便组装。 - 嵌套查询需指定
path字段,内部逻辑和DSL结构完全对应。 - 数值类型的范围查询需用
JsonData.of()包装,确保Elasticsearch能识别正确的类型。
二、API选择建议
优先使用新版Elasticsearch Java API Client,理由如下:
- 类型安全:编译期就能检测字段名拼写、数据类型匹配错误,避免手动写JSON时的低级错误,减少线上bug。
- 可维护性:结构化代码比零散的JSON字符串更易修改,后续调整查询条件时,直接修改对应代码块即可。
- 版本兼容:官方会持续更新API适配Elasticsearch新版本特性,手动写JSON需要自己处理版本差异带来的语法变化。
- 便捷性:API封装了请求序列化、响应反序列化逻辑,不用手动拼接JSON和解析返回结果。
针对资料少的问题,可以通过这些方式弥补:
- 对照DSL示例反向推导API写法,大部分DSL结构都能在API中找到对应方法。
- 查看API源码注释,多数方法都标注了对应的DSL语法。
- 利用IDE自动补全功能,探索API的结构和可用方法。
只有遇到极特殊、API暂不支持的查询场景时,再考虑手动拼接JSON作为临时方案,长期来看官方API是更优选择。
内容的提问来源于stack exchange,提问作者AssHands
相关产品推荐
相关产品推荐

