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

如何用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,理由如下:

  1. 类型安全:编译期就能检测字段名拼写、数据类型匹配错误,避免手动写JSON时的低级错误,减少线上bug。
  2. 可维护性:结构化代码比零散的JSON字符串更易修改,后续调整查询条件时,直接修改对应代码块即可。
  3. 版本兼容:官方会持续更新API适配Elasticsearch新版本特性,手动写JSON需要自己处理版本差异带来的语法变化。
  4. 便捷性:API封装了请求序列化、响应反序列化逻辑,不用手动拼接JSON和解析返回结果。

针对资料少的问题,可以通过这些方式弥补:

  • 对照DSL示例反向推导API写法,大部分DSL结构都能在API中找到对应方法。
  • 查看API源码注释,多数方法都标注了对应的DSL语法。
  • 利用IDE自动补全功能,探索API的结构和可用方法。

只有遇到极特殊、API暂不支持的查询场景时,再考虑手动拼接JSON作为临时方案,长期来看官方API是更优选择。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 07:58:12