在弹性搜索中,如何根据位置接近度对结果进行分组? [英] In elasticsearch, how to group results by location proximity?

查看:105
本文介绍了在弹性搜索中,如何根据位置接近度对结果进行分组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一堆带有位置字段的文档,对于给定坐标给定的搜索查询,我想根据位置是否在给定坐标25英里内进行分组。然而,在每个组内,我希望结果不是按位置接近度排序。有没有什么优雅的方法呢?



举个例子,想象一下,我有以下文件:

  [
{id:1,price:13.5,coords:$ c1},
{id:2,price:10,coords:$ c2 ,
{id:3,price:15,coords:$ c3},
{id:4,price:5,coords:$ c4},
{id :5,价格:1,协调:$ c5},
]

其中$ c1,$ c2,$ c3距离$ c 25英里以内,$ c4,$ c5距离$ c 25英里远。靠近$ c的顺序是$ c3,$ c2,$ c1,$ c5,$ c4。当处理按价格从低到高的排序查询时,我想以

  [
[
{id:2,price:10,coords:$ c2},
{id:1,price:13.5,coords:$ c1},
{id:3 ,价格:15,协调:$ c3},
],
[
{id:5,价格:1,协调:$ c5},
{ 4,价格:5,协调:$ c4},
]
]


解决方案

要以这种方式对结果进行分组,您可以使用聚合(或前面的1.0),特别是地理距离聚合。这将给您计算每组中的结果数(<= 25英里,> 25英里)。然后,要检索每个组中的匹配,请使用地理距离过滤器和原始查询。



在排序中,您应该可以使用像

  {
sort:[
{price:{order:asc}}
],
query:{
。 ..
}
}

要在单个API调用中实现此目的,你可以尝试多搜索API。这是_msearch端点,将采取如下所示的方式:

  GET _msearch 
{}
{
sort:[
{
price:{
order:asc
}
}
]
query:{
filtered:{
query:{
match_all:{}
},
filter :{
geo_distance_range:{
from:0mi,
to:25mi
pin.location:{
纬度:$ c_lat,
lon:$ c_long
}
}
}
}
}
}
{}
{
sort:[
{
price:{
order:asc
}
}
],
query:{
filtered:{
query:{
match_all:{}
}
filter:{
geo_distance_range:{
from:25mi
pin.location:{
lat:$ c_lat,
lon:$ c_long
}
}
}
}
}
}

记下每个查询之前的空标题({}) 。我使用Sense来测试这一点,并且在解析失败时遇到了一些问题 - 使用Ctrl + I在发送之前对JSON进行缩进。



这将返回一个响应数组,每个查询一个 - 每个响应相当于使用与Search API相对应的查询的结果。



如果您的用例总是显示所有结果,第二种方法是适当的,并且满足单个API调用的要求。但是,如果要单独显示结果组,第一种方法可能会更有效,因为您不会检索未使用的结果。



如果此解决方案不做你需要的,请添加一些更详细的问题,我会再想一想!



链接:




I have a bunch of documents with a location field, and for a given search query with given coordinates, I would like to group results by whether their location is within 25 miles of the given coordinates. However within each group I would like the results sorted not by location proximity. Is there any elegant way to do this?

As an example, imagine I have the following documents:

[
  { id: "1", price: 13.5, coords: $c1 },
  { id: "2", price: 10, coords: $c2 },
  { id: "3", price: 15, coords: $c3 },
  { id: "4", price: 5, coords: $c4 },
  { id: "5", price: 1, coords: $c5 },
]

where $c1, $c2, $c3 are within 25 miles of $c, and $c4, $c5 are farther than 25 miles from $c. The order by proximity to $c is $c3, $c2, $c1, $c5, $c4. When handling a query of sorting by price low to high, I would like to return as

[
  [
    { id: "2", price: 10, coords: $c2 },
    { id: "1", price: 13.5, coords: $c1 },
    { id: "3", price: 15, coords: $c3 },
  ],
  [
    { id: "5", price: 1, coords: $c5 },
    { id: "4", price: 5, coords: $c4 },
  ]
]

解决方案

To group results in this way, you could use aggregations (or facets pre-1.0) - specifically the geo distance aggregation. This will give you a count of the number of results in each group ( <= 25 miles, > 25 miles). Then, to retrieve the hits within each group, use a geo distance filter together with your original query.

On the sorting, you should be able to use something like

{
    "sort" : [
        { "price" : {"order" : "asc"}}
    ],
    "query" : {
        ...
    }
}

To achieve this in a single API call, you could try the multi-search API. This is the _msearch endpoint and would take something like the following:

GET _msearch
{}
{
  "sort": [
    {
      "price": {
        "order": "asc"
      }
    }
  ],
  "query": {
    "filtered": {
      "query": {
        "match_all": {}
      },
      "filter": {
        "geo_distance_range" : {
            "from" : "0mi",
            "to" : "25mi"
            "pin.location" : {
                "lat" : $c_lat,
                "lon" : $c_long
            }
        }
      }
    }
  }
}
{}
{
  "sort": [
    {
      "price": {
        "order": "asc"
      }
    }
  ],
  "query": {
    "filtered": {
      "query": {
        "match_all": {}
      },
      "filter": {
        "geo_distance_range" : {
            "from" : "25mi"
            "pin.location" : {
                "lat" : $c_lat,
                "lon" : $c_long
            }
        }
      }
    }
  }
}

Take note of the empty headers ({}) preceding each query. I used Sense to test this out and had a few problems with parsing failures - use Ctrl+I to un-indent the JSON before sending.

This returns an array of responses, one per query - each response is equivalent to the result of using the corresponding query with the Search API.

If your use case is to always display all of the results, the second approach would be appropriate and fulfils the requirement for a single API call. However, if you want to display the result groups individually, the first approach could be more efficient, as you would not be retrieving unused results.

If this solution doesn't do what you need, please add a bit more detail to the question and I'll think again!

Links:

这篇关于在弹性搜索中,如何根据位置接近度对结果进行分组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