如何根据elasticsearch中的父文档字段对嵌套聚合字段进行排序?

问题描述

我有不同地点的商店索引。对于每家商店,我都有一个嵌套的折扣券列表。

现在我有查询获取按给定位置最近的适用优惠券的距离排序的半径 x 公里内所有独特优惠券的列表

数据库 :: Elasticsearch

索引映射::

{
"mappings": {
    "car_stores": {
        "properties": {
            "location": {
                "type": "geo_point"
            },"discount_coupons": {
                "type": "nested","properties": {
                    "name": {
                        "type": "keyword"
                    }
                }
            }
        }
    }
}
}

示例文档::

{
"_index": "stores","_type": "car_stores","_id": "1258c81d-b6f2-400f-a448-bd728f524b55","_score": 1.0,"_source": {
    "location": {
        "lat": 36.053757,"lon": 139.525482
    },"discount_coupons": [
        {
            "name": "c1"
        },{
            "name": "c2"
        }
    ]
}
}

在给定位置的 x 公里区域内获取唯一折扣优惠券名称的旧查询 ::

{
"size": 0,"query": {
    "bool": {
        "must": {
            "match_all": {}
        },"filter": {
            "geo_distance": {
                "distance": "100km","location": {
                    "lat": 40,"lon": -70
                }
            }
        }
    }
},"aggs": {
    "coupon": {
        "nested": {
            "path": "discount_coupons"
        },"aggs": {
            "name": {
                "terms": {
                    "field": "discount_coupons.name","order": {
                        "_key": "asc"
                    },"size": 200
                }
            }
        }
    }
}
}

更新回复::

{
"took": 60,"timed_out": false,"_shards": {
    "total": 3,"successful": 3,"skipped": 0,"Failed": 0
},"hits": {
    "total": 245328,"max_score": 0.0,"hits": []
},"aggregations": {
    "coupon": {
        "doc_count": 657442,"name": {
            "doc_count_error_upper_bound": -1,"sum_other_doc_count": 641189,"buckets": [
                {
                    "key": "local20210211","doc_count": 1611,"back_to_base": {
                        "doc_count": 1611,"distance_script": {
                            "value": 160.61034409639765
                        }
                    }
                },{
                    "key": "local20210117","doc_count": 1621,"back_to_base": {
                        "doc_count": 1621,"distance_script": {
                            "value": 77.51459886447356
                        }
                    }
                },{
                    "key": "local20201220","doc_count": 1622,"back_to_base": {
                        "doc_count": 1622,"distance_script": {
                            "value": 84.15734462544432
                        }
                    }
                },{
                    "key": "kisekae1","doc_count": 1626,"back_to_base": {
                        "doc_count": 1626,"distance_script": {
                            "value": 88.23770888201268
                        }
                    }
                },{
                    "key": "local20210206","distance_script": {
                            "value": 86.78376012847237
                        }
                    }
                },{
                    "key": "local20210106","doc_count": 1628,"back_to_base": {
                        "doc_count": 1628,"distance_script": {
                            "value": 384.12156408078397
                        }
                    }
                },{
                    "key": "local20210113","distance_script": {
                            "value": 153.61681676703674
                        }
                    }
                },{
                    "key": "local20","doc_count": 1629,"back_to_base": {
                        "doc_count": 1629,"distance_script": {
                            "value": 168.74132991524073
                        }
                    }
                },{
                    "key": "local20210213","doc_count": 1630,"back_to_base": {
                        "doc_count": 1630,"distance_script": {
                            "value": 155.8335679860034
                        }
                    }
                },{
                    "key": "local20210208","doc_count": 1632,"back_to_base": {
                        "doc_count": 1632,"distance_script": {
                            "value": 99.58790590445102
                        }
                    }
                }
            ]
        }
    }
}
}

现在上面的查询将返回按计数排序的前 200 张优惠券认值,但我想返回根据给定位置的距离排序的优惠券,即最接近的优惠券应该先出现。

有没有办法根据父键对嵌套聚合进行排序,或者我可以使用不同的数据模型解决这个用例吗?

更新查询::

{
"size": 0,"query": {
    "bool": {
        "filter": [
            {
                "geo_distance": {
                    "distance": "100km","location": {
                        "lat": 35.699104,"lon": 139.825211
                    }
                }
            },{
                "nested": {
                    "path": "discount_coupons","query": {
                        "bool": {
                            "filter": {
                                "exists": {
                                    "field": "discount_coupons"
                                }
                            }
                        }
                    }
                }
            }
        ]
    }
},"order": {
                        "back_to_base": "asc"
                    },"size": 10
                },"aggs": {
                    "back_to_base": {
                        "reverse_nested": {},"aggs": {
                            "distance_script": {
                                "min": {
                                    "script": {
                                        "source": "doc['location'].arcdistance(35.699104,139.825211)"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
}

解决方法

有趣的问题。您始终可以通过数字子聚合的结果 order 一个 terms 聚合。这里的技巧是使用脚本通过 reverse_nested aggregationcalculate the distance 从枢轴中转义嵌套上下文:

{
  "size": 0,"query": {
    "bool": {
      "must": {
        "match_all": {}
      },"filter": {
        "geo_distance": {
          "distance": "100km","location": {
            "lat": 40,"lon": -70
          }
        }
      }
    }
  },"aggs": {
    "coupon": {
      "nested": {
        "path": "discount_coupons"
      },"aggs": {
        "name": {
          "terms": {
            "field": "discount_coupons.name","order": {
              "back_to_base": "asc"
            },"size": 200
          },"aggs": {
            "back_to_base": {
              "reverse_nested": {},"aggs": {
                "distance_script": {
                  "min": {
                    "script": {
                      "source": "doc['location'].arcDistance(40,-70)"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...