聚合脚本仅适用于带有过滤器的排序查询结果,而不是完整数据集

时间:2016-07-29 21:55:29

标签: elasticsearch

FYI - elasticsearch @ v1.5; npm elasticsearch @ 4.0.2

对于我的具体用例,我需要找到五个最近的点,围绕其他点,并计算这五个结果的最大值。出于某种原因,我的下面的查询是返回所有过滤数据的最大值,而不是最近的五个。

到目前为止我的查询:

{}

我的问题是这返回了一个2.99的max_dist,但我可以从命中中清楚地看到它应该只有0.02268!

最后,还有更好的方法来计算最大距离吗?我不需要使用脚本。

见下面的结果:

    elasticsearchAPI = Meteor.npmRequire('elasticsearch');
    esClient = new elasticsearchAPI.Client({
        host: 'myHost'
    });

    var esQueryObject = {
        "index": "ma_homes",
        "size": 5,
        "body": {
            "query": {
                "filtered": {
                    "query": {
                        "match_all": {}
                    },
                    "filter": {
                        "geo_distance": {
                            "LOCATION": {
                                "lat": 42.5125339,
                                "lon": -71.06748
                            },
                            "distance": "3mi",
                            "optimize_bbox": "memory"
                        }
                    }
                }
            },
            "size": 5,
            "sort": [{
                "_geo_distance": {
                    "LOCATION": {
                        "lat": 42.5125339,
                        "lon": -71.06748
                    },
                    "order": "asc",
                    "unit": "mi",
                    "distance_type": "sloppy_arc"
                }
            }],
            "fields": ["F1_V7_2_F1TOWN"],
            "aggs": {
                "max_dist": {
                    "max": {
                        "script": "doc[\u0027LOCATION\u0027].arcDistanceInMiles(lat,lon)",
                        "params" : {
                            "lat" : 42.5125339,
                            "lon" : -71.06748
                        }
                    }
                }
            }
        }
    }



     try {
        esClient.search(esQueryObject, function(err, res) {
            if ( err ) console.log("err: ", err);
            if ( res ) {
                console.log("res: ", JSON.stringify(res, null, "\t"));
            };
        });
    }
    catch(error) {
        console.log("search err: ", error);
    };

1 个答案:

答案 0 :(得分:2)

这里有两个错误,第二个与第一个强烈相关:

  1. 您假设排序顺序对聚合有任何影响。它没有。您可能需要查看Elasticsearch: The Definitive Guide on Scoping Aggregations
    • 要点是查询的总结果,包括未返回的命中,是聚合范围的一部分。在您的确切情况下,它注意到有"total": 19428个文档与您的搜索匹配。你刚回到最近的5。
  2. 您按升序排序,这意味着它从最小到最大排序。这意味着您只能获得前5个最近的距离,这是您想要的,但这并不意味着所有聚合都被视为真正的最大值。
  3. 对于这些要点,你需要弄清楚如何限制前5名,或者根本不进行聚合,我建议这是最简单的事情。只需获得前5名,然后获取最后一个值,您就可以获得所需的两个答案。

    排序 约束到3英里范围内的距离因为3英里,这很好,但也许你可以通过更快的速度做更好的事情取决于你的需求搜索distance_type

    {
      "size": 5,
      "_source": "F1_V7_2_F1TOWN",
      "query": {
        "filtered": {
          "filter": [
            {
              "geo_distance": {
                "LOCATION": {
                  "lat": 42.5125339,
                  "lon": -71.06748
                },
                "distance": "3mi",
                "distance_type": "plane"
              }
            }
          ]
        }
      },
      "sort": [
        {
          "_geo_distance": {
            "LOCATION": {
              "lat": 42.5125339,
              "lon": -71.06748
            },
            "order": "asc",
            "unit": "mi",
            "distance_type": "sloppy_arc"
          }
        }
      ]
    }
    

    注意我没有聚合,我使用_source而不是fieldsfields用于存储字段,不限制源文档输出),我切换到使用plane作为过滤器distance_type,因为它在极点之外的距离更快;我怀疑太多的家庭将使用两极的距离。对于评分,我将其保留为sloppy_arc,因为它可以在过滤后使用稍微更精确的等式。

    我只收到5份文件,其中5份,最后一份将是最远的一份。

    作为一个重要的注意事项,ES 2.2+ increased geo performance significantly