如何仅从ElasticSearch获取匹配的文档以获取嵌套数组字段

时间:2018-07-06 11:16:19

标签: elasticsearch elasticsearch-5

我在弹性搜索中使用了一个数组字段,该数组包含多个JSON文档。像这样:

{
  "imei": 358739050280669,
  "date": "2018-02-20",
  "id": 86739126,
  "totalData": [
    {
      "gpsdt": "2018-02-20",
      "satno": 0,
      "analog3": -1,
      "digital1": 0,
      "digital2": 1,
      "digital3": 1,
      "digital4": 2,
      "lastgpsdt": "2018-02-20T11:54:00",
      "longitude": 78.081218,
      "odometer": 0,
      "intbatlevel": 6,
      "odo": 0,
      "latitude": 29.951449,
      "srtangle": 62,
      "analog4": 13,
      "speed": 0,
      "analog2": -1,
      "analog1": 9,
      "extbatlevel": 0
    },
    {
      "gpsdt": "2018-02-20",
      "speed": 22,
      "satno": 0,
      "digital1": 0,
      "digital2": 1,
      "digital3": 1,
      "digital4": 2,
      "lastgpsdt": "2018-02-20T22:48:00",
      "longitude": 78.062898,
      "odometer": 0,
      "intbatlevel": 6,
      "odo": 113,
      "latitude": 29.948898,
      "srtangle": 67,
      "analog4": 12,
      "analog3": -1,
      "analog2": -1,
      "analog1": 8,
      "extbatlevel": 0
    }
  ]
}

现在我想在"imei"上应用过滤器,在"lastgpsdt"字段上应用日期范围过滤器,在输出中,我只希望那些与应用过滤器匹配的文档。

例如:我必须获取imei358739050280669之间的lastgpsdt2018-02-20T10:54:00和日期范围(字段名称为2018-02-20T12:54:00)的数据

因此,它应该仅从totalData数组字段返回一个文档(根据给定的数据)。

请向我提出查询以实现此目标。

输出应如下所示:

{
  "imei": 358739050280669,
  "date": "2018-02-20",
  "id": 86739126,
  "totalData": [
    {
      "gpsdt": "2018-02-20",
      "satno": 0,
      "analog3": -1,
      "digital1": 0,
      "digital2": 1,
      "digital3": 1,
      "digital4": 2,
      "lastgpsdt": "2018-02-20T11:54:00",
      "longitude": 78.081218,
      "odometer": 0,
      "intbatlevel": 6,
      "odo": 0,
      "latitude": 29.951449,
      "srtangle": 62,
      "analog4": 13,
      "speed": 0,
      "analog2": -1,
      "analog1": 9,
      "extbatlevel": 0
    }
  ]
}

谢谢。

1 个答案:

答案 0 :(得分:0)

您可以使用nested搜索查询的inner hits参数来实现此目的:

  

在很多情况下,了解哪些内部嵌套对象(对于嵌套)或子文档/父文档(对于父/子文档)导致某些信息返回非常有用。内部点击功能可用于此目的。此功能会在搜索响应中为每个搜索命中返回附加的嵌套命中,这些嵌套命中会导致搜索命中匹配范围不同。

如果您有这样的映射:

PUT /mygps
{
  "mappings": {
    "doc": {
      "properties": {
        "date": {
          "type": "date"
        },
        "id": {
          "type": "long"
        },
        "imei": {
          "type": "long"
        },
        "totalData": {
          "type": "nested", 
          "properties": {
            "analog1": {
              "type": "long"
            },
            "analog2": {
              "type": "long"
            },
            "analog3": {
              "type": "long"
            },
            "analog4": {
              "type": "long"
            },
            "digital1": {
              "type": "long"
            },
            "digital2": {
              "type": "long"
            },
            "digital3": {
              "type": "long"
            },
            "digital4": {
              "type": "long"
            },
            "extbatlevel": {
              "type": "long"
            },
            "gpsdt": {
              "type": "date"
            },
            "intbatlevel": {
              "type": "long"
            },
            "lastgpsdt": {
              "type": "date"
            },
            "latitude": {
              "type": "float"
            },
            "longitude": {
              "type": "float"
            },
            "odo": {
              "type": "long"
            },
            "odometer": {
              "type": "long"
            },
            "satno": {
              "type": "long"
            },
            "speed": {
              "type": "long"
            },
            "srtangle": {
              "type": "long"
            }
          }
        }
      }
    }
  }
}

查询可能看起来像这样:

POST /mygps/doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "imei": "358739050280669"
          }
        },
        {
          "nested": {
            "path": "totalData",
            "query": {
              "range": {
                "totalData.lastgpsdt": {
                  "gte": "2018-02-20T10:54:00",
                  "lte": "2018-02-20T12:54:00"
                }
              }
            },
            "inner_hits": {}
          }
        }
      ]
    }
  },
  "_source": ["imei", "date", "id"]
}

这将产生以下输出:

{
  "hits": {
    "total": 1,
    "max_score": 2,
    "hits": [
      {
        "_index": "mygps",
        "_type": "doc",
        "_id": "AWR5Em0m6jWoKaNfOwDA",
        "_score": 2,
        "_source": {
          "date": "2018-02-20",
          "imei": 358739050280669,
          "id": 86739126
        },
        "inner_hits": {
          "totalData": {
            "hits": {
              "total": 1,
              "max_score": 1,
              "hits": [
                {
                  "_nested": {
                    "field": "totalData",
                    "offset": 0
                  },
                  "_score": 1,
                  "_source": {
                    "gpsdt": "2018-02-20",
                    "satno": 0,
                    "analog3": -1,
                    "digital1": 0,
                    "digital2": 1,
                    "digital3": 1,
                    "digital4": 2,
                    "lastgpsdt": "2018-02-20T11:54:00",
                    "longitude": 78.081218,
                    "odometer": 0,
                    "intbatlevel": 6,
                    "odo": 0,
                    "latitude": 29.951449,
                    "srtangle": 62,
                    "analog4": 13,
                    "speed": 0,
                    "analog2": -1,
                    "analog1": 9,
                    "extbatlevel": 0
                  }
                }
              ]
            }
          }
        }
      }
    ]
  }
}

请注意,由于您对totalData的不匹配项不感兴趣,因此我使用Source Filtering从响应中完全排除了该字段。相反,可以在totalData下找到inner_hits的匹配项。

希望有帮助!