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

ReactJS数据表格Elasticsearch过滤后无数据问题排查求助

React数据表格过滤异常排查与修复

问题现象

使用React实现的数据表格通过Node.js后端从Elasticsearch拉取数据填充,未应用过滤条件时数据检索和展示均正常;添加过滤条件后,尽管Elasticsearch的_source中存在匹配记录,数据表格仍显示为空。


相关信息

请求参数结构

{
  "pageIndex": 1,
  "pageSize": 10,
  "sort": { "order": "", "key": "" },
  "query": "",
  "filterData": {
    "analysis": [ "0", "1", "2", "3" ],
    "threat_level_id": [ "1", "2", "3", "4" ]
  }
}

接口地址

POST /api/v1/events/public/list

带过滤的Node.js控制器代码

exports.getPublicEvents = async (req, res) => {
  try {
    client.ping()
    const { pageIndex, pageSize, sort, query, filterData } = req.body
    let esQuery = {
      index: 'ns_*',
      body: {
        query: {
          bool: {
            must: [
              {
                match_all: {},
              },
            ],
            filter: [],
          },
        },
        from: (pageIndex - 1) * pageSize,
        size: pageSize,
      },
    }
    if (query) {
      esQuery.body.query.bool.must = [
        {
          match: {
            'Event.info': {
              query: query,
              fuzziness: 'AUTO',
            },
          },
        },
      ]
    }
    if (filterData.analysis.length > 0) {
      esQuery.body.query.bool.filter.push({
        terms: {
          'Event.analysis': filterData.analysis,
        },
      })
    }
    if (filterData.threat_level_id.length > 0) {
      esQuery.body.query.bool.filter.push({
        terms: {
          'Event.threat_level_id': filterData.threat_level_id,
        },
      })
    }
    let esResponse = await client.search(esQuery)
    let data = esResponse.hits.hits.map((hit) => hit._source)
    let total = esResponse.hits.total.value

    res.status(200).json({
      status: 'success',
      data: data,
      total: total,
    })
  } catch (error) {
    res.status(500).json({
      error: 'Error connecting to Elasticsearch',
      errorMessage: error.message,
    })
  }
}

无过滤的Node.js控制器代码(可正常运行)

exports.getPublicEvents = async (req, res) => {
  try {
    client.ping()
    const { pageIndex, pageSize, sort, query } = req.body
    let esQuery = {
      index: 'ns_*',
      body: {
        query: {
          match_all: {},
        },
        from: (pageIndex - 1) * pageSize,
        size: pageSize,
      },
    }
    if (query) {
      esQuery.body.query = {
        match: {
          'Event.info': {
            query: query,
            fuzziness: 'AUTO',
          },
        },
      }
    }
    let esResponse = await client.search(esQuery)
    let data = esResponse.hits.hits.map((hit) => hit._source)
    let total = esResponse.hits.total.value

    res.status(200).json({
      status: 'success',
      data: data,
      total: total,
    })
  } catch (error) {
    res.status(500).json({
      error: 'Error connecting to Elasticsearch',
      errorMessage: error.message,
    })
  }
}

Elasticsearch版本

7.17.8

生成的esQuery日志

{
  "index": "INDEX_NAME",
  "body": {
    "query": {
      "bool": {
        "must": [{ "match_all": {} }],
        "filter": [
          { "terms": { "Event.analysis": ["0", "1", "2"] } },
          { "terms": { "Event.threat_level_id": ["1", "2", "3", "4"] } }
        ]
      }
    },
    "from": 0,
    "size": 10
  }
}

Elasticsearch中的数据结构

{
    "@version": "1",
    "@timestamp": "2023-02-01T14:43:09.997Z",
    "Event": {
        "info": ".......................",
        "description": ".......................",
        "analysis": 0,
        "threat_level_id": "4",
        "created_at": 1516566351,
        "uuid": "5a64f74f0e543738c12bc973322",
        "updated_at": 1675262417
    }
}

索引映射

