【问题标题】:ElasticSearch - Filtering a result and manipulating the documentsElasticSearch - 过滤结果并操作文档
【发布时间】:2020-12-01 11:24:27
【问题描述】:

我有以下查询 - 工作正常(这可能不是实际查询):

{
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "location",
            "query": {
              "geo_distance": {
                "distance": "16090km",
                "distance_type": "arc",
                "location.point": {
                  "lat": "51.794177",
                  "lon": "-0.063055"
                }
              }
            }
          }
        },
        {
          "geo_distance": {
            "distance": "16090km",
            "distance_type": "arc",
            "location.point": {
              "lat": "51.794177",
              "lon": "-0.063055"
            }
          }
        }
      ]
    }
  }
}

虽然我想做以下事情(作为查询的一部分但不影响现有查询):

  • 查找所有具有field_name = 1 的文档
  • 在所有具有field_name = 1 的文档上按地理距离运行排序
  • 删除具有field_name = 1 且在field_name_2 = 2 下具有相同值的重复项,并在文档结果中保留最接近的项,但删除其余项

更新(进一步解释):

不能使用聚合,因为我们要操作结果中的文档。

同时保持文档内的顺序;意思:

如果我有 20 个文档,按字段排序;我有 5 个 field_name = 1,我想按距离对 5 个进行排序,并消除其中的 4 个;同时仍保持第一类。 (可能在实际查询之前进行地理距离排序和消除?)

不太确定如何执行此操作,感谢任何帮助 - 我目前正在使用 ElasticSearch DSL DRF - 但我可以轻松地将查询转换为 ElasticSearch DSL。

示例文档(操作前):

[{
"field_name": 1,
"field_name_2": 2,
"location": ....
},
{
"field_name": 1,
"field_name_2": 2,
"location": ....
},
{
"field_name": 55,
"field_name_5": 22,
"location": ....
}]

输出(期望):

[{
"field_name": 1,
"field_name_2": 2,
"location": .... <- closest
},
{
"field_name": 55,
"field_name_5": 22,
"location": ....
}]

【问题讨论】:

  • 所以您上面的查询返回给定点的给定距离内的所有文档,但它们不是按距离排序的......但是,我不确定您的其他条件 field_name = 1 应该如何组合使用该初始查询。你能详细解释一下as part of the query but not affecting the existing query是什么意思吗?
  • 对不起,如果我没有正确解释自己 - 所以我目前的查询按距离排序和过滤(如上面的查询所示) - 尽管我也想要一个单独的部分(因为不是所有查询都按距离排序)对所有 field_name = 1 的文档进行排序,然后只选择第一个文档(最接近的) - 即找到 field_name = 1 的最接近的文档,然后删除其余文档,但也留下那些文档没有 field_name = 1,原样。
  • 好的,因为我没有在你的查询中看到任何排序子句,所以你只是依赖默认的_score排序,对吧?
  • 是的@Val,我们只是依赖默认排序

标签: elasticsearch elasticsearch-aggregation elasticsearch-dsl


【解决方案1】:

实现您想要的一种方法是将查询部分保持原样(这样您仍然可以获得所需的命中)并添加一个聚合部分以便在@987654325 上获得带有附加条件的最接近的文档@。聚合部分将由:

聚合部分如下所示:

{
  "query": {
    ...same as you have now...
  },
  "aggs": {
    "field_name": {
      "filter": {
        "term": {
          "field_name": 1           <--- only select desired documents
        }
      },
      "aggs": {
        "geo_distance": {
          "field": "location.point",
          "unit": "km",
          "distance_type": "arc",
          "origin": {
            "lat": "51.794177",
            "lon": "-0.063055"
          },
          "ranges": [
            {
              "to": 1               <---- single bucket for docs < 1km (change as needed)
            }
          ]
        },
        "aggs": {
          "closest": {
            "top_hits": {
              "size": 1,            <---- closest document
              "sort": [
                {
                  "_geo_distance": {
                    "location.point": {
                      "lat": "51.794177",
                      "lon": "-0.063055"
                    },
                    "order": "asc",
                    "unit": "km",
                    "mode": "min",
                    "distance_type": "arc",
                    "ignore_unmapped": true
                  }
                }
              ]
            }
          }
        }
      }
    }
  }
}

【讨论】:

  • 看起来不错,谢谢@Val,请问ranges 到底是做什么的? (单桶)
  • geo_distance 聚合允许创建位于给定点的从到距离之间的文档桶(有点像同心圆)。在这里,我们只对圆中心的最小桶感兴趣。您可以根据需要调整to 的值以使其尽可能小
  • 啊酷!谢谢你的解释! :) 如果我在query 中有 geo_distance 过滤器,我需要在这里再做一次吗? - 按距离排序就够了吗?
  • 结果会不会超出正常查询结果?如果是这样,还有其他方法吗?
  • 另一种解决方案也可以是执行 2 次查询(使用 _msearch endpoint
【解决方案2】:

这可以使用Field Collapsing 来完成——这相当于分组。 - 以下是如何实现的示例:

{"collapse": {"field": "vin",
              "inner_hits": {
                  "name": "closest_dealer",
                  "size": 1,
                  "sort": [
                      {
                          "_geo_distance": {
                              "location.point": {
                                  "lat": "latitude",
                                  "lon": "longitude"
                              },
                              "order": "desc",
                              "unit": "km",
                              "distance_type": "arc",
                              "nested_path": "location"
                          }
                      }
                  ]
              }
              }
 }

折叠是在vin 字段上完成的 - 并且inner_hits 用于对分组的项目进行排序并获得最接近的项目。 (大小 = 1)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-09
    • 2016-09-20
    • 2021-10-15
    • 2015-10-06
    • 1970-01-01
    • 2020-06-24
    • 2017-03-12
    相关资源
    最近更新 更多