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

PHP中使用json_encode生成Elasticsearch查询JSON结构的问题

PHP构建Elasticsearch查询时json_encode的数组结构问题

我尝试用PHP数组构建Elasticsearch查询,再用json_encode()转成JSON,但Elasticsearch无法识别这个JSON。

我的PHP数组片段:

'query' => [
    'bool' => [
        'must' => [
            'multi_match' => [
                'query' => $request->get('keyword'),
                'fields' => ['addressLine1', 'addressCity', 'contactName']
            ],
            'bool' => [
                'should' => [
                    'range' => [
                        '_metrics.count' => [
                            'gte' => 1
                        ]
                    ]
                 ]
            ]
        ],
        'filter' => [
            'term' => [
                'organisationId.keyword' => [
                    'value' => $organisationId
                ]
            ]
        ]
    ]
]

执行json_encode($params)后得到的JSON:

{
   "query":{
      "bool":{
         "must":{
            "multi_match":{
               "query":"277 Some Road",
               "fields":[
                  "addressLine1",
                  "addressCity",
                  "contactName"
               ]
            },
            "bool":{
               "should":{
                  "range":{
                     "_metrics.count":{
                        "gte":1
                     }
                  }
               }
            }
         },
         "filter":{
            "term":{
               "organisationId.keyword":{
                  "value":"xxxx-xxxx-xxxx-xxxx"
               }
            }
         }
      }
   }
}

这个JSON语法合法,但发送给Elasticsearch时返回错误:

{
  "error": {
    "root_cause": [
      {
        "type": "parsing_exception",
        "reason": "[multi_match] malformed query, expected [END_OBJECT] but found [FIELD_NAME]",
        "line": 16,
        "col": 13
      }
    ],
    "type": "x_content_parse_exception",
    "reason": "[16:13] [bool] failed to parse field [must]",
    "caused_by": {
      "type": "parsing_exception",
      "reason": "[multi_match] malformed query, expected [END_OBJECT] but found [FIELD_NAME]",
      "line": 16,
      "col": 13
    }
  },
  "status": 400
}

手动修改成以下JSON结构后可以正常运行:

{
   "query":{
      "bool":{
         "must":[
            {
              "multi_match": {
                "query": "277 Some Road",
                "fields":[
                  "addressLine1",
                  "addressCity",
                  "contactName"
               ]
              }
            },
            {
               "bool":{
                  "should":[
                     {
                        "range":{
                           "_metrics.count":{
                              "gte":1
                           }
                        }
                     }
                  ]
               }
            }
         ],
         "filter":[
            {
               "term":{
                  "organisationId.keyword":{
                     "value":"xxxx-xxxx-xxxx-xxxx"
                  }
               }
            }
          ]
      }
   }
}

能看到核心差异是must和filter需要是对象数组,但我调整PHP数组后始终无法让json_encode()生成正确结构,请问该怎么修改PHP数组?


问题根源

Elasticsearch的bool查询中,must、should、filter这些参数要求的是查询子句的数组,而你原本的PHP数组里,must和filter是关联数组(键值对结构),json_encode()会把它们转成JSON对象,而非数组。

修改后的PHP数组

你需要把must里的每个查询子句都用单独的数组包裹,让整个must变成一个索引数组(不带键名的数组);同理filter也需要改成索引数组:

'query' => [
    'bool' => [
        'must' => [
            // 第一个查询子句:用数组包裹multi_match
            [
                'multi_match' => [
                    'query' => $request->get('keyword'),
                    'fields' => ['addressLine1', 'addressCity', 'contactName']
                ]
            ],
            // 第二个查询子句:用数组包裹bool查询
            [
                'bool' => [
                    'should' => [
                        // should里的range同样需要数组包裹
                        [
                            'range' => [
                                '_metrics.count' => [
                                    'gte' => 1
                                ]
                            ]
                        ]
                    ]
                 ]
            ]
        ],
        'filter' => [
            // filter里的term用数组包裹
            [
                'term' => [
                    'organisationId.keyword' => [
                        'value' => $organisationId
                    ]
                ]
            ]
        ]
    ]
]

原理说明

  • PHP中,不带键名的索引数组会被json_encode()转成JSON数组([]包裹的结构);
  • 带键名的关联数组会被转成JSON对象({}包裹的结构);
  • Elasticsearch要求must/filter是查询子句的数组,所以必须让PHP里对应的结构是索引数组,每个子句是独立的关联数组。

这样修改后,执行json_encode()就能生成Elasticsearch需要的正确JSON结构了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 19:20:44