{
    "index_patterns": ["INDEX_NAME"],
    "template": "TEMPLATE_NAME",
    "settings": {
      "number_of_replicas": 0,
      "index.mapping.nested_objects.limit": 10000000
      },
    "mappings": {
      "dynamic": false,
      "properties": {
          "@timestamp": {
          "type": "date"
        },
        "Event": {
          "type": "nested",
          "properties": {
            "date_occured": {
              "type": "date"
            },
            "threat_level_id": {
              "type": "integer"
            },
            "description": {
              "type": "text"
            },
            "is_shared": {
              "type": "boolean"
            },
            "analysis": {
              "type": "integer"
            },
            "uuid": {
              "type": "text"
            },
            "created_at": {
              "type": "date"
            },
            "info": {
              "type": "text"
            },
            "shared_with": {
                "type": "nested",
                 "properties": {
                  "_id": {
                    "type": "text"
                }
              }
            },
            "updated_at": {
              "type": "date"
            },
            "author": {
              "type": "text"
            },
            "Attributes": {
              "type": "nested",
              "properties": {
                "data": {
                  "type": "text"
                },
                "type": {
                  "type": "text"
                },
                "uuid": {
                  "type": "text"
                },
                "comment": {
                  "type": "text"
                },
                "category": {
                  "type": "text"
                },
                "value": {
                  "type": "text"
                },
                "timestamp": {
                  "type": "date"
                }
              }
            }, 
            "organisation": {
              "type": "nested",
              "properties": {
                "name": {
                  "type": "text"
                },
                "uuid": {
                  "type": "text"
                }
              }
            },
            "Tags": {
              "type": "nested",
              "properties": {
                "color": {
                  "type": "text"
                },
                "name": {
                  "type": "text"
                }
              }
            },
            "TLP": {
              "type": "nested",
              "properties": {
                "color": {
                  "type": "text"
                },
                "name": {
                  "type": "text"
                }
              }
            }
          }
        }  
      }
    }
  }

问题根源与修复方案

问题1:Nested类型字段查询方式错误

从索引映射可知,Event字段是nested类型。Elasticsearch中nested类型字段需使用nested查询语法才能正确匹配,普通terms查询无法穿透nested结构,导致无匹配结果。

问题2:参数类型不匹配

请求中filterData的analysis和threat_level_id是字符串数组,但索引映射中这两个字段类型为integer,字符串与数字类型不匹配,terms查询无法匹配对应数据。

修复后的控制器代码

将过滤部分改为nested查询,并将参数转换为数字类型:

exports.getPublicEvents = async (req, res) => {
  try {
    await client.ping()
    const { pageIndex, pageSize, sort, query, filterData } = req.body
    let esQuery = {
      index: 'ns_*',
      body: {
        query: {
          bool: {
            must: [
              {
                match_all: {},
              },
            ],
            filter: [],
          },
        },
        from: (pageIndex - 1) * pageSize,
        size: pageSize,
      },
    }
    if (query) {
      esQuery.body.query.bool.must = [
        {
          nested: {
            path: 'Event',
            query: {
              match: {
                'Event.info': {
                  query: query,
                  fuzziness: 'AUTO',
                }
              }
            }
          }
        },
      ]
    }
    // 处理analysis过滤:转数字+嵌套查询
    if (filterData.analysis.length > 0) {
      const analysisValues = filterData.analysis.map(val => parseInt(val, 10))
      esQuery.body.query.bool.filter.push({
        nested: {
          path: 'Event',
          query: {
            terms: {
              'Event.analysis': analysisValues
            }
          }
        }
      })
    }
    // 处理threat_level_id过滤:转数字+嵌套查询
    if (filterData.threat_level_id.length > 0) {
      const threatLevelValues = filterData.threat_level_id.map(val => parseInt(val, 10))
      esQuery.body.query.bool.filter.push({
        nested: {
          path: 'Event',
          query: {
            terms: {
              'Event.threat_level_id': threatLevelValues
            }
          }
        }
      })
    }
    let esResponse = await client.search(esQuery)
    let data = esResponse.hits.hits.map((hit) => hit._source)
    let total = esResponse.hits.total.value

    res.status(200).json({
      status: 'success',
      data: data,
      total: total,
    })
  } catch (error) {
    res.status(500).json({
      error: 'Error connecting to Elasticsearch',
      errorMessage: error.message,
    })
  }
}

额外注意点

  • 原代码中client.ping()未加await,会导致ping操作异步执行,无法确保ES连接正常,修复时添加了await。
  • 查询Event.info时,因Event是nested类型,同样需要使用nested查询语法,否则也可能出现查询不到数据的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 20:50:25